Compare commits
21 Commits
5.0
...
release-1.
Author | SHA1 | Date | |
---|---|---|---|
404b9599fd | |||
4a803e4721 | |||
2bcc81a75b | |||
0be9244ade | |||
a852d29262 | |||
7145a55f83 | |||
4f8915da6c | |||
973c4327e3 | |||
820951bce1 | |||
c8257c632a | |||
a4d69cce43 | |||
dfe2e5f44e | |||
dbdd1c83d9 | |||
2519bb96f9 | |||
f169173afa | |||
1c70b29b3d | |||
75b7ca814a | |||
b6b33862ed | |||
0dbd70ba9f | |||
7a5a1a9af7 | |||
938f222791 |
9
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
9
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -27,14 +27,7 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
label: Version of PolyMC
|
label: Version of PolyMC
|
||||||
description: The version of PolyMC used in the bug report.
|
description: The version of PolyMC used in the bug report.
|
||||||
placeholder: PolyMC 1.4.1
|
placeholder: PolyMC 1.2.2
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Version of Qt
|
|
||||||
description: The version of Qt used in the bug report. You can find it in Help -> About PolyMC -> About Qt.
|
|
||||||
placeholder: Qt 6.3.0
|
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
|
3
.github/codeql/codeql-config.yml
vendored
3
.github/codeql/codeql-config.yml
vendored
@ -1,3 +0,0 @@
|
|||||||
query-filters:
|
|
||||||
- exclude:
|
|
||||||
id: cpp/fixme-comment
|
|
2
.github/dco.yml
vendored
2
.github/dco.yml
vendored
@ -1,2 +0,0 @@
|
|||||||
allowRemediationCommits:
|
|
||||||
individual: true
|
|
19
.github/workflows/backport.yml
vendored
Normal file
19
.github/workflows/backport.yml
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
name: Backport PR to stable
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches: [ develop ]
|
||||||
|
types: [ closed ]
|
||||||
|
jobs:
|
||||||
|
release_pull_request:
|
||||||
|
if: github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'backport')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Backport PR by cherry-pick-ing
|
||||||
|
uses: Nathanmalnoury/gh-backport-action@master
|
||||||
|
with:
|
||||||
|
pr_branch: 'stable'
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
229
.github/workflows/build.yml
vendored
229
.github/workflows/build.yml
vendored
@ -7,10 +7,6 @@ on:
|
|||||||
description: Type of build (Debug, Release, RelWithDebInfo, MinSizeRel)
|
description: Type of build (Debug, Release, RelWithDebInfo, MinSizeRel)
|
||||||
type: string
|
type: string
|
||||||
default: Debug
|
default: Debug
|
||||||
secrets:
|
|
||||||
SPARKLE_ED25519_KEY:
|
|
||||||
description: Private key for signing Sparkle updates
|
|
||||||
required: false
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@ -20,39 +16,20 @@ jobs:
|
|||||||
include:
|
include:
|
||||||
|
|
||||||
- os: ubuntu-20.04
|
- os: ubuntu-20.04
|
||||||
qt_ver: 5
|
|
||||||
|
|
||||||
- os: ubuntu-20.04
|
- os: ubuntu-20.04
|
||||||
qt_ver: 6
|
appimage: true
|
||||||
qt_host: linux
|
|
||||||
qt_version: '6.2.4'
|
|
||||||
qt_modules: 'qt5compat qtimageformats'
|
|
||||||
|
|
||||||
- os: windows-2022
|
- os: windows-2022
|
||||||
name: "Windows-Legacy"
|
name: "Windows-i686"
|
||||||
msystem: mingw32
|
msystem: mingw32
|
||||||
qt_ver: 5
|
|
||||||
|
|
||||||
- os: windows-2022
|
- os: windows-2022
|
||||||
name: "Windows"
|
name: "Windows-x86_64"
|
||||||
msystem: mingw32
|
msystem: mingw64
|
||||||
qt_ver: 6
|
|
||||||
|
|
||||||
- os: macos-12
|
- os: macos-11
|
||||||
name: macOS
|
|
||||||
macosx_deployment_target: 10.15
|
|
||||||
qt_ver: 6
|
|
||||||
qt_host: mac
|
|
||||||
qt_version: '6.3.0'
|
|
||||||
qt_modules: 'qt5compat qtimageformats'
|
|
||||||
|
|
||||||
- os: macos-12
|
|
||||||
name: macOS-Legacy
|
|
||||||
macosx_deployment_target: 10.13
|
macosx_deployment_target: 10.13
|
||||||
qt_ver: 5
|
|
||||||
qt_host: mac
|
|
||||||
qt_version: '5.15.2'
|
|
||||||
qt_modules: ''
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
@ -73,14 +50,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
submodules: 'true'
|
submodules: 'true'
|
||||||
|
|
||||||
- name: Initialize CodeQL
|
|
||||||
if: runner.os == 'Linux' && matrix.qt_ver == 6
|
|
||||||
uses: github/codeql-action/init@v2
|
|
||||||
with:
|
|
||||||
config-file: ./.github/codeql/codeql-config.yml
|
|
||||||
queries: security-and-quality
|
|
||||||
languages: cpp, java
|
|
||||||
|
|
||||||
- name: 'Setup MSYS2'
|
- name: 'Setup MSYS2'
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
uses: msys2/setup-msys2@v2
|
uses: msys2/setup-msys2@v2
|
||||||
@ -92,21 +61,16 @@ jobs:
|
|||||||
pacboy: >-
|
pacboy: >-
|
||||||
toolchain:p
|
toolchain:p
|
||||||
cmake:p
|
cmake:p
|
||||||
extra-cmake-modules:p
|
|
||||||
ninja:p
|
ninja:p
|
||||||
qt${{ matrix.qt_ver }}-base:p
|
qt5:p
|
||||||
qt${{ matrix.qt_ver }}-svg:p
|
|
||||||
qt${{ matrix.qt_ver }}-imageformats:p
|
|
||||||
quazip-qt${{ matrix.qt_ver }}:p
|
|
||||||
ccache:p
|
ccache:p
|
||||||
nsis:p
|
nsis:p
|
||||||
${{ matrix.qt_ver == 6 && 'qt6-5compat:p' || '' }}
|
|
||||||
|
|
||||||
- name: Setup ccache
|
- name: Setup ccache
|
||||||
if: runner.os != 'Windows' && inputs.build_type == 'Debug'
|
if: runner.os != 'Windows' && inputs.build_type == 'Debug'
|
||||||
uses: hendrikmuhs/ccache-action@v1.2.1
|
uses: hendrikmuhs/ccache-action@v1.2.1
|
||||||
with:
|
with:
|
||||||
key: ${{ matrix.os }}-qt${{ matrix.qt_ver }}
|
key: ${{ matrix.os }}-${{ matrix.appimage }}
|
||||||
|
|
||||||
- name: Setup ccache (Windows)
|
- name: Setup ccache (Windows)
|
||||||
if: runner.os == 'Windows' && inputs.build_type == 'Debug'
|
if: runner.os == 'Windows' && inputs.build_type == 'Debug'
|
||||||
@ -129,9 +93,9 @@ jobs:
|
|||||||
uses: actions/cache@v3.0.2
|
uses: actions/cache@v3.0.2
|
||||||
with:
|
with:
|
||||||
path: '${{ github.workspace }}\.ccache'
|
path: '${{ github.workspace }}\.ccache'
|
||||||
key: ${{ matrix.os }}-qt${{ matrix.qt_ver }}
|
key: ${{ matrix.os }}-${{ matrix.msystem }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ matrix.os }}-qt${{ matrix.qt_ver }}
|
${{ matrix.os }}-${{ matrix.msystem }}
|
||||||
|
|
||||||
- name: Set short version
|
- name: Set short version
|
||||||
shell: bash
|
shell: bash
|
||||||
@ -139,36 +103,28 @@ jobs:
|
|||||||
ver_short=`git rev-parse --short HEAD`
|
ver_short=`git rev-parse --short HEAD`
|
||||||
echo "VERSION=$ver_short" >> $GITHUB_ENV
|
echo "VERSION=$ver_short" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Install Dependencies (Linux)
|
- name: Install Qt (macOS)
|
||||||
|
if: runner.os == 'macOS'
|
||||||
|
run: |
|
||||||
|
brew update
|
||||||
|
brew install qt@5 ninja
|
||||||
|
|
||||||
|
- name: Update Qt (AppImage)
|
||||||
|
if: runner.os == 'Linux' && matrix.appimage == true
|
||||||
|
run: |
|
||||||
|
sudo add-apt-repository ppa:savoury1/qt-5-15
|
||||||
|
sudo add-apt-repository ppa:savoury1/kde-5-80
|
||||||
|
sudo add-apt-repository ppa:savoury1/gpg
|
||||||
|
sudo add-apt-repository ppa:savoury1/ffmpeg4
|
||||||
|
|
||||||
|
- name: Install Qt (Linux)
|
||||||
if: runner.os == 'Linux'
|
if: runner.os == 'Linux'
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get -y update
|
sudo apt-get -y update
|
||||||
sudo apt-get -y install ninja-build extra-cmake-modules scdoc
|
sudo apt-get -y install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5 ninja-build qt5-image-formats-plugins
|
||||||
|
|
||||||
- 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 Qt (macOS and AppImage)
|
|
||||||
if: runner.os == 'Linux' && matrix.qt_ver == 6 || runner.os == 'macOS'
|
|
||||||
uses: jurplel/install-qt-action@v3
|
|
||||||
with:
|
|
||||||
version: ${{ matrix.qt_version }}
|
|
||||||
host: ${{ matrix.qt_host }}
|
|
||||||
target: 'desktop'
|
|
||||||
modules: ${{ matrix.qt_modules }}
|
|
||||||
cache: true
|
|
||||||
cache-key-prefix: ${{ matrix.qt_host }}-${{ matrix.qt_version }}-"${{ matrix.qt_modules }}"-qt_cache
|
|
||||||
|
|
||||||
- name: Prepare AppImage (Linux)
|
- name: Prepare AppImage (Linux)
|
||||||
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
if: runner.os == 'Linux' && matrix.appimage == true
|
||||||
run: |
|
run: |
|
||||||
wget "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage"
|
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-appimage/releases/download/continuous/linuxdeploy-plugin-appimage-x86_64.AppImage"
|
||||||
@ -181,25 +137,20 @@ jobs:
|
|||||||
##
|
##
|
||||||
|
|
||||||
- name: Configure CMake (macOS)
|
- name: Configure CMake (macOS)
|
||||||
if: runner.os == 'macOS' && matrix.qt_ver == 6
|
if: runner.os == 'macOS'
|
||||||
run: |
|
run: |
|
||||||
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=${{ matrix.name }} -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -G Ninja
|
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DQt5_DIR=/usr/local/opt/qt@5 -DCMAKE_PREFIX_PATH=/usr/local/opt/qt@5 -DLauncher_BUILD_PLATFORM=macOS -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -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=${{ matrix.name }} -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)
|
- name: Configure CMake (Windows)
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
shell: msys2 {0}
|
shell: msys2 {0}
|
||||||
run: |
|
run: |
|
||||||
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=${{ matrix.name }} -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -G Ninja
|
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=${{ matrix.name }} -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -G Ninja
|
||||||
|
|
||||||
- name: Configure CMake (Linux)
|
- name: Configure CMake (Linux)
|
||||||
if: runner.os == 'Linux'
|
if: runner.os == 'Linux'
|
||||||
run: |
|
run: |
|
||||||
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=Linux -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -G Ninja
|
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=Linux -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -G Ninja
|
||||||
|
|
||||||
##
|
##
|
||||||
# BUILD
|
# BUILD
|
||||||
@ -216,29 +167,6 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cmake --build ${{ env.BUILD_DIR }}
|
cmake --build ${{ env.BUILD_DIR }}
|
||||||
|
|
||||||
##
|
|
||||||
# TEST
|
|
||||||
##
|
|
||||||
|
|
||||||
- name: Test
|
|
||||||
if: runner.os != 'Windows'
|
|
||||||
run: |
|
|
||||||
ctest --test-dir build --output-on-failure
|
|
||||||
|
|
||||||
- name: Test (Windows)
|
|
||||||
if: runner.os == 'Windows'
|
|
||||||
shell: msys2 {0}
|
|
||||||
run: |
|
|
||||||
ctest --test-dir build --output-on-failure
|
|
||||||
|
|
||||||
##
|
|
||||||
# CODE SCAN
|
|
||||||
##
|
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
|
||||||
if: runner.os == 'Linux' && matrix.qt_ver == 6
|
|
||||||
uses: github/codeql-action/analyze@v2
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# PACKAGE BUILDS
|
# PACKAGE BUILDS
|
||||||
##
|
##
|
||||||
@ -249,28 +177,9 @@ jobs:
|
|||||||
cmake --install ${{ env.BUILD_DIR }}
|
cmake --install ${{ env.BUILD_DIR }}
|
||||||
|
|
||||||
cd ${{ env.INSTALL_DIR }}
|
cd ${{ env.INSTALL_DIR }}
|
||||||
chmod +x "PrismLauncher.app/Contents/MacOS/prismlauncher"
|
chmod +x "PolyMC.app/Contents/MacOS/polymc"
|
||||||
sudo codesign --sign - --deep --force --entitlements "../program_info/App.entitlements" --options runtime "PrismLauncher.app/Contents/MacOS/prismlauncher"
|
sudo codesign --sign - --deep --force --entitlements "../program_info/App.entitlements" --options runtime "PolyMC.app/Contents/MacOS/polymc"
|
||||||
tar -czf ../PrismLauncher.tar.gz *
|
tar -czf ../PolyMC.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)
|
- name: Package (Windows)
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
@ -279,8 +188,10 @@ jobs:
|
|||||||
cmake --install ${{ env.BUILD_DIR }}
|
cmake --install ${{ env.BUILD_DIR }}
|
||||||
|
|
||||||
cd ${{ env.INSTALL_DIR }}
|
cd ${{ env.INSTALL_DIR }}
|
||||||
if [ "${{ matrix.qt_ver }}" == "5" ]; then
|
if [ "${{ matrix.msystem }}" == "mingw32" ]; then
|
||||||
cp /mingw32/bin/libcrypto-1_1.dll /mingw32/bin/libssl-1_1.dll ./
|
cp /mingw32/bin/libcrypto-1_1.dll /mingw32/bin/libssl-1_1.dll ./
|
||||||
|
elif [ "${{ matrix.msystem }}" == "mingw64" ]; then
|
||||||
|
cp /mingw64/bin/libcrypto-1_1-x64.dll /mingw64/bin/libssl-1_1-x64.dll ./
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Package (Windows, portable)
|
- name: Package (Windows, portable)
|
||||||
@ -298,44 +209,38 @@ jobs:
|
|||||||
makensis -NOCD "${{ github.workspace }}/${{ env.BUILD_DIR }}/program_info/win_install.nsi"
|
makensis -NOCD "${{ github.workspace }}/${{ env.BUILD_DIR }}/program_info/win_install.nsi"
|
||||||
|
|
||||||
- name: Package (Linux)
|
- name: Package (Linux)
|
||||||
if: runner.os == 'Linux'
|
if: runner.os == 'Linux' && matrix.appimage != true
|
||||||
run: |
|
run: |
|
||||||
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_DIR }}
|
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_DIR }}
|
||||||
|
|
||||||
cd ${{ env.INSTALL_DIR }}
|
cd ${{ env.INSTALL_DIR }}
|
||||||
tar --owner root --group root -czf ../PrismLauncher.tar.gz *
|
tar --owner root --group root -czf ../PolyMC.tar.gz *
|
||||||
|
|
||||||
- name: Package (Linux, portable)
|
- name: Package (Linux, portable)
|
||||||
if: runner.os == 'Linux'
|
if: runner.os == 'Linux' && matrix.appimage != true
|
||||||
run: |
|
run: |
|
||||||
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }}
|
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }}
|
||||||
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable
|
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable
|
||||||
|
|
||||||
cd ${{ env.INSTALL_PORTABLE_DIR }}
|
cd ${{ env.INSTALL_PORTABLE_DIR }}
|
||||||
tar -czf ../PrismLauncher-portable.tar.gz *
|
tar -czf ../PolyMC-portable.tar.gz *
|
||||||
|
|
||||||
- name: Package AppImage (Linux)
|
- name: Package AppImage (Linux)
|
||||||
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
if: runner.os == 'Linux' && matrix.appimage == true
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_APPIMAGE_DIR }}/usr
|
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_APPIMAGE_DIR }}/usr
|
||||||
|
|
||||||
export OUTPUT="PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage"
|
export OUTPUT="PolyMC-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage"
|
||||||
|
|
||||||
chmod +x linuxdeploy-*.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/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/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 ${{ github.workspace }}/JREs/jre17/* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-17-openjdk
|
||||||
|
|
||||||
cp -r /home/runner/work/PrismLauncher/Qt/${{ matrix.qt_version }}/gcc_64/plugins/iconengines/* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/plugins/iconengines
|
|
||||||
|
|
||||||
cp /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/
|
|
||||||
|
|
||||||
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ 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/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-8-openjdk/lib/amd64"
|
||||||
@ -343,7 +248,7 @@ jobs:
|
|||||||
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-17-openjdk/lib"
|
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-17-openjdk/lib"
|
||||||
export LD_LIBRARY_PATH
|
export LD_LIBRARY_PATH
|
||||||
|
|
||||||
./linuxdeploy-x86_64.AppImage --appdir ${{ env.INSTALL_APPIMAGE_DIR }} --output appimage --plugin qt -i ${{ env.INSTALL_APPIMAGE_DIR }}/usr/share/icons/hicolor/scalable/apps/org.prismlauncher.PrismLauncher.svg
|
./linuxdeploy-x86_64.AppImage --appdir ${{ env.INSTALL_APPIMAGE_DIR }} --output appimage --plugin qt -i ${{ env.INSTALL_APPIMAGE_DIR }}/usr/share/icons/hicolor/scalable/apps/org.polymc.PolyMC.svg
|
||||||
|
|
||||||
##
|
##
|
||||||
# UPLOAD BUILDS
|
# UPLOAD BUILDS
|
||||||
@ -353,63 +258,49 @@ jobs:
|
|||||||
if: runner.os == 'macOS'
|
if: runner.os == 'macOS'
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
name: PolyMC-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
path: PrismLauncher.tar.gz
|
path: PolyMC.tar.gz
|
||||||
|
|
||||||
- name: Upload binary zip (Windows)
|
- name: Upload binary zip (Windows)
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
name: PolyMC-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
path: ${{ env.INSTALL_DIR }}/**
|
path: ${{ env.INSTALL_DIR }}/**
|
||||||
|
|
||||||
- name: Upload binary zip (Windows, portable)
|
- name: Upload binary zip (Windows, portable)
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ matrix.name }}-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
name: PolyMC-${{ matrix.name }}-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
path: ${{ env.INSTALL_PORTABLE_DIR }}/**
|
path: ${{ env.INSTALL_PORTABLE_DIR }}/**
|
||||||
|
|
||||||
- name: Upload installer (Windows)
|
- name: Upload installer (Windows)
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ matrix.name }}-Setup-${{ env.VERSION }}-${{ inputs.build_type }}
|
name: PolyMC-${{ matrix.name }}-Setup-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
path: PrismLauncher-Setup.exe
|
path: PolyMC-Setup.exe
|
||||||
|
|
||||||
- name: Upload binary tarball (Linux, Qt 5)
|
- name: Upload binary tarball (Linux)
|
||||||
if: runner.os == 'Linux' && matrix.qt_ver != 6
|
if: runner.os == 'Linux' && matrix.appimage != true
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
name: PolyMC-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
path: PrismLauncher.tar.gz
|
path: PolyMC.tar.gz
|
||||||
|
|
||||||
- name: Upload binary tarball (Linux, portable, Qt 5)
|
- name: Upload binary tarball (Linux, portable)
|
||||||
if: runner.os == 'Linux' && matrix.qt_ver != 6
|
if: runner.os == 'Linux' && matrix.appimage != true
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ runner.os }}-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
name: PolyMC-${{ runner.os }}-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
path: PrismLauncher-portable.tar.gz
|
path: PolyMC-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)
|
- name: Upload AppImage (Linux)
|
||||||
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
if: runner.os == 'Linux' && matrix.appimage == true
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
|
name: PolyMC-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
|
||||||
path: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
|
path: PolyMC-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
|
||||||
|
|
||||||
|
|
||||||
|
61
.github/workflows/pr-comment.yml
vendored
Normal file
61
.github/workflows/pr-comment.yml
vendored
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
name: Comment on pull request
|
||||||
|
on:
|
||||||
|
workflow_run:
|
||||||
|
workflows: ['Build Application']
|
||||||
|
types: [completed]
|
||||||
|
jobs:
|
||||||
|
pr_comment:
|
||||||
|
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/github-script@v5
|
||||||
|
with:
|
||||||
|
# This snippet is public-domain, taken from
|
||||||
|
# https://github.com/oprypin/nightly.link/blob/master/.github/workflows/pr-comment.yml
|
||||||
|
script: |
|
||||||
|
async function upsertComment(owner, repo, issue_number, purpose, body) {
|
||||||
|
const {data: comments} = await github.rest.issues.listComments(
|
||||||
|
{owner, repo, issue_number});
|
||||||
|
|
||||||
|
const marker = `<!-- bot: ${purpose} -->`;
|
||||||
|
body = marker + "\n" + body;
|
||||||
|
|
||||||
|
const existing = comments.filter((c) => c.body.includes(marker));
|
||||||
|
if (existing.length > 0) {
|
||||||
|
const last = existing[existing.length - 1];
|
||||||
|
core.info(`Updating comment ${last.id}`);
|
||||||
|
await github.rest.issues.updateComment({
|
||||||
|
owner, repo,
|
||||||
|
body,
|
||||||
|
comment_id: last.id,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
core.info(`Creating a comment in issue / PR #${issue_number}`);
|
||||||
|
await github.rest.issues.createComment({issue_number, body, owner, repo});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const {owner, repo} = context.repo;
|
||||||
|
const run_id = ${{github.event.workflow_run.id}};
|
||||||
|
|
||||||
|
const pull_requests = ${{ toJSON(github.event.workflow_run.pull_requests) }};
|
||||||
|
if (!pull_requests.length) {
|
||||||
|
return core.error("This workflow doesn't match any pull requests!");
|
||||||
|
}
|
||||||
|
|
||||||
|
const artifacts = await github.paginate(
|
||||||
|
github.rest.actions.listWorkflowRunArtifacts, {owner, repo, run_id});
|
||||||
|
if (!artifacts.length) {
|
||||||
|
return core.error(`No artifacts found`);
|
||||||
|
}
|
||||||
|
let body = `Download the artifacts for this pull request:\n`;
|
||||||
|
for (const art of artifacts) {
|
||||||
|
body += `\n* [${art.name}.zip](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
|
||||||
|
}
|
||||||
|
|
||||||
|
core.info("Review thread message body:", body);
|
||||||
|
|
||||||
|
for (const pr of pull_requests) {
|
||||||
|
await upsertComment(owner, repo, pr.number,
|
||||||
|
"nightly-link", body);
|
||||||
|
}
|
4
.github/workflows/trigger_builds.yml
vendored
4
.github/workflows/trigger_builds.yml
vendored
@ -11,7 +11,6 @@ on:
|
|||||||
- '**.nix'
|
- '**.nix'
|
||||||
- 'packages/**'
|
- 'packages/**'
|
||||||
- '.github/ISSUE_TEMPLATE/**'
|
- '.github/ISSUE_TEMPLATE/**'
|
||||||
- '.markdownlint**'
|
|
||||||
pull_request:
|
pull_request:
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '**.md'
|
- '**.md'
|
||||||
@ -20,7 +19,6 @@ on:
|
|||||||
- '**.nix'
|
- '**.nix'
|
||||||
- 'packages/**'
|
- 'packages/**'
|
||||||
- '.github/ISSUE_TEMPLATE/**'
|
- '.github/ISSUE_TEMPLATE/**'
|
||||||
- '.markdownlint**'
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@ -30,5 +28,3 @@ jobs:
|
|||||||
uses: ./.github/workflows/build.yml
|
uses: ./.github/workflows/build.yml
|
||||||
with:
|
with:
|
||||||
build_type: Debug
|
build_type: Debug
|
||||||
secrets:
|
|
||||||
SPARKLE_ED25519_KEY: ${{ secrets.SPARKLE_ED25519_KEY }}
|
|
||||||
|
55
.github/workflows/trigger_release.yml
vendored
55
.github/workflows/trigger_release.yml
vendored
@ -12,8 +12,6 @@ jobs:
|
|||||||
uses: ./.github/workflows/build.yml
|
uses: ./.github/workflows/build.yml
|
||||||
with:
|
with:
|
||||||
build_type: Release
|
build_type: Release
|
||||||
secrets:
|
|
||||||
SPARKLE_ED25519_KEY: ${{ secrets.SPARKLE_ED25519_KEY }}
|
|
||||||
|
|
||||||
create_release:
|
create_release:
|
||||||
needs: build_release
|
needs: build_release
|
||||||
@ -25,7 +23,7 @@ jobs:
|
|||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
submodules: 'true'
|
submodules: 'true'
|
||||||
path: 'PrismLauncher-source'
|
path: 'PolyMC-source'
|
||||||
- name: Download artifacts
|
- name: Download artifacts
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v3
|
||||||
- name: Grab and store version
|
- name: Grab and store version
|
||||||
@ -34,26 +32,22 @@ jobs:
|
|||||||
echo "VERSION=$tag_name" >> $GITHUB_ENV
|
echo "VERSION=$tag_name" >> $GITHUB_ENV
|
||||||
- name: Package artifacts properly
|
- name: Package artifacts properly
|
||||||
run: |
|
run: |
|
||||||
mv ${{ github.workspace }}/PrismLauncher-source PrismLauncher-${{ env.VERSION }}
|
mv ${{ github.workspace }}/PolyMC-source PolyMC-${{ env.VERSION }}
|
||||||
mv PrismLauncher-Linux-Qt6-Portable*/PrismLauncher-portable.tar.gz PrismLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz
|
mv PolyMC-Linux-Portable*/PolyMC-portable.tar.gz PolyMC-Linux-Portable-${{ env.VERSION }}.tar.gz
|
||||||
mv PrismLauncher-Linux-Qt6*/PrismLauncher.tar.gz PrismLauncher-Linux-Qt6-${{ env.VERSION }}.tar.gz
|
mv PolyMC-Linux*/PolyMC.tar.gz PolyMC-Linux-${{ env.VERSION }}.tar.gz
|
||||||
mv PrismLauncher-Linux-Portable*/PrismLauncher-portable.tar.gz PrismLauncher-Linux-Portable-${{ env.VERSION }}.tar.gz
|
mv PolyMC-*.AppImage/PolyMC-*.AppImage PolyMC-Linux-${{ env.VERSION }}-x86_64.AppImage
|
||||||
mv PrismLauncher-Linux*/PrismLauncher.tar.gz PrismLauncher-Linux-${{ env.VERSION }}.tar.gz
|
mv PolyMC-macOS*/PolyMC.tar.gz PolyMC-macOS-${{ env.VERSION }}.tar.gz
|
||||||
mv PrismLauncher-*.AppImage/PrismLauncher-*.AppImage PrismLauncher-Linux-${{ env.VERSION }}-x86_64.AppImage
|
|
||||||
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 -czf PrismLauncher-${{ env.VERSION }}.tar.gz PrismLauncher-${{ env.VERSION }}
|
tar -czf PolyMC-${{ env.VERSION }}.tar.gz PolyMC-${{ env.VERSION }}
|
||||||
|
|
||||||
for d in PrismLauncher-Windows-*; do
|
for d in PolyMC-Windows-*; do
|
||||||
cd "${d}" || continue
|
cd "${d}" || continue
|
||||||
LEGACY="$(echo -n ${d} | grep -o Legacy || true)"
|
ARCH="$(echo -n ${d} | cut -d '-' -f 3)"
|
||||||
INST="$(echo -n ${d} | grep -o Setup || true)"
|
INST="$(echo -n ${d} | grep -o Setup || true)"
|
||||||
PORT="$(echo -n ${d} | grep -o Portable || true)"
|
PORT="$(echo -n ${d} | grep -o Portable || true)"
|
||||||
NAME="PrismLauncher-Windows"
|
NAME="PolyMC-Windows-${ARCH}"
|
||||||
test -z "${LEGACY}" || NAME="${NAME}-Legacy"
|
|
||||||
test -z "${PORT}" || NAME="${NAME}-Portable"
|
test -z "${PORT}" || NAME="${NAME}-Portable"
|
||||||
test -z "${INST}" || mv PrismLauncher-*.exe ../${NAME}-Setup-${{ env.VERSION }}.exe
|
test -z "${INST}" || mv PolyMC-*.exe ../${NAME}-Setup-${{ env.VERSION }}.exe
|
||||||
test -n "${INST}" || zip -r -9 "../${NAME}-${{ env.VERSION }}.zip" *
|
test -n "${INST}" || zip -r -9 "../${NAME}-${{ env.VERSION }}.zip" *
|
||||||
cd ..
|
cd ..
|
||||||
done
|
done
|
||||||
@ -65,21 +59,18 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
tag_name: ${{ github.ref }}
|
tag_name: ${{ github.ref }}
|
||||||
name: PrismLauncher ${{ env.VERSION }}
|
name: PolyMC ${{ env.VERSION }}
|
||||||
draft: true
|
draft: true
|
||||||
prerelease: false
|
prerelease: false
|
||||||
files: |
|
files: |
|
||||||
PrismLauncher-Linux-${{ env.VERSION }}.tar.gz
|
PolyMC-Linux-${{ env.VERSION }}.tar.gz
|
||||||
PrismLauncher-Linux-Portable-${{ env.VERSION }}.tar.gz
|
PolyMC-Linux-Portable-${{ env.VERSION }}.tar.gz
|
||||||
PrismLauncher-Linux-${{ env.VERSION }}-x86_64.AppImage
|
PolyMC-Linux-${{ env.VERSION }}-x86_64.AppImage
|
||||||
PrismLauncher-Windows-Legacy-${{ env.VERSION }}.zip
|
PolyMC-Windows-i686-${{ env.VERSION }}.zip
|
||||||
PrismLauncher-Linux-Qt6-${{ env.VERSION }}.tar.gz
|
PolyMC-Windows-i686-Portable-${{ env.VERSION }}.zip
|
||||||
PrismLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz
|
PolyMC-Windows-i686-Setup-${{ env.VERSION }}.exe
|
||||||
PrismLauncher-Windows-Legacy-Portable-${{ env.VERSION }}.zip
|
PolyMC-Windows-x86_64-${{ env.VERSION }}.zip
|
||||||
PrismLauncher-Windows-Legacy-Setup-${{ env.VERSION }}.exe
|
PolyMC-Windows-x86_64-Portable-${{ env.VERSION }}.zip
|
||||||
PrismLauncher-Windows-${{ env.VERSION }}.zip
|
PolyMC-Windows-x86_64-Setup-${{ env.VERSION }}.exe
|
||||||
PrismLauncher-Windows-Portable-${{ env.VERSION }}.zip
|
PolyMC-macOS-${{ env.VERSION }}.tar.gz
|
||||||
PrismLauncher-Windows-Setup-${{ env.VERSION }}.exe
|
PolyMC-${{ env.VERSION }}.tar.gz
|
||||||
PrismLauncher-macOS-${{ env.VERSION }}.tar.gz
|
|
||||||
PrismLauncher-macOS-Legacy-${{ env.VERSION }}.tar.gz
|
|
||||||
PrismLauncher-${{ env.VERSION }}.tar.gz
|
|
||||||
|
15
.github/workflows/winget.yml
vendored
15
.github/workflows/winget.yml
vendored
@ -1,15 +0,0 @@
|
|||||||
name: Publish to WinGet
|
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types: [released]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
publish:
|
|
||||||
runs-on: windows-latest
|
|
||||||
steps:
|
|
||||||
- uses: vedantmgoyal2009/winget-releaser@v1
|
|
||||||
with:
|
|
||||||
identifier: PrismLauncher.PrismLauncher
|
|
||||||
version: ${{ github.event.release.tag_name }}
|
|
||||||
installers-regex: 'PrismLauncher-Windows-Setup-.+\.exe$'
|
|
||||||
token: ${{ secrets.WINGET_TOKEN }}
|
|
14
.gitmodules
vendored
14
.gitmodules
vendored
@ -1,12 +1,8 @@
|
|||||||
|
[submodule "depends/libnbtplusplus"]
|
||||||
|
path = libraries/libnbtplusplus
|
||||||
|
url = https://github.com/PolyMC/libnbtplusplus.git
|
||||||
|
pushurl = git@github.com:PolyMC/libnbtplusplus.git
|
||||||
|
|
||||||
[submodule "libraries/quazip"]
|
[submodule "libraries/quazip"]
|
||||||
path = libraries/quazip
|
path = libraries/quazip
|
||||||
url = https://github.com/stachenov/quazip.git
|
url = https://github.com/stachenov/quazip.git
|
||||||
[submodule "libraries/tomlplusplus"]
|
|
||||||
path = libraries/tomlplusplus
|
|
||||||
url = https://github.com/marzer/tomlplusplus.git
|
|
||||||
[submodule "libraries/filesystem"]
|
|
||||||
path = libraries/filesystem
|
|
||||||
url = https://github.com/gulrak/filesystem
|
|
||||||
[submodule "libraries/libnbtplusplus"]
|
|
||||||
path = libraries/libnbtplusplus
|
|
||||||
url = https://github.com/PrismLauncher/libnbtplusplus.git
|
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
# MD013/line-length - Line length
|
|
||||||
MD013: false
|
|
||||||
|
|
||||||
# MD024/no-duplicate-heading/no-duplicate-header - Multiple headings with the same content
|
|
||||||
MD024:
|
|
||||||
siblings-only: true
|
|
||||||
|
|
||||||
# MD033/no-inline-html Inline HTML
|
|
||||||
MD033: false
|
|
||||||
|
|
||||||
# MD041/first-line-heading/first-line-h1 First line in a file should be a top-level heading
|
|
||||||
MD041: false
|
|
@ -1,2 +0,0 @@
|
|||||||
libraries/nbtplusplus
|
|
||||||
libraries/quazip
|
|
52
BUILD.md
52
BUILD.md
@ -1,53 +1,5 @@
|
|||||||
# Build Instructions
|
# Build Instructions
|
||||||
|
|
||||||
Full build instructions will be available on [the website](https://prismlauncher.org/wiki/development/build-instructions/).
|
Build instructions are available on [the website](https://polymc.org/wiki/development/build-instructions/).
|
||||||
|
|
||||||
If you would like to contribute or fix an issue with the Build instructions you will be able to do so [here](https://github.com/PrismLauncher/website/blob/master/src/wiki/development/build-instructions.md).
|
|
||||||
|
|
||||||
## Getting the source
|
|
||||||
|
|
||||||
Clone the source code using git, and grab all the submodules. This is generic for all platforms you want to build on.
|
|
||||||
```
|
|
||||||
git clone --recursive https://github.com/PrismLauncher/PrismLauncher
|
|
||||||
cd PrismLauncher
|
|
||||||
```
|
|
||||||
|
|
||||||
## Linux
|
|
||||||
|
|
||||||
This guide will mostly mention dependant packages by their Debian naming and commands are done by a user in the sudoers file.
|
|
||||||
### Dependencies
|
|
||||||
|
|
||||||
- A C++ compiler capable of building C++17 code (can be found in the package `build-essential`).
|
|
||||||
- Qt Development tools 5.12 or newer (on Debian 11 or Debian-based distributions, `qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5`).
|
|
||||||
- `cmake` 3.15 or newer.
|
|
||||||
- `extra-cmake-modules`.
|
|
||||||
- zlib (`zlib1g-dev` on Debian 11 or Debian-based distributions).
|
|
||||||
- Java Development Kit (Java JDK) (`openjdk-17-jdk` on Debian 11 or Debian-based distributions).
|
|
||||||
- Mesa GL headers (`libgl1-mesa-dev` on Debian 11 or Debian-based distributions).
|
|
||||||
- (Optional) `scdoc` to generate man pages.
|
|
||||||
|
|
||||||
In conclusion, to check if all you need is installed (including optional):
|
|
||||||
|
|
||||||
```
|
|
||||||
sudo apt install build-essential qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5 cmake extra-cmake-modules zlib1g-dev openjdk-17-jdk libgl1-mesa-dev scdoc
|
|
||||||
```
|
|
||||||
|
|
||||||
### Compiling
|
|
||||||
#### Building and installing on the system
|
|
||||||
This is usually the suggested way to build the client.
|
|
||||||
|
|
||||||
```
|
|
||||||
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="/usr" -DENABLE_LTO=ON
|
|
||||||
cmake --build build -j$(nproc)
|
|
||||||
sudo cmake --install build
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Building a portable binary
|
|
||||||
|
|
||||||
```
|
|
||||||
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=install
|
|
||||||
cmake --build build -j$(nproc)
|
|
||||||
cmake --install build
|
|
||||||
cmake --install build --component portable
|
|
||||||
```
|
|
||||||
|
|
||||||
|
If you would like to contribute or fix an issue with the Build instructions you can do so [here](https://github.com/PolyMC/polymc.github.io/blob/master/src/wiki/development/build-instructions.md).
|
||||||
|
153
CMakeLists.txt
153
CMakeLists.txt
@ -6,12 +6,14 @@ if(WIN32)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
project(Launcher)
|
project(Launcher)
|
||||||
|
include(CTest)
|
||||||
|
|
||||||
string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BUILD_DIR}" IS_IN_SOURCE_BUILD)
|
string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BUILD_DIR}" IS_IN_SOURCE_BUILD)
|
||||||
if(IS_IN_SOURCE_BUILD)
|
if(IS_IN_SOURCE_BUILD)
|
||||||
message(FATAL_ERROR "You are building the Launcher in-source. Please separate the build tree from the source tree.")
|
message(FATAL_ERROR "You are building the Launcher in-source. Please separate the build tree from the source tree.")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
##################################### Set CMake options #####################################
|
##################################### Set CMake options #####################################
|
||||||
set(CMAKE_AUTOMOC ON)
|
set(CMAKE_AUTOMOC ON)
|
||||||
set(CMAKE_AUTORCC ON)
|
set(CMAKE_AUTORCC ON)
|
||||||
@ -29,10 +31,13 @@ set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${PROJECT_BINARY_DIR}/jars)
|
|||||||
######## Set compiler flags ########
|
######## Set compiler flags ########
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED true)
|
set(CMAKE_CXX_STANDARD_REQUIRED true)
|
||||||
set(CMAKE_C_STANDARD_REQUIRED true)
|
set(CMAKE_C_STANDARD_REQUIRED true)
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
set(CMAKE_C_STANDARD 11)
|
set(CMAKE_C_STANDARD 11)
|
||||||
include(GenerateExportHeader)
|
include(GenerateExportHeader)
|
||||||
set(CMAKE_CXX_FLAGS "-Wall -pedantic -fstack-protector-strong --param=ssp-buffer-size=4 ${CMAKE_CXX_FLAGS}")
|
set(CMAKE_CXX_FLAGS "-Wall -pedantic -Werror -Wno-deprecated-declarations -D_GLIBCXX_USE_CXX11_ABI=0 -fstack-protector-strong --param=ssp-buffer-size=4 ${CMAKE_CXX_FLAGS}")
|
||||||
|
if(UNIX AND APPLE)
|
||||||
|
set(CMAKE_CXX_FLAGS "-stdlib=libc++ ${CMAKE_CXX_FLAGS}")
|
||||||
|
endif()
|
||||||
|
|
||||||
# Fix build with Qt 5.13
|
# Fix build with Qt 5.13
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_NO_DEPRECATED_WARNINGS=Y")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_NO_DEPRECATED_WARNINGS=Y")
|
||||||
@ -58,30 +63,20 @@ if(ENABLE_LTO)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(BUILD_TESTING "Build the testing tree." ON)
|
|
||||||
|
|
||||||
find_package(ECM REQUIRED NO_MODULE)
|
|
||||||
set(CMAKE_MODULE_PATH "${ECM_MODULE_PATH};${CMAKE_MODULE_PATH}")
|
|
||||||
include(CTest)
|
|
||||||
include(ECMAddTests)
|
|
||||||
if(BUILD_TESTING)
|
|
||||||
enable_testing()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
##################################### Set Application options #####################################
|
##################################### Set Application options #####################################
|
||||||
|
|
||||||
######## Set URLs ########
|
######## Set URLs ########
|
||||||
set(Launcher_NEWS_RSS_URL "https://prismlauncher.org/feed/feed.xml" CACHE STRING "URL to fetch PrismLauncher's news RSS feed from.")
|
set(Launcher_NEWS_RSS_URL "https://polymc.org/feed/feed.xml" CACHE STRING "URL to fetch PolyMC'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://polymc.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://polymc.org/wiki/help-pages/%1" CACHE STRING "URL (with arg %1 to be substituted with page-id) that gets opened when the user requests help")
|
||||||
|
|
||||||
######## Set version numbers ########
|
######## Set version numbers ########
|
||||||
set(Launcher_VERSION_MAJOR 5)
|
set(Launcher_VERSION_MAJOR 1)
|
||||||
set(Launcher_VERSION_MINOR 0)
|
set(Launcher_VERSION_MINOR 3)
|
||||||
|
set(Launcher_VERSION_HOTFIX 2)
|
||||||
|
|
||||||
set(Launcher_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}")
|
# Build number
|
||||||
set(Launcher_VERSION_NAME4 "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.0.0")
|
set(Launcher_VERSION_BUILD -1 CACHE STRING "Build number. -1 for no build number.")
|
||||||
set(Launcher_VERSION_NAME4_COMMA "${Launcher_VERSION_MAJOR},${Launcher_VERSION_MINOR},0,0")
|
|
||||||
|
|
||||||
# Build platform.
|
# Build platform.
|
||||||
set(Launcher_BUILD_PLATFORM "" 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 "" CACHE STRING "A short string identifying the platform that this build was built for. Only used to display in the about dialog.")
|
||||||
@ -90,25 +85,27 @@ set(Launcher_BUILD_PLATFORM "" CACHE STRING "A short string identifying the plat
|
|||||||
set(Launcher_UPDATER_BASE "" CACHE STRING "Base URL for the updater.")
|
set(Launcher_UPDATER_BASE "" CACHE STRING "Base URL for the updater.")
|
||||||
|
|
||||||
# The metadata server
|
# The metadata server
|
||||||
set(Launcher_META_URL "https://meta.prismlauncher.org/v1/" CACHE STRING "URL to fetch Launcher's meta files from.")
|
set(Launcher_META_URL "https://meta.polymc.org/v1/" CACHE STRING "URL to fetch Launcher's meta files from.")
|
||||||
|
|
||||||
# Imgur API Client ID
|
# Imgur API Client ID
|
||||||
set(Launcher_IMGUR_CLIENT_ID "5b97b0713fba4a3" CACHE STRING "Client ID you can get from Imgur when you register an application")
|
set(Launcher_IMGUR_CLIENT_ID "5b97b0713fba4a3" CACHE STRING "Client ID you can get from Imgur when you register an application")
|
||||||
|
|
||||||
# Bug tracker URL
|
# Bug tracker URL
|
||||||
set(Launcher_BUG_TRACKER_URL "https://github.com/PrismLauncher/PrismLauncher/issues" CACHE STRING "URL for the bug tracker.")
|
set(Launcher_BUG_TRACKER_URL "https://github.com/PolyMC/PolyMC/issues" CACHE STRING "URL for the bug tracker.")
|
||||||
|
|
||||||
# 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/polymc/polymc/" CACHE STRING "URL for the translations platform.")
|
||||||
|
|
||||||
# Matrix Space
|
# Matrix Space
|
||||||
set(Launcher_MATRIX_URL "https://matrix.to/#/#prismlauncher:matrix.org" CACHE STRING "URL to the Matrix Space")
|
set(Launcher_MATRIX_URL "https://matrix.to/#/#polymc:matrix.org" CACHE STRING "URL to the Matrix Space")
|
||||||
|
|
||||||
# Discord URL
|
# Discord URL
|
||||||
set(Launcher_DISCORD_URL "https://discord.gg/prismlauncher" CACHE STRING "URL for the Discord guild.")
|
set(Launcher_DISCORD_URL "https://discord.gg/Z52pwxWCHP" CACHE STRING "URL for the Discord guild.")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Subreddit URL
|
# Subreddit URL
|
||||||
set(Launcher_SUBREDDIT_URL "https://www.reddit.com/r/PrismLauncher/" CACHE STRING "URL for the subreddit.")
|
set(Launcher_SUBREDDIT_URL "https://www.reddit.com/r/PolyMCLauncher/" CACHE STRING "URL for the subreddit.")
|
||||||
|
|
||||||
# Builds
|
# Builds
|
||||||
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")
|
||||||
@ -123,31 +120,34 @@ set(Launcher_QT_VERSION_MAJOR "5" CACHE STRING "Major Qt version to build agains
|
|||||||
|
|
||||||
# By using this key in your builds you accept the terms of use laid down in
|
# By using this key in your builds you accept the terms of use laid down in
|
||||||
# https://docs.microsoft.com/en-us/legal/microsoft-identity-platform/terms-of-use
|
# https://docs.microsoft.com/en-us/legal/microsoft-identity-platform/terms-of-use
|
||||||
set(Launcher_MSA_CLIENT_ID "c36a9fb6-4f2a-41ff-90bd-ae7cc92031eb" CACHE STRING "Client ID you can get from Microsoft Identity Platform when you register an application")
|
set(Launcher_MSA_CLIENT_ID "549033b2-1532-4d4e-ae77-1bbaa46f9d74" CACHE STRING "Client ID you can get from Microsoft Identity Platform when you register an application")
|
||||||
|
|
||||||
# By using this key in your builds you accept the terms and conditions laid down in
|
# By using this key in your builds you accept the terms and conditions laid down in
|
||||||
# https://support.curseforge.com/en/support/solutions/articles/9000207405-curse-forge-3rd-party-api-terms-and-conditions
|
# https://support.curseforge.com/en/support/solutions/articles/9000207405-curse-forge-3rd-party-api-terms-and-conditions
|
||||||
# NOTE: CurseForge requires you to change this if you make any kind of derivative work.
|
# NOTE: CurseForge requires you to change this if you make any kind of derivative work.
|
||||||
# This key was issued specifically for Prism Launcher
|
set(Launcher_CURSEFORGE_API_KEY "$2a$10$1Oqr2MX3O4n/ilhFGc597u8tfI3L2Hyr9/rtWDAMRjghSQV2QUuxq" CACHE STRING "CurseForge API Key")
|
||||||
set(Launcher_CURSEFORGE_API_KEY "$2a$10$wuAJuNZuted3NORVmpgUC.m8sI.pv1tOPKZyBgLFGjxFp/br0lZCC" CACHE STRING "API key for the CurseForge platform")
|
|
||||||
|
|
||||||
|
|
||||||
#### Check the current Git commit and branch
|
#### Check the current Git commit and branch
|
||||||
include(GetGitRevisionDescription)
|
include(GetGitRevisionDescription)
|
||||||
git_get_exact_tag(Launcher_GIT_TAG)
|
|
||||||
get_git_head_revision(Launcher_GIT_REFSPEC Launcher_GIT_COMMIT)
|
get_git_head_revision(Launcher_GIT_REFSPEC Launcher_GIT_COMMIT)
|
||||||
|
|
||||||
message(STATUS "Git commit: ${Launcher_GIT_COMMIT}")
|
message(STATUS "Git commit: ${Launcher_GIT_COMMIT}")
|
||||||
message(STATUS "Git tag: ${Launcher_GIT_TAG}")
|
|
||||||
message(STATUS "Git refspec: ${Launcher_GIT_REFSPEC}")
|
message(STATUS "Git refspec: ${Launcher_GIT_REFSPEC}")
|
||||||
|
|
||||||
|
set(Launcher_RELEASE_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_HOTFIX}")
|
||||||
|
set(Launcher_RELEASE_VERSION_NAME4 "${Launcher_RELEASE_VERSION_NAME}.0")
|
||||||
|
set(Launcher_RELEASE_VERSION_NAME4_COMMA "${Launcher_VERSION_MAJOR},${Launcher_VERSION_MINOR},${Launcher_VERSION_HOTFIX},0")
|
||||||
string(TIMESTAMP TODAY "%Y-%m-%d")
|
string(TIMESTAMP TODAY "%Y-%m-%d")
|
||||||
set(Launcher_BUILD_TIMESTAMP "${TODAY}")
|
set(Launcher_RELEASE_TIMESTAMP "${TODAY}")
|
||||||
|
|
||||||
|
#### Custom target to just print the version.
|
||||||
|
add_custom_target(version echo "Version: ${Launcher_RELEASE_VERSION_NAME}")
|
||||||
|
add_custom_target(tcversion echo "\\#\\#teamcity[setParameter name=\\'env.LAUNCHER_VERSION\\' value=\\'${Launcher_RELEASE_VERSION_NAME}\\']")
|
||||||
|
|
||||||
################################ 3rd Party Libs ################################
|
################################ 3rd Party Libs ################################
|
||||||
|
|
||||||
# Find the required Qt parts
|
# Find the required Qt parts
|
||||||
include(QtVersionlessBackport)
|
|
||||||
if(Launcher_QT_VERSION_MAJOR EQUAL 5)
|
if(Launcher_QT_VERSION_MAJOR EQUAL 5)
|
||||||
set(QT_VERSION_MAJOR 5)
|
set(QT_VERSION_MAJOR 5)
|
||||||
find_package(Qt5 REQUIRED COMPONENTS Core Widgets Concurrent Network Test Xml)
|
find_package(Qt5 REQUIRED COMPONENTS Core Widgets Concurrent Network Test Xml)
|
||||||
@ -159,48 +159,26 @@ if(Launcher_QT_VERSION_MAJOR EQUAL 5)
|
|||||||
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(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)
|
set(FORCE_BUNDLED_QUAZIP 1)
|
||||||
endif()
|
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)
|
|
||||||
find_package(Qt6 REQUIRED COMPONENTS Core Widgets Concurrent Network Test Xml Core5Compat)
|
|
||||||
list(APPEND Launcher_QT_LIBS Qt6::Core5Compat)
|
|
||||||
|
|
||||||
if(NOT Launcher_FORCE_BUNDLED_LIBS)
|
|
||||||
find_package(QuaZip-Qt6 1.3 QUIET)
|
|
||||||
endif()
|
|
||||||
if (NOT QuaZip-Qt6_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()
|
|
||||||
else()
|
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()
|
||||||
|
|
||||||
include(ECMQueryQt)
|
# The Qt5 cmake files don't provide its install paths, so ask qmake.
|
||||||
ecm_query_qt(QT_PLUGINS_DIR QT_INSTALL_PLUGINS)
|
include(QMakeQuery)
|
||||||
ecm_query_qt(QT_LIBS_DIR QT_INSTALL_LIBS)
|
query_qmake(QT_INSTALL_PLUGINS QT_PLUGINS_DIR)
|
||||||
ecm_query_qt(QT_LIBEXECS_DIR QT_INSTALL_LIBEXECS)
|
query_qmake(QT_INSTALL_IMPORTS QT_IMPORTS_DIR)
|
||||||
ecm_query_qt(QT_DATA_DIR QT_HOST_DATA)
|
query_qmake(QT_INSTALL_LIBS QT_LIBS_DIR)
|
||||||
|
query_qmake(QT_INSTALL_LIBEXECS QT_LIBEXECS_DIR)
|
||||||
|
query_qmake(QT_HOST_DATA QT_DATA_DIR)
|
||||||
set(QT_MKSPECS_DIR ${QT_DATA_DIR}/mkspecs)
|
set(QT_MKSPECS_DIR ${QT_DATA_DIR}/mkspecs)
|
||||||
|
|
||||||
# NOTE: Qt 6 already sets this by default
|
|
||||||
if (Qt5_POSITION_INDEPENDENT_CODE)
|
if (Qt5_POSITION_INDEPENDENT_CODE)
|
||||||
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT Launcher_FORCE_BUNDLED_LIBS)
|
|
||||||
# Find toml++
|
|
||||||
find_package(tomlplusplus 3.2.0 QUIET)
|
|
||||||
|
|
||||||
# Find ghc_filesystem
|
|
||||||
find_package(ghc_filesystem QUIET)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
####################################### Program Info #######################################
|
####################################### Program Info #######################################
|
||||||
|
|
||||||
set(Launcher_APP_BINARY_NAME "prismlauncher" CACHE STRING "Name of the Launcher binary")
|
set(Launcher_APP_BINARY_NAME "polymc" CACHE STRING "Name of the Launcher binary")
|
||||||
add_subdirectory(program_info)
|
add_subdirectory(program_info)
|
||||||
|
|
||||||
####################################### Install layout #######################################
|
####################################### Install layout #######################################
|
||||||
@ -214,7 +192,6 @@ if(UNIX AND APPLE)
|
|||||||
set(BINARY_DEST_DIR "${Launcher_Name}.app/Contents/MacOS")
|
set(BINARY_DEST_DIR "${Launcher_Name}.app/Contents/MacOS")
|
||||||
set(LIBRARY_DEST_DIR "${Launcher_Name}.app/Contents/MacOS")
|
set(LIBRARY_DEST_DIR "${Launcher_Name}.app/Contents/MacOS")
|
||||||
set(PLUGIN_DEST_DIR "${Launcher_Name}.app/Contents/MacOS")
|
set(PLUGIN_DEST_DIR "${Launcher_Name}.app/Contents/MacOS")
|
||||||
set(FRAMEWORK_DEST_DIR "${Launcher_Name}.app/Contents/Frameworks")
|
|
||||||
set(RESOURCES_DEST_DIR "${Launcher_Name}.app/Contents/Resources")
|
set(RESOURCES_DEST_DIR "${Launcher_Name}.app/Contents/Resources")
|
||||||
set(JARS_DEST_DIR "${Launcher_Name}.app/Contents/MacOS/jars")
|
set(JARS_DEST_DIR "${Launcher_Name}.app/Contents/MacOS/jars")
|
||||||
|
|
||||||
@ -224,21 +201,15 @@ if(UNIX AND APPLE)
|
|||||||
# Mac bundle settings
|
# Mac bundle settings
|
||||||
set(MACOSX_BUNDLE_BUNDLE_NAME "${Launcher_Name}")
|
set(MACOSX_BUNDLE_BUNDLE_NAME "${Launcher_Name}")
|
||||||
set(MACOSX_BUNDLE_INFO_STRING "${Launcher_Name}: A custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once.")
|
set(MACOSX_BUNDLE_INFO_STRING "${Launcher_Name}: A custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once.")
|
||||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER "org.prismlauncher.${Launcher_Name}")
|
set(MACOSX_BUNDLE_GUI_IDENTIFIER "org.polymc.${Launcher_Name}")
|
||||||
set(MACOSX_BUNDLE_BUNDLE_VERSION "${Launcher_VERSION_NAME}")
|
set(MACOSX_BUNDLE_BUNDLE_VERSION "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_HOTFIX}")
|
||||||
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${Launcher_VERSION_NAME}")
|
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_HOTFIX}")
|
||||||
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${Launcher_VERSION_NAME}")
|
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_HOTFIX}")
|
||||||
set(MACOSX_BUNDLE_ICON_FILE ${Launcher_Name}.icns)
|
set(MACOSX_BUNDLE_ICON_FILE ${Launcher_Name}.icns)
|
||||||
set(MACOSX_BUNDLE_COPYRIGHT "Copyright 2021-2022 ${Launcher_Copyright}")
|
set(MACOSX_BUNDLE_COPYRIGHT "Copyright 2021-2022 ${Launcher_Copyright}")
|
||||||
set(MACOSX_SPARKLE_UPDATE_PUBLIC_KEY "v55ZWWD6QlPoXGV6VLzOTZxZUggWeE51X8cRQyQh6vA=")
|
|
||||||
set(MACOSX_SPARKLE_UPDATE_FEED_URL "https://prismlauncher.org/feed/appcast.xml")
|
|
||||||
|
|
||||||
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 "bf6ac1caa9f8d321d5784859c88da874f28412f37fb327bc21b7b14c5d61ef94" CACHE STRING "SHA256 checksum for Sparkle release archive")
|
|
||||||
set(MACOSX_SPARKLE_DIR "${CMAKE_BINARY_DIR}/frameworks/Sparkle")
|
|
||||||
|
|
||||||
# directories to look for dependencies
|
# directories to look for dependencies
|
||||||
set(DIRS ${QT_LIBS_DIR} ${QT_LIBEXECS_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${MACOSX_SPARKLE_DIR})
|
set(DIRS ${QT_LIBS_DIR} ${QT_LIBEXECS_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
|
||||||
|
|
||||||
# install as bundle
|
# install as bundle
|
||||||
set(INSTALL_BUNDLE "full")
|
set(INSTALL_BUNDLE "full")
|
||||||
@ -261,13 +232,13 @@ elseif(UNIX)
|
|||||||
# Set RPATH
|
# Set RPATH
|
||||||
SET(Launcher_BINARY_RPATH "$ORIGIN/")
|
SET(Launcher_BINARY_RPATH "$ORIGIN/")
|
||||||
|
|
||||||
|
# jars path is determined on runtime, relative to "Application root path", generally /usr or the root of the portable bundle
|
||||||
|
set(Launcher_APP_BINARY_DEFS "-DLAUNCHER_JARS_LOCATION=${JARS_DEST_DIR}")
|
||||||
|
|
||||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_Desktop} DESTINATION ${LAUNCHER_DESKTOP_DEST_DIR})
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_Desktop} DESTINATION ${LAUNCHER_DESKTOP_DEST_DIR})
|
||||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_MetaInfo} DESTINATION ${LAUNCHER_METAINFO_DEST_DIR})
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_MetaInfo} DESTINATION ${LAUNCHER_METAINFO_DEST_DIR})
|
||||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_SVG} DESTINATION ${LAUNCHER_ICON_DEST_DIR})
|
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_SVG} DESTINATION ${LAUNCHER_ICON_DEST_DIR})
|
||||||
|
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_ManPage} DESTINATION ${LAUNCHER_MAN_DEST_DIR} RENAME "${Launcher_APP_BINARY_NAME}.6")
|
||||||
if(Launcher_ManPage)
|
|
||||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_ManPage} DESTINATION ${LAUNCHER_MAN_DEST_DIR})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Install basic runner script if component "portable" is selected
|
# Install basic runner script if component "portable" is selected
|
||||||
configure_file(launcher/Launcher.in "${CMAKE_CURRENT_BINARY_DIR}/LauncherScript" @ONLY)
|
configure_file(launcher/Launcher.in "${CMAKE_CURRENT_BINARY_DIR}/LauncherScript" @ONLY)
|
||||||
@ -306,6 +277,7 @@ add_subdirectory(libraries/systeminfo) # system information library
|
|||||||
add_subdirectory(libraries/hoedown) # markdown parser
|
add_subdirectory(libraries/hoedown) # markdown parser
|
||||||
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/xz-embedded) # xz compression
|
||||||
if (FORCE_BUNDLED_QUAZIP)
|
if (FORCE_BUNDLED_QUAZIP)
|
||||||
message(STATUS "Using bundled QuaZip")
|
message(STATUS "Using bundled QuaZip")
|
||||||
set(BUILD_SHARED_LIBS 0) # link statically to avoid conflicts.
|
set(BUILD_SHARED_LIBS 0) # link statically to avoid conflicts.
|
||||||
@ -315,31 +287,16 @@ else()
|
|||||||
message(STATUS "Using system QuaZip")
|
message(STATUS "Using system QuaZip")
|
||||||
endif()
|
endif()
|
||||||
add_subdirectory(libraries/rainbow) # Qt extension for colors
|
add_subdirectory(libraries/rainbow) # Qt extension for colors
|
||||||
|
add_subdirectory(libraries/iconfix) # fork of Qt's QIcon loader
|
||||||
add_subdirectory(libraries/LocalPeer) # fork of a library from Qt solutions
|
add_subdirectory(libraries/LocalPeer) # fork of a library from Qt solutions
|
||||||
if(NOT tomlplusplus_FOUND)
|
add_subdirectory(libraries/classparser) # class parser library
|
||||||
message(STATUS "Using bundled tomlplusplus")
|
add_subdirectory(libraries/optional-bare)
|
||||||
add_subdirectory(libraries/tomlplusplus) # toml parser
|
add_subdirectory(libraries/tomlc99) # toml parser
|
||||||
else()
|
|
||||||
message(STATUS "Using system tomlplusplus")
|
|
||||||
endif()
|
|
||||||
add_subdirectory(libraries/katabasis) # An OAuth2 library that tried to do too much
|
add_subdirectory(libraries/katabasis) # An OAuth2 library that tried to do too much
|
||||||
add_subdirectory(libraries/gamemode)
|
|
||||||
add_subdirectory(libraries/murmur2) # Hash for usage with the CurseForge API
|
|
||||||
if (NOT ghc_filesystem_FOUND)
|
|
||||||
message(STATUS "Using bundled ghc_filesystem")
|
|
||||||
set(GHC_FILESYSTEM_WITH_INSTALL OFF) # Workaround ghc::filesystem bug
|
|
||||||
add_subdirectory(libraries/filesystem) # Implementation of std::filesystem for old C++, for usage in old macOS
|
|
||||||
add_library(ghcFilesystem::ghc_filesystem ALIAS ghc_filesystem)
|
|
||||||
else()
|
|
||||||
message(STATUS "Using system ghc_filesystem")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
############################### Built Artifacts ###############################
|
############################### Built Artifacts ###############################
|
||||||
|
|
||||||
add_subdirectory(buildconfig)
|
add_subdirectory(buildconfig)
|
||||||
|
|
||||||
if(BUILD_TESTING)
|
|
||||||
add_subdirectory(tests)
|
|
||||||
endif()
|
|
||||||
# NOTE: this must always be last to appease the CMake deity of quirky install command evaluation order.
|
# NOTE: this must always be last to appease the CMake deity of quirky install command evaluation order.
|
||||||
add_subdirectory(launcher)
|
add_subdirectory(launcher)
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
# Contributor Covenant Code of Conduct
|
# Contributor Covenant Code of Conduct
|
||||||
|
|
||||||
This is a modified version of the Contributor Covenant.
|
This is a modified version of the Contributor Covenant.
|
||||||
See commit history to see our changes.
|
See commit history to see our changes.
|
||||||
|
|
||||||
@ -63,7 +62,7 @@ representative at an online or offline event.
|
|||||||
|
|
||||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
reported to the community leaders responsible for enforcement via email at
|
reported to the community leaders responsible for enforcement via email at
|
||||||
[coc@scrumplex.net](mailto:coc@scrumplex.net) (Email
|
[polymc-enforcement@scrumplex.net](mailto:polymc-enforcement@scrumplex.net) (Email
|
||||||
address subject to change).
|
address subject to change).
|
||||||
All complaints will be reviewed and investigated promptly and fairly.
|
All complaints will be reviewed and investigated promptly and fairly.
|
||||||
|
|
||||||
@ -134,3 +133,4 @@ For answers to common questions about this code of conduct, see the FAQ at
|
|||||||
[Mozilla CoC]: https://github.com/mozilla/diversity
|
[Mozilla CoC]: https://github.com/mozilla/diversity
|
||||||
[FAQ]: https://www.contributor-covenant.org/faq
|
[FAQ]: https://www.contributor-covenant.org/faq
|
||||||
[translations]: https://www.contributor-covenant.org/translations
|
[translations]: https://www.contributor-covenant.org/translations
|
||||||
|
|
||||||
|
@ -1,63 +0,0 @@
|
|||||||
# Contributions Guidelines
|
|
||||||
|
|
||||||
## Code formatting
|
|
||||||
|
|
||||||
Try to follow the existing formatting.
|
|
||||||
If there is no existing formatting, you may use `clang-format` with our included `.clang-format` configuration.
|
|
||||||
|
|
||||||
In general, in order of importance:
|
|
||||||
|
|
||||||
- Make sure your IDE is not messing up line endings or whitespace and avoid using linters.
|
|
||||||
- Prefer readability over dogma.
|
|
||||||
- Keep to the existing formatting.
|
|
||||||
- Indent with 4 space unless it's in a submodule.
|
|
||||||
- Keep lists (of arguments, parameters, initializers...) as lists, not paragraphs. It should either read from top to bottom, or left to right. Not both.
|
|
||||||
|
|
||||||
## Signing your work
|
|
||||||
|
|
||||||
In an effort to ensure that the code you contribute is actually compatible with the licenses in this codebase, we require you to sign-off all your contributions.
|
|
||||||
|
|
||||||
This can be done by appending `-s` to your `git commit` call, or by manually appending the following text to your commit message:
|
|
||||||
|
|
||||||
```
|
|
||||||
<commit message>
|
|
||||||
|
|
||||||
Signed-off-by: Author name <Author email>
|
|
||||||
```
|
|
||||||
|
|
||||||
By signing off your work, you agree to the terms below:
|
|
||||||
|
|
||||||
```
|
|
||||||
Developer's Certificate of Origin 1.1
|
|
||||||
|
|
||||||
By making a contribution to this project, I certify that:
|
|
||||||
|
|
||||||
(a) The contribution was created in whole or in part by me and I
|
|
||||||
have the right to submit it under the open source license
|
|
||||||
indicated in the file; or
|
|
||||||
|
|
||||||
(b) The contribution is based upon previous work that, to the best
|
|
||||||
of my knowledge, is covered under an appropriate open source
|
|
||||||
license and I have the right under that license to submit that
|
|
||||||
work with modifications, whether created in whole or in part
|
|
||||||
by me, under the same open source license (unless I am
|
|
||||||
permitted to submit under a different license), as indicated
|
|
||||||
in the file; or
|
|
||||||
|
|
||||||
(c) The contribution was provided directly to me by some other
|
|
||||||
person who certified (a), (b) or (c) and I have not modified
|
|
||||||
it.
|
|
||||||
|
|
||||||
(d) I understand and agree that this project and the contribution
|
|
||||||
are public and that a record of the contribution (including all
|
|
||||||
personal information I submit with it, including my sign-off) is
|
|
||||||
maintained indefinitely and may be redistributed consistent with
|
|
||||||
this project or the open source license(s) involved.
|
|
||||||
```
|
|
||||||
|
|
||||||
These terms will be enforced once you create a pull request, and you will be informed automatically if any of your commits aren't signed-off by you.
|
|
||||||
|
|
||||||
As a bonus, you can also [cryptographically sign your commits][gh-signing-commits] and enable [vigilant mode][gh-vigilant-mode] on GitHub.
|
|
||||||
|
|
||||||
[gh-signing-commits]: https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits
|
|
||||||
[gh-vigilant-mode]: https://docs.github.com/en/authentication/managing-commit-signature-verification/displaying-verification-statuses-for-all-of-your-commits
|
|
374
COPYING.md
374
COPYING.md
@ -1,121 +1,64 @@
|
|||||||
## Prism Launcher
|
# PolyMC
|
||||||
|
|
||||||
Prism Launcher - Minecraft Launcher
|
Copyright (C) 2012-2021 MultiMC Contributors
|
||||||
Copyright (C) 2022 Prism Launcher Contributors
|
Copyright (C) 2021-2022 PolyMC 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
|
||||||
the Free Software Foundation, version 3.
|
the Free Software Foundation, version 3.
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
This file incorporates work covered by the following copyright and
|
# Launcher (https://github.com/MultiMC/Launcher)
|
||||||
permission notice:
|
Copyright 2012-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
|
||||||
|
|
||||||
Copyright 2013-2021 MultiMC Contributors
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Unless required by applicable law or agreed to in writing, software
|
||||||
you may not use this file except in compliance with the License.
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
You may obtain a copy of the License at
|
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.
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
# MinGW runtime (Windows)
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
Copyright (c) 2012 MinGW.org project
|
||||||
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.
|
|
||||||
|
|
||||||
## PolyMC
|
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:
|
||||||
|
|
||||||
PolyMC - Minecraft Launcher
|
The above copyright notice, this permission notice and the below disclaimer
|
||||||
Copyright (C) 2021-2022 PolyMC Contributors
|
shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
it under the terms of the GNU General Public License as published by
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
the Free Software Foundation, version 3.
|
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.
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
# Qt 5
|
||||||
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
|
Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
Contact: http://www.qt-project.org/legal
|
||||||
|
|
||||||
This file incorporates work covered by the following copyright and
|
Licensed under LGPL v2.1
|
||||||
permission notice:
|
|
||||||
|
|
||||||
Copyright 2013-2021 MultiMC Contributors
|
# libnbt++
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
## MinGW-w64 runtime (Windows)
|
|
||||||
|
|
||||||
Copyright (c) 2009, 2010, 2011, 2012, 2013 by the mingw-w64 project
|
|
||||||
|
|
||||||
This license has been certified as open source. It has also been designated
|
|
||||||
as GPL compatible by the Free Software Foundation (FSF).
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions in source code must retain the accompanying copyright
|
|
||||||
notice, this list of conditions, and the following disclaimer.
|
|
||||||
2. Redistributions in binary form must reproduce the accompanying
|
|
||||||
copyright notice, this list of conditions, and the following disclaimer
|
|
||||||
in the documentation and/or other materials provided with the
|
|
||||||
distribution.
|
|
||||||
3. Names of the copyright holders must not be used to endorse or promote
|
|
||||||
products derived from this software without prior written permission
|
|
||||||
from the copyright holders.
|
|
||||||
4. The right to distribute this software or to use it for any purpose does
|
|
||||||
not give you the right to use Servicemarks (sm) or Trademarks (tm) of
|
|
||||||
the copyright holders. Use of them is covered by separate agreement
|
|
||||||
with the copyright holders.
|
|
||||||
5. If any files are modified, you must cause the modified files to carry
|
|
||||||
prominent notices stating that you changed the files and the date of
|
|
||||||
any change.
|
|
||||||
|
|
||||||
Disclaimer
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED
|
|
||||||
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 HOLDERS 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.
|
|
||||||
|
|
||||||
Information on third party licenses used in MinGW-w64 can be found in its COPYING.MinGW-w64-runtime.txt.
|
|
||||||
|
|
||||||
## Qt 5/6
|
|
||||||
|
|
||||||
Copyright (C) 2022 The Qt Company Ltd and other contributors.
|
|
||||||
Contact: https://www.qt.io/licensing
|
|
||||||
|
|
||||||
Licensed under LGPL v3
|
|
||||||
|
|
||||||
## libnbt++
|
|
||||||
|
|
||||||
libnbt++ - A library for the Minecraft Named Binary Tag format.
|
libnbt++ - A library for the Minecraft Named Binary Tag format.
|
||||||
Copyright (C) 2013, 2015 ljfa-ag
|
Copyright (C) 2013, 2015 ljfa-ag
|
||||||
@ -133,7 +76,7 @@
|
|||||||
You should have received a copy of the GNU Lesser General Public License
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
along with libnbt++. If not, see <http://www.gnu.org/licenses/>.
|
along with libnbt++. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
## rainbow (KGuiAddons)
|
# rainbow (KGuiAddons)
|
||||||
|
|
||||||
Copyright (C) 2007 Matthew Woehlke <mw_triad@users.sourceforge.net>
|
Copyright (C) 2007 Matthew Woehlke <mw_triad@users.sourceforge.net>
|
||||||
Copyright (C) 2007 Olaf Schmidt <ojschmidt@kde.org>
|
Copyright (C) 2007 Olaf Schmidt <ojschmidt@kde.org>
|
||||||
@ -156,7 +99,7 @@
|
|||||||
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
Boston, MA 02110-1301, USA.
|
Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
## Hoedown
|
# Hoedown
|
||||||
|
|
||||||
Copyright (c) 2008, Natacha Porté
|
Copyright (c) 2008, Natacha Porté
|
||||||
Copyright (c) 2011, Vicent Martí
|
Copyright (c) 2011, Vicent Martí
|
||||||
@ -174,7 +117,7 @@
|
|||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
## Batch icon set
|
# Batch icon set
|
||||||
|
|
||||||
You are free to use Batch (the "icon set") or any part thereof (the "icons")
|
You are free to use Batch (the "icon set") or any part thereof (the "icons")
|
||||||
in any personal, open-source or commercial work without obligation of payment
|
in any personal, open-source or commercial work without obligation of payment
|
||||||
@ -190,7 +133,7 @@
|
|||||||
PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THE USE OF THE ICONS,
|
PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THE USE OF THE ICONS,
|
||||||
EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
## Material Design Icons
|
# Material Design Icons
|
||||||
|
|
||||||
Copyright (c) 2014, Austin Andrews (http://materialdesignicons.com/),
|
Copyright (c) 2014, Austin Andrews (http://materialdesignicons.com/),
|
||||||
with Reserved Font Name Material Design Icons.
|
with Reserved Font Name Material Design Icons.
|
||||||
@ -201,82 +144,76 @@
|
|||||||
This license is copied below, and is also available with a FAQ at:
|
This license is copied below, and is also available with a FAQ at:
|
||||||
http://scripts.sil.org/OFL
|
http://scripts.sil.org/OFL
|
||||||
|
|
||||||
## Quazip
|
# Quazip
|
||||||
|
|
||||||
Copyright (C) 2005-2021 Sergey A. Tachenov
|
Copyright (C) 2005-2011 Sergey A. Tachenov
|
||||||
|
|
||||||
The QuaZip library is licensed under the GNU Lesser General Public
|
This program is free software; you can redistribute it and/or modify it
|
||||||
License V2.1 plus a static linking exception.
|
under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
your option) any later version.
|
||||||
|
|
||||||
The original ZIP/UNZIP package (MiniZip) is copyrighted by Gilles
|
This program is distributed in the hope that it will be useful, but
|
||||||
Vollant and contributors, see quazip/(un)zip.h files for details.
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
Basically it's the zlib license.
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
|
||||||
|
General Public License for more details.
|
||||||
|
|
||||||
STATIC LINKING EXCEPTION
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program; if not, write to the Free Software Foundation,
|
||||||
The copyright holders give you permission to link this library with
|
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
independent modules to produce an executable, regardless of the license
|
|
||||||
terms of these independent modules, and to copy and distribute the
|
|
||||||
resulting executable under terms of your choice, provided that you also
|
|
||||||
meet, for each linked independent module, the terms and conditions of
|
|
||||||
the license of that module. An independent module is a module which is
|
|
||||||
not derived from or based on this library. If you modify this library,
|
|
||||||
you must extend this exception to your version of the library.
|
|
||||||
|
|
||||||
See COPYING file for the full LGPL text.
|
See COPYING file for the full LGPL text.
|
||||||
|
|
||||||
## launcher (`libraries/launcher`)
|
Original ZIP package is copyrighted by Gilles Vollant, see
|
||||||
|
quazip/(un)zip.h files for details, basically it's zlib license.
|
||||||
|
|
||||||
PolyMC - Minecraft Launcher
|
# xz-minidec
|
||||||
Copyright (C) 2021-2022 PolyMC Contributors
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
XZ decompressor
|
||||||
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,
|
Authors: Lasse Collin <lasse.collin@tukaani.org>
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
Igor Pavlov <http://7-zip.org/>
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
Linking this library statically or dynamically with other modules is
|
This file has been put into the public domain.
|
||||||
making a combined work based on this library. Thus, the terms and
|
You can do whatever you want with this file.
|
||||||
conditions of the GNU General Public License cover the whole
|
|
||||||
combination.
|
|
||||||
|
|
||||||
As a special exception, the copyright holders of this library give
|
# ColumnResizer
|
||||||
you permission to link this library with independent modules to
|
|
||||||
produce an executable, regardless of the license terms of these
|
|
||||||
independent modules, and to copy and distribute the resulting
|
|
||||||
executable under terms of your choice, provided that you also meet,
|
|
||||||
for each linked independent module, the terms and conditions of the
|
|
||||||
license of that module. An independent module is a module which is
|
|
||||||
not derived from or based on this library. If you modify this
|
|
||||||
library, you may extend this exception to your version of the
|
|
||||||
library, but you are not obliged to do so. If you do not wish to do
|
|
||||||
so, delete this exception statement from your version.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
Copyright (c) 2011-2016 Aurélien Gâteau and contributors.
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
This file incorporates work covered by the following copyright and
|
All rights reserved.
|
||||||
permission notice:
|
|
||||||
|
|
||||||
Copyright 2013-2021 MultiMC Contributors
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted (subject to the limitations in the
|
||||||
|
disclaimer below) provided that the following conditions are met:
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
* Redistributions of source code must retain the above copyright
|
||||||
you may not use this file except in compliance with the License.
|
notice, this list of conditions and the following disclaimer.
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
* 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.
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
* The name of the contributors may not be used to endorse or
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
promote products derived from this software without specific prior
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
written permission.
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
||||||
## lionshead
|
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
|
||||||
|
GRANTED BY THIS LICENSE. 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 OWNER 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.
|
||||||
|
|
||||||
|
# lionshead
|
||||||
|
|
||||||
Code has been taken from https://github.com/natefoo/lionshead and loosely
|
Code has been taken from https://github.com/natefoo/lionshead and loosely
|
||||||
translated to C++ laced with Qt.
|
translated to C++ laced with Qt.
|
||||||
@ -303,26 +240,60 @@
|
|||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
|
|
||||||
## tomlplusplus
|
# optional-bare
|
||||||
|
|
||||||
|
Code from https://github.com/martinmoene/optional-bare/
|
||||||
|
|
||||||
|
Boost Software License - Version 1.0 - August 17th, 2003
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person or organization
|
||||||
|
obtaining a copy of the software and accompanying documentation covered by
|
||||||
|
this license (the "Software") to use, reproduce, display, distribute,
|
||||||
|
execute, and transmit the Software, and to prepare derivative works of the
|
||||||
|
Software, and to permit third-parties to whom the Software is furnished to
|
||||||
|
do so, all subject to the following:
|
||||||
|
|
||||||
|
The copyright notices in the Software and this entire statement, including
|
||||||
|
the above license grant, this restriction and the following disclaimer,
|
||||||
|
must be included in all copies of the Software, in whole or in part, and
|
||||||
|
all derivative works of the Software, unless such copies or derivative
|
||||||
|
works are solely in the form of machine-executable object code generated by
|
||||||
|
a source language processor.
|
||||||
|
|
||||||
|
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||||
|
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||||
|
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
# tomlc99
|
||||||
|
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
|
Copyright (c) 2017 CK Tan
|
||||||
|
https://github.com/cktan/tomlc99
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
|
in the Software without restriction, including without limitation the rights
|
||||||
permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
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
|
The above copyright notice and this permission notice shall be included in all
|
||||||
Software.
|
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
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
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.
|
||||||
|
|
||||||
## O2 (Katabasis fork)
|
# O2 (Katabasis fork)
|
||||||
|
|
||||||
Copyright (c) 2012, Akos Polster
|
Copyright (c) 2012, Akos Polster
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
@ -347,54 +318,3 @@
|
|||||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
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
|
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.
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
## Gamemode
|
|
||||||
|
|
||||||
Copyright (c) 2017-2022, Feral Interactive
|
|
||||||
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.
|
|
||||||
* Neither the name of Feral Interactive nor the names of its contributors
|
|
||||||
may be used to endorse or promote products derived from this software
|
|
||||||
without specific prior written permission.
|
|
||||||
|
|
||||||
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 OWNER 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.
|
|
||||||
|
|
||||||
## 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.
|
|
||||||
|
87
README.md
87
README.md
@ -1,29 +1,92 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="./program_info/org.prismlauncher.PrismLauncher.logo.svg#gh-light-mode-only" alt="Prism Launcher logo" width="50%"/>
|
<img src="./program_info/polymc-header-black.svg#gh-light-mode-only" alt="PolyMC logo"/>
|
||||||
<img src="./program_info/org.prismlauncher.PrismLauncher.logo-darkmode.svg#gh-dark-mode-only" alt="Prism Launcher logo" width="50%"/>
|
<img src="./program_info/polymc-header.svg#gh-dark-mode-only" alt="PolyMC logo"/>
|
||||||
</p>
|
</p>
|
||||||
|
<br>
|
||||||
|
|
||||||
Prism Launcher is a custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once.
|
PolyMC is a custom launcher for Minecraft that focuses on predictability, long term stability and simplicity.
|
||||||
|
|
||||||
We are working on a website and other media, for more info we have a [Discord server](https://discord.gg/prismlauncher).
|
This is a **fork** of the MultiMC Launcher and not endorsed by MultiMC.
|
||||||
|
If you want to read about why this fork was created, check out [our FAQ page](https://polymc.org/wiki/overview/faq/).
|
||||||
|
<br>
|
||||||
|
|
||||||
## Installation
|
# Installation
|
||||||
|
|
||||||
- All downloads and instructions for Prism Launcher will soon be available.
|
- All downloads and instructions for PolyMC can be found [here](https://polymc.org/download/)
|
||||||
- Last build status can be found [here](https://github.com/PrismLauncher/PrismLauncher/actions).
|
- Last build status: https://github.com/PolyMC/PolyMC/actions
|
||||||
|
|
||||||
### Development Builds
|
|
||||||
|
|
||||||
There are development builds available [here](https://github.com/PrismLauncher/PrismLauncher/actions). These have debug information in the binaries, so their file sizes are relatively larger.
|
## Development Builds
|
||||||
|
|
||||||
|
There are per-commit development builds available [here](https://github.com/PolyMC/PolyMC/actions). These have debug information in the binaries, so their file sizes are relatively larger.
|
||||||
Portable builds are provided for AppImage on Linux, Windows, and macOS.
|
Portable builds are provided for AppImage on Linux, Windows, and macOS.
|
||||||
|
|
||||||
## Help & Support
|
For Debian and Arch, you can use these packages for the latest development versions:
|
||||||
|
[](https://aur.archlinux.org/packages/polymc-git/)
|
||||||
|
[](https://mpr.makedeb.org/packages/polymc-git)
|
||||||
|
For flatpak, you can use [flathub-beta](https://discourse.flathub.org/t/how-to-use-flathub-beta/2111)
|
||||||
|
|
||||||
|
# Help & Support
|
||||||
|
|
||||||
[](https://discord.gg/hX4g537UNE)
|
Feel free to create an issue if you need help. However, you might find it easier to ask in the Discord server.
|
||||||
|
|
||||||
|
[](https://discord.gg/xq7fxrgtMP)
|
||||||
|
|
||||||
## License
|
For people who don't want to use Discord, we have a Matrix Space which is bridged to the Discord server:
|
||||||
|
|
||||||
|
[](https://matrix.to/#/#polymc:matrix.org)
|
||||||
|
|
||||||
|
If there are any issues with the space or you are using a client that does not support the feature here are the individual rooms:
|
||||||
|
|
||||||
|
[](https://matrix.to/#/#polymc-development:matrix.org)
|
||||||
|
[](https://matrix.to/#/#polymc-discussion:matrix.org)
|
||||||
|
[](https://matrix.to/#/#polymc-github:matrix.org)
|
||||||
|
[](https://matrix.to/#/#polymc-maintainers:matrix.org)
|
||||||
|
[](https://matrix.to/#/#polymc-news:matrix.org)
|
||||||
|
[](https://matrix.to/#/#polymc-offtopic:matrix.org)
|
||||||
|
[](https://matrix.to/#/#polymc-support:matrix.org)
|
||||||
|
[](https://matrix.to/#/#polymc-voice:matrix.org)
|
||||||
|
|
||||||
|
we also have a subreddit you can post your issues and suggestions on:
|
||||||
|
|
||||||
|
[r/PolyMCLauncher](https://www.reddit.com/r/PolyMCLauncher/)
|
||||||
|
|
||||||
|
# Development
|
||||||
|
|
||||||
|
If you want to contribute to PolyMC you might find it useful to join our Discord Server or Matrix Space.
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
If you want to build PolyMC yourself, check [Build Instructions](https://polymc.org/wiki/development/build-instructions/) for build instructions.
|
||||||
|
|
||||||
|
## Code formatting
|
||||||
|
|
||||||
|
Just follow the existing formatting.
|
||||||
|
|
||||||
|
In general, in order of importance:
|
||||||
|
|
||||||
|
- Make sure your IDE is not messing up line endings or whitespace and avoid using linters.
|
||||||
|
- Prefer readability over dogma.
|
||||||
|
- Keep to the existing formatting.
|
||||||
|
- Indent with 4 space unless it's in a submodule.
|
||||||
|
- Keep lists (of arguments, parameters, initializers...) as lists, not paragraphs. It should either read from top to bottom, or left to right. Not both.
|
||||||
|
|
||||||
|
## Translations
|
||||||
|
|
||||||
|
The translation effort for PolyMC is hosted on [Weblate](https://hosted.weblate.org/projects/polymc/polymc/) and information about translating PolyMC is available at https://github.com/PolyMC/Translations
|
||||||
|
|
||||||
|
## Download information
|
||||||
|
To modify download information or change packaging information send a pull request or issue to the website [Here](https://github.com/PolyMC/polymc.github.io/blob/master/src/download.md)
|
||||||
|
|
||||||
|
## Forking/Redistributing/Custom builds policy
|
||||||
|
|
||||||
|
Do whatever you want, we don't care. Just follow the license. If you have any questions about this feel free to ask in an issue.
|
||||||
|
|
||||||
|
Be aware that if you build this software without removing the provided API keys in [CMakeLists.txt](CMakeLists.txt) you are accepting the following terms and conditions:
|
||||||
|
- [Microsoft Identity Platform Terms of Use](https://docs.microsoft.com/en-us/legal/microsoft-identity-platform/terms-of-use)
|
||||||
|
- [CurseForge 3rd Party API Terms and Conditions](https://support.curseforge.com/en/support/solutions/articles/9000207405-curse-forge-3rd-party-api-terms-and-conditions)
|
||||||
|
If you do not agree with these terms and conditions, then remove the associated API keys from the [CMakeLists.txt](CMakeLists.txt) file.
|
||||||
|
|
||||||
All launcher code is available under the GPL-3.0-only license.
|
All launcher code is available under the GPL-3.0-only license.
|
||||||
|
|
||||||
|
The logo and related assets are under the CC BY-SA 4.0 license.
|
||||||
|
@ -55,36 +55,23 @@ 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_HOTFIX = @Launcher_VERSION_HOTFIX@;
|
||||||
|
VERSION_BUILD = @Launcher_VERSION_BUILD@;
|
||||||
|
|
||||||
BUILD_PLATFORM = "@Launcher_BUILD_PLATFORM@";
|
BUILD_PLATFORM = "@Launcher_BUILD_PLATFORM@";
|
||||||
BUILD_DATE = "@Launcher_BUILD_TIMESTAMP@";
|
|
||||||
UPDATER_BASE = "@Launcher_UPDATER_BASE@";
|
UPDATER_BASE = "@Launcher_UPDATER_BASE@";
|
||||||
|
|
||||||
MAC_SPARKLE_PUB_KEY = "@MACOSX_SPARKLE_UPDATE_PUBLIC_KEY@";
|
|
||||||
MAC_SPARKLE_APPCAST_URL = "@MACOSX_SPARKLE_UPDATE_FEED_URL@";
|
|
||||||
|
|
||||||
if (BUILD_PLATFORM == "macOS" && !MAC_SPARKLE_PUB_KEY.isEmpty() && !MAC_SPARKLE_APPCAST_URL.isEmpty())
|
|
||||||
{
|
|
||||||
UPDATER_ENABLED = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
GIT_COMMIT = "@Launcher_GIT_COMMIT@";
|
GIT_COMMIT = "@Launcher_GIT_COMMIT@";
|
||||||
GIT_TAG = "@Launcher_GIT_TAG@";
|
|
||||||
GIT_REFSPEC = "@Launcher_GIT_REFSPEC@";
|
GIT_REFSPEC = "@Launcher_GIT_REFSPEC@";
|
||||||
|
if (GIT_REFSPEC == QStringLiteral("GITDIR-NOTFOUND"))
|
||||||
// Assume that builds outside of Git repos are "stable"
|
|
||||||
if (GIT_REFSPEC == QStringLiteral("GITDIR-NOTFOUND")
|
|
||||||
|| GIT_TAG == QStringLiteral("GITDIR-NOTFOUND"))
|
|
||||||
{
|
{
|
||||||
GIT_REFSPEC = "refs/heads/stable";
|
VERSION_CHANNEL = QStringLiteral("stable");
|
||||||
GIT_TAG = versionString();
|
|
||||||
}
|
}
|
||||||
|
else if(GIT_REFSPEC.startsWith("refs/heads/"))
|
||||||
if (GIT_REFSPEC.startsWith("refs/heads/"))
|
|
||||||
{
|
{
|
||||||
VERSION_CHANNEL = GIT_REFSPEC;
|
VERSION_CHANNEL = GIT_REFSPEC;
|
||||||
VERSION_CHANNEL.remove("refs/heads/");
|
VERSION_CHANNEL.remove("refs/heads/");
|
||||||
if(!UPDATER_BASE.isEmpty() && !BUILD_PLATFORM.isEmpty()) {
|
if(!UPDATER_BASE.isEmpty() && !BUILD_PLATFORM.isEmpty() && VERSION_BUILD >= 0) {
|
||||||
UPDATER_ENABLED = true;
|
UPDATER_ENABLED = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,15 +81,16 @@ Config::Config()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
VERSION_CHANNEL = "unknown";
|
VERSION_CHANNEL = QObject::tr("unknown");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VERSION_STR = "@Launcher_VERSION_STRING@";
|
||||||
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@";
|
||||||
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@";
|
CURSEFORGE_API_KEY = "@Launcher_CURSEFORGE_API_KEY@";
|
||||||
META_URL = "@Launcher_META_URL@";
|
META_URL = "@Launcher_META_URL@";
|
||||||
|
|
||||||
BUG_TRACKER_URL = "@Launcher_BUG_TRACKER_URL@";
|
BUG_TRACKER_URL = "@Launcher_BUG_TRACKER_URL@";
|
||||||
@ -112,19 +100,20 @@ Config::Config()
|
|||||||
SUBREDDIT_URL = "@Launcher_SUBREDDIT_URL@";
|
SUBREDDIT_URL = "@Launcher_SUBREDDIT_URL@";
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Config::versionString() const
|
|
||||||
{
|
|
||||||
return QString("%1.%2").arg(VERSION_MAJOR).arg(VERSION_MINOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Config::printableVersionString() const
|
QString Config::printableVersionString() const
|
||||||
{
|
{
|
||||||
QString vstr = versionString();
|
QString vstr = QString("%1.%2.%3").arg(QString::number(VERSION_MAJOR), QString::number(VERSION_MINOR), QString::number(VERSION_HOTFIX));
|
||||||
|
|
||||||
// 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")
|
||||||
{
|
{
|
||||||
vstr += "-" + VERSION_CHANNEL;
|
vstr += "-" + VERSION_CHANNEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if a build number is set, also add it to the end
|
||||||
|
if(VERSION_BUILD >= 0)
|
||||||
|
{
|
||||||
|
vstr += "-" + QString::number(VERSION_BUILD);
|
||||||
|
}
|
||||||
return vstr;
|
return vstr;
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,10 @@ class Config {
|
|||||||
int VERSION_MAJOR;
|
int VERSION_MAJOR;
|
||||||
/// The minor version number.
|
/// The minor version number.
|
||||||
int VERSION_MINOR;
|
int VERSION_MINOR;
|
||||||
|
/// The hotfix number.
|
||||||
|
int VERSION_HOTFIX;
|
||||||
|
/// The build number.
|
||||||
|
int VERSION_BUILD;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The version channel
|
* The version channel
|
||||||
@ -67,18 +71,9 @@ class Config {
|
|||||||
/// A short string identifying this build's platform. For example, "lin64" or "win32".
|
/// A short string identifying this build's platform. For example, "lin64" or "win32".
|
||||||
QString BUILD_PLATFORM;
|
QString BUILD_PLATFORM;
|
||||||
|
|
||||||
/// A string containing the build timestamp
|
|
||||||
QString BUILD_DATE;
|
|
||||||
|
|
||||||
/// URL for the updater's channel
|
/// URL for the updater's channel
|
||||||
QString UPDATER_BASE;
|
QString UPDATER_BASE;
|
||||||
|
|
||||||
/// The public key used to sign releases for the Sparkle updater appcast
|
|
||||||
QString MAC_SPARKLE_PUB_KEY;
|
|
||||||
|
|
||||||
/// URL for the Sparkle updater's appcast
|
|
||||||
QString MAC_SPARKLE_APPCAST_URL;
|
|
||||||
|
|
||||||
/// User-Agent to use.
|
/// User-Agent to use.
|
||||||
QString USER_AGENT;
|
QString USER_AGENT;
|
||||||
|
|
||||||
@ -88,12 +83,12 @@ class Config {
|
|||||||
/// The git commit hash of this build
|
/// The git commit hash of this build
|
||||||
QString GIT_COMMIT;
|
QString GIT_COMMIT;
|
||||||
|
|
||||||
/// The git tag of this build
|
|
||||||
QString GIT_TAG;
|
|
||||||
|
|
||||||
/// The git refspec of this build
|
/// The git refspec of this build
|
||||||
QString GIT_REFSPEC;
|
QString GIT_REFSPEC;
|
||||||
|
|
||||||
|
/// This is printed on start to standard output
|
||||||
|
QString VERSION_STR;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is used to fetch the news RSS feed.
|
* This is used to fetch the news RSS feed.
|
||||||
* It defaults in CMakeLists.txt to "https://multimc.org/rss.xml"
|
* It defaults in CMakeLists.txt to "https://multimc.org/rss.xml"
|
||||||
@ -123,7 +118,7 @@ class Config {
|
|||||||
/**
|
/**
|
||||||
* Client API key for CurseForge
|
* Client API key for CurseForge
|
||||||
*/
|
*/
|
||||||
QString FLAME_API_KEY;
|
QString CURSEFORGE_API_KEY;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Metadata repository URL prefix
|
* Metadata repository URL prefix
|
||||||
@ -140,8 +135,8 @@ class Config {
|
|||||||
QString LIBRARY_BASE = "https://libraries.minecraft.net/";
|
QString LIBRARY_BASE = "https://libraries.minecraft.net/";
|
||||||
QString AUTH_BASE = "https://authserver.mojang.com/";
|
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 = "https://files.prismlauncher.org/fmllibs/"; // FIXME: move into CMakeLists
|
QString FMLLIBS_BASE_URL = "https://files.polymc.org/fmllibs/";
|
||||||
QString TRANSLATIONS_BASE_URL = "https://i18n.prismlauncher.org/"; // FIXME: move into CMakeLists
|
QString TRANSLATIONS_BASE_URL = "https://i18n.polymc.org/";
|
||||||
|
|
||||||
QString MODPACKSCH_API_BASE_URL = "https://api.modpacks.ch/";
|
QString MODPACKSCH_API_BASE_URL = "https://api.modpacks.ch/";
|
||||||
|
|
||||||
@ -159,7 +154,6 @@ class Config {
|
|||||||
QString MODRINTH_STAGING_URL = "https://staging-api.modrinth.com/v2";
|
QString MODRINTH_STAGING_URL = "https://staging-api.modrinth.com/v2";
|
||||||
QString MODRINTH_PROD_URL = "https://api.modrinth.com/v2";
|
QString MODRINTH_PROD_URL = "https://api.modrinth.com/v2";
|
||||||
|
|
||||||
QString versionString() const;
|
|
||||||
/**
|
/**
|
||||||
* \brief Converts the Version to a string.
|
* \brief Converts the Version to a string.
|
||||||
* \return The version number in string format (major.minor.revision.build).
|
* \return The version number in string format (major.minor.revision.build).
|
||||||
|
@ -7,5 +7,5 @@ add_library(BuildConfig STATIC
|
|||||||
${CMAKE_CURRENT_BINARY_DIR}/BuildConfig.cpp
|
${CMAKE_CURRENT_BINARY_DIR}/BuildConfig.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(BuildConfig Qt${QT_VERSION_MAJOR}::Core)
|
target_link_libraries(BuildConfig Qt5::Core)
|
||||||
target_include_directories(BuildConfig PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
|
target_include_directories(BuildConfig PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
|
@ -1,100 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: 2014 Rohan Garg <rohan16garg@gmail.com>
|
|
||||||
# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org>
|
|
||||||
# SPDX-FileCopyrightText: 2014-2016 Aleix Pol <aleixpol@kde.org>
|
|
||||||
# SPDX-FileCopyrightText: 2017 Friedrich W. H. Kossebau <kossebau@kde.org>
|
|
||||||
# SPDX-FileCopyrightText: 2022 Ahmad Samir <a.samir78@gmail.com>
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: BSD-3-Clause
|
|
||||||
#[=======================================================================[.rst:
|
|
||||||
ECMQueryQt
|
|
||||||
---------------
|
|
||||||
This module can be used to query the installation paths used by Qt.
|
|
||||||
|
|
||||||
For Qt5 this uses ``qmake``, and for Qt6 this used ``qtpaths`` (the latter has built-in
|
|
||||||
support to query the paths of a target platform when cross-compiling).
|
|
||||||
|
|
||||||
This module defines the following function:
|
|
||||||
::
|
|
||||||
|
|
||||||
ecm_query_qt(<result_variable> <qt_variable> [TRY])
|
|
||||||
|
|
||||||
Passing ``TRY`` will result in the method not making the build fail if the executable
|
|
||||||
used for querying has not been found, but instead simply print a warning message and
|
|
||||||
return an empty string.
|
|
||||||
|
|
||||||
Example usage:
|
|
||||||
|
|
||||||
.. code-block:: cmake
|
|
||||||
|
|
||||||
include(ECMQueryQt)
|
|
||||||
ecm_query_qt(bin_dir QT_INSTALL_BINS)
|
|
||||||
|
|
||||||
If the call succeeds ``${bin_dir}`` will be set to ``<prefix>/path/to/bin/dir`` (e.g.
|
|
||||||
``/usr/lib64/qt/bin/``).
|
|
||||||
|
|
||||||
Since: 5.93
|
|
||||||
#]=======================================================================]
|
|
||||||
|
|
||||||
include(${CMAKE_CURRENT_LIST_DIR}/QtVersionOption.cmake)
|
|
||||||
include(CheckLanguage)
|
|
||||||
check_language(CXX)
|
|
||||||
if (CMAKE_CXX_COMPILER)
|
|
||||||
# Enable the CXX language to let CMake look for config files in library dirs.
|
|
||||||
# See: https://gitlab.kitware.com/cmake/cmake/-/issues/23266
|
|
||||||
enable_language(CXX)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (QT_MAJOR_VERSION STREQUAL "5")
|
|
||||||
# QUIET to accommodate the TRY option
|
|
||||||
find_package(Qt${QT_MAJOR_VERSION}Core QUIET)
|
|
||||||
if(TARGET Qt5::qmake)
|
|
||||||
get_target_property(_qmake_executable_default Qt5::qmake LOCATION)
|
|
||||||
|
|
||||||
set(QUERY_EXECUTABLE ${_qmake_executable_default}
|
|
||||||
CACHE FILEPATH "Location of the Qt5 qmake executable")
|
|
||||||
set(_exec_name_text "Qt5 qmake")
|
|
||||||
set(_cli_option "-query")
|
|
||||||
endif()
|
|
||||||
elseif(QT_MAJOR_VERSION STREQUAL "6")
|
|
||||||
# QUIET to accommodate the TRY option
|
|
||||||
find_package(Qt6 COMPONENTS CoreTools QUIET CONFIG)
|
|
||||||
if (TARGET Qt6::qtpaths)
|
|
||||||
get_target_property(_qtpaths_executable Qt6::qtpaths LOCATION)
|
|
||||||
|
|
||||||
set(QUERY_EXECUTABLE ${_qtpaths_executable}
|
|
||||||
CACHE FILEPATH "Location of the Qt6 qtpaths executable")
|
|
||||||
set(_exec_name_text "Qt6 qtpaths")
|
|
||||||
set(_cli_option "--query")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
function(ecm_query_qt result_variable qt_variable)
|
|
||||||
set(options TRY)
|
|
||||||
set(oneValueArgs)
|
|
||||||
set(multiValueArgs)
|
|
||||||
|
|
||||||
cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
|
||||||
|
|
||||||
if(NOT QUERY_EXECUTABLE)
|
|
||||||
if(ARGS_TRY)
|
|
||||||
set(${result_variable} "" PARENT_SCOPE)
|
|
||||||
message(STATUS "No ${_exec_name_text} executable found. Can't check ${qt_variable}")
|
|
||||||
return()
|
|
||||||
else()
|
|
||||||
message(FATAL_ERROR "No ${_exec_name_text} executable found. Can't check ${qt_variable} as required")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
execute_process(
|
|
||||||
COMMAND ${QUERY_EXECUTABLE} ${_cli_option} "${qt_variable}"
|
|
||||||
RESULT_VARIABLE return_code
|
|
||||||
OUTPUT_VARIABLE output
|
|
||||||
)
|
|
||||||
if(return_code EQUAL 0)
|
|
||||||
string(STRIP "${output}" output)
|
|
||||||
file(TO_CMAKE_PATH "${output}" output_path)
|
|
||||||
set(${result_variable} "${output_path}" PARENT_SCOPE)
|
|
||||||
else()
|
|
||||||
message(WARNING "Failed call: ${_command} \"${qt_variable}\"")
|
|
||||||
message(FATAL_ERROR "${_exec_name_text} call failed: ${return_code}")
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
@ -3,7 +3,7 @@
|
|||||||
# These functions force a re-configure on each git commit so that you can
|
# These functions force a re-configure on each git commit so that you can
|
||||||
# trust the values of the variables in your build system.
|
# trust the values of the variables in your build system.
|
||||||
#
|
#
|
||||||
# get_git_head_revision(<refspecvar> <hashvar> [ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR])
|
# get_git_head_revision(<refspecvar> <hashvar> [<additional arguments to git describe> ...])
|
||||||
#
|
#
|
||||||
# Returns the refspec and sha hash of the current head revision
|
# Returns the refspec and sha hash of the current head revision
|
||||||
#
|
#
|
||||||
@ -12,33 +12,20 @@
|
|||||||
# Returns the results of git describe on the source tree, and adjusting
|
# Returns the results of git describe on the source tree, and adjusting
|
||||||
# the output so that it tests false if an error occurs.
|
# the output so that it tests false if an error occurs.
|
||||||
#
|
#
|
||||||
# git_describe_working_tree(<var> [<additional arguments to git describe> ...])
|
|
||||||
#
|
|
||||||
# Returns the results of git describe on the working tree (--dirty option),
|
|
||||||
# and adjusting the output so that it tests false if an error occurs.
|
|
||||||
#
|
|
||||||
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
|
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
|
||||||
#
|
#
|
||||||
# Returns the results of git describe --exact-match on the source tree,
|
# Returns the results of git describe --exact-match on the source tree,
|
||||||
# and adjusting the output so that it tests false if there was no exact
|
# and adjusting the output so that it tests false if there was no exact
|
||||||
# matching tag.
|
# matching tag.
|
||||||
#
|
#
|
||||||
# git_local_changes(<var>)
|
|
||||||
#
|
|
||||||
# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes.
|
|
||||||
# Uses the return code of "git diff-index --quiet HEAD --".
|
|
||||||
# Does not regard untracked files.
|
|
||||||
#
|
|
||||||
# Requires CMake 2.6 or newer (uses the 'function' command)
|
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||||
#
|
#
|
||||||
# Original Author:
|
# Original Author:
|
||||||
# 2009-2020 Ryan Pavlik <ryan.pavlik@gmail.com> <abiryan@ryand.net>
|
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
||||||
# http://academic.cleardefinition.com
|
# http://academic.cleardefinition.com
|
||||||
|
# Iowa State University HCI Graduate Program/VRAC
|
||||||
#
|
#
|
||||||
# Copyright 2009-2013, Iowa State University.
|
# Copyright Iowa State University 2009-2010.
|
||||||
# Copyright 2013-2020, Ryan Pavlik
|
|
||||||
# Copyright 2013-2020, Contributors
|
|
||||||
# SPDX-License-Identifier: BSL-1.0
|
|
||||||
# Distributed under the Boost Software License, Version 1.0.
|
# Distributed under the Boost Software License, Version 1.0.
|
||||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
# http://www.boost.org/LICENSE_1_0.txt)
|
# http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@ -52,124 +39,45 @@ set(__get_git_revision_description YES)
|
|||||||
# to find the path to this module rather than the path to a calling list file
|
# to find the path to this module rather than the path to a calling list file
|
||||||
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
|
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
|
||||||
|
|
||||||
# Function _git_find_closest_git_dir finds the next closest .git directory
|
function(get_git_head_revision _refspecvar _hashvar)
|
||||||
# that is part of any directory in the path defined by _start_dir.
|
set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
# The result is returned in the parent scope variable whose name is passed
|
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
|
||||||
# as variable _git_dir_var. If no .git directory can be found, the
|
while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories
|
||||||
# function returns an empty string via _git_dir_var.
|
set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}")
|
||||||
#
|
get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH)
|
||||||
# Example: Given a path C:/bla/foo/bar and assuming C:/bla/.git exists and
|
if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT)
|
||||||
# neither foo nor bar contain a file/directory .git. This wil return
|
|
||||||
# C:/bla/.git
|
|
||||||
#
|
|
||||||
function(_git_find_closest_git_dir _start_dir _git_dir_var)
|
|
||||||
set(cur_dir "${_start_dir}")
|
|
||||||
set(git_dir "${_start_dir}/.git")
|
|
||||||
while(NOT EXISTS "${git_dir}")
|
|
||||||
# .git dir not found, search parent directories
|
|
||||||
set(git_previous_parent "${cur_dir}")
|
|
||||||
get_filename_component(cur_dir "${cur_dir}" DIRECTORY)
|
|
||||||
if(cur_dir STREQUAL git_previous_parent)
|
|
||||||
# We have reached the root directory, we are not in git
|
# We have reached the root directory, we are not in git
|
||||||
set(${_git_dir_var}
|
set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
|
||||||
""
|
set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
|
||||||
PARENT_SCOPE)
|
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
set(git_dir "${cur_dir}/.git")
|
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
|
||||||
endwhile()
|
endwhile()
|
||||||
set(${_git_dir_var}
|
# check if this is a submodule
|
||||||
"${git_dir}"
|
|
||||||
PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(get_git_head_revision _refspecvar _hashvar)
|
|
||||||
_git_find_closest_git_dir("${CMAKE_CURRENT_SOURCE_DIR}" GIT_DIR)
|
|
||||||
|
|
||||||
if("${ARGN}" STREQUAL "ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR")
|
|
||||||
set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR TRUE)
|
|
||||||
else()
|
|
||||||
set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR FALSE)
|
|
||||||
endif()
|
|
||||||
if(NOT "${GIT_DIR}" STREQUAL "")
|
|
||||||
file(RELATIVE_PATH _relative_to_source_dir "${CMAKE_SOURCE_DIR}"
|
|
||||||
"${GIT_DIR}")
|
|
||||||
if("${_relative_to_source_dir}" MATCHES "[.][.]" AND NOT ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR)
|
|
||||||
# We've gone above the CMake root dir.
|
|
||||||
set(GIT_DIR "")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
if("${GIT_DIR}" STREQUAL "")
|
|
||||||
set(${_refspecvar}
|
|
||||||
"GITDIR-NOTFOUND"
|
|
||||||
PARENT_SCOPE)
|
|
||||||
set(${_hashvar}
|
|
||||||
"GITDIR-NOTFOUND"
|
|
||||||
PARENT_SCOPE)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Check if the current source dir is a git submodule or a worktree.
|
|
||||||
# In both cases .git is a file instead of a directory.
|
|
||||||
#
|
|
||||||
if(NOT IS_DIRECTORY ${GIT_DIR})
|
if(NOT IS_DIRECTORY ${GIT_DIR})
|
||||||
# The following git command will return a non empty string that
|
file(READ ${GIT_DIR} submodule)
|
||||||
# points to the super project working tree if the current
|
string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule})
|
||||||
# source dir is inside a git submodule.
|
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
|
||||||
# Otherwise the command will return an empty string.
|
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE)
|
||||||
#
|
|
||||||
execute_process(
|
|
||||||
COMMAND "${GIT_EXECUTABLE}" rev-parse
|
|
||||||
--show-superproject-working-tree
|
|
||||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
|
||||||
OUTPUT_VARIABLE out
|
|
||||||
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
|
||||||
if(NOT "${out}" STREQUAL "")
|
|
||||||
# If out is empty, GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a submodule
|
|
||||||
file(READ ${GIT_DIR} submodule)
|
|
||||||
string(REGEX REPLACE "gitdir: (.*)$" "\\1" GIT_DIR_RELATIVE
|
|
||||||
${submodule})
|
|
||||||
string(STRIP ${GIT_DIR_RELATIVE} GIT_DIR_RELATIVE)
|
|
||||||
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
|
|
||||||
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE}
|
|
||||||
ABSOLUTE)
|
|
||||||
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
|
|
||||||
else()
|
|
||||||
# GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a worktree
|
|
||||||
file(READ ${GIT_DIR} worktree_ref)
|
|
||||||
# The .git directory contains a path to the worktree information directory
|
|
||||||
# inside the parent git repo of the worktree.
|
|
||||||
#
|
|
||||||
string(REGEX REPLACE "gitdir: (.*)$" "\\1" git_worktree_dir
|
|
||||||
${worktree_ref})
|
|
||||||
string(STRIP ${git_worktree_dir} git_worktree_dir)
|
|
||||||
_git_find_closest_git_dir("${git_worktree_dir}" GIT_DIR)
|
|
||||||
set(HEAD_SOURCE_FILE "${git_worktree_dir}/HEAD")
|
|
||||||
endif()
|
|
||||||
else()
|
|
||||||
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
|
|
||||||
endif()
|
endif()
|
||||||
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
|
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
|
||||||
if(NOT EXISTS "${GIT_DATA}")
|
if(NOT EXISTS "${GIT_DATA}")
|
||||||
file(MAKE_DIRECTORY "${GIT_DATA}")
|
file(MAKE_DIRECTORY "${GIT_DATA}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT EXISTS "${HEAD_SOURCE_FILE}")
|
if(NOT EXISTS "${GIT_DIR}/HEAD")
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
set(HEAD_FILE "${GIT_DATA}/HEAD")
|
set(HEAD_FILE "${GIT_DATA}/HEAD")
|
||||||
configure_file("${HEAD_SOURCE_FILE}" "${HEAD_FILE}" COPYONLY)
|
configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY)
|
||||||
|
|
||||||
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
|
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
|
||||||
"${GIT_DATA}/grabRef.cmake" @ONLY)
|
"${GIT_DATA}/grabRef.cmake"
|
||||||
|
@ONLY)
|
||||||
include("${GIT_DATA}/grabRef.cmake")
|
include("${GIT_DATA}/grabRef.cmake")
|
||||||
|
|
||||||
set(${_refspecvar}
|
set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE)
|
||||||
"${HEAD_REF}"
|
set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE)
|
||||||
PARENT_SCOPE)
|
|
||||||
set(${_hashvar}
|
|
||||||
"${HEAD_HASH}"
|
|
||||||
PARENT_SCOPE)
|
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
function(git_describe _var)
|
function(git_describe _var)
|
||||||
@ -178,107 +86,45 @@ function(git_describe _var)
|
|||||||
endif()
|
endif()
|
||||||
get_git_head_revision(refspec hash)
|
get_git_head_revision(refspec hash)
|
||||||
if(NOT GIT_FOUND)
|
if(NOT GIT_FOUND)
|
||||||
set(${_var}
|
set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
|
||||||
"GIT-NOTFOUND"
|
|
||||||
PARENT_SCOPE)
|
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
if(NOT hash)
|
if(NOT hash)
|
||||||
set(${_var}
|
set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
|
||||||
"HEAD-HASH-NOTFOUND"
|
|
||||||
PARENT_SCOPE)
|
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# TODO sanitize
|
# TODO sanitize
|
||||||
#if((${ARGN}" MATCHES "&&") OR
|
#if((${ARGN}" MATCHES "&&") OR
|
||||||
# (ARGN MATCHES "||") OR
|
# (ARGN MATCHES "||") OR
|
||||||
# (ARGN MATCHES "\\;"))
|
# (ARGN MATCHES "\\;"))
|
||||||
# message("Please report the following error to the project!")
|
# message("Please report the following error to the project!")
|
||||||
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
|
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
|
||||||
#endif()
|
#endif()
|
||||||
|
|
||||||
#message(STATUS "Arguments to execute_process: ${ARGN}")
|
#message(STATUS "Arguments to execute_process: ${ARGN}")
|
||||||
|
|
||||||
execute_process(
|
execute_process(COMMAND
|
||||||
COMMAND "${GIT_EXECUTABLE}" describe --tags --always ${hash} ${ARGN}
|
"${GIT_EXECUTABLE}"
|
||||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
describe
|
||||||
RESULT_VARIABLE res
|
${hash}
|
||||||
OUTPUT_VARIABLE out
|
${ARGN}
|
||||||
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
WORKING_DIRECTORY
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
RESULT_VARIABLE
|
||||||
|
res
|
||||||
|
OUTPUT_VARIABLE
|
||||||
|
out
|
||||||
|
ERROR_QUIET
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
if(NOT res EQUAL 0)
|
if(NOT res EQUAL 0)
|
||||||
set(out "${out}-${res}-NOTFOUND")
|
set(out "${out}-${res}-NOTFOUND")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(${_var}
|
set(${_var} "${out}" PARENT_SCOPE)
|
||||||
"${out}"
|
|
||||||
PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(git_describe_working_tree _var)
|
|
||||||
if(NOT GIT_FOUND)
|
|
||||||
find_package(Git QUIET)
|
|
||||||
endif()
|
|
||||||
if(NOT GIT_FOUND)
|
|
||||||
set(${_var}
|
|
||||||
"GIT-NOTFOUND"
|
|
||||||
PARENT_SCOPE)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
execute_process(
|
|
||||||
COMMAND "${GIT_EXECUTABLE}" describe --dirty ${ARGN}
|
|
||||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
|
||||||
RESULT_VARIABLE res
|
|
||||||
OUTPUT_VARIABLE out
|
|
||||||
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
|
||||||
if(NOT res EQUAL 0)
|
|
||||||
set(out "${out}-${res}-NOTFOUND")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(${_var}
|
|
||||||
"${out}"
|
|
||||||
PARENT_SCOPE)
|
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
function(git_get_exact_tag _var)
|
function(git_get_exact_tag _var)
|
||||||
git_describe(out --exact-match ${ARGN})
|
git_describe(out --exact-match ${ARGN})
|
||||||
set(${_var}
|
set(${_var} "${out}" PARENT_SCOPE)
|
||||||
"${out}"
|
|
||||||
PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(git_local_changes _var)
|
|
||||||
if(NOT GIT_FOUND)
|
|
||||||
find_package(Git QUIET)
|
|
||||||
endif()
|
|
||||||
get_git_head_revision(refspec hash)
|
|
||||||
if(NOT GIT_FOUND)
|
|
||||||
set(${_var}
|
|
||||||
"GIT-NOTFOUND"
|
|
||||||
PARENT_SCOPE)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
if(NOT hash)
|
|
||||||
set(${_var}
|
|
||||||
"HEAD-HASH-NOTFOUND"
|
|
||||||
PARENT_SCOPE)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
execute_process(
|
|
||||||
COMMAND "${GIT_EXECUTABLE}" diff-index --quiet HEAD --
|
|
||||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
|
||||||
RESULT_VARIABLE res
|
|
||||||
OUTPUT_VARIABLE out
|
|
||||||
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
|
||||||
if(res EQUAL 0)
|
|
||||||
set(${_var}
|
|
||||||
"CLEAN"
|
|
||||||
PARENT_SCOPE)
|
|
||||||
else()
|
|
||||||
set(${_var}
|
|
||||||
"DIRTY"
|
|
||||||
PARENT_SCOPE)
|
|
||||||
endif()
|
|
||||||
endfunction()
|
endfunction()
|
||||||
|
@ -8,12 +8,10 @@
|
|||||||
# http://academic.cleardefinition.com
|
# http://academic.cleardefinition.com
|
||||||
# Iowa State University HCI Graduate Program/VRAC
|
# Iowa State University HCI Graduate Program/VRAC
|
||||||
#
|
#
|
||||||
# Copyright 2009-2012, Iowa State University
|
# Copyright Iowa State University 2009-2010.
|
||||||
# Copyright 2011-2015, Contributors
|
|
||||||
# Distributed under the Boost Software License, Version 1.0.
|
# Distributed under the Boost Software License, Version 1.0.
|
||||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
# http://www.boost.org/LICENSE_1_0.txt)
|
# http://www.boost.org/LICENSE_1_0.txt)
|
||||||
# SPDX-License-Identifier: BSL-1.0
|
|
||||||
|
|
||||||
set(HEAD_HASH)
|
set(HEAD_HASH)
|
||||||
|
|
||||||
@ -21,23 +19,23 @@ file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
|
|||||||
|
|
||||||
string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
|
string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
|
||||||
if(HEAD_CONTENTS MATCHES "ref")
|
if(HEAD_CONTENTS MATCHES "ref")
|
||||||
# named branch
|
# named branch
|
||||||
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
|
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
|
||||||
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
|
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
|
||||||
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
|
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
|
||||||
else()
|
else()
|
||||||
configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY)
|
configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY)
|
||||||
file(READ "@GIT_DATA@/packed-refs" PACKED_REFS)
|
file(READ "@GIT_DATA@/packed-refs" PACKED_REFS)
|
||||||
if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}")
|
if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}")
|
||||||
set(HEAD_HASH "${CMAKE_MATCH_1}")
|
set(HEAD_HASH "${CMAKE_MATCH_1}")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
# detached HEAD
|
# detached HEAD
|
||||||
configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
|
configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT HEAD_HASH)
|
if(NOT HEAD_HASH)
|
||||||
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
|
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
|
||||||
string(STRIP "${HEAD_HASH}" HEAD_HASH)
|
string(STRIP "${HEAD_HASH}" HEAD_HASH)
|
||||||
endif()
|
endif()
|
||||||
|
@ -40,9 +40,5 @@
|
|||||||
<true/>
|
<true/>
|
||||||
<key>NSHumanReadableCopyright</key>
|
<key>NSHumanReadableCopyright</key>
|
||||||
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
|
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
|
||||||
<key>SUPublicEDKey</key>
|
|
||||||
<string>${MACOSX_SPARKLE_UPDATE_PUBLIC_KEY}</string>
|
|
||||||
<key>SUFeedURL</key>
|
|
||||||
<string>${MACOSX_SPARKLE_UPDATE_FEED_URL}</string>
|
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
14
cmake/QMakeQuery.cmake
Normal file
14
cmake/QMakeQuery.cmake
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
if(__QMAKEQUERY_CMAKE__)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(__QMAKEQUERY_CMAKE__ TRUE)
|
||||||
|
|
||||||
|
get_target_property(QMAKE_EXECUTABLE Qt5::qmake LOCATION)
|
||||||
|
|
||||||
|
function(QUERY_QMAKE VAR RESULT)
|
||||||
|
exec_program(${QMAKE_EXECUTABLE} ARGS "-query ${VAR}" RETURN_VALUE return_code OUTPUT_VARIABLE output )
|
||||||
|
if(NOT return_code)
|
||||||
|
file(TO_CMAKE_PATH "${output}" output)
|
||||||
|
set(${RESULT} ${output} PARENT_SCOPE)
|
||||||
|
endif(NOT return_code)
|
||||||
|
endfunction(QUERY_QMAKE)
|
@ -1,38 +0,0 @@
|
|||||||
#.rst:
|
|
||||||
# QtVersionOption
|
|
||||||
# ---------------
|
|
||||||
#
|
|
||||||
# Adds a build option to select the major Qt version if necessary,
|
|
||||||
# that is, if the major Qt version has not yet been determined otherwise
|
|
||||||
# (e.g. by a corresponding find_package() call).
|
|
||||||
#
|
|
||||||
# This module is typically included by other modules requiring knowledge
|
|
||||||
# about the major Qt version.
|
|
||||||
#
|
|
||||||
# ``QT_MAJOR_VERSION`` is defined to either be "5" or "6".
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# Since 5.82.0.
|
|
||||||
|
|
||||||
#=============================================================================
|
|
||||||
# SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: BSD-3-Clause
|
|
||||||
|
|
||||||
if (DEFINED QT_MAJOR_VERSION)
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (TARGET Qt5::Core)
|
|
||||||
set(QT_MAJOR_VERSION 5)
|
|
||||||
elseif (TARGET Qt6::Core)
|
|
||||||
set(QT_MAJOR_VERSION 6)
|
|
||||||
else()
|
|
||||||
option(BUILD_WITH_QT6 "Build against Qt 6" OFF)
|
|
||||||
|
|
||||||
if (BUILD_WITH_QT6)
|
|
||||||
set(QT_MAJOR_VERSION 6)
|
|
||||||
else()
|
|
||||||
set(QT_MAJOR_VERSION 5)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
@ -1,97 +0,0 @@
|
|||||||
#=============================================================================
|
|
||||||
# Copyright 2005-2011 Kitware, Inc.
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
# * Neither the name of Kitware, Inc. nor the names of its
|
|
||||||
# contributors may be used to endorse or promote products derived
|
|
||||||
# from this software without specific prior written permission.
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#=============================================================================
|
|
||||||
|
|
||||||
# From Qt5CoreMacros.cmake
|
|
||||||
|
|
||||||
function(qt_generate_moc)
|
|
||||||
if(QT_VERSION_MAJOR EQUAL 5)
|
|
||||||
qt5_generate_moc(${ARGV})
|
|
||||||
elseif(QT_VERSION_MAJOR EQUAL 6)
|
|
||||||
qt6_generate_moc(${ARGV})
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(qt_wrap_cpp outfiles)
|
|
||||||
if(QT_VERSION_MAJOR EQUAL 5)
|
|
||||||
qt5_wrap_cpp("${outfiles}" ${ARGN})
|
|
||||||
elseif(QT_VERSION_MAJOR EQUAL 6)
|
|
||||||
qt6_wrap_cpp("${outfiles}" ${ARGN})
|
|
||||||
endif()
|
|
||||||
set("${outfiles}" "${${outfiles}}" PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(qt_add_binary_resources)
|
|
||||||
if(QT_VERSION_MAJOR EQUAL 5)
|
|
||||||
qt5_add_binary_resources(${ARGV})
|
|
||||||
elseif(QT_VERSION_MAJOR EQUAL 6)
|
|
||||||
qt6_add_binary_resources(${ARGV})
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(qt_add_resources outfiles)
|
|
||||||
if(QT_VERSION_MAJOR EQUAL 5)
|
|
||||||
qt5_add_resources("${outfiles}" ${ARGN})
|
|
||||||
elseif(QT_VERSION_MAJOR EQUAL 6)
|
|
||||||
qt6_add_resources("${outfiles}" ${ARGN})
|
|
||||||
endif()
|
|
||||||
set("${outfiles}" "${${outfiles}}" PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(qt_add_big_resources outfiles)
|
|
||||||
if(QT_VERSION_MAJOR EQUAL 5)
|
|
||||||
qt5_add_big_resources(${outfiles} ${ARGN})
|
|
||||||
elseif(QT_VERSION_MAJOR EQUAL 6)
|
|
||||||
qt6_add_big_resources(${outfiles} ${ARGN})
|
|
||||||
endif()
|
|
||||||
set("${outfiles}" "${${outfiles}}" PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(qt_import_plugins)
|
|
||||||
if(QT_VERSION_MAJOR EQUAL 5)
|
|
||||||
qt5_import_plugins(${ARGV})
|
|
||||||
elseif(QT_VERSION_MAJOR EQUAL 6)
|
|
||||||
qt6_import_plugins(${ARGV})
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
|
|
||||||
# From Qt5WidgetsMacros.cmake
|
|
||||||
|
|
||||||
function(qt_wrap_ui outfiles)
|
|
||||||
if(QT_VERSION_MAJOR EQUAL 5)
|
|
||||||
qt5_wrap_ui("${outfiles}" ${ARGN})
|
|
||||||
elseif(QT_VERSION_MAJOR EQUAL 6)
|
|
||||||
qt6_wrap_ui("${outfiles}" ${ARGN})
|
|
||||||
endif()
|
|
||||||
set("${outfiles}" "${${outfiles}}" PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
||||||
|
|
50
cmake/UnitTest.cmake
Normal file
50
cmake/UnitTest.cmake
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
find_package(Qt5Test REQUIRED)
|
||||||
|
|
||||||
|
set(TEST_RESOURCE_PATH ${CMAKE_CURRENT_LIST_DIR})
|
||||||
|
|
||||||
|
message(${TEST_RESOURCE_PATH})
|
||||||
|
|
||||||
|
function(add_unit_test name)
|
||||||
|
if(BUILD_TESTING)
|
||||||
|
set(options "")
|
||||||
|
set(oneValueArgs DATA)
|
||||||
|
set(multiValueArgs SOURCES LIBS)
|
||||||
|
|
||||||
|
cmake_parse_arguments(OPT "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
add_executable(${name}_test ${OPT_SOURCES} ${TEST_RESOURCE_PATH}/UnitTest/test.rc)
|
||||||
|
else()
|
||||||
|
add_executable(${name}_test ${OPT_SOURCES})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT "${OPT_DATA}" STREQUAL "")
|
||||||
|
set(TEST_DATA_PATH "${CMAKE_CURRENT_BINARY_DIR}/data")
|
||||||
|
set(TEST_DATA_PATH_SRC "${CMAKE_CURRENT_SOURCE_DIR}/${OPT_DATA}")
|
||||||
|
message("From ${TEST_DATA_PATH_SRC} to ${TEST_DATA_PATH}")
|
||||||
|
string(REGEX REPLACE "[/\\:]" "_" DATA_TARGET_NAME "${TEST_DATA_PATH_SRC}")
|
||||||
|
if(UNIX)
|
||||||
|
# on unix we get the third / from the filename
|
||||||
|
set(TEST_DATA_URL "file://${TEST_DATA_PATH}")
|
||||||
|
else()
|
||||||
|
# we don't on windows, so we have to add it ourselves
|
||||||
|
set(TEST_DATA_URL "file:///${TEST_DATA_PATH}")
|
||||||
|
endif()
|
||||||
|
if(NOT TARGET "${DATA_TARGET_NAME}")
|
||||||
|
add_custom_target(${DATA_TARGET_NAME})
|
||||||
|
add_dependencies(${name}_test ${DATA_TARGET_NAME})
|
||||||
|
add_custom_command(
|
||||||
|
TARGET ${DATA_TARGET_NAME}
|
||||||
|
COMMAND ${CMAKE_COMMAND} "-DTEST_DATA_URL=${TEST_DATA_URL}" -DSOURCE=${TEST_DATA_PATH_SRC} -DDESTINATION=${TEST_DATA_PATH} -P ${TEST_RESOURCE_PATH}/UnitTest/generate_test_data.cmake
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_link_libraries(${name}_test Qt5::Test ${OPT_LIBS})
|
||||||
|
|
||||||
|
target_include_directories(${name}_test PRIVATE "${TEST_RESOURCE_PATH}/UnitTest/")
|
||||||
|
|
||||||
|
add_test(NAME ${name} COMMAND ${name}_test WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
endif()
|
||||||
|
endfunction()
|
28
cmake/UnitTest/TestUtil.h
Normal file
28
cmake/UnitTest/TestUtil.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QTest>
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
|
#define expandstr(s) expandstr2(s)
|
||||||
|
#define expandstr2(s) #s
|
||||||
|
|
||||||
|
class TestsInternal
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static QByteArray readFile(const QString &fileName)
|
||||||
|
{
|
||||||
|
QFile f(fileName);
|
||||||
|
f.open(QFile::ReadOnly);
|
||||||
|
return f.readAll();
|
||||||
|
}
|
||||||
|
static QString readFileUtf8(const QString &fileName)
|
||||||
|
{
|
||||||
|
return QString::fromUtf8(readFile(fileName));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#define GET_TEST_FILE(file) TestsInternal::readFile(QFINDTESTDATA(file))
|
||||||
|
#define GET_TEST_FILE_UTF8(file) TestsInternal::readFileUtf8(QFINDTESTDATA(file))
|
||||||
|
|
23
cmake/UnitTest/generate_test_data.cmake
Normal file
23
cmake/UnitTest/generate_test_data.cmake
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# Copy files from source directory to destination directory, substituting any
|
||||||
|
# variables. Create destination directory if it does not exist.
|
||||||
|
|
||||||
|
function(configure_files srcDir destDir)
|
||||||
|
make_directory(${destDir})
|
||||||
|
|
||||||
|
file(GLOB templateFiles RELATIVE ${srcDir} ${srcDir}/*)
|
||||||
|
foreach(templateFile ${templateFiles})
|
||||||
|
set(srcTemplatePath ${srcDir}/${templateFile})
|
||||||
|
if(NOT IS_DIRECTORY ${srcTemplatePath})
|
||||||
|
configure_file(
|
||||||
|
${srcTemplatePath}
|
||||||
|
${destDir}/${templateFile}
|
||||||
|
@ONLY
|
||||||
|
NEWLINE_STYLE LF
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
configure_files("${srcTemplatePath}" "${destDir}/${templateFile}")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
configure_files(${SOURCE} ${DESTINATION})
|
27
cmake/UnitTest/test.manifest
Normal file
27
cmake/UnitTest/test.manifest
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<assemblyIdentity name="Launcher.Test.0" type="win32" version="5.0.0.0" />
|
||||||
|
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<security>
|
||||||
|
<requestedPrivileges>
|
||||||
|
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
|
||||||
|
</requestedPrivileges>
|
||||||
|
</security>
|
||||||
|
</trustInfo>
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="x86" publicKeyToken="6595b64144ccf1df" language="*"/>
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
<description>Custom Minecraft launcher for managing multiple installs.</description>
|
||||||
|
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||||
|
<application>
|
||||||
|
<!--The ID below indicates app support for Windows Vista -->
|
||||||
|
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
|
||||||
|
<!--The ID below indicates app support for Windows 7 -->
|
||||||
|
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
|
||||||
|
<!--The ID below indicates app support for Windows Developer Preview / Windows 8 -->
|
||||||
|
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
|
||||||
|
</application>
|
||||||
|
</compatibility>
|
||||||
|
</assembly>
|
28
cmake/UnitTest/test.rc
Normal file
28
cmake/UnitTest/test.rc
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
1 RT_MANIFEST "test.manifest"
|
||||||
|
|
||||||
|
VS_VERSION_INFO VERSIONINFO
|
||||||
|
FILEVERSION 1,0,0,0
|
||||||
|
FILEOS VOS_NT_WINDOWS32
|
||||||
|
FILETYPE VFT_APP
|
||||||
|
BEGIN
|
||||||
|
BLOCK "StringFileInfo"
|
||||||
|
BEGIN
|
||||||
|
BLOCK "000004b0"
|
||||||
|
BEGIN
|
||||||
|
VALUE "CompanyName", "MultiMC & PolyMC Contributors"
|
||||||
|
VALUE "FileDescription", "Testcase"
|
||||||
|
VALUE "FileVersion", "1.0.0.0"
|
||||||
|
VALUE "ProductName", "Launcher Testcase"
|
||||||
|
VALUE "ProductVersion", "5"
|
||||||
|
END
|
||||||
|
END
|
||||||
|
BLOCK "VarFileInfo"
|
||||||
|
BEGIN
|
||||||
|
VALUE "Translation", 0x0000, 0x04b0 // Unicode
|
||||||
|
END
|
||||||
|
END
|
35
flake.lock
generated
35
flake.lock
generated
@ -19,26 +19,26 @@
|
|||||||
"libnbtplusplus": {
|
"libnbtplusplus": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1650031308,
|
"lastModified": 1591558203,
|
||||||
"narHash": "sha256-TvVOjkUobYJD9itQYueELJX3wmecvEdCbJ0FinW2mL4=",
|
"narHash": "sha256-QgvNvaoFflCXEPCCFBCeZvYTpuiwScBG7EosUgFwFNQ=",
|
||||||
"owner": "PrismLauncher",
|
"owner": "multimc",
|
||||||
"repo": "libnbtplusplus",
|
"repo": "libnbtplusplus",
|
||||||
"rev": "2203af7eeb48c45398139b583615134efd8d407f",
|
"rev": "dc72a20b7efd304d12af2025223fad07b4b78464",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "PrismLauncher",
|
"owner": "multimc",
|
||||||
"repo": "libnbtplusplus",
|
"repo": "libnbtplusplus",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1666057921,
|
"lastModified": 1654665288,
|
||||||
"narHash": "sha256-VpQqtXdj6G7cH//SvoprjR7XT3KS7p+tCVebGK1N6tE=",
|
"narHash": "sha256-7blJpfoZEu7GKb84uh3io/5eSJNdaagXD9d15P9iQMs=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "88eab1e431cabd0ed621428d8b40d425a07af39f",
|
"rev": "43ecbe7840d155fa933ee8a500fb00dbbc651fc8",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -52,24 +52,7 @@
|
|||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-compat": "flake-compat",
|
"flake-compat": "flake-compat",
|
||||||
"libnbtplusplus": "libnbtplusplus",
|
"libnbtplusplus": "libnbtplusplus",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs"
|
||||||
"tomlplusplus": "tomlplusplus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tomlplusplus": {
|
|
||||||
"flake": false,
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1666091090,
|
|
||||||
"narHash": "sha256-djpMCFPvkJcfynV8WnsYdtwLq+J7jpV1iM4C6TojiyM=",
|
|
||||||
"owner": "marzer",
|
|
||||||
"repo": "tomlplusplus",
|
|
||||||
"rev": "1e4a3833d013aee08f58c5b31c69f709afc69f73",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "marzer",
|
|
||||||
"repo": "tomlplusplus",
|
|
||||||
"type": "github"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
33
flake.nix
33
flake.nix
@ -4,35 +4,36 @@
|
|||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
|
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
|
||||||
flake-compat = { url = "github:edolstra/flake-compat"; flake = false; };
|
flake-compat = { url = "github:edolstra/flake-compat"; flake = false; };
|
||||||
libnbtplusplus = { url = "github:PrismLauncher/libnbtplusplus"; flake = false; };
|
libnbtplusplus = { url = "github:multimc/libnbtplusplus"; flake = false; };
|
||||||
tomlplusplus = { url = "github:marzer/tomlplusplus"; flake = false; };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = { self, nixpkgs, libnbtplusplus, tomlplusplus, ... }:
|
outputs = { self, nixpkgs, libnbtplusplus, ... }:
|
||||||
let
|
let
|
||||||
# User-friendly version number.
|
# Generate a user-friendly version number.
|
||||||
version = builtins.substring 0 8 self.lastModifiedDate;
|
version = builtins.substring 0 8 self.lastModifiedDate;
|
||||||
|
|
||||||
# Supported systems (qtbase is currently broken for "aarch64-darwin")
|
# System types to support (qtbase is currently broken for "aarch64-darwin")
|
||||||
supportedSystems = [ "x86_64-linux" "x86_64-darwin" "aarch64-linux" ];
|
supportedSystems = [ "x86_64-linux" "x86_64-darwin" "aarch64-linux" ];
|
||||||
|
|
||||||
# Helper function to generate an attrset '{ x86_64-linux = f "x86_64-linux"; ... }'.
|
# Helper function to generate an attrset '{ x86_64-linux = f "x86_64-linux"; ... }'.
|
||||||
forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
|
forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
|
||||||
|
|
||||||
# Nixpkgs instantiated for supported systems.
|
# Nixpkgs instantiated for supported system types.
|
||||||
pkgs = forAllSystems (system: nixpkgs.legacyPackages.${system});
|
pkgs = forAllSystems (system: nixpkgs.legacyPackages.${system});
|
||||||
|
|
||||||
packagesFn = pkgs: rec {
|
|
||||||
prismlauncher = pkgs.libsForQt5.callPackage ./nix { inherit version self libnbtplusplus tomlplusplus; };
|
|
||||||
prismlauncher-qt6 = pkgs.qt6Packages.callPackage ./nix { inherit version self libnbtplusplus tomlplusplus; };
|
|
||||||
};
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
packages = forAllSystems (system:
|
packages = forAllSystems (system: rec {
|
||||||
let packages = packagesFn pkgs.${system}; in
|
polymc = pkgs.${system}.libsForQt5.callPackage ./nix { inherit version self libnbtplusplus; };
|
||||||
packages // { default = packages.prismlauncher; }
|
polymc-qt6 = pkgs.${system}.qt6Packages.callPackage ./nix { inherit version self libnbtplusplus; };
|
||||||
);
|
|
||||||
|
default = polymc;
|
||||||
|
});
|
||||||
|
|
||||||
overlay = final: packagesFn;
|
defaultPackage = forAllSystems (system: self.packages.${system}.default);
|
||||||
|
|
||||||
|
apps = forAllSystems (system: rec { polymc = { type = "app"; program = "${self.defaultPackage.${system}}/bin/polymc"; }; default = polymc; });
|
||||||
|
defaultApp = forAllSystems (system: self.apps.${system}.default);
|
||||||
|
|
||||||
|
overlay = final: prev: { polymc = self.defaultPackage.${final.system}; };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -60,10 +60,6 @@
|
|||||||
#include "ui/themes/BrightTheme.h"
|
#include "ui/themes/BrightTheme.h"
|
||||||
#include "ui/themes/CustomTheme.h"
|
#include "ui/themes/CustomTheme.h"
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
#include "ui/WinDarkmode.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "ui/setupwizard/SetupWizard.h"
|
#include "ui/setupwizard/SetupWizard.h"
|
||||||
#include "ui/setupwizard/LanguageWizardPage.h"
|
#include "ui/setupwizard/LanguageWizardPage.h"
|
||||||
#include "ui/setupwizard/JavaWizardPage.h"
|
#include "ui/setupwizard/JavaWizardPage.h"
|
||||||
@ -78,7 +74,6 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include <QAccessible>
|
#include <QAccessible>
|
||||||
#include <QCommandLineParser>
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
@ -89,7 +84,6 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QStyleFactory>
|
#include <QStyleFactory>
|
||||||
#include <QWindow>
|
#include <QWindow>
|
||||||
#include <QIcon>
|
|
||||||
|
|
||||||
#include "InstanceList.h"
|
#include "InstanceList.h"
|
||||||
|
|
||||||
@ -105,23 +99,20 @@
|
|||||||
#include "tools/JVisualVM.h"
|
#include "tools/JVisualVM.h"
|
||||||
#include "tools/MCEditTool.h"
|
#include "tools/MCEditTool.h"
|
||||||
|
|
||||||
|
#include <xdgicon.h>
|
||||||
#include "settings/INISettingsObject.h"
|
#include "settings/INISettingsObject.h"
|
||||||
#include "settings/Setting.h"
|
#include "settings/Setting.h"
|
||||||
|
|
||||||
#include "translations/TranslationsModel.h"
|
#include "translations/TranslationsModel.h"
|
||||||
#include "meta/Index.h"
|
#include "meta/Index.h"
|
||||||
|
|
||||||
|
#include <Commandline.h>
|
||||||
#include <FileSystem.h>
|
#include <FileSystem.h>
|
||||||
#include <DesktopServices.h>
|
#include <DesktopServices.h>
|
||||||
#include <LocalPeer.h>
|
#include <LocalPeer.h>
|
||||||
|
|
||||||
#include <sys.h>
|
#include <sys.h>
|
||||||
|
|
||||||
#ifdef Q_OS_LINUX
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#include "gamemode_client.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#if defined Q_OS_WIN32
|
#if defined Q_OS_WIN32
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
@ -136,6 +127,12 @@
|
|||||||
|
|
||||||
static const QLatin1String liveCheckFile("live.check");
|
static const QLatin1String liveCheckFile("live.check");
|
||||||
|
|
||||||
|
using namespace Commandline;
|
||||||
|
|
||||||
|
#define MACOS_HINT "If you are on macOS Sierra, you might have to move the app to your /Applications or ~/Applications folder. "\
|
||||||
|
"This usually fixes the problem and you can move the application elsewhere afterwards.\n"\
|
||||||
|
"\n"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void appDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
|
void appDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
|
||||||
{
|
{
|
||||||
@ -227,7 +224,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
setOrganizationName(BuildConfig.LAUNCHER_NAME);
|
setOrganizationName(BuildConfig.LAUNCHER_NAME);
|
||||||
setOrganizationDomain(BuildConfig.LAUNCHER_DOMAIN);
|
setOrganizationDomain(BuildConfig.LAUNCHER_DOMAIN);
|
||||||
setApplicationName(BuildConfig.LAUNCHER_NAME);
|
setApplicationName(BuildConfig.LAUNCHER_NAME);
|
||||||
setApplicationDisplayName(QString("%1 %2").arg(BuildConfig.LAUNCHER_DISPLAYNAME, BuildConfig.printableVersionString()));
|
setApplicationDisplayName(BuildConfig.LAUNCHER_DISPLAYNAME);
|
||||||
setApplicationVersion(BuildConfig.printableVersionString());
|
setApplicationVersion(BuildConfig.printableVersionString());
|
||||||
setDesktopFileName(BuildConfig.LAUNCHER_DESKTOPFILENAME);
|
setDesktopFileName(BuildConfig.LAUNCHER_DESKTOPFILENAME);
|
||||||
startTime = QDateTime::currentDateTime();
|
startTime = QDateTime::currentDateTime();
|
||||||
@ -236,27 +233,80 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
this->setQuitOnLastWindowClosed(false);
|
this->setQuitOnLastWindowClosed(false);
|
||||||
|
|
||||||
// Commandline parsing
|
// Commandline parsing
|
||||||
QCommandLineParser parser;
|
QHash<QString, QVariant> args;
|
||||||
parser.setApplicationDescription(BuildConfig.LAUNCHER_DISPLAYNAME);
|
{
|
||||||
|
Parser parser(FlagStyle::GNU, ArgumentStyle::SpaceAndEquals);
|
||||||
|
|
||||||
parser.addOptions({
|
// --help
|
||||||
{{"d", "dir"}, "Use a custom path as application root (use '.' for current directory)", "directory"},
|
parser.addSwitch("help");
|
||||||
{{"l", "launch"}, "Launch the specified instance (by instance ID)", "instance"},
|
parser.addShortOpt("help", 'h');
|
||||||
{{"s", "server"}, "Join the specified server on launch (only valid in combination with --launch)", "address"},
|
parser.addDocumentation("help", "Display this help and exit.");
|
||||||
{{"a", "profile"}, "Use the account specified by its profile name (only valid in combination with --launch)", "profile"},
|
// --version
|
||||||
{"alive", "Write a small '" + liveCheckFile + "' file after the launcher starts"},
|
parser.addSwitch("version");
|
||||||
{{"I", "import"}, "Import instance from specified zip (local path or URL)", "file"}
|
parser.addShortOpt("version", 'V');
|
||||||
});
|
parser.addDocumentation("version", "Display program version and exit.");
|
||||||
parser.addHelpOption();
|
// --dir
|
||||||
parser.addVersionOption();
|
parser.addOption("dir");
|
||||||
|
parser.addShortOpt("dir", 'd');
|
||||||
|
parser.addDocumentation("dir", "Use the supplied folder as application root instead of the binary location (use '.' for current)");
|
||||||
|
// --launch
|
||||||
|
parser.addOption("launch");
|
||||||
|
parser.addShortOpt("launch", 'l');
|
||||||
|
parser.addDocumentation("launch", "Launch the specified instance (by instance ID)");
|
||||||
|
// --server
|
||||||
|
parser.addOption("server");
|
||||||
|
parser.addShortOpt("server", 's');
|
||||||
|
parser.addDocumentation("server", "Join the specified server on launch (only valid in combination with --launch)");
|
||||||
|
// --profile
|
||||||
|
parser.addOption("profile");
|
||||||
|
parser.addShortOpt("profile", 'a');
|
||||||
|
parser.addDocumentation("profile", "Use the account specified by its profile name (only valid in combination with --launch)");
|
||||||
|
// --alive
|
||||||
|
parser.addSwitch("alive");
|
||||||
|
parser.addDocumentation("alive", "Write a small '" + liveCheckFile + "' file after the launcher starts");
|
||||||
|
// --import
|
||||||
|
parser.addOption("import");
|
||||||
|
parser.addShortOpt("import", 'I');
|
||||||
|
parser.addDocumentation("import", "Import instance from specified zip (local path or URL)");
|
||||||
|
|
||||||
parser.process(arguments());
|
// parse the arguments
|
||||||
|
try
|
||||||
|
{
|
||||||
|
args = parser.parse(arguments());
|
||||||
|
}
|
||||||
|
catch (const ParsingError &e)
|
||||||
|
{
|
||||||
|
std::cerr << "CommandLineError: " << e.what() << std::endl;
|
||||||
|
if(argc > 0)
|
||||||
|
std::cerr << "Try '" << argv[0] << " -h' to get help on command line parameters."
|
||||||
|
<< std::endl;
|
||||||
|
m_status = Application::Failed;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
m_instanceIdToLaunch = parser.value("launch");
|
// display help and exit
|
||||||
m_serverToJoin = parser.value("server");
|
if (args["help"].toBool())
|
||||||
m_profileToUse = parser.value("profile");
|
{
|
||||||
m_liveCheck = parser.isSet("alive");
|
std::cout << qPrintable(parser.compileHelp(arguments()[0]));
|
||||||
m_zipToImport = parser.value("import");
|
m_status = Application::Succeeded;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// display version and exit
|
||||||
|
if (args["version"].toBool())
|
||||||
|
{
|
||||||
|
std::cout << "Version " << BuildConfig.printableVersionString().toStdString() << std::endl;
|
||||||
|
std::cout << "Git " << BuildConfig.GIT_COMMIT.toStdString() << std::endl;
|
||||||
|
m_status = Application::Succeeded;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_instanceIdToLaunch = args["launch"].toString();
|
||||||
|
m_serverToJoin = args["server"].toString();
|
||||||
|
m_profileToUse = args["profile"].toString();
|
||||||
|
m_liveCheck = args["alive"].toBool();
|
||||||
|
m_zipToImport = args["import"].toUrl();
|
||||||
|
|
||||||
// error if --launch is missing with --server or --profile
|
// error if --launch is missing with --server or --profile
|
||||||
if((!m_serverToJoin.isEmpty() || !m_profileToUse.isEmpty()) && m_instanceIdToLaunch.isEmpty())
|
if((!m_serverToJoin.isEmpty() || !m_profileToUse.isEmpty()) && m_instanceIdToLaunch.isEmpty())
|
||||||
@ -271,7 +321,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
|
|
||||||
{
|
{
|
||||||
// Root path is used for updates and portable data
|
// Root path is used for updates and portable data
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||||
QDir foo(FS::PathCombine(binPath, "..")); // typically portable-root or /usr
|
QDir foo(FS::PathCombine(binPath, "..")); // typically portable-root or /usr
|
||||||
m_rootPath = foo.absolutePath();
|
m_rootPath = foo.absolutePath();
|
||||||
#elif defined(Q_OS_WIN32)
|
#elif defined(Q_OS_WIN32)
|
||||||
@ -282,12 +332,16 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
// on macOS, touch the root to force Finder to reload the .app metadata (and fix any icon change issues)
|
// on macOS, touch the root to force Finder to reload the .app metadata (and fix any icon change issues)
|
||||||
FS::updateTimestamp(m_rootPath);
|
FS::updateTimestamp(m_rootPath);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef LAUNCHER_JARS_LOCATION
|
||||||
|
m_jarsPath = TOSTRING(LAUNCHER_JARS_LOCATION);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
QString adjustedBy;
|
QString adjustedBy;
|
||||||
QString dataPath;
|
QString dataPath;
|
||||||
// change folder
|
// change folder
|
||||||
QString dirParam = parser.value("dir");
|
QString dirParam = args["dir"].toString();
|
||||||
if (!dirParam.isEmpty())
|
if (!dirParam.isEmpty())
|
||||||
{
|
{
|
||||||
// the dir param. it makes multimc data path point to whatever the user specified
|
// the dir param. it makes multimc data path point to whatever the user specified
|
||||||
@ -301,12 +355,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
dataPath = foo.absolutePath();
|
dataPath = foo.absolutePath();
|
||||||
adjustedBy = "Persistent data path";
|
adjustedBy = "Persistent data path";
|
||||||
|
|
||||||
QDir polymcData(FS::PathCombine(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation), "PolyMC"));
|
|
||||||
if (polymcData.exists()) {
|
|
||||||
dataPath = polymcData.absolutePath();
|
|
||||||
adjustedBy = "PolyMC data path";
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
// TODO: this should be removed in a future version
|
// TODO: this should be removed in a future version
|
||||||
// TODO: provide a migration path similar to macOS migration
|
// TODO: provide a migration path similar to macOS migration
|
||||||
@ -332,6 +380,9 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
QString(
|
QString(
|
||||||
"The launcher data folder could not be created.\n"
|
"The launcher data folder could not be created.\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
#if defined(Q_OS_MAC)
|
||||||
|
MACOS_HINT
|
||||||
|
#endif
|
||||||
"Make sure you have the right permissions to the launcher data folder and any folder needed to access it.\n"
|
"Make sure you have the right permissions to the launcher data folder and any folder needed to access it.\n"
|
||||||
"(%1)\n"
|
"(%1)\n"
|
||||||
"\n"
|
"\n"
|
||||||
@ -347,6 +398,9 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
QString(
|
QString(
|
||||||
"The launcher data folder could not be opened.\n"
|
"The launcher data folder could not be opened.\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
#if defined(Q_OS_MAC)
|
||||||
|
MACOS_HINT
|
||||||
|
#endif
|
||||||
"Make sure you have the right permissions to the launcher data folder.\n"
|
"Make sure you have the right permissions to the launcher data folder.\n"
|
||||||
"(%1)\n"
|
"(%1)\n"
|
||||||
"\n"
|
"\n"
|
||||||
@ -427,6 +481,9 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
QString(
|
QString(
|
||||||
"The launcher couldn't create a log file - the data folder is not writable.\n"
|
"The launcher couldn't create a log file - the data folder is not writable.\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
#if defined(Q_OS_MAC)
|
||||||
|
MACOS_HINT
|
||||||
|
#endif
|
||||||
"Make sure you have write permissions to the data folder.\n"
|
"Make sure you have write permissions to the data folder.\n"
|
||||||
"(%1)\n"
|
"(%1)\n"
|
||||||
"\n"
|
"\n"
|
||||||
@ -488,10 +545,8 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
|
|
||||||
// Initialize application settings
|
// Initialize application settings
|
||||||
{
|
{
|
||||||
// Provide a fallback for migration from PolyMC
|
m_settings.reset(new INISettingsObject(BuildConfig.LAUNCHER_CONFIGFILE, this));
|
||||||
m_settings.reset(new INISettingsObject({ BuildConfig.LAUNCHER_CONFIGFILE, "polymc.cfg", "multimc.cfg" }, this));
|
|
||||||
// Updates
|
// Updates
|
||||||
// Multiple channels are separated by spaces
|
|
||||||
m_settings->registerSetting("UpdateChannel", BuildConfig.VERSION_CHANNEL);
|
m_settings->registerSetting("UpdateChannel", BuildConfig.VERSION_CHANNEL);
|
||||||
m_settings->registerSetting("AutoUpdate", true);
|
m_settings->registerSetting("AutoUpdate", true);
|
||||||
|
|
||||||
@ -569,7 +624,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
m_settings->registerSetting("JavaPath", "");
|
m_settings->registerSetting("JavaPath", "");
|
||||||
m_settings->registerSetting("JavaTimestamp", 0);
|
m_settings->registerSetting("JavaTimestamp", 0);
|
||||||
m_settings->registerSetting("JavaArchitecture", "");
|
m_settings->registerSetting("JavaArchitecture", "");
|
||||||
m_settings->registerSetting("JavaRealArchitecture", "");
|
|
||||||
m_settings->registerSetting("JavaVersion", "");
|
m_settings->registerSetting("JavaVersion", "");
|
||||||
m_settings->registerSetting("JavaVendor", "");
|
m_settings->registerSetting("JavaVendor", "");
|
||||||
m_settings->registerSetting("LastHostname", "");
|
m_settings->registerSetting("LastHostname", "");
|
||||||
@ -581,11 +635,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
m_settings->registerSetting("UseNativeOpenAL", false);
|
m_settings->registerSetting("UseNativeOpenAL", false);
|
||||||
m_settings->registerSetting("UseNativeGLFW", false);
|
m_settings->registerSetting("UseNativeGLFW", false);
|
||||||
|
|
||||||
// Peformance related options
|
|
||||||
m_settings->registerSetting("EnableFeralGamemode", false);
|
|
||||||
m_settings->registerSetting("EnableMangoHud", false);
|
|
||||||
m_settings->registerSetting("UseDiscreteGpu", false);
|
|
||||||
|
|
||||||
// Game time
|
// Game time
|
||||||
m_settings->registerSetting("ShowGameTime", true);
|
m_settings->registerSetting("ShowGameTime", true);
|
||||||
m_settings->registerSetting("ShowGlobalGameTime", true);
|
m_settings->registerSetting("ShowGlobalGameTime", true);
|
||||||
@ -594,9 +643,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
// Minecraft launch method
|
// Minecraft launch method
|
||||||
m_settings->registerSetting("MCLaunchMethod", "LauncherPart");
|
m_settings->registerSetting("MCLaunchMethod", "LauncherPart");
|
||||||
|
|
||||||
// Minecraft mods
|
|
||||||
m_settings->registerSetting("ModMetadataDisabled", false);
|
|
||||||
|
|
||||||
// Minecraft offline player name
|
// Minecraft offline player name
|
||||||
m_settings->registerSetting("LastOfflinePlayerName", "");
|
m_settings->registerSetting("LastOfflinePlayerName", "");
|
||||||
|
|
||||||
@ -628,8 +674,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
|
|
||||||
m_settings->registerSetting("UpdateDialogGeometry", "");
|
m_settings->registerSetting("UpdateDialogGeometry", "");
|
||||||
|
|
||||||
m_settings->registerSetting("ModDownloadGeometry", "");
|
|
||||||
|
|
||||||
// HACK: This code feels so stupid is there a less stupid way of doing this?
|
// HACK: This code feels so stupid is there a less stupid way of doing this?
|
||||||
{
|
{
|
||||||
m_settings->registerSetting("PastebinURL", "");
|
m_settings->registerSetting("PastebinURL", "");
|
||||||
@ -661,21 +705,9 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
m_settings->registerSetting("CloseAfterLaunch", false);
|
m_settings->registerSetting("CloseAfterLaunch", false);
|
||||||
m_settings->registerSetting("QuitAfterGameStop", false);
|
m_settings->registerSetting("QuitAfterGameStop", false);
|
||||||
|
|
||||||
// Custom Microsoft Authentication Client ID
|
// Custom MSA credentials
|
||||||
m_settings->registerSetting("MSAClientIDOverride", "");
|
m_settings->registerSetting("MSAClientIDOverride", "");
|
||||||
|
m_settings->registerSetting("CFKeyOverride", "");
|
||||||
// Custom Flame API Key
|
|
||||||
{
|
|
||||||
m_settings->registerSetting("CFKeyOverride", "");
|
|
||||||
m_settings->registerSetting("FlameKeyOverride", "");
|
|
||||||
|
|
||||||
QString flameKey = m_settings->get("CFKeyOverride").toString();
|
|
||||||
|
|
||||||
if (!flameKey.isEmpty())
|
|
||||||
m_settings->set("FlameKeyOverride", flameKey);
|
|
||||||
m_settings->reset("CFKeyOverride");
|
|
||||||
}
|
|
||||||
m_settings->registerSetting("UserAgentOverride", "");
|
|
||||||
|
|
||||||
// Init page provider
|
// Init page provider
|
||||||
{
|
{
|
||||||
@ -724,7 +756,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
auto platform = getIdealPlatform(BuildConfig.BUILD_PLATFORM);
|
auto platform = getIdealPlatform(BuildConfig.BUILD_PLATFORM);
|
||||||
auto channelUrl = BuildConfig.UPDATER_BASE + platform + "/channels.json";
|
auto channelUrl = BuildConfig.UPDATER_BASE + platform + "/channels.json";
|
||||||
qDebug() << "Initializing updater with platform: " << platform << " -- " << channelUrl;
|
qDebug() << "Initializing updater with platform: " << platform << " -- " << channelUrl;
|
||||||
m_updateChecker.reset(new UpdateChecker(m_network, channelUrl, BuildConfig.VERSION_CHANNEL));
|
m_updateChecker.reset(new UpdateChecker(m_network, channelUrl, BuildConfig.VERSION_CHANNEL, BuildConfig.VERSION_BUILD));
|
||||||
qDebug() << "<> Updater started.";
|
qDebug() << "<> Updater started.";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -814,9 +846,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
m_metacache->addBase("ModpacksCHPacks", QDir("cache/ModpacksCHPacks").absolutePath());
|
m_metacache->addBase("ModpacksCHPacks", QDir("cache/ModpacksCHPacks").absolutePath());
|
||||||
m_metacache->addBase("TechnicPacks", QDir("cache/TechnicPacks").absolutePath());
|
m_metacache->addBase("TechnicPacks", QDir("cache/TechnicPacks").absolutePath());
|
||||||
m_metacache->addBase("FlamePacks", QDir("cache/FlamePacks").absolutePath());
|
m_metacache->addBase("FlamePacks", QDir("cache/FlamePacks").absolutePath());
|
||||||
m_metacache->addBase("FlameMods", QDir("cache/FlameMods").absolutePath());
|
|
||||||
m_metacache->addBase("ModrinthPacks", QDir("cache/ModrinthPacks").absolutePath());
|
m_metacache->addBase("ModrinthPacks", QDir("cache/ModrinthPacks").absolutePath());
|
||||||
m_metacache->addBase("ModrinthModpacks", QDir("cache/ModrinthModpacks").absolutePath());
|
|
||||||
m_metacache->addBase("root", QDir::currentPath());
|
m_metacache->addBase("root", QDir::currentPath());
|
||||||
m_metacache->addBase("translations", QDir("translations").absolutePath());
|
m_metacache->addBase("translations", QDir("translations").absolutePath());
|
||||||
m_metacache->addBase("icons", QDir("cache/icons").absolutePath());
|
m_metacache->addBase("icons", QDir("cache/icons").absolutePath());
|
||||||
@ -867,13 +897,10 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
qDebug() << "<> Application theme set.";
|
qDebug() << "<> Application theme set.";
|
||||||
}
|
}
|
||||||
|
|
||||||
updateCapabilities();
|
|
||||||
|
|
||||||
if(createSetupWizard())
|
if(createSetupWizard())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
performMainStartupAction();
|
performMainStartupAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -982,7 +1009,7 @@ void Application::performMainStartupAction()
|
|||||||
qDebug() << " Launching with account" << m_profileToUse;
|
qDebug() << " Launching with account" << m_profileToUse;
|
||||||
}
|
}
|
||||||
|
|
||||||
launch(inst, true, false, nullptr, serverToJoin, accountToUse);
|
launch(inst, true, nullptr, serverToJoin, accountToUse);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1086,7 +1113,6 @@ void Application::messageReceived(const QByteArray& message)
|
|||||||
launch(
|
launch(
|
||||||
instance,
|
instance,
|
||||||
true,
|
true,
|
||||||
false,
|
|
||||||
nullptr,
|
nullptr,
|
||||||
serverObject,
|
serverObject,
|
||||||
accountObject
|
accountObject
|
||||||
@ -1141,15 +1167,6 @@ void Application::setApplicationTheme(const QString& name, bool initial)
|
|||||||
{
|
{
|
||||||
auto & theme = (*themeIter).second;
|
auto & theme = (*themeIter).second;
|
||||||
theme->apply(initial);
|
theme->apply(initial);
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
if (m_mainWindow) {
|
|
||||||
if (QString::compare(theme->id(), "dark") == 0) {
|
|
||||||
WinDarkmode::setDarkWinTitlebar(m_mainWindow->winId(), true);
|
|
||||||
} else {
|
|
||||||
WinDarkmode::setDarkWinTitlebar(m_mainWindow->winId(), false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1159,15 +1176,15 @@ void Application::setApplicationTheme(const QString& name, bool initial)
|
|||||||
|
|
||||||
void Application::setIconTheme(const QString& name)
|
void Application::setIconTheme(const QString& name)
|
||||||
{
|
{
|
||||||
QIcon::setThemeName(name);
|
XdgIcon::setThemeName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
QIcon Application::getThemedIcon(const QString& name)
|
QIcon Application::getThemedIcon(const QString& name)
|
||||||
{
|
{
|
||||||
if(name == "logo") {
|
if(name == "logo") {
|
||||||
return QIcon(":/org.prismlauncher.PrismLauncher.svg"); // FIXME: Make this a BuildConfig variable
|
return QIcon(":/org.polymc.PolyMC.svg");
|
||||||
}
|
}
|
||||||
return QIcon::fromTheme(name);
|
return XdgIcon::fromTheme(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Application::openJsonEditor(const QString &filename)
|
bool Application::openJsonEditor(const QString &filename)
|
||||||
@ -1187,7 +1204,6 @@ bool Application::openJsonEditor(const QString &filename)
|
|||||||
bool Application::launch(
|
bool Application::launch(
|
||||||
InstancePtr instance,
|
InstancePtr instance,
|
||||||
bool online,
|
bool online,
|
||||||
bool demo,
|
|
||||||
BaseProfilerFactory *profiler,
|
BaseProfilerFactory *profiler,
|
||||||
MinecraftServerTargetPtr serverToJoin,
|
MinecraftServerTargetPtr serverToJoin,
|
||||||
MinecraftAccountPtr accountToUse
|
MinecraftAccountPtr accountToUse
|
||||||
@ -1211,7 +1227,6 @@ bool Application::launch(
|
|||||||
controller.reset(new LaunchController());
|
controller.reset(new LaunchController());
|
||||||
controller->setInstance(instance);
|
controller->setInstance(instance);
|
||||||
controller->setOnline(online);
|
controller->setOnline(online);
|
||||||
controller->setDemo(demo);
|
|
||||||
controller->setProfiler(profiler);
|
controller->setProfiler(profiler);
|
||||||
controller->setServerToJoin(serverToJoin);
|
controller->setServerToJoin(serverToJoin);
|
||||||
controller->setAccountToUse(accountToUse);
|
controller->setAccountToUse(accountToUse);
|
||||||
@ -1225,9 +1240,6 @@ bool Application::launch(
|
|||||||
}
|
}
|
||||||
connect(controller.get(), &LaunchController::succeeded, this, &Application::controllerSucceeded);
|
connect(controller.get(), &LaunchController::succeeded, this, &Application::controllerSucceeded);
|
||||||
connect(controller.get(), &LaunchController::failed, this, &Application::controllerFailed);
|
connect(controller.get(), &LaunchController::failed, this, &Application::controllerFailed);
|
||||||
connect(controller.get(), &LaunchController::aborted, this, [this] {
|
|
||||||
controllerFailed(tr("Aborted"));
|
|
||||||
});
|
|
||||||
addRunningInstance();
|
addRunningInstance();
|
||||||
controller->start();
|
controller->start();
|
||||||
return true;
|
return true;
|
||||||
@ -1382,13 +1394,6 @@ MainWindow* Application::showMainWindow(bool minimized)
|
|||||||
m_mainWindow = new MainWindow();
|
m_mainWindow = new MainWindow();
|
||||||
m_mainWindow->restoreState(QByteArray::fromBase64(APPLICATION->settings()->get("MainWindowState").toByteArray()));
|
m_mainWindow->restoreState(QByteArray::fromBase64(APPLICATION->settings()->get("MainWindowState").toByteArray()));
|
||||||
m_mainWindow->restoreGeometry(QByteArray::fromBase64(APPLICATION->settings()->get("MainWindowGeometry").toByteArray()));
|
m_mainWindow->restoreGeometry(QByteArray::fromBase64(APPLICATION->settings()->get("MainWindowGeometry").toByteArray()));
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
if (QString::compare(settings()->get("ApplicationTheme").toString(), "dark") == 0) {
|
|
||||||
WinDarkmode::setDarkWinTitlebar(m_mainWindow->winId(), true);
|
|
||||||
} else {
|
|
||||||
WinDarkmode::setDarkWinTitlebar(m_mainWindow->winId(), false);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if(minimized)
|
if(minimized)
|
||||||
{
|
{
|
||||||
m_mainWindow->showMinimized();
|
m_mainWindow->showMinimized();
|
||||||
@ -1541,48 +1546,13 @@ shared_qobject_ptr<Meta::Index> Application::metadataIndex()
|
|||||||
return m_metadataIndex;
|
return m_metadataIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::updateCapabilities()
|
QString Application::getJarsPath()
|
||||||
{
|
{
|
||||||
m_capabilities = None;
|
if(m_jarsPath.isEmpty())
|
||||||
if (!getMSAClientID().isEmpty())
|
|
||||||
m_capabilities |= SupportsMSA;
|
|
||||||
if (!getFlameAPIKey().isEmpty())
|
|
||||||
m_capabilities |= SupportsFlame;
|
|
||||||
|
|
||||||
#ifdef Q_OS_LINUX
|
|
||||||
if (gamemode_query_status() >= 0)
|
|
||||||
m_capabilities |= SupportsGameMode;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
void *dummy = dlopen("libMangoHud_dlsym.so", RTLD_LAZY);
|
return FS::PathCombine(QCoreApplication::applicationDirPath(), "jars");
|
||||||
// try normal variant as well
|
|
||||||
if (dummy == NULL)
|
|
||||||
dummy = dlopen("libMangoHud.so", RTLD_LAZY);
|
|
||||||
|
|
||||||
if (dummy != NULL) {
|
|
||||||
dlclose(dummy);
|
|
||||||
m_capabilities |= SupportsMangoHud;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
return FS::PathCombine(m_rootPath, m_jarsPath);
|
||||||
}
|
|
||||||
|
|
||||||
QString Application::getJarPath(QString jarFile)
|
|
||||||
{
|
|
||||||
QStringList potentialPaths = {
|
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
|
||||||
FS::PathCombine(m_rootPath, "share/jars"),
|
|
||||||
#endif
|
|
||||||
FS::PathCombine(m_rootPath, "jars"),
|
|
||||||
FS::PathCombine(applicationDirPath(), "jars")
|
|
||||||
};
|
|
||||||
for(QString p : potentialPaths)
|
|
||||||
{
|
|
||||||
QString jarPath = FS::PathCombine(p, jarFile);
|
|
||||||
if (QFileInfo(jarPath).isFile())
|
|
||||||
return jarPath;
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Application::getMSAClientID()
|
QString Application::getMSAClientID()
|
||||||
@ -1595,33 +1565,12 @@ QString Application::getMSAClientID()
|
|||||||
return BuildConfig.MSA_CLIENT_ID;
|
return BuildConfig.MSA_CLIENT_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Application::getFlameAPIKey()
|
QString Application::getCurseKey()
|
||||||
{
|
{
|
||||||
QString keyOverride = m_settings->get("FlameKeyOverride").toString();
|
QString keyOverride = m_settings->get("CFKeyOverride").toString();
|
||||||
if (!keyOverride.isEmpty()) {
|
if (!keyOverride.isEmpty()) {
|
||||||
return keyOverride;
|
return keyOverride;
|
||||||
}
|
}
|
||||||
|
|
||||||
return BuildConfig.FLAME_API_KEY;
|
return BuildConfig.CURSEFORGE_API_KEY;
|
||||||
}
|
|
||||||
|
|
||||||
QString Application::getUserAgent()
|
|
||||||
{
|
|
||||||
QString uaOverride = m_settings->get("UserAgentOverride").toString();
|
|
||||||
if (!uaOverride.isEmpty()) {
|
|
||||||
return uaOverride.replace("$LAUNCHER_VER", BuildConfig.printableVersionString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return BuildConfig.USER_AGENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Application::getUserAgentUncached()
|
|
||||||
{
|
|
||||||
QString uaOverride = m_settings->get("UserAgentOverride").toString();
|
|
||||||
if (!uaOverride.isEmpty()) {
|
|
||||||
uaOverride += " (Uncached)";
|
|
||||||
return uaOverride.replace("$LAUNCHER_VER", BuildConfig.printableVersionString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return BuildConfig.USER_AGENT_UNCACHED;
|
|
||||||
}
|
}
|
||||||
|
@ -90,16 +90,6 @@ public:
|
|||||||
Initialized
|
Initialized
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Capability {
|
|
||||||
None = 0,
|
|
||||||
|
|
||||||
SupportsMSA = 1 << 0,
|
|
||||||
SupportsFlame = 1 << 1,
|
|
||||||
SupportsGameMode = 1 << 2,
|
|
||||||
SupportsMangoHud = 1 << 3,
|
|
||||||
};
|
|
||||||
Q_DECLARE_FLAGS(Capabilities, Capability)
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Application(int &argc, char **argv);
|
Application(int &argc, char **argv);
|
||||||
virtual ~Application();
|
virtual ~Application();
|
||||||
@ -164,28 +154,16 @@ public:
|
|||||||
|
|
||||||
shared_qobject_ptr<Meta::Index> metadataIndex();
|
shared_qobject_ptr<Meta::Index> metadataIndex();
|
||||||
|
|
||||||
void updateCapabilities();
|
QString getJarsPath();
|
||||||
|
|
||||||
/*!
|
|
||||||
* Finds and returns the full path to a jar file.
|
|
||||||
* Returns a null-string if it could not be found.
|
|
||||||
*/
|
|
||||||
QString getJarPath(QString jarFile);
|
|
||||||
|
|
||||||
QString getMSAClientID();
|
QString getMSAClientID();
|
||||||
QString getFlameAPIKey();
|
QString getCurseKey();
|
||||||
QString getUserAgent();
|
|
||||||
QString getUserAgentUncached();
|
|
||||||
|
|
||||||
/// this is the root of the 'installation'. Used for automatic updates
|
/// this is the root of the 'installation'. Used for automatic updates
|
||||||
const QString &root() {
|
const QString &root() {
|
||||||
return m_rootPath;
|
return m_rootPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Capabilities capabilities() {
|
|
||||||
return m_capabilities;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Opens a json file using either a system default editor, or, if not empty, the editor
|
* Opens a json file using either a system default editor, or, if not empty, the editor
|
||||||
* specified in the settings
|
* specified in the settings
|
||||||
@ -213,7 +191,6 @@ public slots:
|
|||||||
bool launch(
|
bool launch(
|
||||||
InstancePtr instance,
|
InstancePtr instance,
|
||||||
bool online = true,
|
bool online = true,
|
||||||
bool demo = false,
|
|
||||||
BaseProfilerFactory *profiler = nullptr,
|
BaseProfilerFactory *profiler = nullptr,
|
||||||
MinecraftServerTargetPtr serverToJoin = nullptr,
|
MinecraftServerTargetPtr serverToJoin = nullptr,
|
||||||
MinecraftAccountPtr accountToUse = nullptr
|
MinecraftAccountPtr accountToUse = nullptr
|
||||||
@ -259,13 +236,13 @@ private:
|
|||||||
std::shared_ptr<GenericPageProvider> m_globalSettingsProvider;
|
std::shared_ptr<GenericPageProvider> m_globalSettingsProvider;
|
||||||
std::map<QString, std::unique_ptr<ITheme>> m_themes;
|
std::map<QString, std::unique_ptr<ITheme>> m_themes;
|
||||||
std::unique_ptr<MCEditTool> m_mcedit;
|
std::unique_ptr<MCEditTool> m_mcedit;
|
||||||
|
QString m_jarsPath;
|
||||||
QSet<QString> m_features;
|
QSet<QString> m_features;
|
||||||
|
|
||||||
QMap<QString, std::shared_ptr<BaseProfilerFactory>> m_profilers;
|
QMap<QString, std::shared_ptr<BaseProfilerFactory>> m_profilers;
|
||||||
|
|
||||||
QString m_rootPath;
|
QString m_rootPath;
|
||||||
Status m_status = Application::StartingUp;
|
Status m_status = Application::StartingUp;
|
||||||
Capabilities m_capabilities;
|
|
||||||
|
|
||||||
#ifdef Q_OS_MACOS
|
#ifdef Q_OS_MACOS
|
||||||
Qt::ApplicationState m_prevAppState = Qt::ApplicationInactive;
|
Qt::ApplicationState m_prevAppState = Qt::ApplicationInactive;
|
||||||
|
@ -1,47 +1,11 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
/*
|
|
||||||
* PolyMC - Minecraft Launcher
|
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
*
|
|
||||||
* 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 "ApplicationMessage.h"
|
#include "ApplicationMessage.h"
|
||||||
|
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include "Json.h"
|
|
||||||
|
|
||||||
void ApplicationMessage::parse(const QByteArray & input) {
|
void ApplicationMessage::parse(const QByteArray & input) {
|
||||||
auto doc = Json::requireDocument(input, "ApplicationMessage");
|
auto doc = QJsonDocument::fromBinaryData(input);
|
||||||
auto root = Json::requireObject(doc, "ApplicationMessage");
|
auto root = doc.object();
|
||||||
|
|
||||||
command = root.value("command").toString();
|
command = root.value("command").toString();
|
||||||
args.clear();
|
args.clear();
|
||||||
@ -61,5 +25,7 @@ QByteArray ApplicationMessage::serialize() {
|
|||||||
}
|
}
|
||||||
root.insert("args", outArgs);
|
root.insert("args", outArgs);
|
||||||
|
|
||||||
return Json::toText(root);
|
QJsonDocument out;
|
||||||
|
out.setObject(root);
|
||||||
|
return out.toBinaryData();
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
/*
|
/*
|
||||||
* PolyMC - Minecraft Launcher
|
* PolyMC - Minecraft Launcher
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
|
||||||
*
|
*
|
||||||
* 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
|
||||||
@ -39,7 +38,6 @@
|
|||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QRegularExpression>
|
|
||||||
|
|
||||||
#include "settings/INISettingsObject.h"
|
#include "settings/INISettingsObject.h"
|
||||||
#include "settings/Setting.h"
|
#include "settings/Setting.h"
|
||||||
@ -53,22 +51,15 @@ BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr s
|
|||||||
: QObject()
|
: QObject()
|
||||||
{
|
{
|
||||||
m_settings = settings;
|
m_settings = settings;
|
||||||
m_global_settings = globalSettings;
|
|
||||||
m_rootDir = rootDir;
|
m_rootDir = rootDir;
|
||||||
|
|
||||||
m_settings->registerSetting("name", "Unnamed Instance");
|
m_settings->registerSetting("name", "Unnamed Instance");
|
||||||
m_settings->registerSetting("iconKey", "default");
|
m_settings->registerSetting("iconKey", "default");
|
||||||
m_settings->registerSetting("notes", "");
|
m_settings->registerSetting("notes", "");
|
||||||
|
|
||||||
m_settings->registerSetting("lastLaunchTime", 0);
|
m_settings->registerSetting("lastLaunchTime", 0);
|
||||||
m_settings->registerSetting("totalTimePlayed", 0);
|
m_settings->registerSetting("totalTimePlayed", 0);
|
||||||
m_settings->registerSetting("lastTimePlayed", 0);
|
m_settings->registerSetting("lastTimePlayed", 0);
|
||||||
|
|
||||||
// Game time override
|
|
||||||
auto gameTimeOverride = m_settings->registerSetting("OverrideGameTime", false);
|
|
||||||
m_settings->registerOverride(globalSettings->getSetting("ShowGameTime"), gameTimeOverride);
|
|
||||||
m_settings->registerOverride(globalSettings->getSetting("RecordGameTime"), gameTimeOverride);
|
|
||||||
|
|
||||||
// NOTE: Sometimees InstanceType is already registered, as it was used to identify the type of
|
// NOTE: Sometimees InstanceType is already registered, as it was used to identify the type of
|
||||||
// a locally stored instance
|
// a locally stored instance
|
||||||
if (!m_settings->getSetting("InstanceType"))
|
if (!m_settings->getSetting("InstanceType"))
|
||||||
@ -89,14 +80,6 @@ BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr s
|
|||||||
|
|
||||||
m_settings->registerPassthrough(globalSettings->getSetting("ConsoleMaxLines"), nullptr);
|
m_settings->registerPassthrough(globalSettings->getSetting("ConsoleMaxLines"), nullptr);
|
||||||
m_settings->registerPassthrough(globalSettings->getSetting("ConsoleOverflowStop"), nullptr);
|
m_settings->registerPassthrough(globalSettings->getSetting("ConsoleOverflowStop"), nullptr);
|
||||||
|
|
||||||
// Managed Packs
|
|
||||||
m_settings->registerSetting("ManagedPack", false);
|
|
||||||
m_settings->registerSetting("ManagedPackType", "");
|
|
||||||
m_settings->registerSetting("ManagedPackID", "");
|
|
||||||
m_settings->registerSetting("ManagedPackName", "");
|
|
||||||
m_settings->registerSetting("ManagedPackVersionID", "");
|
|
||||||
m_settings->registerSetting("ManagedPackVersionName", "");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString BaseInstance::getPreLaunchCommand()
|
QString BaseInstance::getPreLaunchCommand()
|
||||||
@ -114,59 +97,9 @@ QString BaseInstance::getPostExitCommand()
|
|||||||
return settings()->get("PostExitCommand").toString();
|
return settings()->get("PostExitCommand").toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseInstance::isManagedPack() const
|
|
||||||
{
|
|
||||||
return m_settings->get("ManagedPack").toBool();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString BaseInstance::getManagedPackType() const
|
|
||||||
{
|
|
||||||
return m_settings->get("ManagedPackType").toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString BaseInstance::getManagedPackID() const
|
|
||||||
{
|
|
||||||
return m_settings->get("ManagedPackID").toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString BaseInstance::getManagedPackName() const
|
|
||||||
{
|
|
||||||
return m_settings->get("ManagedPackName").toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString BaseInstance::getManagedPackVersionID() const
|
|
||||||
{
|
|
||||||
return m_settings->get("ManagedPackVersionID").toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString BaseInstance::getManagedPackVersionName() const
|
|
||||||
{
|
|
||||||
return m_settings->get("ManagedPackVersionName").toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseInstance::setManagedPack(const QString& type, const QString& id, const QString& name, const QString& versionId, const QString& version)
|
|
||||||
{
|
|
||||||
m_settings->set("ManagedPack", true);
|
|
||||||
m_settings->set("ManagedPackType", type);
|
|
||||||
m_settings->set("ManagedPackID", id);
|
|
||||||
m_settings->set("ManagedPackName", name);
|
|
||||||
m_settings->set("ManagedPackVersionID", versionId);
|
|
||||||
m_settings->set("ManagedPackVersionName", version);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseInstance::copyManagedPack(BaseInstance& other)
|
|
||||||
{
|
|
||||||
m_settings->set("ManagedPack", other.isManagedPack());
|
|
||||||
m_settings->set("ManagedPackType", other.getManagedPackType());
|
|
||||||
m_settings->set("ManagedPackID", other.getManagedPackID());
|
|
||||||
m_settings->set("ManagedPackName", other.getManagedPackName());
|
|
||||||
m_settings->set("ManagedPackVersionID", other.getManagedPackVersionID());
|
|
||||||
m_settings->set("ManagedPackVersionName", other.getManagedPackVersionName());
|
|
||||||
}
|
|
||||||
|
|
||||||
int BaseInstance::getConsoleMaxLines() const
|
int BaseInstance::getConsoleMaxLines() const
|
||||||
{
|
{
|
||||||
auto lineSetting = m_settings->getSetting("ConsoleMaxLines");
|
auto lineSetting = settings()->getSetting("ConsoleMaxLines");
|
||||||
bool conversionOk = false;
|
bool conversionOk = false;
|
||||||
int maxLines = lineSetting->get().toInt(&conversionOk);
|
int maxLines = lineSetting->get().toInt(&conversionOk);
|
||||||
if(!conversionOk)
|
if(!conversionOk)
|
||||||
@ -179,7 +112,7 @@ int BaseInstance::getConsoleMaxLines() const
|
|||||||
|
|
||||||
bool BaseInstance::shouldStopOnConsoleOverflow() const
|
bool BaseInstance::shouldStopOnConsoleOverflow() const
|
||||||
{
|
{
|
||||||
return m_settings->get("ConsoleOverflowStop").toBool();
|
return settings()->get("ConsoleOverflowStop").toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseInstance::iconUpdated(QString key)
|
void BaseInstance::iconUpdated(QString key)
|
||||||
@ -254,7 +187,7 @@ void BaseInstance::setRunning(bool running)
|
|||||||
|
|
||||||
int64_t BaseInstance::totalTimePlayed() const
|
int64_t BaseInstance::totalTimePlayed() const
|
||||||
{
|
{
|
||||||
qint64 current = m_settings->get("totalTimePlayed").toLongLong();
|
qint64 current = settings()->get("totalTimePlayed").toLongLong();
|
||||||
if(m_isRunning)
|
if(m_isRunning)
|
||||||
{
|
{
|
||||||
QDateTime timeNow = QDateTime::currentDateTime();
|
QDateTime timeNow = QDateTime::currentDateTime();
|
||||||
@ -270,7 +203,7 @@ int64_t BaseInstance::lastTimePlayed() const
|
|||||||
QDateTime timeNow = QDateTime::currentDateTime();
|
QDateTime timeNow = QDateTime::currentDateTime();
|
||||||
return m_timeStarted.secsTo(timeNow);
|
return m_timeStarted.secsTo(timeNow);
|
||||||
}
|
}
|
||||||
return m_settings->get("lastTimePlayed").toLongLong();
|
return settings()->get("lastTimePlayed").toLongLong();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseInstance::resetTimePlayed()
|
void BaseInstance::resetTimePlayed()
|
||||||
@ -289,10 +222,8 @@ QString BaseInstance::instanceRoot() const
|
|||||||
return m_rootDir;
|
return m_rootDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsObjectPtr BaseInstance::settings()
|
SettingsObjectPtr BaseInstance::settings() const
|
||||||
{
|
{
|
||||||
loadSpecificSettings();
|
|
||||||
|
|
||||||
return m_settings;
|
return m_settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -355,11 +286,11 @@ QString BaseInstance::name() const
|
|||||||
|
|
||||||
QString BaseInstance::windowTitle() const
|
QString BaseInstance::windowTitle() const
|
||||||
{
|
{
|
||||||
return BuildConfig.LAUNCHER_DISPLAYNAME + ": " + name().replace(QRegularExpression("\\s+"), " ");
|
return BuildConfig.LAUNCHER_NAME + ": " + name().replace(QRegExp("[ \n\r\t]+"), " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: why is this here? move it to MinecraftInstance!!!
|
// FIXME: why is this here? move it to MinecraftInstance!!!
|
||||||
QStringList BaseInstance::extraArguments()
|
QStringList BaseInstance::extraArguments() const
|
||||||
{
|
{
|
||||||
return Commandline::splitArgs(settings()->get("JvmArgs").toString());
|
return Commandline::splitArgs(settings()->get("JvmArgs").toString());
|
||||||
}
|
}
|
||||||
@ -368,8 +299,3 @@ shared_qobject_ptr<LaunchTask> BaseInstance::getLaunchTask()
|
|||||||
{
|
{
|
||||||
return m_launchProcess;
|
return m_launchProcess;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseInstance::updateRuntimeContext()
|
|
||||||
{
|
|
||||||
// NOOP
|
|
||||||
}
|
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
/*
|
/*
|
||||||
* PolyMC - Minecraft Launcher
|
* PolyMC - Minecraft Launcher
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
|
||||||
*
|
*
|
||||||
* 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
|
||||||
@ -54,7 +53,6 @@
|
|||||||
#include "net/Mode.h"
|
#include "net/Mode.h"
|
||||||
|
|
||||||
#include "minecraft/launch/MinecraftServerTarget.h"
|
#include "minecraft/launch/MinecraftServerTarget.h"
|
||||||
#include "RuntimeContext.h"
|
|
||||||
|
|
||||||
class QDir;
|
class QDir;
|
||||||
class Task;
|
class Task;
|
||||||
@ -141,22 +139,13 @@ public:
|
|||||||
QString getPostExitCommand();
|
QString getPostExitCommand();
|
||||||
QString getWrapperCommand();
|
QString getWrapperCommand();
|
||||||
|
|
||||||
bool isManagedPack() const;
|
|
||||||
QString getManagedPackType() const;
|
|
||||||
QString getManagedPackID() const;
|
|
||||||
QString getManagedPackName() const;
|
|
||||||
QString getManagedPackVersionID() const;
|
|
||||||
QString getManagedPackVersionName() const;
|
|
||||||
void setManagedPack(const QString& type, const QString& id, const QString& name, const QString& versionId, const QString& version);
|
|
||||||
void copyManagedPack(BaseInstance& other);
|
|
||||||
|
|
||||||
/// guess log level from a line of game log
|
/// guess log level from a line of game log
|
||||||
virtual MessageLevel::Enum guessLevel(const QString &line, MessageLevel::Enum level)
|
virtual MessageLevel::Enum guessLevel(const QString &line, MessageLevel::Enum level)
|
||||||
{
|
{
|
||||||
return level;
|
return level;
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual QStringList extraArguments();
|
virtual QStringList extraArguments() const;
|
||||||
|
|
||||||
/// Traits. Normally inside the version, depends on instance implementation.
|
/// Traits. Normally inside the version, depends on instance implementation.
|
||||||
virtual QSet <QString> traits() const = 0;
|
virtual QSet <QString> traits() const = 0;
|
||||||
@ -172,18 +161,9 @@ public:
|
|||||||
/*!
|
/*!
|
||||||
* \brief Gets this instance's settings object.
|
* \brief Gets this instance's settings object.
|
||||||
* This settings object stores instance-specific settings.
|
* This settings object stores instance-specific settings.
|
||||||
*
|
|
||||||
* Note that this method is not const.
|
|
||||||
* It may call loadSpecificSettings() to ensure those are loaded.
|
|
||||||
*
|
|
||||||
* \return A pointer to this instance's settings object.
|
* \return A pointer to this instance's settings object.
|
||||||
*/
|
*/
|
||||||
virtual SettingsObjectPtr settings();
|
virtual SettingsObjectPtr settings() const;
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Loads settings specific to an instance type if they're not already loaded.
|
|
||||||
*/
|
|
||||||
virtual void loadSpecificSettings() = 0;
|
|
||||||
|
|
||||||
/// returns a valid update task
|
/// returns a valid update task
|
||||||
virtual Task::Ptr createUpdateTask(Net::Mode mode) = 0;
|
virtual Task::Ptr createUpdateTask(Net::Mode mode) = 0;
|
||||||
@ -199,7 +179,6 @@ public:
|
|||||||
* Create envrironment variables for running the instance
|
* Create envrironment variables for running the instance
|
||||||
*/
|
*/
|
||||||
virtual QProcessEnvironment createEnvironment() = 0;
|
virtual QProcessEnvironment createEnvironment() = 0;
|
||||||
virtual QProcessEnvironment createLaunchEnvironment() = 0;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Returns a matcher that can maps relative paths within the instance to whether they are 'log files'
|
* Returns a matcher that can maps relative paths within the instance to whether they are 'log files'
|
||||||
@ -217,16 +196,10 @@ public:
|
|||||||
virtual QString instanceConfigFolder() const = 0;
|
virtual QString instanceConfigFolder() const = 0;
|
||||||
|
|
||||||
/// get variables this instance exports
|
/// get variables this instance exports
|
||||||
virtual QMap<QString, QString> getVariables() = 0;
|
virtual QMap<QString, QString> getVariables() const = 0;
|
||||||
|
|
||||||
virtual QString typeName() const = 0;
|
virtual QString typeName() const = 0;
|
||||||
|
|
||||||
void updateRuntimeContext();
|
|
||||||
RuntimeContext runtimeContext() const
|
|
||||||
{
|
|
||||||
return m_runtimeContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasVersionBroken() const
|
bool hasVersionBroken() const
|
||||||
{
|
{
|
||||||
return m_hasBrokenVersion;
|
return m_hasBrokenVersion;
|
||||||
@ -285,11 +258,6 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
void changeStatus(Status newStatus);
|
void changeStatus(Status newStatus);
|
||||||
|
|
||||||
SettingsObjectPtr globalSettings() const { return m_global_settings.lock(); };
|
|
||||||
|
|
||||||
bool isSpecificSettingsLoaded() const { return m_specific_settings_loaded; }
|
|
||||||
void setSpecificSettingsLoaded(bool loaded) { m_specific_settings_loaded = loaded; }
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/*!
|
/*!
|
||||||
* \brief Signal emitted when properties relevant to the instance view change
|
* \brief Signal emitted when properties relevant to the instance view change
|
||||||
@ -312,17 +280,12 @@ protected: /* data */
|
|||||||
bool m_isRunning = false;
|
bool m_isRunning = false;
|
||||||
shared_qobject_ptr<LaunchTask> m_launchProcess;
|
shared_qobject_ptr<LaunchTask> m_launchProcess;
|
||||||
QDateTime m_timeStarted;
|
QDateTime m_timeStarted;
|
||||||
RuntimeContext m_runtimeContext;
|
|
||||||
|
|
||||||
private: /* data */
|
private: /* data */
|
||||||
Status m_status = Status::Present;
|
Status m_status = Status::Present;
|
||||||
bool m_crashed = false;
|
bool m_crashed = false;
|
||||||
bool m_hasUpdate = false;
|
bool m_hasUpdate = false;
|
||||||
bool m_hasBrokenVersion = false;
|
bool m_hasBrokenVersion = false;
|
||||||
|
|
||||||
SettingsObjectWeakPtr m_global_settings;
|
|
||||||
bool m_specific_settings_loaded = false;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(shared_qobject_ptr<BaseInstance>)
|
Q_DECLARE_METATYPE(shared_qobject_ptr<BaseInstance>)
|
||||||
|
@ -1,36 +1,16 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
/* Copyright 2013-2021 MultiMC Contributors
|
||||||
/*
|
|
||||||
* PolyMC - Minecraft Launcher
|
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* it under the terms of the GNU General Public License as published by
|
* you may not use this file except in compliance with the License.
|
||||||
* the Free Software Foundation, version 3.
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
* 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
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
*
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* This file incorporates work covered by the following copyright and
|
* See the License for the specific language governing permissions and
|
||||||
* permission notice:
|
* limitations under the License.
|
||||||
*
|
|
||||||
* 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 "BaseVersionList.h"
|
#include "BaseVersionList.h"
|
||||||
@ -71,7 +51,7 @@ QVariant BaseVersionList::data(const QModelIndex &index, int role) const
|
|||||||
switch (role)
|
switch (role)
|
||||||
{
|
{
|
||||||
case VersionPointerRole:
|
case VersionPointerRole:
|
||||||
return QVariant::fromValue(version);
|
return qVariantFromValue(version);
|
||||||
|
|
||||||
case VersionRole:
|
case VersionRole:
|
||||||
return version->name();
|
return version->name();
|
||||||
|
@ -4,6 +4,8 @@ project(application)
|
|||||||
|
|
||||||
######## Sources and headers ########
|
######## Sources and headers ########
|
||||||
|
|
||||||
|
include (UnitTest)
|
||||||
|
|
||||||
set(CORE_SOURCES
|
set(CORE_SOURCES
|
||||||
# LOGIC - Base classes and infrastructure
|
# LOGIC - Base classes and infrastructure
|
||||||
BaseInstaller.h
|
BaseInstaller.h
|
||||||
@ -26,7 +28,6 @@ set(CORE_SOURCES
|
|||||||
MMCZip.cpp
|
MMCZip.cpp
|
||||||
MMCStrings.h
|
MMCStrings.h
|
||||||
MMCStrings.cpp
|
MMCStrings.cpp
|
||||||
RuntimeContext.h
|
|
||||||
|
|
||||||
# Basic instance manipulation tasks (derived from InstanceTask)
|
# Basic instance manipulation tasks (derived from InstanceTask)
|
||||||
InstanceCreationTask.h
|
InstanceCreationTask.h
|
||||||
@ -89,6 +90,17 @@ set(CORE_SOURCES
|
|||||||
MMCTime.cpp
|
MMCTime.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_unit_test(FileSystem
|
||||||
|
SOURCES FileSystem_test.cpp
|
||||||
|
LIBS Launcher_logic
|
||||||
|
DATA testdata
|
||||||
|
)
|
||||||
|
|
||||||
|
add_unit_test(GZip
|
||||||
|
SOURCES GZip_test.cpp
|
||||||
|
LIBS Launcher_logic
|
||||||
|
)
|
||||||
|
|
||||||
set(PATHMATCHER_SOURCES
|
set(PATHMATCHER_SOURCES
|
||||||
# Path matchers
|
# Path matchers
|
||||||
pathmatcher/FSTreeMatcher.h
|
pathmatcher/FSTreeMatcher.h
|
||||||
@ -112,7 +124,6 @@ set(NET_SOURCES
|
|||||||
net/NetAction.h
|
net/NetAction.h
|
||||||
net/NetJob.cpp
|
net/NetJob.cpp
|
||||||
net/NetJob.h
|
net/NetJob.h
|
||||||
net/NetUtils.h
|
|
||||||
net/PasteUpload.cpp
|
net/PasteUpload.cpp
|
||||||
net/PasteUpload.h
|
net/PasteUpload.h
|
||||||
net/Sink.h
|
net/Sink.h
|
||||||
@ -153,13 +164,19 @@ set(UPDATE_SOURCES
|
|||||||
updater/UpdateChecker.cpp
|
updater/UpdateChecker.cpp
|
||||||
updater/DownloadTask.h
|
updater/DownloadTask.h
|
||||||
updater/DownloadTask.cpp
|
updater/DownloadTask.cpp
|
||||||
updater/ExternalUpdater.h
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(MAC_UPDATE_SOURCES
|
add_unit_test(UpdateChecker
|
||||||
updater/MacSparkleUpdater.h
|
SOURCES updater/UpdateChecker_test.cpp
|
||||||
updater/MacSparkleUpdater.mm
|
LIBS Launcher_logic
|
||||||
)
|
DATA updater/testdata
|
||||||
|
)
|
||||||
|
|
||||||
|
add_unit_test(DownloadTask
|
||||||
|
SOURCES updater/DownloadTask_test.cpp
|
||||||
|
LIBS Launcher_logic
|
||||||
|
DATA updater/testdata
|
||||||
|
)
|
||||||
|
|
||||||
# Backend for the news bar... there's usually no news.
|
# Backend for the news bar... there's usually no news.
|
||||||
set(NEWS_SOURCES
|
set(NEWS_SOURCES
|
||||||
@ -289,6 +306,8 @@ set(MINECRAFT_SOURCES
|
|||||||
minecraft/Rule.h
|
minecraft/Rule.h
|
||||||
minecraft/OneSixVersionFormat.cpp
|
minecraft/OneSixVersionFormat.cpp
|
||||||
minecraft/OneSixVersionFormat.h
|
minecraft/OneSixVersionFormat.h
|
||||||
|
minecraft/OpSys.cpp
|
||||||
|
minecraft/OpSys.h
|
||||||
minecraft/ParseUtils.cpp
|
minecraft/ParseUtils.cpp
|
||||||
minecraft/ParseUtils.h
|
minecraft/ParseUtils.h
|
||||||
minecraft/ProfileUtils.cpp
|
minecraft/ProfileUtils.cpp
|
||||||
@ -296,8 +315,6 @@ set(MINECRAFT_SOURCES
|
|||||||
minecraft/Library.cpp
|
minecraft/Library.cpp
|
||||||
minecraft/Library.h
|
minecraft/Library.h
|
||||||
minecraft/MojangDownloadInfo.h
|
minecraft/MojangDownloadInfo.h
|
||||||
minecraft/VanillaInstanceCreationTask.cpp
|
|
||||||
minecraft/VanillaInstanceCreationTask.h
|
|
||||||
minecraft/VersionFile.cpp
|
minecraft/VersionFile.cpp
|
||||||
minecraft/VersionFile.h
|
minecraft/VersionFile.h
|
||||||
minecraft/VersionFilterData.h
|
minecraft/VersionFilterData.h
|
||||||
@ -307,36 +324,19 @@ set(MINECRAFT_SOURCES
|
|||||||
minecraft/WorldList.h
|
minecraft/WorldList.h
|
||||||
minecraft/WorldList.cpp
|
minecraft/WorldList.cpp
|
||||||
|
|
||||||
minecraft/mod/MetadataHandler.h
|
|
||||||
minecraft/mod/Mod.h
|
minecraft/mod/Mod.h
|
||||||
minecraft/mod/Mod.cpp
|
minecraft/mod/Mod.cpp
|
||||||
minecraft/mod/ModDetails.h
|
minecraft/mod/ModDetails.h
|
||||||
minecraft/mod/ModFolderModel.h
|
minecraft/mod/ModFolderModel.h
|
||||||
minecraft/mod/ModFolderModel.cpp
|
minecraft/mod/ModFolderModel.cpp
|
||||||
minecraft/mod/Resource.h
|
minecraft/mod/ModFolderLoadTask.h
|
||||||
minecraft/mod/Resource.cpp
|
minecraft/mod/ModFolderLoadTask.cpp
|
||||||
minecraft/mod/ResourceFolderModel.h
|
minecraft/mod/LocalModParseTask.h
|
||||||
minecraft/mod/ResourceFolderModel.cpp
|
minecraft/mod/LocalModParseTask.cpp
|
||||||
minecraft/mod/ResourcePack.h
|
|
||||||
minecraft/mod/ResourcePack.cpp
|
|
||||||
minecraft/mod/ResourcePackFolderModel.h
|
minecraft/mod/ResourcePackFolderModel.h
|
||||||
minecraft/mod/ResourcePackFolderModel.cpp
|
minecraft/mod/ResourcePackFolderModel.cpp
|
||||||
minecraft/mod/TexturePack.h
|
|
||||||
minecraft/mod/TexturePack.cpp
|
|
||||||
minecraft/mod/TexturePackFolderModel.h
|
minecraft/mod/TexturePackFolderModel.h
|
||||||
minecraft/mod/TexturePackFolderModel.cpp
|
minecraft/mod/TexturePackFolderModel.cpp
|
||||||
minecraft/mod/ShaderPackFolderModel.h
|
|
||||||
minecraft/mod/tasks/BasicFolderLoadTask.h
|
|
||||||
minecraft/mod/tasks/ModFolderLoadTask.h
|
|
||||||
minecraft/mod/tasks/ModFolderLoadTask.cpp
|
|
||||||
minecraft/mod/tasks/LocalModParseTask.h
|
|
||||||
minecraft/mod/tasks/LocalModParseTask.cpp
|
|
||||||
minecraft/mod/tasks/LocalModUpdateTask.h
|
|
||||||
minecraft/mod/tasks/LocalModUpdateTask.cpp
|
|
||||||
minecraft/mod/tasks/LocalResourcePackParseTask.h
|
|
||||||
minecraft/mod/tasks/LocalResourcePackParseTask.cpp
|
|
||||||
minecraft/mod/tasks/LocalTexturePackParseTask.h
|
|
||||||
minecraft/mod/tasks/LocalTexturePackParseTask.cpp
|
|
||||||
|
|
||||||
# Assets
|
# Assets
|
||||||
minecraft/AssetsUtils.h
|
minecraft/AssetsUtils.h
|
||||||
@ -354,6 +354,52 @@ set(MINECRAFT_SOURCES
|
|||||||
mojang/PackageManifest.cpp
|
mojang/PackageManifest.cpp
|
||||||
minecraft/Agent.h)
|
minecraft/Agent.h)
|
||||||
|
|
||||||
|
add_unit_test(GradleSpecifier
|
||||||
|
SOURCES minecraft/GradleSpecifier_test.cpp
|
||||||
|
LIBS Launcher_logic
|
||||||
|
)
|
||||||
|
|
||||||
|
if(BUILD_TESTING)
|
||||||
|
add_executable(PackageManifest
|
||||||
|
mojang/PackageManifest_test.cpp
|
||||||
|
)
|
||||||
|
target_link_libraries(PackageManifest
|
||||||
|
Launcher_logic
|
||||||
|
Qt5::Test
|
||||||
|
)
|
||||||
|
target_include_directories(PackageManifest
|
||||||
|
PRIVATE ../cmake/UnitTest/
|
||||||
|
)
|
||||||
|
add_test(
|
||||||
|
NAME PackageManifest
|
||||||
|
COMMAND PackageManifest
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_unit_test(MojangVersionFormat
|
||||||
|
SOURCES minecraft/MojangVersionFormat_test.cpp
|
||||||
|
LIBS Launcher_logic
|
||||||
|
DATA minecraft/testdata
|
||||||
|
)
|
||||||
|
|
||||||
|
add_unit_test(Library
|
||||||
|
SOURCES minecraft/Library_test.cpp
|
||||||
|
LIBS Launcher_logic
|
||||||
|
)
|
||||||
|
|
||||||
|
# FIXME: shares data with FileSystem test
|
||||||
|
add_unit_test(ModFolderModel
|
||||||
|
SOURCES minecraft/mod/ModFolderModel_test.cpp
|
||||||
|
DATA testdata
|
||||||
|
LIBS Launcher_logic
|
||||||
|
)
|
||||||
|
|
||||||
|
add_unit_test(ParseUtils
|
||||||
|
SOURCES minecraft/ParseUtils_test.cpp
|
||||||
|
LIBS Launcher_logic
|
||||||
|
)
|
||||||
|
|
||||||
# the screenshots feature
|
# the screenshots feature
|
||||||
set(SCREENSHOTS_SOURCES
|
set(SCREENSHOTS_SOURCES
|
||||||
screenshots/Screenshot.h
|
screenshots/Screenshot.h
|
||||||
@ -367,14 +413,15 @@ set(TASKS_SOURCES
|
|||||||
# Tasks
|
# Tasks
|
||||||
tasks/Task.h
|
tasks/Task.h
|
||||||
tasks/Task.cpp
|
tasks/Task.cpp
|
||||||
tasks/ConcurrentTask.h
|
|
||||||
tasks/ConcurrentTask.cpp
|
|
||||||
tasks/SequentialTask.h
|
tasks/SequentialTask.h
|
||||||
tasks/SequentialTask.cpp
|
tasks/SequentialTask.cpp
|
||||||
tasks/MultipleOptionsTask.h
|
|
||||||
tasks/MultipleOptionsTask.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_unit_test(Task
|
||||||
|
SOURCES tasks/Task_test.cpp
|
||||||
|
LIBS Launcher_logic
|
||||||
|
)
|
||||||
|
|
||||||
set(SETTINGS_SOURCES
|
set(SETTINGS_SOURCES
|
||||||
# Settings
|
# Settings
|
||||||
settings/INIFile.cpp
|
settings/INIFile.cpp
|
||||||
@ -391,6 +438,11 @@ set(SETTINGS_SOURCES
|
|||||||
settings/SettingsObject.h
|
settings/SettingsObject.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_unit_test(INIFile
|
||||||
|
SOURCES settings/INIFile_test.cpp
|
||||||
|
LIBS Launcher_logic
|
||||||
|
)
|
||||||
|
|
||||||
set(JAVA_SOURCES
|
set(JAVA_SOURCES
|
||||||
java/JavaChecker.h
|
java/JavaChecker.h
|
||||||
java/JavaChecker.cpp
|
java/JavaChecker.cpp
|
||||||
@ -406,6 +458,11 @@ set(JAVA_SOURCES
|
|||||||
java/JavaVersion.cpp
|
java/JavaVersion.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_unit_test(JavaVersion
|
||||||
|
SOURCES java/JavaVersion_test.cpp
|
||||||
|
LIBS Launcher_logic
|
||||||
|
)
|
||||||
|
|
||||||
set(TRANSLATIONS_SOURCES
|
set(TRANSLATIONS_SOURCES
|
||||||
translations/TranslationsModel.h
|
translations/TranslationsModel.h
|
||||||
translations/TranslationsModel.cpp
|
translations/TranslationsModel.cpp
|
||||||
@ -442,26 +499,13 @@ set(META_SOURCES
|
|||||||
)
|
)
|
||||||
|
|
||||||
set(API_SOURCES
|
set(API_SOURCES
|
||||||
modplatform/ModIndex.h
|
|
||||||
modplatform/ModIndex.cpp
|
|
||||||
|
|
||||||
modplatform/ModAPI.h
|
modplatform/ModAPI.h
|
||||||
|
|
||||||
modplatform/EnsureMetadataTask.h
|
|
||||||
modplatform/EnsureMetadataTask.cpp
|
|
||||||
|
|
||||||
modplatform/CheckUpdateTask.h
|
|
||||||
|
|
||||||
modplatform/flame/FlameAPI.h
|
modplatform/flame/FlameAPI.h
|
||||||
modplatform/flame/FlameAPI.cpp
|
|
||||||
modplatform/modrinth/ModrinthAPI.h
|
modplatform/modrinth/ModrinthAPI.h
|
||||||
modplatform/modrinth/ModrinthAPI.cpp
|
|
||||||
modplatform/helpers/NetworkModAPI.h
|
modplatform/helpers/NetworkModAPI.h
|
||||||
modplatform/helpers/NetworkModAPI.cpp
|
modplatform/helpers/NetworkModAPI.cpp
|
||||||
modplatform/helpers/HashUtils.h
|
|
||||||
modplatform/helpers/HashUtils.cpp
|
|
||||||
modplatform/helpers/OverrideUtils.h
|
|
||||||
modplatform/helpers/OverrideUtils.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(FTB_SOURCES
|
set(FTB_SOURCES
|
||||||
@ -485,10 +529,6 @@ set(FLAME_SOURCES
|
|||||||
modplatform/flame/PackManifest.cpp
|
modplatform/flame/PackManifest.cpp
|
||||||
modplatform/flame/FileResolvingTask.h
|
modplatform/flame/FileResolvingTask.h
|
||||||
modplatform/flame/FileResolvingTask.cpp
|
modplatform/flame/FileResolvingTask.cpp
|
||||||
modplatform/flame/FlameCheckUpdate.cpp
|
|
||||||
modplatform/flame/FlameCheckUpdate.h
|
|
||||||
modplatform/flame/FlameInstanceCreationTask.h
|
|
||||||
modplatform/flame/FlameInstanceCreationTask.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(MODRINTH_SOURCES
|
set(MODRINTH_SOURCES
|
||||||
@ -496,10 +536,6 @@ set(MODRINTH_SOURCES
|
|||||||
modplatform/modrinth/ModrinthPackIndex.h
|
modplatform/modrinth/ModrinthPackIndex.h
|
||||||
modplatform/modrinth/ModrinthPackManifest.cpp
|
modplatform/modrinth/ModrinthPackManifest.cpp
|
||||||
modplatform/modrinth/ModrinthPackManifest.h
|
modplatform/modrinth/ModrinthPackManifest.h
|
||||||
modplatform/modrinth/ModrinthCheckUpdate.cpp
|
|
||||||
modplatform/modrinth/ModrinthCheckUpdate.h
|
|
||||||
modplatform/modrinth/ModrinthInstanceCreationTask.cpp
|
|
||||||
modplatform/modrinth/ModrinthInstanceCreationTask.h
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(MODPACKSCH_SOURCES
|
set(MODPACKSCH_SOURCES
|
||||||
@ -509,12 +545,6 @@ set(MODPACKSCH_SOURCES
|
|||||||
modplatform/modpacksch/FTBPackManifest.cpp
|
modplatform/modpacksch/FTBPackManifest.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(PACKWIZ_SOURCES
|
|
||||||
modplatform/packwiz/Packwiz.h
|
|
||||||
modplatform/packwiz/Packwiz.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
set(TECHNIC_SOURCES
|
set(TECHNIC_SOURCES
|
||||||
modplatform/technic/SingleZipPackInstallTask.h
|
modplatform/technic/SingleZipPackInstallTask.h
|
||||||
modplatform/technic/SingleZipPackInstallTask.cpp
|
modplatform/technic/SingleZipPackInstallTask.cpp
|
||||||
@ -537,6 +567,11 @@ set(ATLAUNCHER_SOURCES
|
|||||||
modplatform/atlauncher/ATLShareCode.h
|
modplatform/atlauncher/ATLShareCode.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_unit_test(Index
|
||||||
|
SOURCES meta/Index_test.cpp
|
||||||
|
LIBS Launcher_logic
|
||||||
|
)
|
||||||
|
|
||||||
################################ COMPILE ################################
|
################################ COMPILE ################################
|
||||||
|
|
||||||
# we need zlib
|
# we need zlib
|
||||||
@ -563,15 +598,10 @@ set(LOGIC_SOURCES
|
|||||||
${FLAME_SOURCES}
|
${FLAME_SOURCES}
|
||||||
${MODRINTH_SOURCES}
|
${MODRINTH_SOURCES}
|
||||||
${MODPACKSCH_SOURCES}
|
${MODPACKSCH_SOURCES}
|
||||||
${PACKWIZ_SOURCES}
|
|
||||||
${TECHNIC_SOURCES}
|
${TECHNIC_SOURCES}
|
||||||
${ATLAUNCHER_SOURCES}
|
${ATLAUNCHER_SOURCES}
|
||||||
)
|
)
|
||||||
|
|
||||||
if(APPLE)
|
|
||||||
set (LOGIC_SOURCES ${LOGIC_SOURCES} ${MAC_UPDATE_SOURCES})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
SET(LAUNCHER_SOURCES
|
SET(LAUNCHER_SOURCES
|
||||||
# Application base
|
# Application base
|
||||||
Application.h
|
Application.h
|
||||||
@ -667,8 +697,6 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/pages/BasePageProvider.h
|
ui/pages/BasePageProvider.h
|
||||||
|
|
||||||
# GUI - instance pages
|
# GUI - instance pages
|
||||||
ui/pages/instance/ExternalResourcesPage.cpp
|
|
||||||
ui/pages/instance/ExternalResourcesPage.h
|
|
||||||
ui/pages/instance/GameOptionsPage.cpp
|
ui/pages/instance/GameOptionsPage.cpp
|
||||||
ui/pages/instance/GameOptionsPage.h
|
ui/pages/instance/GameOptionsPage.h
|
||||||
ui/pages/instance/VersionPage.cpp
|
ui/pages/instance/VersionPage.cpp
|
||||||
@ -730,8 +758,6 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/pages/modplatform/atlauncher/AtlOptionalModDialog.h
|
ui/pages/modplatform/atlauncher/AtlOptionalModDialog.h
|
||||||
ui/pages/modplatform/atlauncher/AtlPage.cpp
|
ui/pages/modplatform/atlauncher/AtlPage.cpp
|
||||||
ui/pages/modplatform/atlauncher/AtlPage.h
|
ui/pages/modplatform/atlauncher/AtlPage.h
|
||||||
ui/pages/modplatform/atlauncher/AtlUserInteractionSupportImpl.cpp
|
|
||||||
ui/pages/modplatform/atlauncher/AtlUserInteractionSupportImpl.h
|
|
||||||
|
|
||||||
ui/pages/modplatform/ftb/FtbFilterModel.cpp
|
ui/pages/modplatform/ftb/FtbFilterModel.cpp
|
||||||
ui/pages/modplatform/ftb/FtbFilterModel.h
|
ui/pages/modplatform/ftb/FtbFilterModel.h
|
||||||
@ -799,8 +825,6 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/dialogs/NewComponentDialog.h
|
ui/dialogs/NewComponentDialog.h
|
||||||
ui/dialogs/NewInstanceDialog.cpp
|
ui/dialogs/NewInstanceDialog.cpp
|
||||||
ui/dialogs/NewInstanceDialog.h
|
ui/dialogs/NewInstanceDialog.h
|
||||||
ui/dialogs/NewsDialog.cpp
|
|
||||||
ui/dialogs/NewsDialog.h
|
|
||||||
ui/pagedialog/PageDialog.cpp
|
ui/pagedialog/PageDialog.cpp
|
||||||
ui/pagedialog/PageDialog.h
|
ui/pagedialog/PageDialog.h
|
||||||
ui/dialogs/ProgressDialog.cpp
|
ui/dialogs/ProgressDialog.cpp
|
||||||
@ -817,12 +841,6 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/dialogs/ModDownloadDialog.h
|
ui/dialogs/ModDownloadDialog.h
|
||||||
ui/dialogs/ScrollMessageBox.cpp
|
ui/dialogs/ScrollMessageBox.cpp
|
||||||
ui/dialogs/ScrollMessageBox.h
|
ui/dialogs/ScrollMessageBox.h
|
||||||
ui/dialogs/BlockedModsDialog.cpp
|
|
||||||
ui/dialogs/BlockedModsDialog.h
|
|
||||||
ui/dialogs/ChooseProviderDialog.h
|
|
||||||
ui/dialogs/ChooseProviderDialog.cpp
|
|
||||||
ui/dialogs/ModUpdateDialog.cpp
|
|
||||||
ui/dialogs/ModUpdateDialog.h
|
|
||||||
|
|
||||||
# GUI - widgets
|
# GUI - widgets
|
||||||
ui/widgets/Common.cpp
|
ui/widgets/Common.cpp
|
||||||
@ -845,8 +863,8 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/widgets/LineSeparator.h
|
ui/widgets/LineSeparator.h
|
||||||
ui/widgets/LogView.cpp
|
ui/widgets/LogView.cpp
|
||||||
ui/widgets/LogView.h
|
ui/widgets/LogView.h
|
||||||
ui/widgets/InfoFrame.cpp
|
ui/widgets/MCModInfoFrame.cpp
|
||||||
ui/widgets/InfoFrame.h
|
ui/widgets/MCModInfoFrame.h
|
||||||
ui/widgets/ModFilterWidget.cpp
|
ui/widgets/ModFilterWidget.cpp
|
||||||
ui/widgets/ModFilterWidget.h
|
ui/widgets/ModFilterWidget.h
|
||||||
ui/widgets/ModListView.cpp
|
ui/widgets/ModListView.cpp
|
||||||
@ -854,12 +872,6 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/widgets/PageContainer.cpp
|
ui/widgets/PageContainer.cpp
|
||||||
ui/widgets/PageContainer.h
|
ui/widgets/PageContainer.h
|
||||||
ui/widgets/PageContainer_p.h
|
ui/widgets/PageContainer_p.h
|
||||||
ui/widgets/ProjectDescriptionPage.h
|
|
||||||
ui/widgets/ProjectDescriptionPage.cpp
|
|
||||||
ui/widgets/VariableSizedImageObject.h
|
|
||||||
ui/widgets/VariableSizedImageObject.cpp
|
|
||||||
ui/widgets/ProjectItem.h
|
|
||||||
ui/widgets/ProjectItem.cpp
|
|
||||||
ui/widgets/VersionListView.cpp
|
ui/widgets/VersionListView.cpp
|
||||||
ui/widgets/VersionListView.h
|
ui/widgets/VersionListView.h
|
||||||
ui/widgets/VersionSelectWidget.cpp
|
ui/widgets/VersionSelectWidget.cpp
|
||||||
@ -883,17 +895,7 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/instanceview/VisualGroup.h
|
ui/instanceview/VisualGroup.h
|
||||||
)
|
)
|
||||||
|
|
||||||
if(WIN32)
|
qt5_wrap_ui(LAUNCHER_UI
|
||||||
set(LAUNCHER_SOURCES
|
|
||||||
${LAUNCHER_SOURCES}
|
|
||||||
|
|
||||||
# GUI - dark titlebar for Windows 10/11
|
|
||||||
ui/WinDarkmode.h
|
|
||||||
ui/WinDarkmode.cpp
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
qt_wrap_ui(LAUNCHER_UI
|
|
||||||
ui/setupwizard/PasteWizardPage.ui
|
ui/setupwizard/PasteWizardPage.ui
|
||||||
ui/pages/global/AccountListPage.ui
|
ui/pages/global/AccountListPage.ui
|
||||||
ui/pages/global/JavaPage.ui
|
ui/pages/global/JavaPage.ui
|
||||||
@ -902,7 +904,7 @@ qt_wrap_ui(LAUNCHER_UI
|
|||||||
ui/pages/global/ProxyPage.ui
|
ui/pages/global/ProxyPage.ui
|
||||||
ui/pages/global/MinecraftPage.ui
|
ui/pages/global/MinecraftPage.ui
|
||||||
ui/pages/global/ExternalToolsPage.ui
|
ui/pages/global/ExternalToolsPage.ui
|
||||||
ui/pages/instance/ExternalResourcesPage.ui
|
ui/pages/instance/ModFolderPage.ui
|
||||||
ui/pages/instance/NotesPage.ui
|
ui/pages/instance/NotesPage.ui
|
||||||
ui/pages/instance/LogPage.ui
|
ui/pages/instance/LogPage.ui
|
||||||
ui/pages/instance/ServersPage.ui
|
ui/pages/instance/ServersPage.ui
|
||||||
@ -924,7 +926,7 @@ qt_wrap_ui(LAUNCHER_UI
|
|||||||
ui/pages/modplatform/technic/TechnicPage.ui
|
ui/pages/modplatform/technic/TechnicPage.ui
|
||||||
ui/widgets/InstanceCardWidget.ui
|
ui/widgets/InstanceCardWidget.ui
|
||||||
ui/widgets/CustomCommands.ui
|
ui/widgets/CustomCommands.ui
|
||||||
ui/widgets/InfoFrame.ui
|
ui/widgets/MCModInfoFrame.ui
|
||||||
ui/widgets/ModFilterWidget.ui
|
ui/widgets/ModFilterWidget.ui
|
||||||
ui/dialogs/CopyInstanceDialog.ui
|
ui/dialogs/CopyInstanceDialog.ui
|
||||||
ui/dialogs/ProfileSetupDialog.ui
|
ui/dialogs/ProfileSetupDialog.ui
|
||||||
@ -932,7 +934,6 @@ qt_wrap_ui(LAUNCHER_UI
|
|||||||
ui/dialogs/NewInstanceDialog.ui
|
ui/dialogs/NewInstanceDialog.ui
|
||||||
ui/dialogs/UpdateDialog.ui
|
ui/dialogs/UpdateDialog.ui
|
||||||
ui/dialogs/NewComponentDialog.ui
|
ui/dialogs/NewComponentDialog.ui
|
||||||
ui/dialogs/NewsDialog.ui
|
|
||||||
ui/dialogs/ProfileSelectDialog.ui
|
ui/dialogs/ProfileSelectDialog.ui
|
||||||
ui/dialogs/SkinUploadDialog.ui
|
ui/dialogs/SkinUploadDialog.ui
|
||||||
ui/dialogs/ExportInstanceDialog.ui
|
ui/dialogs/ExportInstanceDialog.ui
|
||||||
@ -944,11 +945,9 @@ qt_wrap_ui(LAUNCHER_UI
|
|||||||
ui/dialogs/EditAccountDialog.ui
|
ui/dialogs/EditAccountDialog.ui
|
||||||
ui/dialogs/ReviewMessageBox.ui
|
ui/dialogs/ReviewMessageBox.ui
|
||||||
ui/dialogs/ScrollMessageBox.ui
|
ui/dialogs/ScrollMessageBox.ui
|
||||||
ui/dialogs/BlockedModsDialog.ui
|
|
||||||
ui/dialogs/ChooseProviderDialog.ui
|
|
||||||
)
|
)
|
||||||
|
|
||||||
qt_add_resources(LAUNCHER_RESOURCES
|
qt5_add_resources(LAUNCHER_RESOURCES
|
||||||
resources/backgrounds/backgrounds.qrc
|
resources/backgrounds/backgrounds.qrc
|
||||||
resources/multimc/multimc.qrc
|
resources/multimc/multimc.qrc
|
||||||
resources/pe_dark/pe_dark.qrc
|
resources/pe_dark/pe_dark.qrc
|
||||||
@ -969,56 +968,30 @@ endif()
|
|||||||
|
|
||||||
# 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})
|
||||||
target_include_directories(Launcher_logic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
|
||||||
target_link_libraries(Launcher_logic
|
target_link_libraries(Launcher_logic
|
||||||
systeminfo
|
systeminfo
|
||||||
Launcher_murmur2
|
Launcher_classparser
|
||||||
nbt++
|
nbt++
|
||||||
${ZLIB_LIBRARIES}
|
${ZLIB_LIBRARIES}
|
||||||
tomlplusplus::tomlplusplus
|
optional-bare
|
||||||
|
tomlc99
|
||||||
BuildConfig
|
BuildConfig
|
||||||
Katabasis
|
Katabasis
|
||||||
Qt${QT_VERSION_MAJOR}::Widgets
|
|
||||||
ghcFilesystem::ghc_filesystem
|
|
||||||
)
|
|
||||||
|
|
||||||
if (UNIX AND NOT CYGWIN AND NOT APPLE)
|
|
||||||
target_link_libraries(Launcher_logic
|
|
||||||
gamemode
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_link_libraries(Launcher_logic
|
|
||||||
Qt${QT_VERSION_MAJOR}::Core
|
|
||||||
Qt${QT_VERSION_MAJOR}::Xml
|
|
||||||
Qt${QT_VERSION_MAJOR}::Network
|
|
||||||
Qt${QT_VERSION_MAJOR}::Concurrent
|
|
||||||
Qt${QT_VERSION_MAJOR}::Gui
|
|
||||||
Qt${QT_VERSION_MAJOR}::Widgets
|
|
||||||
${Launcher_QT_LIBS}
|
|
||||||
)
|
)
|
||||||
target_link_libraries(Launcher_logic
|
target_link_libraries(Launcher_logic
|
||||||
|
Qt5::Core
|
||||||
|
Qt5::Xml
|
||||||
|
Qt5::Network
|
||||||
|
Qt5::Concurrent
|
||||||
|
Qt5::Gui
|
||||||
|
)
|
||||||
|
target_link_libraries(Launcher_logic
|
||||||
|
Launcher_iconfix
|
||||||
QuaZip::QuaZip
|
QuaZip::QuaZip
|
||||||
hoedown
|
hoedown
|
||||||
LocalPeer
|
LocalPeer
|
||||||
Launcher_rainbow
|
Launcher_rainbow
|
||||||
)
|
)
|
||||||
if(APPLE)
|
|
||||||
set(CMAKE_MACOSX_RPATH 1)
|
|
||||||
set(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks/")
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
find_library(SPARKLE_FRAMEWORK Sparkle "${CMAKE_BINARY_DIR}/frameworks/Sparkle")
|
|
||||||
target_link_libraries(Launcher_logic
|
|
||||||
"-framework AppKit"
|
|
||||||
"-framework Carbon"
|
|
||||||
"-framework Foundation"
|
|
||||||
"-framework ApplicationServices"
|
|
||||||
)
|
|
||||||
target_link_libraries(Launcher_logic ${SPARKLE_FRAMEWORK})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_link_libraries(Launcher_logic)
|
target_link_libraries(Launcher_logic)
|
||||||
|
|
||||||
@ -1041,16 +1014,8 @@ install(TARGETS ${Launcher_Name}
|
|||||||
BUNDLE DESTINATION "." COMPONENT Runtime
|
BUNDLE DESTINATION "." COMPONENT Runtime
|
||||||
LIBRARY DESTINATION ${LIBRARY_DEST_DIR} COMPONENT Runtime
|
LIBRARY DESTINATION ${LIBRARY_DEST_DIR} COMPONENT Runtime
|
||||||
RUNTIME DESTINATION ${BINARY_DEST_DIR} COMPONENT Runtime
|
RUNTIME DESTINATION ${BINARY_DEST_DIR} COMPONENT Runtime
|
||||||
FRAMEWORK DESTINATION ${FRAMEWORK_DEST_DIR} COMPONENT Runtime
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (UNIX AND APPLE)
|
|
||||||
# Add Sparkle updater
|
|
||||||
# It has to be copied here instead of just allowing fixup_bundle to install it, otherwise essential parts of
|
|
||||||
# the framework aren't installed
|
|
||||||
install(DIRECTORY ${MACOSX_SPARKLE_DIR}/Sparkle.framework DESTINATION ${FRAMEWORK_DEST_DIR} USE_SOURCE_PERMISSIONS)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
#### The bundle mess! ####
|
#### The bundle mess! ####
|
||||||
# Bundle utilities are used to complete the portable packages - they add all the libraries that would otherwise be missing on the target system.
|
# Bundle utilities are used to complete the portable packages - they add all the libraries that would otherwise be missing on the target system.
|
||||||
# NOTE: it seems that this absolutely has to be here, and nowhere else.
|
# NOTE: it seems that this absolutely has to be here, and nowhere else.
|
||||||
@ -1091,14 +1056,6 @@ if(INSTALL_BUNDLE STREQUAL "full")
|
|||||||
COMPONENT Runtime
|
COMPONENT Runtime
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
# TLS plugins (Qt 6 only)
|
|
||||||
if(EXISTS "${QT_PLUGINS_DIR}/tls")
|
|
||||||
install(
|
|
||||||
DIRECTORY "${QT_PLUGINS_DIR}/tls"
|
|
||||||
DESTINATION ${PLUGIN_DEST_DIR}
|
|
||||||
COMPONENT Runtime
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
else()
|
else()
|
||||||
# Image formats
|
# Image formats
|
||||||
install(
|
install(
|
||||||
@ -1141,16 +1098,6 @@ if(INSTALL_BUNDLE STREQUAL "full")
|
|||||||
REGEX "\\.dSYM" EXCLUDE
|
REGEX "\\.dSYM" EXCLUDE
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
# TLS plugins (Qt 6 only)
|
|
||||||
if(EXISTS "${QT_PLUGINS_DIR}/tls")
|
|
||||||
install(
|
|
||||||
DIRECTORY "${QT_PLUGINS_DIR}/tls"
|
|
||||||
DESTINATION ${PLUGIN_DEST_DIR}
|
|
||||||
COMPONENT Runtime
|
|
||||||
REGEX "_debug\\." EXCLUDE
|
|
||||||
REGEX "\\.dSYM" EXCLUDE
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
configure_file(
|
configure_file(
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/install_prereqs.cmake.in"
|
"${CMAKE_CURRENT_SOURCE_DIR}/install_prereqs.cmake.in"
|
||||||
|
@ -1,38 +1,18 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
/* Copyright 2013-2021 MultiMC Contributors
|
||||||
/*
|
|
||||||
* PolyMC - Minecraft Launcher
|
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
|
||||||
* 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,
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* you may not use this file except in compliance with the License.
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* You may obtain a copy of the License at
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
*
|
||||||
* This file incorporates work covered by the following copyright and
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* permission notice:
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
*
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* Copyright 2013-2021 MultiMC Contributors
|
* See the License for the specific language governing permissions and
|
||||||
*
|
* limitations under the License.
|
||||||
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
|
|
||||||
*
|
|
||||||
* 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 "Commandline.h"
|
#include "Commandline.h"
|
||||||
@ -67,7 +47,7 @@ QStringList splitArgs(QString args)
|
|||||||
if (cchar == '\\')
|
if (cchar == '\\')
|
||||||
escape = true;
|
escape = true;
|
||||||
else if (cchar == inquotes)
|
else if (cchar == inquotes)
|
||||||
inquotes = QChar::Null;
|
inquotes = 0;
|
||||||
else
|
else
|
||||||
current += cchar;
|
current += cchar;
|
||||||
// otherwise
|
// otherwise
|
||||||
@ -92,4 +72,412 @@ QStringList splitArgs(QString args)
|
|||||||
argv << current;
|
argv << current;
|
||||||
return argv;
|
return argv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Parser::Parser(FlagStyle::Enum flagStyle, ArgumentStyle::Enum argStyle)
|
||||||
|
{
|
||||||
|
m_flagStyle = flagStyle;
|
||||||
|
m_argStyle = argStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// styles setter/getter
|
||||||
|
void Parser::setArgumentStyle(ArgumentStyle::Enum style)
|
||||||
|
{
|
||||||
|
m_argStyle = style;
|
||||||
|
}
|
||||||
|
ArgumentStyle::Enum Parser::argumentStyle()
|
||||||
|
{
|
||||||
|
return m_argStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Parser::setFlagStyle(FlagStyle::Enum style)
|
||||||
|
{
|
||||||
|
m_flagStyle = style;
|
||||||
|
}
|
||||||
|
FlagStyle::Enum Parser::flagStyle()
|
||||||
|
{
|
||||||
|
return m_flagStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup methods
|
||||||
|
void Parser::addSwitch(QString name, bool def)
|
||||||
|
{
|
||||||
|
if (m_params.contains(name))
|
||||||
|
throw "Name not unique";
|
||||||
|
|
||||||
|
OptionDef *param = new OptionDef;
|
||||||
|
param->type = otSwitch;
|
||||||
|
param->name = name;
|
||||||
|
param->metavar = QString("<%1>").arg(name);
|
||||||
|
param->def = def;
|
||||||
|
|
||||||
|
m_options[name] = param;
|
||||||
|
m_params[name] = (CommonDef *)param;
|
||||||
|
m_optionList.append(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Parser::addOption(QString name, QVariant def)
|
||||||
|
{
|
||||||
|
if (m_params.contains(name))
|
||||||
|
throw "Name not unique";
|
||||||
|
|
||||||
|
OptionDef *param = new OptionDef;
|
||||||
|
param->type = otOption;
|
||||||
|
param->name = name;
|
||||||
|
param->metavar = QString("<%1>").arg(name);
|
||||||
|
param->def = def;
|
||||||
|
|
||||||
|
m_options[name] = param;
|
||||||
|
m_params[name] = (CommonDef *)param;
|
||||||
|
m_optionList.append(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Parser::addArgument(QString name, bool required, QVariant def)
|
||||||
|
{
|
||||||
|
if (m_params.contains(name))
|
||||||
|
throw "Name not unique";
|
||||||
|
|
||||||
|
PositionalDef *param = new PositionalDef;
|
||||||
|
param->name = name;
|
||||||
|
param->def = def;
|
||||||
|
param->required = required;
|
||||||
|
param->metavar = name;
|
||||||
|
|
||||||
|
m_positionals.append(param);
|
||||||
|
m_params[name] = (CommonDef *)param;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Parser::addDocumentation(QString name, QString doc, QString metavar)
|
||||||
|
{
|
||||||
|
if (!m_params.contains(name))
|
||||||
|
throw "Name does not exist";
|
||||||
|
|
||||||
|
CommonDef *param = m_params[name];
|
||||||
|
param->doc = doc;
|
||||||
|
if (!metavar.isNull())
|
||||||
|
param->metavar = metavar;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Parser::addShortOpt(QString name, QChar flag)
|
||||||
|
{
|
||||||
|
if (!m_params.contains(name))
|
||||||
|
throw "Name does not exist";
|
||||||
|
if (!m_options.contains(name))
|
||||||
|
throw "Name is not an Option or Swtich";
|
||||||
|
|
||||||
|
OptionDef *param = m_options[name];
|
||||||
|
m_flags[flag] = param;
|
||||||
|
param->flag = flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
// help methods
|
||||||
|
QString Parser::compileHelp(QString progName, int helpIndent, bool useFlags)
|
||||||
|
{
|
||||||
|
QStringList help;
|
||||||
|
help << compileUsage(progName, useFlags) << "\r\n";
|
||||||
|
|
||||||
|
// positionals
|
||||||
|
if (!m_positionals.isEmpty())
|
||||||
|
{
|
||||||
|
help << "\r\n";
|
||||||
|
help << "Positional arguments:\r\n";
|
||||||
|
QListIterator<PositionalDef *> it2(m_positionals);
|
||||||
|
while (it2.hasNext())
|
||||||
|
{
|
||||||
|
PositionalDef *param = it2.next();
|
||||||
|
help << " " << param->metavar;
|
||||||
|
help << " " << QString(helpIndent - param->metavar.length() - 1, ' ');
|
||||||
|
help << param->doc << "\r\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Options
|
||||||
|
if (!m_optionList.isEmpty())
|
||||||
|
{
|
||||||
|
help << "\r\n";
|
||||||
|
QString optPrefix, flagPrefix;
|
||||||
|
getPrefix(optPrefix, flagPrefix);
|
||||||
|
|
||||||
|
help << "Options & Switches:\r\n";
|
||||||
|
QListIterator<OptionDef *> it(m_optionList);
|
||||||
|
while (it.hasNext())
|
||||||
|
{
|
||||||
|
OptionDef *option = it.next();
|
||||||
|
help << " ";
|
||||||
|
int nameLength = optPrefix.length() + option->name.length();
|
||||||
|
if (!option->flag.isNull())
|
||||||
|
{
|
||||||
|
nameLength += 3 + flagPrefix.length();
|
||||||
|
help << flagPrefix << option->flag << ", ";
|
||||||
|
}
|
||||||
|
help << optPrefix << option->name;
|
||||||
|
if (option->type == otOption)
|
||||||
|
{
|
||||||
|
QString arg = QString("%1%2").arg(
|
||||||
|
((m_argStyle == ArgumentStyle::Equals) ? "=" : " "), option->metavar);
|
||||||
|
nameLength += arg.length();
|
||||||
|
help << arg;
|
||||||
|
}
|
||||||
|
help << " " << QString(helpIndent - nameLength - 1, ' ');
|
||||||
|
help << option->doc << "\r\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return help.join("");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Parser::compileUsage(QString progName, bool useFlags)
|
||||||
|
{
|
||||||
|
QStringList usage;
|
||||||
|
usage << "Usage: " << progName;
|
||||||
|
|
||||||
|
QString optPrefix, flagPrefix;
|
||||||
|
getPrefix(optPrefix, flagPrefix);
|
||||||
|
|
||||||
|
// options
|
||||||
|
QListIterator<OptionDef *> it(m_optionList);
|
||||||
|
while (it.hasNext())
|
||||||
|
{
|
||||||
|
OptionDef *option = it.next();
|
||||||
|
usage << " [";
|
||||||
|
if (!option->flag.isNull() && useFlags)
|
||||||
|
usage << flagPrefix << option->flag;
|
||||||
|
else
|
||||||
|
usage << optPrefix << option->name;
|
||||||
|
if (option->type == otOption)
|
||||||
|
usage << ((m_argStyle == ArgumentStyle::Equals) ? "=" : " ") << option->metavar;
|
||||||
|
usage << "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
// arguments
|
||||||
|
QListIterator<PositionalDef *> it2(m_positionals);
|
||||||
|
while (it2.hasNext())
|
||||||
|
{
|
||||||
|
PositionalDef *param = it2.next();
|
||||||
|
usage << " " << (param->required ? "<" : "[");
|
||||||
|
usage << param->metavar;
|
||||||
|
usage << (param->required ? ">" : "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
return usage.join("");
|
||||||
|
}
|
||||||
|
|
||||||
|
// parsing
|
||||||
|
QHash<QString, QVariant> Parser::parse(QStringList argv)
|
||||||
|
{
|
||||||
|
QHash<QString, QVariant> map;
|
||||||
|
|
||||||
|
QStringListIterator it(argv);
|
||||||
|
QString programName = it.next();
|
||||||
|
|
||||||
|
QString optionPrefix;
|
||||||
|
QString flagPrefix;
|
||||||
|
QListIterator<PositionalDef *> positionals(m_positionals);
|
||||||
|
QStringList expecting;
|
||||||
|
|
||||||
|
getPrefix(optionPrefix, flagPrefix);
|
||||||
|
|
||||||
|
while (it.hasNext())
|
||||||
|
{
|
||||||
|
QString arg = it.next();
|
||||||
|
|
||||||
|
if (!expecting.isEmpty())
|
||||||
|
// we were expecting an argument
|
||||||
|
{
|
||||||
|
QString name = expecting.first();
|
||||||
|
/*
|
||||||
|
if (map.contains(name))
|
||||||
|
throw ParsingError(
|
||||||
|
QString("Option %2%1 was given multiple times").arg(name, optionPrefix));
|
||||||
|
*/
|
||||||
|
map[name] = QVariant(arg);
|
||||||
|
|
||||||
|
expecting.removeFirst();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg.startsWith(optionPrefix))
|
||||||
|
// we have an option
|
||||||
|
{
|
||||||
|
// qDebug("Found option %s", qPrintable(arg));
|
||||||
|
|
||||||
|
QString name = arg.mid(optionPrefix.length());
|
||||||
|
QString equals;
|
||||||
|
|
||||||
|
if ((m_argStyle == ArgumentStyle::Equals ||
|
||||||
|
m_argStyle == ArgumentStyle::SpaceAndEquals) &&
|
||||||
|
name.contains("="))
|
||||||
|
{
|
||||||
|
int i = name.indexOf("=");
|
||||||
|
equals = name.mid(i + 1);
|
||||||
|
name = name.left(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_options.contains(name))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
if (map.contains(name))
|
||||||
|
throw ParsingError(QString("Option %2%1 was given multiple times")
|
||||||
|
.arg(name, optionPrefix));
|
||||||
|
*/
|
||||||
|
OptionDef *option = m_options[name];
|
||||||
|
if (option->type == otSwitch)
|
||||||
|
map[name] = true;
|
||||||
|
else // if (option->type == otOption)
|
||||||
|
{
|
||||||
|
if (m_argStyle == ArgumentStyle::Space)
|
||||||
|
expecting.append(name);
|
||||||
|
else if (!equals.isNull())
|
||||||
|
map[name] = equals;
|
||||||
|
else if (m_argStyle == ArgumentStyle::SpaceAndEquals)
|
||||||
|
expecting.append(name);
|
||||||
|
else
|
||||||
|
throw ParsingError(QString("Option %2%1 reqires an argument.")
|
||||||
|
.arg(name, optionPrefix));
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw ParsingError(QString("Unknown Option %2%1").arg(name, optionPrefix));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg.startsWith(flagPrefix))
|
||||||
|
// we have (a) flag(s)
|
||||||
|
{
|
||||||
|
// qDebug("Found flags %s", qPrintable(arg));
|
||||||
|
|
||||||
|
QString flags = arg.mid(flagPrefix.length());
|
||||||
|
QString equals;
|
||||||
|
|
||||||
|
if ((m_argStyle == ArgumentStyle::Equals ||
|
||||||
|
m_argStyle == ArgumentStyle::SpaceAndEquals) &&
|
||||||
|
flags.contains("="))
|
||||||
|
{
|
||||||
|
int i = flags.indexOf("=");
|
||||||
|
equals = flags.mid(i + 1);
|
||||||
|
flags = flags.left(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < flags.length(); i++)
|
||||||
|
{
|
||||||
|
QChar flag = flags.at(i);
|
||||||
|
|
||||||
|
if (!m_flags.contains(flag))
|
||||||
|
throw ParsingError(QString("Unknown flag %2%1").arg(flag, flagPrefix));
|
||||||
|
|
||||||
|
OptionDef *option = m_flags[flag];
|
||||||
|
/*
|
||||||
|
if (map.contains(option->name))
|
||||||
|
throw ParsingError(QString("Option %2%1 was given multiple times")
|
||||||
|
.arg(option->name, optionPrefix));
|
||||||
|
*/
|
||||||
|
if (option->type == otSwitch)
|
||||||
|
map[option->name] = true;
|
||||||
|
else // if (option->type == otOption)
|
||||||
|
{
|
||||||
|
if (m_argStyle == ArgumentStyle::Space)
|
||||||
|
expecting.append(option->name);
|
||||||
|
else if (!equals.isNull())
|
||||||
|
if (i == flags.length() - 1)
|
||||||
|
map[option->name] = equals;
|
||||||
|
else
|
||||||
|
throw ParsingError(QString("Flag %4%2 of Argument-requiring Option "
|
||||||
|
"%1 not last flag in %4%3")
|
||||||
|
.arg(option->name, flag, flags, flagPrefix));
|
||||||
|
else if (m_argStyle == ArgumentStyle::SpaceAndEquals)
|
||||||
|
expecting.append(option->name);
|
||||||
|
else
|
||||||
|
throw ParsingError(QString("Option %1 reqires an argument. (flag %3%2)")
|
||||||
|
.arg(option->name, flag, flagPrefix));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// must be a positional argument
|
||||||
|
if (!positionals.hasNext())
|
||||||
|
throw ParsingError(QString("Don't know what to do with '%1'").arg(arg));
|
||||||
|
|
||||||
|
PositionalDef *param = positionals.next();
|
||||||
|
|
||||||
|
map[param->name] = arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if we're missing something
|
||||||
|
if (!expecting.isEmpty())
|
||||||
|
throw ParsingError(QString("Was still expecting arguments for %2%1").arg(
|
||||||
|
expecting.join(QString(", ") + optionPrefix), optionPrefix));
|
||||||
|
|
||||||
|
while (positionals.hasNext())
|
||||||
|
{
|
||||||
|
PositionalDef *param = positionals.next();
|
||||||
|
if (param->required)
|
||||||
|
throw ParsingError(
|
||||||
|
QString("Missing required positional argument '%1'").arg(param->name));
|
||||||
|
else
|
||||||
|
map[param->name] = param->def;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fill out gaps
|
||||||
|
QListIterator<OptionDef *> iter(m_optionList);
|
||||||
|
while (iter.hasNext())
|
||||||
|
{
|
||||||
|
OptionDef *option = iter.next();
|
||||||
|
if (!map.contains(option->name))
|
||||||
|
map[option->name] = option->def;
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear defs
|
||||||
|
void Parser::clear()
|
||||||
|
{
|
||||||
|
m_flags.clear();
|
||||||
|
m_params.clear();
|
||||||
|
m_options.clear();
|
||||||
|
|
||||||
|
QMutableListIterator<OptionDef *> it(m_optionList);
|
||||||
|
while (it.hasNext())
|
||||||
|
{
|
||||||
|
OptionDef *option = it.next();
|
||||||
|
it.remove();
|
||||||
|
delete option;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMutableListIterator<PositionalDef *> it2(m_positionals);
|
||||||
|
while (it2.hasNext())
|
||||||
|
{
|
||||||
|
PositionalDef *arg = it2.next();
|
||||||
|
it2.remove();
|
||||||
|
delete arg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destructor
|
||||||
|
Parser::~Parser()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// getPrefix
|
||||||
|
void Parser::getPrefix(QString &opt, QString &flag)
|
||||||
|
{
|
||||||
|
if (m_flagStyle == FlagStyle::Windows)
|
||||||
|
opt = flag = "/";
|
||||||
|
else if (m_flagStyle == FlagStyle::Unix)
|
||||||
|
opt = flag = "-";
|
||||||
|
// else if (m_flagStyle == FlagStyle::GNU)
|
||||||
|
else
|
||||||
|
{
|
||||||
|
opt = "--";
|
||||||
|
flag = "-";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParsingError
|
||||||
|
ParsingError::ParsingError(const QString &what) : std::runtime_error(what.toStdString())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
@ -17,7 +17,12 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QVariant>
|
||||||
|
#include <QHash>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -34,4 +39,212 @@ namespace Commandline
|
|||||||
* @return a QStringList containing all arguments
|
* @return a QStringList containing all arguments
|
||||||
*/
|
*/
|
||||||
QStringList splitArgs(QString args);
|
QStringList splitArgs(QString args);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The FlagStyle enum
|
||||||
|
* Specifies how flags are decorated
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace FlagStyle
|
||||||
|
{
|
||||||
|
enum Enum
|
||||||
|
{
|
||||||
|
GNU, /**< --option and -o (GNU Style) */
|
||||||
|
Unix, /**< -option and -o (Unix Style) */
|
||||||
|
Windows, /**< /option and /o (Windows Style) */
|
||||||
|
#ifdef Q_OS_WIN32
|
||||||
|
Default = Windows
|
||||||
|
#else
|
||||||
|
Default = GNU
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The ArgumentStyle enum
|
||||||
|
*/
|
||||||
|
namespace ArgumentStyle
|
||||||
|
{
|
||||||
|
enum Enum
|
||||||
|
{
|
||||||
|
Space, /**< --option value */
|
||||||
|
Equals, /**< --option=value */
|
||||||
|
SpaceAndEquals, /**< --option[= ]value */
|
||||||
|
#ifdef Q_OS_WIN32
|
||||||
|
Default = Equals
|
||||||
|
#else
|
||||||
|
Default = SpaceAndEquals
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The ParsingError class
|
||||||
|
*/
|
||||||
|
class ParsingError : public std::runtime_error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ParsingError(const QString &what);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The Parser class
|
||||||
|
*/
|
||||||
|
class Parser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Parser constructor
|
||||||
|
* @param flagStyle the FlagStyle to use in this Parser
|
||||||
|
* @param argStyle the ArgumentStyle to use in this Parser
|
||||||
|
*/
|
||||||
|
Parser(FlagStyle::Enum flagStyle = FlagStyle::Default,
|
||||||
|
ArgumentStyle::Enum argStyle = ArgumentStyle::Default);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief set the flag style
|
||||||
|
* @param style
|
||||||
|
*/
|
||||||
|
void setFlagStyle(FlagStyle::Enum style);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get the flag style
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
FlagStyle::Enum flagStyle();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief set the argument style
|
||||||
|
* @param style
|
||||||
|
*/
|
||||||
|
void setArgumentStyle(ArgumentStyle::Enum style);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get the argument style
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
ArgumentStyle::Enum argumentStyle();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief define a boolean switch
|
||||||
|
* @param name the parameter name
|
||||||
|
* @param def the default value
|
||||||
|
*/
|
||||||
|
void addSwitch(QString name, bool def = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief define an option that takes an additional argument
|
||||||
|
* @param name the parameter name
|
||||||
|
* @param def the default value
|
||||||
|
*/
|
||||||
|
void addOption(QString name, QVariant def = QVariant());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief define a positional argument
|
||||||
|
* @param name the parameter name
|
||||||
|
* @param required wether this argument is required
|
||||||
|
* @param def the default value
|
||||||
|
*/
|
||||||
|
void addArgument(QString name, bool required = true, QVariant def = QVariant());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief adds a flag to an existing parameter
|
||||||
|
* @param name the (existing) parameter name
|
||||||
|
* @param flag the flag character
|
||||||
|
* @see addSwitch addArgument addOption
|
||||||
|
* Note: any one parameter can only have one flag
|
||||||
|
*/
|
||||||
|
void addShortOpt(QString name, QChar flag);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief adds documentation to a Parameter
|
||||||
|
* @param name the parameter name
|
||||||
|
* @param metavar a string to be displayed as placeholder for the value
|
||||||
|
* @param doc a QString containing the documentation
|
||||||
|
* Note: on positional arguments, metavar replaces the name as displayed.
|
||||||
|
* on options , metavar replaces the value placeholder
|
||||||
|
*/
|
||||||
|
void addDocumentation(QString name, QString doc, QString metavar = QString());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief generate a help message
|
||||||
|
* @param progName the program name to use in the help message
|
||||||
|
* @param helpIndent how much the parameter documentation should be indented
|
||||||
|
* @param flagsInUsage whether we should use flags instead of options in the usage
|
||||||
|
* @return a help message
|
||||||
|
*/
|
||||||
|
QString compileHelp(QString progName, int helpIndent = 22, bool flagsInUsage = true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief generate a short usage message
|
||||||
|
* @param progName the program name to use in the usage message
|
||||||
|
* @param useFlags whether we should use flags instead of options
|
||||||
|
* @return a usage message
|
||||||
|
*/
|
||||||
|
QString compileUsage(QString progName, bool useFlags = true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief parse
|
||||||
|
* @param argv a QStringList containing the program ARGV
|
||||||
|
* @return a QHash mapping argument names to their values
|
||||||
|
*/
|
||||||
|
QHash<QString, QVariant> parse(QStringList argv);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief clear all definitions
|
||||||
|
*/
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
~Parser();
|
||||||
|
|
||||||
|
private:
|
||||||
|
FlagStyle::Enum m_flagStyle;
|
||||||
|
ArgumentStyle::Enum m_argStyle;
|
||||||
|
|
||||||
|
enum OptionType
|
||||||
|
{
|
||||||
|
otSwitch,
|
||||||
|
otOption
|
||||||
|
};
|
||||||
|
|
||||||
|
// Important: the common part MUST BE COMMON ON ALL THREE structs
|
||||||
|
struct CommonDef
|
||||||
|
{
|
||||||
|
QString name;
|
||||||
|
QString doc;
|
||||||
|
QString metavar;
|
||||||
|
QVariant def;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OptionDef
|
||||||
|
{
|
||||||
|
// common
|
||||||
|
QString name;
|
||||||
|
QString doc;
|
||||||
|
QString metavar;
|
||||||
|
QVariant def;
|
||||||
|
// option
|
||||||
|
OptionType type;
|
||||||
|
QChar flag;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PositionalDef
|
||||||
|
{
|
||||||
|
// common
|
||||||
|
QString name;
|
||||||
|
QString doc;
|
||||||
|
QString metavar;
|
||||||
|
QVariant def;
|
||||||
|
// positional
|
||||||
|
bool required;
|
||||||
|
};
|
||||||
|
|
||||||
|
QHash<QString, OptionDef *> m_options;
|
||||||
|
QHash<QChar, OptionDef *> m_flags;
|
||||||
|
QHash<QString, CommonDef *> m_params;
|
||||||
|
QList<PositionalDef *> m_positionals;
|
||||||
|
QList<OptionDef *> m_optionList;
|
||||||
|
|
||||||
|
void getPrefix(QString &opt, QString &flag);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,134 +1,77 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// Licensed under the Apache-2.0 license. See README.md for details.
|
||||||
/*
|
|
||||||
* PolyMC - Minecraft Launcher
|
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
*
|
|
||||||
* 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 "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QDirIterator>
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QFileInfo>
|
|
||||||
#include <QSaveFile>
|
#include <QSaveFile>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QUrl>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
#include <QUrl>
|
|
||||||
|
|
||||||
#if defined Q_OS_WIN32
|
#if defined Q_OS_WIN32
|
||||||
#include <objbase.h>
|
#include <windows.h>
|
||||||
#include <objidl.h>
|
#include <string>
|
||||||
#include <shlguid.h>
|
#include <sys/utime.h>
|
||||||
#include <shlobj.h>
|
#include <winnls.h>
|
||||||
#include <shobjidl.h>
|
#include <shobjidl.h>
|
||||||
#include <sys/utime.h>
|
#include <objbase.h>
|
||||||
#include <windows.h>
|
#include <objidl.h>
|
||||||
#include <winnls.h>
|
#include <shlguid.h>
|
||||||
#include <string>
|
#include <shlobj.h>
|
||||||
#else
|
#else
|
||||||
#include <utime.h>
|
#include <utime.h>
|
||||||
#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>
|
|
||||||
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
|
|
||||||
|
|
||||||
#if defined Q_OS_WIN32
|
|
||||||
|
|
||||||
std::wstring toStdString(QString s)
|
|
||||||
{
|
|
||||||
return s.toStdWString();
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
std::string toStdString(QString s)
|
|
||||||
{
|
|
||||||
return s.toStdString();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace FS {
|
namespace FS {
|
||||||
|
|
||||||
void ensureExists(const QDir& dir)
|
void ensureExists(const QDir &dir)
|
||||||
{
|
{
|
||||||
if (!QDir().mkpath(dir.absolutePath())) {
|
if (!QDir().mkpath(dir.absolutePath()))
|
||||||
throw FileSystemException("Unable to create folder " + dir.dirName() + " (" + dir.absolutePath() + ")");
|
{
|
||||||
|
throw FileSystemException("Unable to create folder " + dir.dirName() + " (" +
|
||||||
|
dir.absolutePath() + ")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(const QString& filename, const QByteArray& data)
|
void write(const QString &filename, const QByteArray &data)
|
||||||
{
|
{
|
||||||
ensureExists(QFileInfo(filename).dir());
|
ensureExists(QFileInfo(filename).dir());
|
||||||
QSaveFile file(filename);
|
QSaveFile file(filename);
|
||||||
if (!file.open(QSaveFile::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))
|
||||||
throw FileSystemException("Error writing data to " + filename + ": " + file.errorString());
|
{
|
||||||
|
throw FileSystemException("Error writing data to " + filename + ": " +
|
||||||
|
file.errorString());
|
||||||
}
|
}
|
||||||
if (!file.commit()) {
|
if (!file.commit())
|
||||||
throw FileSystemException("Error while committing data to " + filename + ": " + file.errorString());
|
{
|
||||||
|
throw FileSystemException("Error while committing data to " + filename + ": " +
|
||||||
|
file.errorString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray read(const QString& filename)
|
QByteArray read(const QString &filename)
|
||||||
{
|
{
|
||||||
QFile file(filename);
|
QFile file(filename);
|
||||||
if (!file.open(QFile::ReadOnly)) {
|
if (!file.open(QFile::ReadOnly))
|
||||||
throw FileSystemException("Unable to open " + filename + " for reading: " + file.errorString());
|
{
|
||||||
|
throw FileSystemException("Unable to open " + filename + " for reading: " +
|
||||||
|
file.errorString());
|
||||||
}
|
}
|
||||||
const qint64 size = file.size();
|
const qint64 size = file.size();
|
||||||
QByteArray data(int(size), 0);
|
QByteArray data(int(size), 0);
|
||||||
const qint64 ret = file.read(data.data(), size);
|
const qint64 ret = file.read(data.data(), size);
|
||||||
if (ret == -1 || ret != size) {
|
if (ret == -1 || ret != size)
|
||||||
throw FileSystemException("Error reading data from " + filename + ": " + file.errorString());
|
{
|
||||||
|
throw FileSystemException("Error reading data from " + filename + ": " +
|
||||||
|
file.errorString());
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
@ -162,91 +105,149 @@ bool ensureFolderPathExists(QString foldernamepath)
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool copy::operator()(const QString& offset)
|
bool copy::operator()(const QString &offset)
|
||||||
{
|
{
|
||||||
using copy_opts = fs::copy_options;
|
//NOTE always deep copy on windows. the alternatives are too messy.
|
||||||
|
#if defined Q_OS_WIN32
|
||||||
// NOTE always deep copy on windows. the alternatives are too messy.
|
|
||||||
#if defined Q_OS_WIN32
|
|
||||||
m_followSymlinks = true;
|
m_followSymlinks = true;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
auto src = PathCombine(m_src.absolutePath(), offset);
|
auto src = PathCombine(m_src.absolutePath(), offset);
|
||||||
auto dst = PathCombine(m_dst.absolutePath(), offset);
|
auto dst = PathCombine(m_dst.absolutePath(), offset);
|
||||||
|
|
||||||
std::error_code err;
|
QFileInfo currentSrc(src);
|
||||||
|
if (!currentSrc.exists())
|
||||||
|
return false;
|
||||||
|
|
||||||
fs::copy_options opt = copy_opts::none;
|
if(!m_followSymlinks && currentSrc.isSymLink())
|
||||||
|
{
|
||||||
// The default behavior is to follow symlinks
|
qDebug() << "creating symlink" << src << " - " << dst;
|
||||||
if (!m_followSymlinks)
|
if (!ensureFilePathExists(dst))
|
||||||
opt |= copy_opts::copy_symlinks;
|
{
|
||||||
|
qWarning() << "Cannot create path!";
|
||||||
|
return false;
|
||||||
// We can't use copy_opts::recursive because we need to take into account the
|
}
|
||||||
// blacklisted paths, so we iterate over the source directory, and if there's no blacklist
|
return QFile::link(currentSrc.symLinkTarget(), dst);
|
||||||
// match, we copy the file.
|
}
|
||||||
QDir src_dir(src);
|
else if(currentSrc.isFile())
|
||||||
QDirIterator source_it(src, QDir::Filter::Files | QDir::Filter::Hidden, QDirIterator::Subdirectories);
|
{
|
||||||
|
qDebug() << "copying file" << src << " - " << dst;
|
||||||
while (source_it.hasNext()) {
|
if (!ensureFilePathExists(dst))
|
||||||
auto src_path = source_it.next();
|
{
|
||||||
auto relative_path = src_dir.relativeFilePath(src_path);
|
qWarning() << "Cannot create path!";
|
||||||
|
return false;
|
||||||
if (m_blacklist && m_blacklist->matches(relative_path))
|
}
|
||||||
continue;
|
return QFile::copy(src, dst);
|
||||||
|
}
|
||||||
auto dst_path = PathCombine(dst, relative_path);
|
else if(currentSrc.isDir())
|
||||||
ensureFilePathExists(dst_path);
|
{
|
||||||
|
qDebug() << "recursing" << offset;
|
||||||
fs::copy(toStdString(src_path), toStdString(dst_path), opt, err);
|
if (!ensureFolderPathExists(dst))
|
||||||
if (err) {
|
{
|
||||||
qWarning() << "Failed to copy files:" << QString::fromStdString(err.message());
|
qWarning() << "Cannot create path!";
|
||||||
qDebug() << "Source file:" << src_path;
|
return false;
|
||||||
qDebug() << "Destination file:" << dst_path;
|
}
|
||||||
|
QDir currentDir(src);
|
||||||
|
for(auto & f : currentDir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System))
|
||||||
|
{
|
||||||
|
auto inner_offset = PathCombine(offset, f);
|
||||||
|
// ignore and skip stuff that matches the blacklist.
|
||||||
|
if(m_blacklist && m_blacklist->matches(inner_offset))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(!operator()(inner_offset))
|
||||||
|
{
|
||||||
|
qWarning() << "Failed to copy" << inner_offset;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
return err.value() == 0;
|
{
|
||||||
|
qCritical() << "Copy ERROR: Unknown filesystem object:" << src;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deletePath(QString path)
|
bool deletePath(QString path)
|
||||||
{
|
{
|
||||||
std::error_code err;
|
bool OK = true;
|
||||||
|
QFileInfo finfo(path);
|
||||||
fs::remove_all(toStdString(path), err);
|
if(finfo.isFile()) {
|
||||||
|
return QFile::remove(path);
|
||||||
if (err) {
|
|
||||||
qWarning() << "Failed to remove files:" << QString::fromStdString(err.message());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return err.value() == 0;
|
QDir dir(path);
|
||||||
}
|
|
||||||
|
|
||||||
bool trash(QString path, QString *pathInTrash = nullptr)
|
if (!dir.exists())
|
||||||
{
|
{
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
|
return OK;
|
||||||
return false;
|
}
|
||||||
|
auto allEntries = dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden |
|
||||||
|
QDir::AllDirs | QDir::Files,
|
||||||
|
QDir::DirsFirst);
|
||||||
|
|
||||||
|
for(auto & info: allEntries)
|
||||||
|
{
|
||||||
|
#if defined Q_OS_WIN32
|
||||||
|
QString nativePath = QDir::toNativeSeparators(info.absoluteFilePath());
|
||||||
|
auto wString = nativePath.toStdWString();
|
||||||
|
DWORD dwAttrs = GetFileAttributesW(wString.c_str());
|
||||||
|
// Windows: check for junctions, reparse points and other nasty things of that sort
|
||||||
|
if(dwAttrs & FILE_ATTRIBUTE_REPARSE_POINT)
|
||||||
|
{
|
||||||
|
if (info.isFile())
|
||||||
|
{
|
||||||
|
OK &= QFile::remove(info.absoluteFilePath());
|
||||||
|
}
|
||||||
|
else if (info.isDir())
|
||||||
|
{
|
||||||
|
OK &= dir.rmdir(info.absoluteFilePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
return QFile::moveToTrash(path, pathInTrash);
|
// We do not trust Qt with reparse points, but do trust it with unix symlinks.
|
||||||
|
if(info.isSymLink())
|
||||||
|
{
|
||||||
|
OK &= QFile::remove(info.absoluteFilePath());
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
else if (info.isDir())
|
||||||
|
{
|
||||||
|
OK &= deletePath(info.absoluteFilePath());
|
||||||
|
}
|
||||||
|
else if (info.isFile())
|
||||||
|
{
|
||||||
|
OK &= QFile::remove(info.absoluteFilePath());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OK = false;
|
||||||
|
qCritical() << "Delete ERROR: Unknown filesystem object:" << info.absoluteFilePath();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OK &= dir.rmdir(dir.absolutePath());
|
||||||
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString PathCombine(const QString& path1, const QString& path2)
|
|
||||||
|
QString PathCombine(const QString & path1, const QString & path2)
|
||||||
{
|
{
|
||||||
if (!path1.size())
|
if(!path1.size())
|
||||||
return path2;
|
return path2;
|
||||||
if (!path2.size())
|
if(!path2.size())
|
||||||
return path1;
|
return path1;
|
||||||
return QDir::cleanPath(path1 + QDir::separator() + path2);
|
return QDir::cleanPath(path1 + QDir::separator() + path2);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString PathCombine(const QString& path1, const QString& path2, const QString& path3)
|
QString PathCombine(const QString & path1, const QString & path2, const QString & path3)
|
||||||
{
|
{
|
||||||
return PathCombine(PathCombine(path1, path2), path3);
|
return PathCombine(PathCombine(path1, path2), path3);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString PathCombine(const QString& path1, const QString& path2, const QString& path3, const QString& path4)
|
QString PathCombine(const QString & path1, const QString & path2, const QString & path3, const QString & path4)
|
||||||
{
|
{
|
||||||
return PathCombine(PathCombine(path1, path2, path3), path4);
|
return PathCombine(PathCombine(path1, path2, path3), path4);
|
||||||
}
|
}
|
||||||
@ -258,14 +259,17 @@ QString AbsolutePath(QString path)
|
|||||||
|
|
||||||
QString ResolveExecutable(QString path)
|
QString ResolveExecutable(QString path)
|
||||||
{
|
{
|
||||||
if (path.isEmpty()) {
|
if (path.isEmpty())
|
||||||
|
{
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
if (!path.contains('/')) {
|
if(!path.contains('/'))
|
||||||
|
{
|
||||||
path = QStandardPaths::findExecutable(path);
|
path = QStandardPaths::findExecutable(path);
|
||||||
}
|
}
|
||||||
QFileInfo pathInfo(path);
|
QFileInfo pathInfo(path);
|
||||||
if (!pathInfo.exists() || !pathInfo.isExecutable()) {
|
if(!pathInfo.exists() || !pathInfo.isExecutable())
|
||||||
|
{
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
return pathInfo.absoluteFilePath();
|
return pathInfo.absoluteFilePath();
|
||||||
@ -285,9 +289,12 @@ QString NormalizePath(QString path)
|
|||||||
QDir b(path);
|
QDir b(path);
|
||||||
QString newAbsolute = b.absolutePath();
|
QString newAbsolute = b.absolutePath();
|
||||||
|
|
||||||
if (newAbsolute.startsWith(currentAbsolute)) {
|
if (newAbsolute.startsWith(currentAbsolute))
|
||||||
|
{
|
||||||
return a.relativeFilePath(newAbsolute);
|
return a.relativeFilePath(newAbsolute);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return newAbsolute;
|
return newAbsolute;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -296,8 +303,10 @@ QString badFilenameChars = "\"\\/?<>:;*|!+\r\n";
|
|||||||
|
|
||||||
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 (badFilenameChars.contains(string[i])) {
|
{
|
||||||
|
if (badFilenameChars.contains(string[i]))
|
||||||
|
{
|
||||||
string[i] = replaceWith;
|
string[i] = replaceWith;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -309,11 +318,15 @@ QString DirNameFromString(QString string, QString inDir)
|
|||||||
int num = 0;
|
int num = 0;
|
||||||
QString baseName = RemoveInvalidFilenameChars(string, '-');
|
QString baseName = RemoveInvalidFilenameChars(string, '-');
|
||||||
QString dirName;
|
QString dirName;
|
||||||
do {
|
do
|
||||||
if (num == 0) {
|
{
|
||||||
|
if(num == 0)
|
||||||
|
{
|
||||||
dirName = baseName;
|
dirName = baseName;
|
||||||
} else {
|
}
|
||||||
dirName = baseName + "(" + QString::number(num) + ")";
|
else
|
||||||
|
{
|
||||||
|
dirName = baseName + QString::number(num);;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it's over 9000
|
// If it's over 9000
|
||||||
@ -332,13 +345,63 @@ bool checkProblemticPathJava(QDir folder)
|
|||||||
return pathfoldername.contains("!", Qt::CaseInsensitive);
|
return pathfoldername.contains("!", Qt::CaseInsensitive);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Win32 crap
|
||||||
|
#if defined Q_OS_WIN
|
||||||
|
|
||||||
|
bool called_coinit = false;
|
||||||
|
|
||||||
|
HRESULT CreateLink(LPCSTR linkPath, LPCSTR targetPath, LPCSTR args)
|
||||||
|
{
|
||||||
|
HRESULT hres;
|
||||||
|
|
||||||
|
if (!called_coinit)
|
||||||
|
{
|
||||||
|
hres = CoInitialize(NULL);
|
||||||
|
called_coinit = true;
|
||||||
|
|
||||||
|
if (!SUCCEEDED(hres))
|
||||||
|
{
|
||||||
|
qWarning("Failed to initialize COM. Error 0x%08lX", hres);
|
||||||
|
return hres;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IShellLink *link;
|
||||||
|
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink,
|
||||||
|
(LPVOID *)&link);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hres))
|
||||||
|
{
|
||||||
|
IPersistFile *persistFile;
|
||||||
|
|
||||||
|
link->SetPath(targetPath);
|
||||||
|
link->SetArguments(args);
|
||||||
|
|
||||||
|
hres = link->QueryInterface(IID_IPersistFile, (LPVOID *)&persistFile);
|
||||||
|
if (SUCCEEDED(hres))
|
||||||
|
{
|
||||||
|
WCHAR wstr[MAX_PATH];
|
||||||
|
|
||||||
|
MultiByteToWideChar(CP_ACP, 0, linkPath, -1, wstr, MAX_PATH);
|
||||||
|
|
||||||
|
hres = persistFile->Save(wstr, TRUE);
|
||||||
|
persistFile->Release();
|
||||||
|
}
|
||||||
|
link->Release();
|
||||||
|
}
|
||||||
|
return hres;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
QString getDesktopDir()
|
QString getDesktopDir()
|
||||||
{
|
{
|
||||||
return QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
return QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cross-platform Shortcut creation
|
// Cross-platform Shortcut creation
|
||||||
bool createShortCut(QString location, QString dest, QStringList args, QString name, QString icon)
|
bool createShortCut(QString location, QString dest, QStringList args, QString name,
|
||||||
|
QString icon)
|
||||||
{
|
{
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||||
location = PathCombine(location, name + ".desktop");
|
location = PathCombine(location, name + ".desktop");
|
||||||
@ -363,7 +426,8 @@ bool createShortCut(QString location, QString dest, QStringList args, QString na
|
|||||||
stream.flush();
|
stream.flush();
|
||||||
f.close();
|
f.close();
|
||||||
|
|
||||||
f.setPermissions(f.permissions() | QFileDevice::ExeOwner | QFileDevice::ExeGroup | QFileDevice::ExeOther);
|
f.setPermissions(f.permissions() | QFileDevice::ExeOwner | QFileDevice::ExeGroup |
|
||||||
|
QFileDevice::ExeOther);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
#elif defined Q_OS_WIN
|
#elif defined Q_OS_WIN
|
||||||
@ -391,24 +455,46 @@ bool createShortCut(QString location, QString dest, QStringList args, QString na
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList listFolderPaths(QDir root)
|
||||||
|
{
|
||||||
|
auto createAbsPath = [](QFileInfo const& entry) { return FS::PathCombine(entry.path(), entry.fileName()); };
|
||||||
|
|
||||||
|
QStringList entries;
|
||||||
|
|
||||||
|
root.refresh();
|
||||||
|
for (auto entry : root.entryInfoList(QDir::Filter::Files)) {
|
||||||
|
entries.append(createAbsPath(entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto entry : root.entryInfoList(QDir::Filter::AllDirs | QDir::Filter::NoDotAndDotDot)) {
|
||||||
|
entries.append(listFolderPaths(createAbsPath(entry)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
bool overrideFolder(QString overwritten_path, QString override_path)
|
bool overrideFolder(QString overwritten_path, QString override_path)
|
||||||
{
|
{
|
||||||
using copy_opts = fs::copy_options;
|
|
||||||
|
|
||||||
if (!FS::ensureFolderPathExists(overwritten_path))
|
if (!FS::ensureFolderPathExists(overwritten_path))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
std::error_code err;
|
QStringList paths_to_override;
|
||||||
fs::copy_options opt = copy_opts::recursive | copy_opts::overwrite_existing;
|
QDir root_override (override_path);
|
||||||
|
for (auto file : listFolderPaths(root_override)) {
|
||||||
|
QString destination = file;
|
||||||
|
destination.replace(override_path, overwritten_path);
|
||||||
|
|
||||||
fs::copy(toStdString(override_path), toStdString(overwritten_path), opt, err);
|
qDebug() << QString("Applying override %1 in %2").arg(file, destination);
|
||||||
|
|
||||||
if (err) {
|
if (QFile::exists(destination))
|
||||||
qCritical() << QString("Failed to apply override from %1 to %2").arg(override_path, overwritten_path);
|
QFile::remove(destination);
|
||||||
qCritical() << "Reason:" << QString::fromStdString(err.message());
|
if (!QFile::rename(file, destination)) {
|
||||||
|
qCritical() << QString("Failed to apply override from %1 to %2").arg(file, destination);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return err.value() == 0;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,37 +1,4 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// Licensed under the Apache-2.0 license. See README.md for details.
|
||||||
/*
|
|
||||||
* PolyMC - Minecraft Launcher
|
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
*
|
|
||||||
* 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,27 +8,29 @@
|
|||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFlags>
|
#include <QFlags>
|
||||||
|
|
||||||
namespace FS {
|
namespace FS
|
||||||
|
{
|
||||||
|
|
||||||
class FileSystemException : public ::Exception {
|
class FileSystemException : public ::Exception
|
||||||
public:
|
{
|
||||||
FileSystemException(const QString& message) : Exception(message) {}
|
public:
|
||||||
|
FileSystemException(const QString &message) : Exception(message) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* write data to a file safely
|
* write data to a file safely
|
||||||
*/
|
*/
|
||||||
void write(const QString& filename, const QByteArray& data);
|
void write(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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the last changed timestamp of an existing file
|
* Update the last changed timestamp of an existing file
|
||||||
*/
|
*/
|
||||||
bool updateTimestamp(const QString& filename);
|
bool updateTimestamp(const QString & filename);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates all the folders in a path for the specified path
|
* Creates all the folders in a path for the specified path
|
||||||
@ -75,31 +44,35 @@ bool ensureFilePathExists(QString filenamepath);
|
|||||||
*/
|
*/
|
||||||
bool ensureFolderPathExists(QString filenamepath);
|
bool ensureFolderPathExists(QString filenamepath);
|
||||||
|
|
||||||
class copy {
|
class copy
|
||||||
public:
|
{
|
||||||
copy(const QString& src, const QString& dst)
|
public:
|
||||||
|
copy(const QString & src, const QString & dst)
|
||||||
{
|
{
|
||||||
m_src.setPath(src);
|
m_src = src;
|
||||||
m_dst.setPath(dst);
|
m_dst = dst;
|
||||||
}
|
}
|
||||||
copy& followSymlinks(const bool follow)
|
copy & followSymlinks(const bool follow)
|
||||||
{
|
{
|
||||||
m_followSymlinks = follow;
|
m_followSymlinks = follow;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
copy& blacklist(const IPathMatcher* filter)
|
copy & blacklist(const IPathMatcher * filter)
|
||||||
{
|
{
|
||||||
m_blacklist = filter;
|
m_blacklist = filter;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
bool operator()() { return operator()(QString()); }
|
bool operator()()
|
||||||
|
{
|
||||||
|
return operator()(QString());
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool operator()(const QString& offset);
|
bool operator()(const QString &offset);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_followSymlinks = true;
|
bool m_followSymlinks = true;
|
||||||
const IPathMatcher* m_blacklist = nullptr;
|
const IPathMatcher * m_blacklist = nullptr;
|
||||||
QDir m_src;
|
QDir m_src;
|
||||||
QDir m_dst;
|
QDir m_dst;
|
||||||
};
|
};
|
||||||
@ -109,14 +82,9 @@ class copy {
|
|||||||
*/
|
*/
|
||||||
bool deletePath(QString path);
|
bool deletePath(QString path);
|
||||||
|
|
||||||
/**
|
QString PathCombine(const QString &path1, const QString &path2);
|
||||||
* Trash a folder / file
|
QString PathCombine(const QString &path1, const QString &path2, const QString &path3);
|
||||||
*/
|
QString PathCombine(const QString &path1, const QString &path2, const QString &path3, const QString &path4);
|
||||||
bool trash(QString path, QString *pathInTrash);
|
|
||||||
|
|
||||||
QString PathCombine(const QString& path1, const QString& path2);
|
|
||||||
QString PathCombine(const QString& path1, const QString& path2, const QString& path3);
|
|
||||||
QString PathCombine(const QString& path1, const QString& path2, const QString& path3, const QString& path4);
|
|
||||||
|
|
||||||
QString AbsolutePath(QString path);
|
QString AbsolutePath(QString path);
|
||||||
|
|
||||||
@ -152,6 +120,11 @@ bool checkProblemticPathJava(QDir folder);
|
|||||||
// Get the Directory representing the User's Desktop
|
// Get the Directory representing the User's Desktop
|
||||||
QString getDesktopDir();
|
QString getDesktopDir();
|
||||||
|
|
||||||
|
// Create a shortcut at *location*, pointing to *dest* called with the arguments *args*
|
||||||
|
// call it *name* and assign it the icon *icon*
|
||||||
|
// return true if operation succeeded
|
||||||
|
bool createShortCut(QString location, QString dest, QStringList args, QString name, QString iconLocation);
|
||||||
|
|
||||||
// Overrides one folder with the contents of another, preserving items exclusive to the first folder
|
// Overrides one folder with the contents of another, preserving items exclusive to the first folder
|
||||||
// Equivalent to doing QDir::rename, but allowing for overrides
|
// Equivalent to doing QDir::rename, but allowing for overrides
|
||||||
bool overrideFolder(QString overwritten_path, QString override_path);
|
bool overrideFolder(QString overwritten_path, QString override_path);
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
#include <QTest>
|
#include <QTest>
|
||||||
#include <QTemporaryDir>
|
#include <QTemporaryDir>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
|
#include "TestUtil.h"
|
||||||
|
|
||||||
#include <FileSystem.h>
|
#include "FileSystem.h"
|
||||||
|
|
||||||
#include <pathmatcher/RegexpMatcher.h>
|
|
||||||
|
|
||||||
class FileSystemTest : public QObject
|
class FileSystemTest : public QObject
|
||||||
{
|
{
|
||||||
@ -82,7 +81,7 @@ slots:
|
|||||||
|
|
||||||
void test_copy()
|
void test_copy()
|
||||||
{
|
{
|
||||||
QString folder = QFINDTESTDATA("testdata/FileSystem/test_folder");
|
QString folder = QFINDTESTDATA("data/test_folder");
|
||||||
auto f = [&folder]()
|
auto f = [&folder]()
|
||||||
{
|
{
|
||||||
QTemporaryDir tempDir;
|
QTemporaryDir tempDir;
|
||||||
@ -113,80 +112,51 @@ slots:
|
|||||||
f();
|
f();
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_copy_with_blacklist()
|
|
||||||
{
|
|
||||||
QString folder = QFINDTESTDATA("testdata/FileSystem/test_folder");
|
|
||||||
auto f = [&folder]()
|
|
||||||
{
|
|
||||||
QTemporaryDir tempDir;
|
|
||||||
tempDir.setAutoRemove(true);
|
|
||||||
qDebug() << "From:" << folder << "To:" << tempDir.path();
|
|
||||||
|
|
||||||
QDir target_dir(FS::PathCombine(tempDir.path(), "test_folder"));
|
|
||||||
qDebug() << tempDir.path();
|
|
||||||
qDebug() << target_dir.path();
|
|
||||||
FS::copy c(folder, target_dir.path());
|
|
||||||
c.blacklist(new RegexpMatcher("[.]?mcmeta"));
|
|
||||||
c();
|
|
||||||
|
|
||||||
for(auto entry: target_dir.entryList())
|
|
||||||
{
|
|
||||||
qDebug() << entry;
|
|
||||||
}
|
|
||||||
QVERIFY(!target_dir.entryList().contains("pack.mcmeta"));
|
|
||||||
QVERIFY(target_dir.entryList().contains("assets"));
|
|
||||||
};
|
|
||||||
|
|
||||||
// first try variant without trailing /
|
|
||||||
QVERIFY(!folder.endsWith('/'));
|
|
||||||
f();
|
|
||||||
|
|
||||||
// then variant with trailing /
|
|
||||||
folder.append('/');
|
|
||||||
QVERIFY(folder.endsWith('/'));
|
|
||||||
f();
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_copy_with_dot_hidden()
|
|
||||||
{
|
|
||||||
QString folder = QFINDTESTDATA("testdata/FileSystem/test_folder");
|
|
||||||
auto f = [&folder]()
|
|
||||||
{
|
|
||||||
QTemporaryDir tempDir;
|
|
||||||
tempDir.setAutoRemove(true);
|
|
||||||
qDebug() << "From:" << folder << "To:" << tempDir.path();
|
|
||||||
|
|
||||||
QDir target_dir(FS::PathCombine(tempDir.path(), "test_folder"));
|
|
||||||
qDebug() << tempDir.path();
|
|
||||||
qDebug() << target_dir.path();
|
|
||||||
FS::copy c(folder, target_dir.path());
|
|
||||||
c();
|
|
||||||
|
|
||||||
auto filter = QDir::Filter::Files | QDir::Filter::Dirs | QDir::Filter::Hidden;
|
|
||||||
|
|
||||||
for (auto entry: target_dir.entryList(filter)) {
|
|
||||||
qDebug() << entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
QVERIFY(target_dir.entryList(filter).contains(".secret_folder"));
|
|
||||||
target_dir.cd(".secret_folder");
|
|
||||||
QVERIFY(target_dir.entryList(filter).contains(".secret_file.txt"));
|
|
||||||
};
|
|
||||||
|
|
||||||
// first try variant without trailing /
|
|
||||||
QVERIFY(!folder.endsWith('/'));
|
|
||||||
f();
|
|
||||||
|
|
||||||
// then variant with trailing /
|
|
||||||
folder.append('/');
|
|
||||||
QVERIFY(folder.endsWith('/'));
|
|
||||||
f();
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_getDesktop()
|
void test_getDesktop()
|
||||||
{
|
{
|
||||||
QCOMPARE(FS::getDesktopDir(), QStandardPaths::writableLocation(QStandardPaths::DesktopLocation));
|
QCOMPARE(FS::getDesktopDir(), QStandardPaths::writableLocation(QStandardPaths::DesktopLocation));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this is only valid on linux
|
||||||
|
// FIXME: implement on windows, OSX, then test.
|
||||||
|
#if defined(Q_OS_LINUX)
|
||||||
|
void test_createShortcut_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<QString>("location");
|
||||||
|
QTest::addColumn<QString>("dest");
|
||||||
|
QTest::addColumn<QStringList>("args");
|
||||||
|
QTest::addColumn<QString>("name");
|
||||||
|
QTest::addColumn<QString>("iconLocation");
|
||||||
|
QTest::addColumn<QByteArray>("result");
|
||||||
|
|
||||||
|
QTest::newRow("unix") << QDir::currentPath()
|
||||||
|
<< "asdfDest"
|
||||||
|
<< (QStringList() << "arg1" << "arg2")
|
||||||
|
<< "asdf"
|
||||||
|
<< QString()
|
||||||
|
#if defined(Q_OS_LINUX)
|
||||||
|
<< GET_TEST_FILE("data/FileSystem-test_createShortcut-unix")
|
||||||
|
#elif defined(Q_OS_WIN)
|
||||||
|
<< QByteArray()
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_createShortcut()
|
||||||
|
{
|
||||||
|
QFETCH(QString, location);
|
||||||
|
QFETCH(QString, dest);
|
||||||
|
QFETCH(QStringList, args);
|
||||||
|
QFETCH(QString, name);
|
||||||
|
QFETCH(QString, iconLocation);
|
||||||
|
QFETCH(QByteArray, result);
|
||||||
|
|
||||||
|
QVERIFY(FS::createShortCut(location, dest, args, name, iconLocation));
|
||||||
|
QCOMPARE(QString::fromLocal8Bit(TestsInternal::readFile(location + QDir::separator() + name + ".desktop")), QString::fromLocal8Bit(result));
|
||||||
|
|
||||||
|
//QDir().remove(location);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
QTEST_GUILESS_MAIN(FileSystemTest)
|
QTEST_GUILESS_MAIN(FileSystemTest)
|
@ -1,38 +1,3 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
/*
|
|
||||||
* PolyMC - Minecraft Launcher
|
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
*
|
|
||||||
* 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 "GZip.h"
|
#include "GZip.h"
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
@ -102,7 +67,7 @@ bool GZip::zip(const QByteArray &uncompressedBytes, QByteArray &compressedBytes)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned compLength = qMin(uncompressedBytes.size(), 16);
|
unsigned compLength = std::min(uncompressedBytes.size(), 16);
|
||||||
compressedBytes.clear();
|
compressedBytes.clear();
|
||||||
compressedBytes.resize(compLength);
|
compressedBytes.resize(compLength);
|
||||||
|
|
||||||
@ -147,4 +112,4 @@ bool GZip::zip(const QByteArray &uncompressedBytes, QByteArray &compressedBytes)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
@ -1,6 +1,7 @@
|
|||||||
#include <QTest>
|
#include <QTest>
|
||||||
|
#include "TestUtil.h"
|
||||||
|
|
||||||
#include <GZip.h>
|
#include "GZip.h"
|
||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
void fib(int &prev, int &cur)
|
void fib(int &prev, int &cur)
|
@ -44,7 +44,7 @@ void InstanceCopyTask::copyFinished()
|
|||||||
auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(m_stagingPath, "instance.cfg"));
|
auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(m_stagingPath, "instance.cfg"));
|
||||||
|
|
||||||
InstancePtr inst(new NullInstance(m_globalSettings, instanceSettings, m_stagingPath));
|
InstancePtr inst(new NullInstance(m_globalSettings, instanceSettings, m_stagingPath));
|
||||||
inst->setName(name());
|
inst->setName(m_instName);
|
||||||
inst->setIconKey(m_instIcon);
|
inst->setIconKey(m_instIcon);
|
||||||
if(!m_keepPlaytime) {
|
if(!m_keepPlaytime) {
|
||||||
inst->resetTimePlayed();
|
inst->resetTimePlayed();
|
||||||
|
@ -1,56 +1,40 @@
|
|||||||
#include "InstanceCreationTask.h"
|
#include "InstanceCreationTask.h"
|
||||||
|
#include "settings/INISettingsObject.h"
|
||||||
|
#include "FileSystem.h"
|
||||||
|
|
||||||
#include <QDebug>
|
//FIXME: remove this
|
||||||
#include <QFile>
|
#include "minecraft/MinecraftInstance.h"
|
||||||
|
#include "minecraft/PackProfile.h"
|
||||||
|
|
||||||
InstanceCreationTask::InstanceCreationTask() = default;
|
InstanceCreationTask::InstanceCreationTask(BaseVersionPtr version)
|
||||||
|
{
|
||||||
|
m_version = version;
|
||||||
|
m_usingLoader = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
InstanceCreationTask::InstanceCreationTask(BaseVersionPtr version, QString loader, BaseVersionPtr loaderVersion)
|
||||||
|
{
|
||||||
|
m_version = version;
|
||||||
|
m_usingLoader = true;
|
||||||
|
m_loader = loader;
|
||||||
|
m_loaderVersion = loaderVersion;
|
||||||
|
}
|
||||||
|
|
||||||
void InstanceCreationTask::executeTask()
|
void InstanceCreationTask::executeTask()
|
||||||
{
|
{
|
||||||
setAbortable(true);
|
setStatus(tr("Creating instance from version %1").arg(m_version->name()));
|
||||||
|
{
|
||||||
if (updateInstance()) {
|
auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(m_stagingPath, "instance.cfg"));
|
||||||
emitSucceeded();
|
instanceSettings->suspendSave();
|
||||||
return;
|
MinecraftInstance inst(m_globalSettings, instanceSettings, m_stagingPath);
|
||||||
|
auto components = inst.getPackProfile();
|
||||||
|
components->buildingFromScratch();
|
||||||
|
components->setComponentVersion("net.minecraft", m_version->descriptor(), true);
|
||||||
|
if(m_usingLoader)
|
||||||
|
components->setComponentVersion(m_loader, m_loaderVersion->descriptor());
|
||||||
|
inst.setName(m_instName);
|
||||||
|
inst.setIconKey(m_instIcon);
|
||||||
|
instanceSettings->resumeSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
// When the user aborted in the update stage.
|
|
||||||
if (m_abort) {
|
|
||||||
emitAborted();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!createInstance()) {
|
|
||||||
if (m_abort)
|
|
||||||
return;
|
|
||||||
|
|
||||||
qWarning() << "Instance creation failed!";
|
|
||||||
if (!m_error_message.isEmpty())
|
|
||||||
qWarning() << "Reason: " << m_error_message;
|
|
||||||
emitFailed(tr("Error while creating new instance."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this is set, it means we're updating an instance. So, we now need to remove the
|
|
||||||
// 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.
|
|
||||||
if (shouldOverride()) {
|
|
||||||
setAbortable(false);
|
|
||||||
setStatus(tr("Removing old conflicting files..."));
|
|
||||||
qDebug() << "Removing old files";
|
|
||||||
|
|
||||||
for (auto path : m_files_to_remove) {
|
|
||||||
if (!QFile::exists(path))
|
|
||||||
continue;
|
|
||||||
qDebug() << "Removing" << path;
|
|
||||||
if (!QFile::remove(path)) {
|
|
||||||
qCritical() << "Couldn't remove the old conflicting files.";
|
|
||||||
emitFailed(tr("Failed to remove old conflicting files."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
@ -1,46 +1,26 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "tasks/Task.h"
|
||||||
|
#include "net/NetJob.h"
|
||||||
|
#include <QUrl>
|
||||||
|
#include "settings/SettingsObject.h"
|
||||||
#include "BaseVersion.h"
|
#include "BaseVersion.h"
|
||||||
#include "InstanceTask.h"
|
#include "InstanceTask.h"
|
||||||
|
|
||||||
class InstanceCreationTask : public InstanceTask {
|
class InstanceCreationTask : public InstanceTask
|
||||||
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
InstanceCreationTask();
|
explicit InstanceCreationTask(BaseVersionPtr version);
|
||||||
virtual ~InstanceCreationTask() = default;
|
explicit InstanceCreationTask(BaseVersionPtr version, QString loader, BaseVersionPtr loaderVersion);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void executeTask() final override;
|
//! Entry point for tasks.
|
||||||
|
virtual void executeTask() override;
|
||||||
|
|
||||||
/**
|
private: /* data */
|
||||||
* Tries to update an already existing instance.
|
BaseVersionPtr m_version;
|
||||||
*
|
bool m_usingLoader;
|
||||||
* This can be implemented by subclasses to provide a way of updating an already existing
|
QString m_loader;
|
||||||
* instance, according to that implementation's concept of 'identity' (i.e. instances that
|
BaseVersionPtr m_loaderVersion;
|
||||||
* are updates / downgrades of one another).
|
|
||||||
*
|
|
||||||
* If this returns true, createInstance() will not run, so you should do all update steps in here.
|
|
||||||
* Otherwise, createInstance() is run as normal.
|
|
||||||
*/
|
|
||||||
virtual bool updateInstance() { return false; };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new instance.
|
|
||||||
*
|
|
||||||
* Returns whether the instance creation was successful (true) or not (false).
|
|
||||||
*/
|
|
||||||
virtual bool createInstance() { return false; };
|
|
||||||
|
|
||||||
QString getError() const { return m_error_message; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void setError(QString message) { m_error_message = message; };
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool m_abort = false;
|
|
||||||
|
|
||||||
QStringList m_files_to_remove;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString m_error_message;
|
|
||||||
};
|
};
|
||||||
|
@ -35,25 +35,34 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "InstanceImportTask.h"
|
#include "InstanceImportTask.h"
|
||||||
|
#include <QtConcurrentRun>
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
#include "BaseInstance.h"
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include "MMCZip.h"
|
#include "MMCZip.h"
|
||||||
#include "NullInstance.h"
|
#include "NullInstance.h"
|
||||||
|
|
||||||
#include "icons/IconList.h"
|
#include "icons/IconList.h"
|
||||||
#include "icons/IconUtils.h"
|
#include "icons/IconUtils.h"
|
||||||
|
|
||||||
#include "modplatform/technic/TechnicPackProcessor.h"
|
|
||||||
#include "modplatform/modrinth/ModrinthInstanceCreationTask.h"
|
|
||||||
#include "modplatform/flame/FlameInstanceCreationTask.h"
|
|
||||||
|
|
||||||
#include "settings/INISettingsObject.h"
|
#include "settings/INISettingsObject.h"
|
||||||
|
|
||||||
#include <QtConcurrentRun>
|
// FIXME: this does not belong here, it's Minecraft/Flame specific
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include <quazip/quazipdir.h>
|
#include <quazip/quazipdir.h>
|
||||||
|
#include "Json.h"
|
||||||
|
#include "minecraft/MinecraftInstance.h"
|
||||||
|
#include "minecraft/PackProfile.h"
|
||||||
|
#include "modplatform/flame/FileResolvingTask.h"
|
||||||
|
#include "modplatform/flame/PackManifest.h"
|
||||||
|
#include "modplatform/modrinth/ModrinthPackManifest.h"
|
||||||
|
#include "modplatform/technic/TechnicPackProcessor.h"
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
#include "icons/IconList.h"
|
||||||
|
#include "net/ChecksumValidator.h"
|
||||||
|
|
||||||
|
#include "ui/dialogs/CustomMessageBox.h"
|
||||||
|
#include "ui/dialogs/ScrollMessageBox.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
InstanceImportTask::InstanceImportTask(const QUrl sourceUrl, QWidget* parent)
|
InstanceImportTask::InstanceImportTask(const QUrl sourceUrl, QWidget* parent)
|
||||||
{
|
{
|
||||||
@ -63,41 +72,35 @@ InstanceImportTask::InstanceImportTask(const QUrl sourceUrl, QWidget* parent)
|
|||||||
|
|
||||||
bool InstanceImportTask::abort()
|
bool InstanceImportTask::abort()
|
||||||
{
|
{
|
||||||
if (!canAbort())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (m_filesNetJob)
|
if (m_filesNetJob)
|
||||||
m_filesNetJob->abort();
|
m_filesNetJob->abort();
|
||||||
m_extractFuture.cancel();
|
m_extractFuture.cancel();
|
||||||
|
|
||||||
return Task::abort();
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceImportTask::executeTask()
|
void InstanceImportTask::executeTask()
|
||||||
{
|
{
|
||||||
setAbortable(true);
|
if (m_sourceUrl.isLocalFile())
|
||||||
|
{
|
||||||
if (m_sourceUrl.isLocalFile()) {
|
|
||||||
m_archivePath = m_sourceUrl.toLocalFile();
|
m_archivePath = m_sourceUrl.toLocalFile();
|
||||||
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;
|
m_downloadRequired = true;
|
||||||
|
|
||||||
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_archivePath = entry->getFullPath();
|
|
||||||
|
|
||||||
m_filesNetJob = new NetJob(tr("Modpack download"), APPLICATION->network());
|
m_filesNetJob = new NetJob(tr("Modpack download"), APPLICATION->network());
|
||||||
m_filesNetJob->addNetAction(Net::Download::makeCached(m_sourceUrl, entry));
|
m_filesNetJob->addNetAction(Net::Download::makeCached(m_sourceUrl, entry));
|
||||||
|
m_archivePath = entry->getFullPath();
|
||||||
connect(m_filesNetJob.get(), &NetJob::succeeded, this, &InstanceImportTask::downloadSucceeded);
|
auto job = m_filesNetJob.get();
|
||||||
connect(m_filesNetJob.get(), &NetJob::progress, this, &InstanceImportTask::downloadProgressChanged);
|
connect(job, &NetJob::succeeded, this, &InstanceImportTask::downloadSucceeded);
|
||||||
connect(m_filesNetJob.get(), &NetJob::failed, this, &InstanceImportTask::downloadFailed);
|
connect(job, &NetJob::progress, this, &InstanceImportTask::downloadProgressChanged);
|
||||||
connect(m_filesNetJob.get(), &NetJob::aborted, this, &InstanceImportTask::downloadAborted);
|
connect(job, &NetJob::failed, this, &InstanceImportTask::downloadFailed);
|
||||||
|
|
||||||
m_filesNetJob->start();
|
m_filesNetJob->start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,13 +119,7 @@ void InstanceImportTask::downloadFailed(QString reason)
|
|||||||
|
|
||||||
void InstanceImportTask::downloadProgressChanged(qint64 current, qint64 total)
|
void InstanceImportTask::downloadProgressChanged(qint64 current, qint64 total)
|
||||||
{
|
{
|
||||||
setProgress(current, total);
|
setProgress(current / 2, total);
|
||||||
}
|
|
||||||
|
|
||||||
void InstanceImportTask::downloadAborted()
|
|
||||||
{
|
|
||||||
emitAborted();
|
|
||||||
m_filesNetJob.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceImportTask::processZipPack()
|
void InstanceImportTask::processZipPack()
|
||||||
@ -258,31 +255,291 @@ void InstanceImportTask::extractFinished()
|
|||||||
|
|
||||||
void InstanceImportTask::extractAborted()
|
void InstanceImportTask::extractAborted()
|
||||||
{
|
{
|
||||||
emitAborted();
|
emitFailed(tr("Instance import has been aborted."));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceImportTask::processFlame()
|
void InstanceImportTask::processFlame()
|
||||||
{
|
{
|
||||||
auto* inst_creation_task = new FlameCreationTask(m_stagingPath, m_globalSettings, m_parent);
|
const static QMap<QString,QString> forgemap = {
|
||||||
|
{"1.2.5", "3.4.9.171"},
|
||||||
|
{"1.4.2", "6.0.1.355"},
|
||||||
|
{"1.4.7", "6.6.2.534"},
|
||||||
|
{"1.5.2", "7.8.1.737"}
|
||||||
|
};
|
||||||
|
Flame::Manifest pack;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
QString configPath = FS::PathCombine(m_stagingPath, "manifest.json");
|
||||||
|
Flame::loadManifest(pack, configPath);
|
||||||
|
QFile::remove(configPath);
|
||||||
|
}
|
||||||
|
catch (const JSONValidationError &e)
|
||||||
|
{
|
||||||
|
emitFailed(tr("Could not understand pack manifest:\n") + e.cause());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(!pack.overrides.isEmpty())
|
||||||
|
{
|
||||||
|
QString overridePath = FS::PathCombine(m_stagingPath, pack.overrides);
|
||||||
|
if (QFile::exists(overridePath))
|
||||||
|
{
|
||||||
|
QString mcPath = FS::PathCombine(m_stagingPath, "minecraft");
|
||||||
|
if (!QFile::rename(overridePath, mcPath))
|
||||||
|
{
|
||||||
|
emitFailed(tr("Could not rename the overrides folder:\n") + pack.overrides);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logWarning(tr("The specified overrides folder (%1) is missing. Maybe the modpack was already used before?").arg(pack.overrides));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inst_creation_task->setName(*this);
|
QString forgeVersion;
|
||||||
inst_creation_task->setIcon(m_instIcon);
|
QString fabricVersion;
|
||||||
inst_creation_task->setGroup(m_instGroup);
|
// TODO: is Quilt relevant here?
|
||||||
|
for(auto &loader: pack.minecraft.modLoaders)
|
||||||
connect(inst_creation_task, &Task::succeeded, this, [this, inst_creation_task] {
|
{
|
||||||
setOverride(inst_creation_task->shouldOverride());
|
auto id = loader.id;
|
||||||
emitSucceeded();
|
if(id.startsWith("forge-"))
|
||||||
|
{
|
||||||
|
id.remove("forge-");
|
||||||
|
forgeVersion = id;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(id.startsWith("fabric-"))
|
||||||
|
{
|
||||||
|
id.remove("fabric-");
|
||||||
|
fabricVersion = id;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
logWarning(tr("Unknown mod loader in manifest: %1").arg(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString configPath = FS::PathCombine(m_stagingPath, "instance.cfg");
|
||||||
|
auto instanceSettings = std::make_shared<INISettingsObject>(configPath);
|
||||||
|
MinecraftInstance instance(m_globalSettings, instanceSettings, m_stagingPath);
|
||||||
|
auto mcVersion = pack.minecraft.version;
|
||||||
|
// Hack to correct some 'special sauce'...
|
||||||
|
if(mcVersion.endsWith('.'))
|
||||||
|
{
|
||||||
|
mcVersion.remove(QRegExp("[.]+$"));
|
||||||
|
logWarning(tr("Mysterious trailing dots removed from Minecraft version while importing pack."));
|
||||||
|
}
|
||||||
|
auto components = instance.getPackProfile();
|
||||||
|
components->buildingFromScratch();
|
||||||
|
components->setComponentVersion("net.minecraft", mcVersion, true);
|
||||||
|
if(!forgeVersion.isEmpty())
|
||||||
|
{
|
||||||
|
// FIXME: dirty, nasty, hack. Proper solution requires dependency resolution and knowledge of the metadata.
|
||||||
|
if(forgeVersion == "recommended")
|
||||||
|
{
|
||||||
|
if(forgemap.contains(mcVersion))
|
||||||
|
{
|
||||||
|
forgeVersion = forgemap[mcVersion];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logWarning(tr("Could not map recommended Forge version for Minecraft %1").arg(mcVersion));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
components->setComponentVersion("net.minecraftforge", forgeVersion);
|
||||||
|
}
|
||||||
|
if(!fabricVersion.isEmpty())
|
||||||
|
{
|
||||||
|
components->setComponentVersion("net.fabricmc.fabric-loader", fabricVersion);
|
||||||
|
}
|
||||||
|
if (m_instIcon != "default")
|
||||||
|
{
|
||||||
|
instance.setIconKey(m_instIcon);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(pack.name.contains("Direwolf20"))
|
||||||
|
{
|
||||||
|
instance.setIconKey("steve");
|
||||||
|
}
|
||||||
|
else if(pack.name.contains("FTB") || pack.name.contains("Feed The Beast"))
|
||||||
|
{
|
||||||
|
instance.setIconKey("ftb_logo");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// default to something other than the MultiMC default to distinguish these
|
||||||
|
instance.setIconKey("flame");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QString jarmodsPath = FS::PathCombine(m_stagingPath, "minecraft", "jarmods");
|
||||||
|
QFileInfo jarmodsInfo(jarmodsPath);
|
||||||
|
if(jarmodsInfo.isDir())
|
||||||
|
{
|
||||||
|
// install all the jar mods
|
||||||
|
qDebug() << "Found jarmods:";
|
||||||
|
QDir jarmodsDir(jarmodsPath);
|
||||||
|
QStringList jarMods;
|
||||||
|
for (auto info: jarmodsDir.entryInfoList(QDir::NoDotAndDotDot | QDir::Files))
|
||||||
|
{
|
||||||
|
qDebug() << info.fileName();
|
||||||
|
jarMods.push_back(info.absoluteFilePath());
|
||||||
|
}
|
||||||
|
auto profile = instance.getPackProfile();
|
||||||
|
profile->installJarMods(jarMods);
|
||||||
|
// nuke the original files
|
||||||
|
FS::deletePath(jarmodsPath);
|
||||||
|
}
|
||||||
|
instance.setName(m_instName);
|
||||||
|
m_modIdResolver = new Flame::FileResolvingTask(APPLICATION->network(), pack);
|
||||||
|
connect(m_modIdResolver.get(), &Flame::FileResolvingTask::succeeded, [&]()
|
||||||
|
{
|
||||||
|
auto results = m_modIdResolver->getResults();
|
||||||
|
//first check for blocked mods
|
||||||
|
QString text;
|
||||||
|
auto anyBlocked = false;
|
||||||
|
for(const auto& result: results.files.values()) {
|
||||||
|
if (!result.resolved || result.url.isEmpty()) {
|
||||||
|
text += QString("%1: <a href='%2'>%2</a><br/>").arg(result.fileName, result.websiteUrl);
|
||||||
|
anyBlocked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(anyBlocked) {
|
||||||
|
qWarning() << "Blocked mods found, displaying mod list";
|
||||||
|
|
||||||
|
auto message_dialog = new ScrollMessageBox(m_parent,
|
||||||
|
tr("Blocked mods found"),
|
||||||
|
tr("The following mods were blocked on third party launchers.<br/>"
|
||||||
|
"You will need to manually download them and add them to the modpack"),
|
||||||
|
text);
|
||||||
|
message_dialog->setModal(true);
|
||||||
|
message_dialog->show();
|
||||||
|
connect(message_dialog, &QDialog::rejected, [&]() {
|
||||||
|
m_modIdResolver.reset();
|
||||||
|
emitFailed("Canceled");
|
||||||
|
});
|
||||||
|
connect(message_dialog, &QDialog::accepted, [&]() {
|
||||||
|
m_filesNetJob = new NetJob(tr("Mod download"), APPLICATION->network());
|
||||||
|
for (const auto &result: m_modIdResolver->getResults().files) {
|
||||||
|
QString filename = result.fileName;
|
||||||
|
if (!result.required) {
|
||||||
|
filename += ".disabled";
|
||||||
|
}
|
||||||
|
|
||||||
|
auto relpath = FS::PathCombine("minecraft", result.targetFolder, filename);
|
||||||
|
auto path = FS::PathCombine(m_stagingPath, relpath);
|
||||||
|
|
||||||
|
switch (result.type) {
|
||||||
|
case Flame::File::Type::Folder: {
|
||||||
|
logWarning(tr("This 'Folder' may need extracting: %1").arg(relpath));
|
||||||
|
// fall-through intentional, we treat these as plain old mods and dump them wherever.
|
||||||
|
}
|
||||||
|
case Flame::File::Type::SingleFile:
|
||||||
|
case Flame::File::Type::Mod: {
|
||||||
|
if (!result.url.isEmpty()) {
|
||||||
|
qDebug() << "Will download" << result.url << "to" << path;
|
||||||
|
auto dl = Net::Download::makeFile(result.url, path);
|
||||||
|
m_filesNetJob->addNetAction(dl);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Flame::File::Type::Modpack:
|
||||||
|
logWarning(
|
||||||
|
tr("Nesting modpacks in modpacks is not implemented, nothing was downloaded: %1").arg(
|
||||||
|
relpath));
|
||||||
|
break;
|
||||||
|
case Flame::File::Type::Cmod2:
|
||||||
|
case Flame::File::Type::Ctoc:
|
||||||
|
case Flame::File::Type::Unknown:
|
||||||
|
logWarning(tr("Unrecognized/unhandled PackageType for: %1").arg(relpath));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_modIdResolver.reset();
|
||||||
|
connect(m_filesNetJob.get(), &NetJob::succeeded, this, [&]() {
|
||||||
|
m_filesNetJob.reset();
|
||||||
|
emitSucceeded();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
connect(m_filesNetJob.get(), &NetJob::failed, [&](QString reason) {
|
||||||
|
m_filesNetJob.reset();
|
||||||
|
emitFailed(reason);
|
||||||
|
});
|
||||||
|
connect(m_filesNetJob.get(), &NetJob::progress, [&](qint64 current, qint64 total) {
|
||||||
|
setProgress(current, total);
|
||||||
|
});
|
||||||
|
setStatus(tr("Downloading mods..."));
|
||||||
|
m_filesNetJob->start();
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
//TODO extract to function ?
|
||||||
|
m_filesNetJob = new NetJob(tr("Mod download"), APPLICATION->network());
|
||||||
|
for (const auto &result: m_modIdResolver->getResults().files) {
|
||||||
|
QString filename = result.fileName;
|
||||||
|
if (!result.required) {
|
||||||
|
filename += ".disabled";
|
||||||
|
}
|
||||||
|
|
||||||
|
auto relpath = FS::PathCombine("minecraft", result.targetFolder, filename);
|
||||||
|
auto path = FS::PathCombine(m_stagingPath, relpath);
|
||||||
|
|
||||||
|
switch (result.type) {
|
||||||
|
case Flame::File::Type::Folder: {
|
||||||
|
logWarning(tr("This 'Folder' may need extracting: %1").arg(relpath));
|
||||||
|
// fall-through intentional, we treat these as plain old mods and dump them wherever.
|
||||||
|
}
|
||||||
|
case Flame::File::Type::SingleFile:
|
||||||
|
case Flame::File::Type::Mod: {
|
||||||
|
if (!result.url.isEmpty()) {
|
||||||
|
qDebug() << "Will download" << result.url << "to" << path;
|
||||||
|
auto dl = Net::Download::makeFile(result.url, path);
|
||||||
|
m_filesNetJob->addNetAction(dl);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Flame::File::Type::Modpack:
|
||||||
|
logWarning(
|
||||||
|
tr("Nesting modpacks in modpacks is not implemented, nothing was downloaded: %1").arg(
|
||||||
|
relpath));
|
||||||
|
break;
|
||||||
|
case Flame::File::Type::Cmod2:
|
||||||
|
case Flame::File::Type::Ctoc:
|
||||||
|
case Flame::File::Type::Unknown:
|
||||||
|
logWarning(tr("Unrecognized/unhandled PackageType for: %1").arg(relpath));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_modIdResolver.reset();
|
||||||
|
connect(m_filesNetJob.get(), &NetJob::succeeded, this, [&]() {
|
||||||
|
m_filesNetJob.reset();
|
||||||
|
emitSucceeded();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
connect(m_filesNetJob.get(), &NetJob::failed, [&](QString reason) {
|
||||||
|
m_filesNetJob.reset();
|
||||||
|
emitFailed(reason);
|
||||||
|
});
|
||||||
|
connect(m_filesNetJob.get(), &NetJob::progress, [&](qint64 current, qint64 total) {
|
||||||
|
setProgress(current, total);
|
||||||
|
});
|
||||||
|
setStatus(tr("Downloading mods..."));
|
||||||
|
m_filesNetJob->start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
connect(m_modIdResolver.get(), &Flame::FileResolvingTask::failed, [&](QString reason)
|
||||||
|
{
|
||||||
|
m_modIdResolver.reset();
|
||||||
|
emitFailed(tr("Unable to resolve mod IDs:\n") + reason);
|
||||||
});
|
});
|
||||||
connect(inst_creation_task, &Task::failed, this, &InstanceImportTask::emitFailed);
|
connect(m_modIdResolver.get(), &Flame::FileResolvingTask::progress, [&](qint64 current, qint64 total)
|
||||||
connect(inst_creation_task, &Task::progress, this, &InstanceImportTask::setProgress);
|
{
|
||||||
connect(inst_creation_task, &Task::status, this, &InstanceImportTask::setStatus);
|
setProgress(current, total);
|
||||||
connect(inst_creation_task, &Task::finished, inst_creation_task, &InstanceCreationTask::deleteLater);
|
});
|
||||||
|
connect(m_modIdResolver.get(), &Flame::FileResolvingTask::status, [&](QString status)
|
||||||
connect(this, &Task::aborted, inst_creation_task, &InstanceCreationTask::abort);
|
{
|
||||||
connect(inst_creation_task, &Task::aborted, this, &Task::abort);
|
setStatus(status);
|
||||||
connect(inst_creation_task, &Task::abortStatusChanged, this, &Task::setAbortable);
|
});
|
||||||
|
m_modIdResolver->start();
|
||||||
inst_creation_task->start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceImportTask::processTechnic()
|
void InstanceImportTask::processTechnic()
|
||||||
@ -290,7 +547,7 @@ void InstanceImportTask::processTechnic()
|
|||||||
shared_qobject_ptr<Technic::TechnicPackProcessor> packProcessor = new Technic::TechnicPackProcessor();
|
shared_qobject_ptr<Technic::TechnicPackProcessor> packProcessor = new Technic::TechnicPackProcessor();
|
||||||
connect(packProcessor.get(), &Technic::TechnicPackProcessor::succeeded, this, &InstanceImportTask::emitSucceeded);
|
connect(packProcessor.get(), &Technic::TechnicPackProcessor::succeeded, this, &InstanceImportTask::emitSucceeded);
|
||||||
connect(packProcessor.get(), &Technic::TechnicPackProcessor::failed, this, &InstanceImportTask::emitFailed);
|
connect(packProcessor.get(), &Technic::TechnicPackProcessor::failed, this, &InstanceImportTask::emitFailed);
|
||||||
packProcessor->run(m_globalSettings, name(), m_instIcon, m_stagingPath);
|
packProcessor->run(m_globalSettings, m_instName, m_instIcon, m_stagingPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceImportTask::processMultiMC()
|
void InstanceImportTask::processMultiMC()
|
||||||
@ -304,7 +561,7 @@ void InstanceImportTask::processMultiMC()
|
|||||||
instance.resetTimePlayed();
|
instance.resetTimePlayed();
|
||||||
|
|
||||||
// set a new nice name
|
// set a new nice name
|
||||||
instance.setName(name());
|
instance.setName(m_instName);
|
||||||
|
|
||||||
// if the icon was specified by user, use that. otherwise pull icon from the pack
|
// if the icon was specified by user, use that. otherwise pull icon from the pack
|
||||||
if (m_instIcon != "default") {
|
if (m_instIcon != "default") {
|
||||||
@ -325,26 +582,198 @@ void InstanceImportTask::processMultiMC()
|
|||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://docs.modrinth.com/docs/modpacks/format_definition/
|
||||||
void InstanceImportTask::processModrinth()
|
void InstanceImportTask::processModrinth()
|
||||||
{
|
{
|
||||||
auto* inst_creation_task = new ModrinthCreationTask(m_stagingPath, m_globalSettings, m_parent, m_sourceUrl.toString());
|
std::vector<Modrinth::File> files;
|
||||||
|
QString minecraftVersion, fabricVersion, quiltVersion, forgeVersion;
|
||||||
|
try {
|
||||||
|
QString indexPath = FS::PathCombine(m_stagingPath, "modrinth.index.json");
|
||||||
|
auto doc = Json::requireDocument(indexPath);
|
||||||
|
auto obj = Json::requireObject(doc, "modrinth.index.json");
|
||||||
|
int formatVersion = Json::requireInteger(obj, "formatVersion", "modrinth.index.json");
|
||||||
|
if (formatVersion == 1) {
|
||||||
|
auto game = Json::requireString(obj, "game", "modrinth.index.json");
|
||||||
|
if (game != "minecraft") {
|
||||||
|
throw JSONValidationError("Unknown game: " + game);
|
||||||
|
}
|
||||||
|
|
||||||
inst_creation_task->setName(*this);
|
auto jsonFiles = Json::requireIsArrayOf<QJsonObject>(obj, "files", "modrinth.index.json");
|
||||||
inst_creation_task->setIcon(m_instIcon);
|
bool had_optional = false;
|
||||||
inst_creation_task->setGroup(m_instGroup);
|
for (auto modInfo : jsonFiles) {
|
||||||
|
Modrinth::File file;
|
||||||
|
file.path = Json::requireString(modInfo, "path");
|
||||||
|
|
||||||
|
auto env = Json::ensureObject(modInfo, "env");
|
||||||
|
// 'env' field is optional
|
||||||
|
if (!env.isEmpty()) {
|
||||||
|
QString support = Json::ensureString(env, "client", "unsupported");
|
||||||
|
if (support == "unsupported") {
|
||||||
|
continue;
|
||||||
|
} else if (support == "optional") {
|
||||||
|
// TODO: Make a review dialog for choosing which ones the user wants!
|
||||||
|
if (!had_optional) {
|
||||||
|
had_optional = true;
|
||||||
|
auto info = CustomMessageBox::selectable(
|
||||||
|
m_parent, tr("Optional mod detected!"),
|
||||||
|
tr("One or more mods from this modpack are optional. They will be downloaded, but disabled by default!"),
|
||||||
|
QMessageBox::Information);
|
||||||
|
info->exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file.path.endsWith(".jar"))
|
||||||
|
file.path += ".disabled";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject hashes = Json::requireObject(modInfo, "hashes");
|
||||||
|
QString hash;
|
||||||
|
QCryptographicHash::Algorithm hashAlgorithm;
|
||||||
|
hash = Json::ensureString(hashes, "sha1");
|
||||||
|
hashAlgorithm = QCryptographicHash::Sha1;
|
||||||
|
if (hash.isEmpty()) {
|
||||||
|
hash = Json::ensureString(hashes, "sha512");
|
||||||
|
hashAlgorithm = QCryptographicHash::Sha512;
|
||||||
|
if (hash.isEmpty()) {
|
||||||
|
hash = Json::ensureString(hashes, "sha256");
|
||||||
|
hashAlgorithm = QCryptographicHash::Sha256;
|
||||||
|
if (hash.isEmpty()) {
|
||||||
|
throw JSONValidationError("No hash found for: " + file.path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file.hash = QByteArray::fromHex(hash.toLatin1());
|
||||||
|
file.hashAlgorithm = hashAlgorithm;
|
||||||
|
|
||||||
|
// Do not use requireUrl, which uses StrictMode, instead use QUrl's default TolerantMode
|
||||||
|
// (as Modrinth seems to incorrectly handle spaces)
|
||||||
|
|
||||||
|
auto download_arr = Json::ensureArray(modInfo, "downloads");
|
||||||
|
for(auto download : download_arr) {
|
||||||
|
qWarning() << download.toString();
|
||||||
|
bool is_last = download.toString() == download_arr.last().toString();
|
||||||
|
|
||||||
|
auto download_url = QUrl(download.toString());
|
||||||
|
|
||||||
|
if (!download_url.isValid()) {
|
||||||
|
qDebug() << QString("Download URL (%1) for %2 is not a correctly formatted URL")
|
||||||
|
.arg(download_url.toString(), file.path);
|
||||||
|
if(is_last && file.downloads.isEmpty())
|
||||||
|
throw JSONValidationError(tr("Download URL for %1 is not a correctly formatted URL").arg(file.path));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
file.downloads.push_back(download_url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
files.push_back(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto dependencies = Json::requireObject(obj, "dependencies", "modrinth.index.json");
|
||||||
|
for (auto it = dependencies.begin(), end = dependencies.end(); it != end; ++it) {
|
||||||
|
QString name = it.key();
|
||||||
|
if (name == "minecraft") {
|
||||||
|
minecraftVersion = Json::requireString(*it, "Minecraft version");
|
||||||
|
}
|
||||||
|
else if (name == "fabric-loader") {
|
||||||
|
fabricVersion = Json::requireString(*it, "Fabric Loader version");
|
||||||
|
}
|
||||||
|
else if (name == "quilt-loader") {
|
||||||
|
quiltVersion = Json::requireString(*it, "Quilt Loader version");
|
||||||
|
}
|
||||||
|
else if (name == "forge") {
|
||||||
|
forgeVersion = Json::requireString(*it, "Forge version");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw JSONValidationError("Unknown dependency type: " + name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw JSONValidationError(QStringLiteral("Unknown format version: %s").arg(formatVersion));
|
||||||
|
}
|
||||||
|
QFile::remove(indexPath);
|
||||||
|
} catch (const JSONValidationError& e) {
|
||||||
|
emitFailed(tr("Could not understand pack index:\n") + e.cause());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
connect(inst_creation_task, &Task::succeeded, this, [this, inst_creation_task] {
|
auto mcPath = FS::PathCombine(m_stagingPath, ".minecraft");
|
||||||
setOverride(inst_creation_task->shouldOverride());
|
|
||||||
emitSucceeded();
|
auto override_path = FS::PathCombine(m_stagingPath, "overrides");
|
||||||
|
if (QFile::exists(override_path)) {
|
||||||
|
if (!QFile::rename(override_path, mcPath)) {
|
||||||
|
emitFailed(tr("Could not rename the overrides folder:\n") + "overrides");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do client overrides
|
||||||
|
auto client_override_path = FS::PathCombine(m_stagingPath, "client-overrides");
|
||||||
|
if (QFile::exists(client_override_path)) {
|
||||||
|
if (!FS::overrideFolder(mcPath, client_override_path)) {
|
||||||
|
emitFailed(tr("Could not rename the client overrides folder:\n") + "client overrides");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString configPath = FS::PathCombine(m_stagingPath, "instance.cfg");
|
||||||
|
auto instanceSettings = std::make_shared<INISettingsObject>(configPath);
|
||||||
|
MinecraftInstance instance(m_globalSettings, instanceSettings, m_stagingPath);
|
||||||
|
auto components = instance.getPackProfile();
|
||||||
|
components->buildingFromScratch();
|
||||||
|
components->setComponentVersion("net.minecraft", minecraftVersion, true);
|
||||||
|
if (!fabricVersion.isEmpty())
|
||||||
|
components->setComponentVersion("net.fabricmc.fabric-loader", fabricVersion, true);
|
||||||
|
if (!quiltVersion.isEmpty())
|
||||||
|
components->setComponentVersion("org.quiltmc.quilt-loader", quiltVersion, true);
|
||||||
|
if (!forgeVersion.isEmpty())
|
||||||
|
components->setComponentVersion("net.minecraftforge", forgeVersion, true);
|
||||||
|
if (m_instIcon != "default")
|
||||||
|
{
|
||||||
|
instance.setIconKey(m_instIcon);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
instance.setIconKey("modrinth");
|
||||||
|
}
|
||||||
|
instance.setName(m_instName);
|
||||||
|
instance.saveNow();
|
||||||
|
|
||||||
|
m_filesNetJob = new NetJob(tr("Mod download"), APPLICATION->network());
|
||||||
|
for (auto file : files)
|
||||||
|
{
|
||||||
|
auto path = FS::PathCombine(m_stagingPath, ".minecraft", file.path);
|
||||||
|
qDebug() << "Will try to download" << file.downloads.front() << "to" << path;
|
||||||
|
auto dl = Net::Download::makeFile(file.downloads.dequeue(), path);
|
||||||
|
dl->addValidator(new Net::ChecksumValidator(file.hashAlgorithm, file.hash));
|
||||||
|
m_filesNetJob->addNetAction(dl);
|
||||||
|
|
||||||
|
if (file.downloads.size() > 0) {
|
||||||
|
// FIXME: This really needs to be put into a ConcurrentTask of
|
||||||
|
// MultipleOptionsTask's , once those exist :)
|
||||||
|
connect(dl.get(), &NetAction::failed, [this, &file, path, dl]{
|
||||||
|
auto dl = Net::Download::makeFile(file.downloads.dequeue(), path);
|
||||||
|
dl->addValidator(new Net::ChecksumValidator(file.hashAlgorithm, file.hash));
|
||||||
|
m_filesNetJob->addNetAction(dl);
|
||||||
|
dl->succeeded();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
connect(m_filesNetJob.get(), &NetJob::succeeded, this, [&]()
|
||||||
|
{
|
||||||
|
m_filesNetJob.reset();
|
||||||
|
emitSucceeded();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
connect(m_filesNetJob.get(), &NetJob::failed, [&](const QString &reason)
|
||||||
|
{
|
||||||
|
m_filesNetJob.reset();
|
||||||
|
emitFailed(reason);
|
||||||
});
|
});
|
||||||
connect(inst_creation_task, &Task::failed, this, &InstanceImportTask::emitFailed);
|
connect(m_filesNetJob.get(), &NetJob::progress, [&](qint64 current, qint64 total)
|
||||||
connect(inst_creation_task, &Task::progress, this, &InstanceImportTask::setProgress);
|
{
|
||||||
connect(inst_creation_task, &Task::status, this, &InstanceImportTask::setStatus);
|
setProgress(current, total);
|
||||||
connect(inst_creation_task, &Task::finished, inst_creation_task, &InstanceCreationTask::deleteLater);
|
});
|
||||||
|
setStatus(tr("Downloading mods..."));
|
||||||
connect(this, &Task::aborted, inst_creation_task, &InstanceCreationTask::abort);
|
m_filesNetJob->start();
|
||||||
connect(inst_creation_task, &Task::aborted, this, &Task::abort);
|
|
||||||
connect(inst_creation_task, &Task::abortStatusChanged, this, &Task::setAbortable);
|
|
||||||
|
|
||||||
inst_creation_task->start();
|
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@
|
|||||||
#include "QObjectPtr.h"
|
#include "QObjectPtr.h"
|
||||||
#include "modplatform/flame/PackManifest.h"
|
#include "modplatform/flame/PackManifest.h"
|
||||||
|
|
||||||
#include <optional>
|
#include <nonstd/optional>
|
||||||
|
|
||||||
class QuaZip;
|
class QuaZip;
|
||||||
namespace Flame
|
namespace Flame
|
||||||
@ -58,6 +58,7 @@ class InstanceImportTask : public InstanceTask
|
|||||||
public:
|
public:
|
||||||
explicit InstanceImportTask(const QUrl sourceUrl, QWidget* parent = nullptr);
|
explicit InstanceImportTask(const QUrl sourceUrl, QWidget* parent = nullptr);
|
||||||
|
|
||||||
|
bool canAbort() const override { return true; }
|
||||||
bool abort() override;
|
bool abort() override;
|
||||||
const QVector<Flame::File> &getBlockedFiles() const
|
const QVector<Flame::File> &getBlockedFiles() const
|
||||||
{
|
{
|
||||||
@ -79,7 +80,6 @@ private slots:
|
|||||||
void downloadSucceeded();
|
void downloadSucceeded();
|
||||||
void downloadFailed(QString reason);
|
void downloadFailed(QString reason);
|
||||||
void downloadProgressChanged(qint64 current, qint64 total);
|
void downloadProgressChanged(qint64 current, qint64 total);
|
||||||
void downloadAborted();
|
|
||||||
void extractFinished();
|
void extractFinished();
|
||||||
void extractAborted();
|
void extractAborted();
|
||||||
|
|
||||||
@ -90,8 +90,8 @@ private: /* data */
|
|||||||
QString m_archivePath;
|
QString m_archivePath;
|
||||||
bool m_downloadRequired = false;
|
bool m_downloadRequired = false;
|
||||||
std::unique_ptr<QuaZip> m_packZip;
|
std::unique_ptr<QuaZip> m_packZip;
|
||||||
QFuture<std::optional<QStringList>> m_extractFuture;
|
QFuture<nonstd::optional<QStringList>> m_extractFuture;
|
||||||
QFutureWatcher<std::optional<QStringList>> m_extractFutureWatcher;
|
QFutureWatcher<nonstd::optional<QStringList>> m_extractFutureWatcher;
|
||||||
QVector<Flame::File> m_blockedMods;
|
QVector<Flame::File> m_blockedMods;
|
||||||
enum class ModpackType{
|
enum class ModpackType{
|
||||||
Unknown,
|
Unknown,
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -19,15 +19,13 @@
|
|||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QStack>
|
|
||||||
#include <QPair>
|
|
||||||
|
|
||||||
#include "BaseInstance.h"
|
#include "BaseInstance.h"
|
||||||
|
|
||||||
|
#include "QObjectPtr.h"
|
||||||
|
|
||||||
class QFileSystemWatcher;
|
class QFileSystemWatcher;
|
||||||
class InstanceTask;
|
class InstanceTask;
|
||||||
struct InstanceName;
|
|
||||||
|
|
||||||
using InstanceId = QString;
|
using InstanceId = QString;
|
||||||
using GroupId = QString;
|
using GroupId = QString;
|
||||||
using InstanceLocator = std::pair<InstancePtr, int>;
|
using InstanceLocator = std::pair<InstancePtr, int>;
|
||||||
@ -48,12 +46,6 @@ enum class GroupsState
|
|||||||
Dirty
|
Dirty
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TrashHistoryItem {
|
|
||||||
QString id;
|
|
||||||
QString polyPath;
|
|
||||||
QString trashPath;
|
|
||||||
QString groupName;
|
|
||||||
};
|
|
||||||
|
|
||||||
class InstanceList : public QAbstractListModel
|
class InstanceList : public QAbstractListModel
|
||||||
{
|
{
|
||||||
@ -101,10 +93,7 @@ public:
|
|||||||
InstListError loadList();
|
InstListError loadList();
|
||||||
void saveNow();
|
void saveNow();
|
||||||
|
|
||||||
/* O(n) */
|
|
||||||
InstancePtr getInstanceById(QString id) const;
|
InstancePtr getInstanceById(QString id) const;
|
||||||
/* O(n) */
|
|
||||||
InstancePtr getInstanceByManagedName(const QString& managed_name) const;
|
|
||||||
QModelIndex getInstanceIndexById(const QString &id) const;
|
QModelIndex getInstanceIndexById(const QString &id) const;
|
||||||
QStringList getGroups();
|
QStringList getGroups();
|
||||||
bool isGroupCollapsed(const QString &groupName);
|
bool isGroupCollapsed(const QString &groupName);
|
||||||
@ -113,9 +102,6 @@ public:
|
|||||||
void setInstanceGroup(const InstanceId & id, const GroupId& name);
|
void setInstanceGroup(const InstanceId & id, const GroupId& name);
|
||||||
|
|
||||||
void deleteGroup(const GroupId & name);
|
void deleteGroup(const GroupId & name);
|
||||||
bool trashInstance(const InstanceId &id);
|
|
||||||
bool trashedSomething();
|
|
||||||
void undoTrashInstance();
|
|
||||||
void deleteInstance(const InstanceId & id);
|
void deleteInstance(const InstanceId & id);
|
||||||
|
|
||||||
// Wrap an instance creation task in some more task machinery and make it ready to be used
|
// Wrap an instance creation task in some more task machinery and make it ready to be used
|
||||||
@ -130,10 +116,8 @@ public:
|
|||||||
/**
|
/**
|
||||||
* Commit the staging area given by @keyPath to the provider - used when creation succeeds.
|
* Commit the staging area given by @keyPath to the provider - used when creation succeeds.
|
||||||
* Used by instance manipulation tasks.
|
* Used by instance manipulation tasks.
|
||||||
* should_override is used when another similar instance already exists, and we want to override it
|
|
||||||
* - for instance, when updating it.
|
|
||||||
*/
|
*/
|
||||||
bool commitStagedInstance(const QString& keyPath, const InstanceName& instanceName, const QString& groupName, bool should_override);
|
bool commitStagedInstance(const QString & keyPath, const QString& instanceName, const QString & groupName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy a previously created staging area given by @keyPath - used when creation fails.
|
* Destroy a previously created staging area given by @keyPath - used when creation fails.
|
||||||
@ -196,6 +180,4 @@ private:
|
|||||||
QSet<InstanceId> instanceSet;
|
QSet<InstanceId> instanceSet;
|
||||||
bool m_groupsLoaded = false;
|
bool m_groupsLoaded = false;
|
||||||
bool m_instancesProbed = false;
|
bool m_instancesProbed = false;
|
||||||
|
|
||||||
QStack<TrashHistoryItem> m_trashHistory;
|
|
||||||
};
|
};
|
||||||
|
@ -33,13 +33,13 @@ public:
|
|||||||
values.append(new LogPage(inst));
|
values.append(new LogPage(inst));
|
||||||
std::shared_ptr<MinecraftInstance> onesix = std::dynamic_pointer_cast<MinecraftInstance>(inst);
|
std::shared_ptr<MinecraftInstance> onesix = std::dynamic_pointer_cast<MinecraftInstance>(inst);
|
||||||
values.append(new VersionPage(onesix.get()));
|
values.append(new VersionPage(onesix.get()));
|
||||||
auto modsPage = new ModFolderPage(onesix.get(), onesix->loaderModList());
|
auto modsPage = new ModFolderPage(onesix.get(), onesix->loaderModList(), "mods", "loadermods", tr("Mods"), "Loader-mods");
|
||||||
modsPage->setFilter("%1 (*.zip *.jar *.litemod)");
|
modsPage->setFilter("%1 (*.zip *.jar *.litemod)");
|
||||||
values.append(modsPage);
|
values.append(modsPage);
|
||||||
values.append(new CoreModFolderPage(onesix.get(), onesix->coreModList()));
|
values.append(new CoreModFolderPage(onesix.get(), onesix->coreModList(), "coremods", "coremods", tr("Core mods"), "Core-mods"));
|
||||||
values.append(new ResourcePackPage(onesix.get(), onesix->resourcePackList()));
|
values.append(new ResourcePackPage(onesix.get()));
|
||||||
values.append(new TexturePackPage(onesix.get(), onesix->texturePackList()));
|
values.append(new TexturePackPage(onesix.get()));
|
||||||
values.append(new ShaderPackPage(onesix.get(), onesix->shaderPackList()));
|
values.append(new ShaderPackPage(onesix.get()));
|
||||||
values.append(new NotesPage(onesix.get()));
|
values.append(new NotesPage(onesix.get()));
|
||||||
values.append(new WorldListPage(onesix.get(), onesix->worldList()));
|
values.append(new WorldListPage(onesix.get(), onesix->worldList()));
|
||||||
values.append(new ServersPage(onesix));
|
values.append(new ServersPage(onesix));
|
||||||
|
@ -1,52 +1,9 @@
|
|||||||
#include "InstanceTask.h"
|
#include "InstanceTask.h"
|
||||||
|
|
||||||
#include "ui/dialogs/CustomMessageBox.h"
|
InstanceTask::InstanceTask()
|
||||||
|
|
||||||
InstanceNameChange askForChangingInstanceName(QWidget* parent, const QString& old_name, const QString& new_name)
|
|
||||||
{
|
{
|
||||||
auto dialog =
|
|
||||||
CustomMessageBox::selectable(parent, QObject::tr("Change instance name"),
|
|
||||||
QObject::tr("The instance's name seems to include the old version. Would you like to update it?\n\n"
|
|
||||||
"Old name: %1\n"
|
|
||||||
"New name: %2")
|
|
||||||
.arg(old_name, new_name),
|
|
||||||
QMessageBox::Question, QMessageBox::No | QMessageBox::Yes);
|
|
||||||
auto result = dialog->exec();
|
|
||||||
|
|
||||||
if (result == QMessageBox::Yes)
|
|
||||||
return InstanceNameChange::ShouldChange;
|
|
||||||
return InstanceNameChange::ShouldKeep;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString InstanceName::name() const
|
InstanceTask::~InstanceTask()
|
||||||
{
|
{
|
||||||
if (!m_modified_name.isEmpty())
|
|
||||||
return modifiedName();
|
|
||||||
return QString("%1 %2").arg(m_original_name, m_original_version);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString InstanceName::originalName() const
|
|
||||||
{
|
|
||||||
return m_original_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString InstanceName::modifiedName() const
|
|
||||||
{
|
|
||||||
if (!m_modified_name.isEmpty())
|
|
||||||
return m_modified_name;
|
|
||||||
return m_original_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString InstanceName::version() const
|
|
||||||
{
|
|
||||||
return m_original_version;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InstanceName::setName(InstanceName& other)
|
|
||||||
{
|
|
||||||
m_original_name = other.m_original_name;
|
|
||||||
m_original_version = other.m_original_version;
|
|
||||||
m_modified_name = other.m_modified_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
InstanceTask::InstanceTask() : Task(), InstanceName() {}
|
|
||||||
|
@ -1,57 +1,52 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "settings/SettingsObject.h"
|
|
||||||
#include "tasks/Task.h"
|
#include "tasks/Task.h"
|
||||||
|
#include "settings/SettingsObject.h"
|
||||||
|
|
||||||
/* Helpers */
|
class InstanceTask : public Task
|
||||||
enum class InstanceNameChange { ShouldChange, ShouldKeep };
|
{
|
||||||
[[nodiscard]] InstanceNameChange askForChangingInstanceName(QWidget* parent, const QString& old_name, const QString& new_name);
|
|
||||||
|
|
||||||
struct InstanceName {
|
|
||||||
public:
|
|
||||||
InstanceName() = default;
|
|
||||||
InstanceName(QString name, QString version) : m_original_name(std::move(name)), m_original_version(std::move(version)) {}
|
|
||||||
|
|
||||||
[[nodiscard]] QString modifiedName() const;
|
|
||||||
[[nodiscard]] QString originalName() const;
|
|
||||||
[[nodiscard]] QString name() const;
|
|
||||||
[[nodiscard]] QString version() const;
|
|
||||||
|
|
||||||
void setName(QString name) { m_modified_name = name; }
|
|
||||||
void setName(InstanceName& other);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
QString m_original_name;
|
|
||||||
QString m_original_version;
|
|
||||||
|
|
||||||
QString m_modified_name;
|
|
||||||
};
|
|
||||||
|
|
||||||
class InstanceTask : public Task, public InstanceName {
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
InstanceTask();
|
explicit InstanceTask();
|
||||||
~InstanceTask() override = default;
|
virtual ~InstanceTask();
|
||||||
|
|
||||||
void setParentSettings(SettingsObjectPtr settings) { m_globalSettings = settings; }
|
void setParentSettings(SettingsObjectPtr settings)
|
||||||
|
{
|
||||||
|
m_globalSettings = settings;
|
||||||
|
}
|
||||||
|
|
||||||
void setStagingPath(const QString& stagingPath) { m_stagingPath = stagingPath; }
|
void setStagingPath(const QString &stagingPath)
|
||||||
|
{
|
||||||
|
m_stagingPath = stagingPath;
|
||||||
|
}
|
||||||
|
|
||||||
void setIcon(const QString& icon) { m_instIcon = icon; }
|
void setName(const QString &name)
|
||||||
|
{
|
||||||
|
m_instName = name;
|
||||||
|
}
|
||||||
|
QString name() const
|
||||||
|
{
|
||||||
|
return m_instName;
|
||||||
|
}
|
||||||
|
|
||||||
void setGroup(const QString& group) { m_instGroup = group; }
|
void setIcon(const QString &icon)
|
||||||
QString group() const { return m_instGroup; }
|
{
|
||||||
|
m_instIcon = icon;
|
||||||
|
}
|
||||||
|
|
||||||
bool shouldOverride() const { return m_override_existing; }
|
void setGroup(const QString &group)
|
||||||
|
{
|
||||||
|
m_instGroup = group;
|
||||||
|
}
|
||||||
|
QString group() const
|
||||||
|
{
|
||||||
|
return m_instGroup;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected: /* data */
|
||||||
void setOverride(bool override) { m_override_existing = override; }
|
|
||||||
|
|
||||||
protected: /* data */
|
|
||||||
SettingsObjectPtr m_globalSettings;
|
SettingsObjectPtr m_globalSettings;
|
||||||
|
QString m_instName;
|
||||||
QString m_instIcon;
|
QString m_instIcon;
|
||||||
QString m_instGroup;
|
QString m_instGroup;
|
||||||
QString m_stagingPath;
|
QString m_stagingPath;
|
||||||
|
|
||||||
bool m_override_existing = false;
|
|
||||||
};
|
};
|
||||||
|
@ -1,47 +1,10 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
/*
|
|
||||||
* PolyMC - Minecraft Launcher
|
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
*
|
|
||||||
* 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 "JavaCommon.h"
|
#include "JavaCommon.h"
|
||||||
#include "java/JavaUtils.h"
|
|
||||||
#include "ui/dialogs/CustomMessageBox.h"
|
#include "ui/dialogs/CustomMessageBox.h"
|
||||||
#include <MMCStrings.h>
|
#include <MMCStrings.h>
|
||||||
#include <QRegularExpression>
|
|
||||||
|
|
||||||
bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget *parent)
|
bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget *parent)
|
||||||
{
|
{
|
||||||
if (jvmargs.contains("-XX:PermSize=") || jvmargs.contains(QRegularExpression("-Xm[sx]"))
|
if (jvmargs.contains("-XX:PermSize=") || jvmargs.contains(QRegExp("-Xm[sx]"))
|
||||||
|| jvmargs.contains("-XX-MaxHeapSize") || jvmargs.contains("-XX:InitialHeapSize"))
|
|| jvmargs.contains("-XX-MaxHeapSize") || jvmargs.contains("-XX:InitialHeapSize"))
|
||||||
{
|
{
|
||||||
auto warnStr = QObject::tr(
|
auto warnStr = QObject::tr(
|
||||||
@ -55,7 +18,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(QRegularExpression("-version:.*"))) {
|
if (jvmargs.contains(QRegExp("-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 allowed.\n"
|
"You tried to pass required Java version argument to the JVM (using \"-version:xxx\"). This is not safe and will not be allowed.\n"
|
||||||
"This message will be displayed until you remove this from the JVM arguments.");
|
"This message will be displayed until you remove this from the JVM arguments.");
|
||||||
@ -102,13 +65,6 @@ void JavaCommon::javaBinaryWasBad(QWidget *parent, JavaCheckResult result)
|
|||||||
CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
|
CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JavaCommon::javaCheckNotFound(QWidget *parent)
|
|
||||||
{
|
|
||||||
QString text;
|
|
||||||
text += QObject::tr("Java checker library could not be found. Please check your installation.");
|
|
||||||
CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
|
|
||||||
}
|
|
||||||
|
|
||||||
void JavaCommon::TestCheck::run()
|
void JavaCommon::TestCheck::run()
|
||||||
{
|
{
|
||||||
if (!JavaCommon::checkJVMArgs(m_args, m_parent))
|
if (!JavaCommon::checkJVMArgs(m_args, m_parent))
|
||||||
@ -116,11 +72,6 @@ void JavaCommon::TestCheck::run()
|
|||||||
emit finished();
|
emit finished();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (JavaUtils::getJavaCheckPath().isEmpty()) {
|
|
||||||
javaCheckNotFound(m_parent);
|
|
||||||
emit finished();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
checker.reset(new JavaChecker());
|
checker.reset(new JavaChecker());
|
||||||
connect(checker.get(), SIGNAL(checkFinished(JavaCheckResult)), this,
|
connect(checker.get(), SIGNAL(checkFinished(JavaCheckResult)), this,
|
||||||
SLOT(checkFinished(JavaCheckResult)));
|
SLOT(checkFinished(JavaCheckResult)));
|
||||||
|
@ -10,14 +10,12 @@ namespace JavaCommon
|
|||||||
{
|
{
|
||||||
bool checkJVMArgs(QString args, QWidget *parent);
|
bool checkJVMArgs(QString args, QWidget *parent);
|
||||||
|
|
||||||
// Show a dialog saying that the Java binary was usable
|
|
||||||
void javaWasOk(QWidget *parent, JavaCheckResult result);
|
|
||||||
// Show a dialog saying that the Java binary was not usable because of bad options
|
|
||||||
void javaArgsWereBad(QWidget *parent, 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, JavaCheckResult result);
|
void javaBinaryWasBad(QWidget *parent, JavaCheckResult result);
|
||||||
// Show a dialog if we couldn't find Java Checker
|
// Show a dialog saying that the Java binary was not usable because of bad options
|
||||||
void javaCheckNotFound(QWidget *parent);
|
void javaArgsWereBad(QWidget *parent, JavaCheckResult result);
|
||||||
|
// Show a dialog saying that the Java binary was usable
|
||||||
|
void javaWasOk(QWidget *parent, JavaCheckResult result);
|
||||||
|
|
||||||
class TestCheck : public QObject
|
class TestCheck : public QObject
|
||||||
{
|
{
|
||||||
|
@ -1,37 +1,4 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// Licensed under the Apache-2.0 license. See README.md for details.
|
||||||
/*
|
|
||||||
* PolyMC - Minecraft Launcher
|
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
*
|
|
||||||
* 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 "Json.h"
|
#include "Json.h"
|
||||||
|
|
||||||
@ -55,6 +22,14 @@ void write(const QJsonArray &array, const QString &filename)
|
|||||||
write(QJsonDocument(array), filename);
|
write(QJsonDocument(array), filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QByteArray toBinary(const QJsonObject &obj)
|
||||||
|
{
|
||||||
|
return QJsonDocument(obj).toBinaryData();
|
||||||
|
}
|
||||||
|
QByteArray toBinary(const QJsonArray &array)
|
||||||
|
{
|
||||||
|
return QJsonDocument(array).toBinaryData();
|
||||||
|
}
|
||||||
QByteArray toText(const QJsonObject &obj)
|
QByteArray toText(const QJsonObject &obj)
|
||||||
{
|
{
|
||||||
return QJsonDocument(obj).toJson(QJsonDocument::Compact);
|
return QJsonDocument(obj).toJson(QJsonDocument::Compact);
|
||||||
@ -73,8 +48,12 @@ QJsonDocument requireDocument(const QByteArray &data, const QString &what)
|
|||||||
{
|
{
|
||||||
if (isBinaryJson(data))
|
if (isBinaryJson(data))
|
||||||
{
|
{
|
||||||
// FIXME: Is this needed?
|
QJsonDocument doc = QJsonDocument::fromBinaryData(data);
|
||||||
throw JsonException(what + ": Invalid JSON. Binary JSON unsupported");
|
if (doc.isNull())
|
||||||
|
{
|
||||||
|
throw JsonException(what + ": Invalid JSON (binary JSON detected)");
|
||||||
|
}
|
||||||
|
return doc;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1,37 +1,4 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// Licensed under the Apache-2.0 license. See README.md for details.
|
||||||
/*
|
|
||||||
* PolyMC - Minecraft Launcher
|
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
*
|
|
||||||
* 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
|
||||||
|
|
||||||
@ -62,6 +29,8 @@ void write(const QJsonObject &object, const QString &filename);
|
|||||||
/// @throw FileSystemException
|
/// @throw FileSystemException
|
||||||
void write(const QJsonArray &array, const QString &filename);
|
void write(const QJsonArray &array, const QString &filename);
|
||||||
|
|
||||||
|
QByteArray toBinary(const QJsonObject &obj);
|
||||||
|
QByteArray toBinary(const QJsonArray &array);
|
||||||
QByteArray toText(const QJsonObject &obj);
|
QByteArray toText(const QJsonObject &obj);
|
||||||
QByteArray toText(const QJsonArray &array);
|
QByteArray toText(const QJsonArray &array);
|
||||||
|
|
||||||
|
@ -93,8 +93,8 @@ void LaunchController::decideAccount()
|
|||||||
auto reply = CustomMessageBox::selectable(
|
auto reply = CustomMessageBox::selectable(
|
||||||
m_parentWidget,
|
m_parentWidget,
|
||||||
tr("No Accounts"),
|
tr("No Accounts"),
|
||||||
tr("In order to play Minecraft, you must have at least one Microsoft or Mojang "
|
tr("In order to play Minecraft, you must have at least one Mojang or Microsoft "
|
||||||
"account logged in. Mojang accounts can only be used offline. "
|
"account logged in. "
|
||||||
"Would you like to open the account manager to add an account now?"),
|
"Would you like to open the account manager to add an account now?"),
|
||||||
QMessageBox::Information,
|
QMessageBox::Information,
|
||||||
QMessageBox::Yes | QMessageBox::No
|
QMessageBox::Yes | QMessageBox::No
|
||||||
@ -145,29 +145,18 @@ void LaunchController::login() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we try empty password first :)
|
||||||
|
QString password;
|
||||||
// we loop until the user succeeds in logging in or gives up
|
// we loop until the user succeeds in logging in or gives up
|
||||||
bool tryagain = true;
|
bool tryagain = true;
|
||||||
unsigned int tries = 0;
|
// the failure. the default failure.
|
||||||
|
const QString needLoginAgain = tr("Your account is currently not logged in. Please enter your password to log in again. <br /> <br /> This could be caused by a password change.");
|
||||||
|
QString failReason = needLoginAgain;
|
||||||
|
|
||||||
while (tryagain)
|
while (tryagain)
|
||||||
{
|
{
|
||||||
if (tries > 0 && tries % 3 == 0) {
|
|
||||||
auto result = QMessageBox::question(
|
|
||||||
m_parentWidget,
|
|
||||||
tr("Continue launch?"),
|
|
||||||
tr("It looks like we couldn't launch after %1 tries. Do you want to continue trying?")
|
|
||||||
.arg(tries)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result == QMessageBox::No) {
|
|
||||||
emitAborted();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tries++;
|
|
||||||
m_session = std::make_shared<AuthSession>();
|
m_session = std::make_shared<AuthSession>();
|
||||||
m_session->wants_online = m_online;
|
m_session->wants_online = m_online;
|
||||||
m_session->demo = m_demo;
|
|
||||||
m_accountToUse->fillSession(m_session);
|
m_accountToUse->fillSession(m_session);
|
||||||
|
|
||||||
// Launch immediately in true offline mode
|
// Launch immediately in true offline mode
|
||||||
@ -185,18 +174,12 @@ void LaunchController::login() {
|
|||||||
if(!m_session->wants_online) {
|
if(!m_session->wants_online) {
|
||||||
// we ask the user for a player name
|
// we ask the user for a player name
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
|
|
||||||
QString message = tr("Choose your offline mode player name.");
|
|
||||||
if(m_session->demo) {
|
|
||||||
message = tr("Choose your demo mode player name.");
|
|
||||||
}
|
|
||||||
|
|
||||||
QString lastOfflinePlayerName = APPLICATION->settings()->get("LastOfflinePlayerName").toString();
|
QString lastOfflinePlayerName = APPLICATION->settings()->get("LastOfflinePlayerName").toString();
|
||||||
QString usedname = lastOfflinePlayerName.isEmpty() ? m_session->player_name : lastOfflinePlayerName;
|
QString usedname = lastOfflinePlayerName.isEmpty() ? m_session->player_name : lastOfflinePlayerName;
|
||||||
QString name = QInputDialog::getText(
|
QString name = QInputDialog::getText(
|
||||||
m_parentWidget,
|
m_parentWidget,
|
||||||
tr("Player name"),
|
tr("Player name"),
|
||||||
message,
|
tr("Choose your offline mode player name."),
|
||||||
QLineEdit::Normal,
|
QLineEdit::Normal,
|
||||||
usedname,
|
usedname,
|
||||||
&ok
|
&ok
|
||||||
@ -376,13 +359,13 @@ void LaunchController::launchInstance()
|
|||||||
}
|
}
|
||||||
m_launcher->prependStep(new TextPrint(m_launcher.get(), resolved_servers, MessageLevel::Launcher));
|
m_launcher->prependStep(new TextPrint(m_launcher.get(), resolved_servers, MessageLevel::Launcher));
|
||||||
} else {
|
} else {
|
||||||
online_mode = m_demo ? "demo" : "offline";
|
online_mode = "offline";
|
||||||
}
|
}
|
||||||
|
|
||||||
m_launcher->prependStep(new TextPrint(m_launcher.get(), "Launched instance in " + online_mode + " mode\n", MessageLevel::Launcher));
|
m_launcher->prependStep(new TextPrint(m_launcher.get(), "Launched instance in " + online_mode + " mode\n", MessageLevel::Launcher));
|
||||||
|
|
||||||
// Prepend Version
|
// Prepend Version
|
||||||
m_launcher->prependStep(new TextPrint(m_launcher.get(), BuildConfig.LAUNCHER_DISPLAYNAME + " version: " + BuildConfig.printableVersionString() + "\n\n", MessageLevel::Launcher));
|
m_launcher->prependStep(new TextPrint(m_launcher.get(), BuildConfig.LAUNCHER_NAME + " version: " + BuildConfig.printableVersionString() + "\n\n", MessageLevel::Launcher));
|
||||||
m_launcher->start();
|
m_launcher->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,10 +63,6 @@ public:
|
|||||||
m_online = online;
|
m_online = online;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setDemo(bool demo) {
|
|
||||||
m_demo = demo;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setProfiler(BaseProfilerFactory *profiler) {
|
void setProfiler(BaseProfilerFactory *profiler) {
|
||||||
m_profiler = profiler;
|
m_profiler = profiler;
|
||||||
}
|
}
|
||||||
@ -105,7 +101,6 @@ private slots:
|
|||||||
private:
|
private:
|
||||||
BaseProfilerFactory *m_profiler = nullptr;
|
BaseProfilerFactory *m_profiler = nullptr;
|
||||||
bool m_online = true;
|
bool m_online = true;
|
||||||
bool m_demo = false;
|
|
||||||
InstancePtr m_instance;
|
InstancePtr m_instance;
|
||||||
QWidget * m_parentWidget = nullptr;
|
QWidget * m_parentWidget = nullptr;
|
||||||
InstanceWindow *m_console = nullptr;
|
InstanceWindow *m_console = nullptr;
|
||||||
|
@ -18,17 +18,13 @@ LAUNCHER_NAME=@Launcher_APP_BINARY_NAME@
|
|||||||
LAUNCHER_DIR="$(dirname "$(readlink -f "$0")")"
|
LAUNCHER_DIR="$(dirname "$(readlink -f "$0")")"
|
||||||
echo "Launcher Dir: ${LAUNCHER_DIR}"
|
echo "Launcher Dir: ${LAUNCHER_DIR}"
|
||||||
|
|
||||||
# Set up env.
|
# Set up env - filter out input LD_ variables but pass them in under different names
|
||||||
# Pass our custom variables separately so that the launcher can remove them for child processes
|
export GAME_LIBRARY_PATH=${GAME_LIBRARY_PATH-${LD_LIBRARY_PATH}}
|
||||||
export LAUNCHER_LD_LIBRARY_PATH="${LAUNCHER_DIR}/lib@LIB_SUFFIX@"
|
export GAME_PRELOAD=${GAME_PRELOAD-${LD_PRELOAD}}
|
||||||
export LAUNCHER_LD_PRELOAD=""
|
export LD_LIBRARY_PATH="${LAUNCHER_DIR}/lib@LIB_SUFFIX@":$LAUNCHER_LIBRARY_PATH
|
||||||
export LAUNCHER_QT_PLUGIN_PATH="${LAUNCHER_DIR}/plugins"
|
export LD_PRELOAD=$LAUNCHER_PRELOAD
|
||||||
export LAUNCHER_QT_FONTPATH="${LAUNCHER_DIR}/fonts"
|
export QT_PLUGIN_PATH="${LAUNCHER_DIR}/plugins"
|
||||||
|
export QT_FONTPATH="${LAUNCHER_DIR}/fonts"
|
||||||
export LD_LIBRARY_PATH="$LAUNCHER_LD_LIBRARY_PATH:$LD_LIBRARY_PATH"
|
|
||||||
export LD_PRELOAD="$LAUNCHER_LD_PRELOAD:$LD_PRELOAD"
|
|
||||||
export QT_PLUGIN_PATH="$LAUNCHER_QT_PLUGIN_PATH:$QT_PLUGIN_PATH"
|
|
||||||
export QT_FONTPATH="$LAUNCHER_QT_FONTPATH:$QT_FONTPATH"
|
|
||||||
|
|
||||||
# Detect missing dependencies...
|
# Detect missing dependencies...
|
||||||
DEPS_LIST=`ldd "${LAUNCHER_DIR}"/plugins/*/*.so 2>/dev/null | grep "not found" | sort -u | awk -vORS=", " '{ print $1 }'`
|
DEPS_LIST=`ldd "${LAUNCHER_DIR}"/plugins/*/*.so 2>/dev/null | grep "not found" | sort -u | awk -vORS=", " '{ print $1 }'`
|
||||||
|
@ -1,42 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
/*
|
|
||||||
* PolyMC - Minecraft Launcher
|
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
*
|
|
||||||
* 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 "LoggedProcess.h"
|
#include "LoggedProcess.h"
|
||||||
#include <QDebug>
|
|
||||||
#include <QTextDecoder>
|
|
||||||
#include "MessageLevel.h"
|
#include "MessageLevel.h"
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
LoggedProcess::LoggedProcess(QObject *parent) : QProcess(parent)
|
LoggedProcess::LoggedProcess(QObject *parent) : QProcess(parent)
|
||||||
{
|
{
|
||||||
@ -44,11 +8,7 @@ LoggedProcess::LoggedProcess(QObject *parent) : QProcess(parent)
|
|||||||
connect(this, &QProcess::readyReadStandardOutput, this, &LoggedProcess::on_stdOut);
|
connect(this, &QProcess::readyReadStandardOutput, this, &LoggedProcess::on_stdOut);
|
||||||
connect(this, &QProcess::readyReadStandardError, this, &LoggedProcess::on_stdErr);
|
connect(this, &QProcess::readyReadStandardError, this, &LoggedProcess::on_stdErr);
|
||||||
connect(this, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(on_exit(int,QProcess::ExitStatus)));
|
connect(this, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(on_exit(int,QProcess::ExitStatus)));
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
|
||||||
connect(this, SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(on_error(QProcess::ProcessError)));
|
|
||||||
#else
|
|
||||||
connect(this, SIGNAL(error(QProcess::ProcessError)), this, SLOT(on_error(QProcess::ProcessError)));
|
connect(this, SIGNAL(error(QProcess::ProcessError)), this, SLOT(on_error(QProcess::ProcessError)));
|
||||||
#endif
|
|
||||||
connect(this, &QProcess::stateChanged, this, &LoggedProcess::on_stateChange);
|
connect(this, &QProcess::stateChanged, this, &LoggedProcess::on_stateChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,26 +20,25 @@ LoggedProcess::~LoggedProcess()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList reprocess(const QByteArray& data, QTextDecoder& decoder)
|
QStringList reprocess(const QByteArray & data, QString & leftover)
|
||||||
{
|
{
|
||||||
auto str = decoder.toUnicode(data);
|
QString str = leftover + QString::fromLocal8Bit(data);
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
|
||||||
auto lines = str.remove(QChar::CarriageReturn).split(QChar::LineFeed, QString::SkipEmptyParts);
|
str.remove('\r');
|
||||||
#else
|
QStringList lines = str.split("\n");
|
||||||
auto lines = str.remove(QChar::CarriageReturn).split(QChar::LineFeed, Qt::SkipEmptyParts);
|
leftover = lines.takeLast();
|
||||||
#endif
|
|
||||||
return lines;
|
return lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoggedProcess::on_stdErr()
|
void LoggedProcess::on_stdErr()
|
||||||
{
|
{
|
||||||
auto lines = reprocess(readAllStandardError(), m_err_decoder);
|
auto lines = reprocess(readAllStandardError(), m_err_leftover);
|
||||||
emit log(lines, MessageLevel::StdErr);
|
emit log(lines, MessageLevel::StdErr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoggedProcess::on_stdOut()
|
void LoggedProcess::on_stdOut()
|
||||||
{
|
{
|
||||||
auto lines = reprocess(readAllStandardOutput(), m_out_decoder);
|
auto lines = reprocess(readAllStandardOutput(), m_out_leftover);
|
||||||
emit log(lines, MessageLevel::StdOut);
|
emit log(lines, MessageLevel::StdOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,6 +47,18 @@ void LoggedProcess::on_exit(int exit_code, QProcess::ExitStatus status)
|
|||||||
// save the exit code
|
// save the exit code
|
||||||
m_exit_code = exit_code;
|
m_exit_code = exit_code;
|
||||||
|
|
||||||
|
// Flush console window
|
||||||
|
if (!m_err_leftover.isEmpty())
|
||||||
|
{
|
||||||
|
emit log({m_err_leftover}, MessageLevel::StdErr);
|
||||||
|
m_err_leftover.clear();
|
||||||
|
}
|
||||||
|
if (!m_out_leftover.isEmpty())
|
||||||
|
{
|
||||||
|
emit log({m_err_leftover}, MessageLevel::StdOut);
|
||||||
|
m_out_leftover.clear();
|
||||||
|
}
|
||||||
|
|
||||||
// based on state, send signals
|
// based on state, send signals
|
||||||
if (!m_is_aborting)
|
if (!m_is_aborting)
|
||||||
{
|
{
|
||||||
@ -186,6 +157,19 @@ void LoggedProcess::on_stateChange(QProcess::ProcessState state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined Q_OS_WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
qint64 LoggedProcess::processId() const
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
return pid() ? pid()->dwProcessId : 0;
|
||||||
|
#else
|
||||||
|
return pid();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void LoggedProcess::setDetachable(bool detachable)
|
void LoggedProcess::setDetachable(bool detachable)
|
||||||
{
|
{
|
||||||
m_is_detachable = detachable;
|
m_is_detachable = detachable;
|
||||||
|
@ -1,42 +1,21 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
/* Copyright 2013-2021 MultiMC Contributors
|
||||||
/*
|
|
||||||
* PolyMC - Minecraft Launcher
|
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* it under the terms of the GNU General Public License as published by
|
* you may not use this file except in compliance with the License.
|
||||||
* the Free Software Foundation, version 3.
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
* 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
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
*
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* This file incorporates work covered by the following copyright and
|
* See the License for the specific language governing permissions and
|
||||||
* permission notice:
|
* limitations under the License.
|
||||||
*
|
|
||||||
* Copyright 2013-2021 MultiMC Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#include <QTextDecoder>
|
|
||||||
#include "MessageLevel.h"
|
#include "MessageLevel.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -64,6 +43,7 @@ public:
|
|||||||
|
|
||||||
State state() const;
|
State state() const;
|
||||||
int exitCode() const;
|
int exitCode() const;
|
||||||
|
qint64 processId() const;
|
||||||
|
|
||||||
void setDetachable(bool detachable);
|
void setDetachable(bool detachable);
|
||||||
|
|
||||||
@ -89,8 +69,8 @@ private:
|
|||||||
void changeState(LoggedProcess::State state);
|
void changeState(LoggedProcess::State state);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QTextDecoder m_err_decoder = QTextDecoder(QTextCodec::codecForLocale());
|
QString m_err_leftover;
|
||||||
QTextDecoder m_out_decoder = QTextDecoder(QTextCodec::codecForLocale());
|
QString m_out_leftover;
|
||||||
bool m_killed = false;
|
bool m_killed = false;
|
||||||
State m_state = NotRunning;
|
State m_state = NotRunning;
|
||||||
int m_exit_code = 0;
|
int m_exit_code = 0;
|
||||||
|
@ -127,7 +127,7 @@ bool MMCZip::compressDirFiles(QString fileCompressed, QString dir, QFileInfoList
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ours
|
// ours
|
||||||
bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<Mod*>& mods)
|
bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<Mod>& mods)
|
||||||
{
|
{
|
||||||
QuaZip zipOut(targetJarPath);
|
QuaZip zipOut(targetJarPath);
|
||||||
if (!zipOut.open(QuaZip::mdCreate))
|
if (!zipOut.open(QuaZip::mdCreate))
|
||||||
@ -141,41 +141,42 @@ bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const
|
|||||||
QSet<QString> addedFiles;
|
QSet<QString> addedFiles;
|
||||||
|
|
||||||
// Modify the jar
|
// Modify the jar
|
||||||
// This needs to be done in reverse-order to ensure we respect the loading order of components
|
QListIterator<Mod> i(mods);
|
||||||
for (auto i = mods.crbegin(); i != mods.crend(); i++)
|
i.toBack();
|
||||||
|
while (i.hasPrevious())
|
||||||
{
|
{
|
||||||
const auto* mod = *i;
|
const Mod &mod = i.previous();
|
||||||
// do not merge disabled mods.
|
// do not merge disabled mods.
|
||||||
if (!mod->enabled())
|
if (!mod.enabled())
|
||||||
continue;
|
continue;
|
||||||
if (mod->type() == ResourceType::ZIPFILE)
|
if (mod.type() == Mod::MOD_ZIPFILE)
|
||||||
{
|
{
|
||||||
if (!mergeZipFiles(&zipOut, mod->fileinfo(), addedFiles))
|
if (!mergeZipFiles(&zipOut, mod.filename(), addedFiles))
|
||||||
{
|
{
|
||||||
zipOut.close();
|
zipOut.close();
|
||||||
QFile::remove(targetJarPath);
|
QFile::remove(targetJarPath);
|
||||||
qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar.";
|
qCritical() << "Failed to add" << mod.filename().fileName() << "to the jar.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (mod->type() == ResourceType::SINGLEFILE)
|
else if (mod.type() == Mod::MOD_SINGLEFILE)
|
||||||
{
|
{
|
||||||
// FIXME: buggy - does not work with addedFiles
|
// FIXME: buggy - does not work with addedFiles
|
||||||
auto filename = mod->fileinfo();
|
auto filename = mod.filename();
|
||||||
if (!JlCompress::compressFile(&zipOut, filename.absoluteFilePath(), filename.fileName()))
|
if (!JlCompress::compressFile(&zipOut, filename.absoluteFilePath(), filename.fileName()))
|
||||||
{
|
{
|
||||||
zipOut.close();
|
zipOut.close();
|
||||||
QFile::remove(targetJarPath);
|
QFile::remove(targetJarPath);
|
||||||
qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar.";
|
qCritical() << "Failed to add" << mod.filename().fileName() << "to the jar.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
addedFiles.insert(filename.fileName());
|
addedFiles.insert(filename.fileName());
|
||||||
}
|
}
|
||||||
else if (mod->type() == ResourceType::FOLDER)
|
else if (mod.type() == Mod::MOD_FOLDER)
|
||||||
{
|
{
|
||||||
// untested, but seems to be unused / not possible to reach
|
// untested, but seems to be unused / not possible to reach
|
||||||
// FIXME: buggy - does not work with addedFiles
|
// FIXME: buggy - does not work with addedFiles
|
||||||
auto filename = mod->fileinfo();
|
auto filename = mod.filename();
|
||||||
QString what_to_zip = filename.absoluteFilePath();
|
QString what_to_zip = filename.absoluteFilePath();
|
||||||
QDir dir(what_to_zip);
|
QDir dir(what_to_zip);
|
||||||
dir.cdUp();
|
dir.cdUp();
|
||||||
@ -192,7 +193,7 @@ bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const
|
|||||||
{
|
{
|
||||||
zipOut.close();
|
zipOut.close();
|
||||||
QFile::remove(targetJarPath);
|
QFile::remove(targetJarPath);
|
||||||
qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar.";
|
qCritical() << "Failed to add" << mod.filename().fileName() << "to the jar.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
qDebug() << "Adding folder " << filename.fileName() << " from "
|
qDebug() << "Adding folder " << filename.fileName() << " from "
|
||||||
@ -203,7 +204,7 @@ bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const
|
|||||||
// Make sure we do not continue launching when something is missing or undefined...
|
// Make sure we do not continue launching when something is missing or undefined...
|
||||||
zipOut.close();
|
zipOut.close();
|
||||||
QFile::remove(targetJarPath);
|
QFile::remove(targetJarPath);
|
||||||
qCritical() << "Failed to add unknown mod type" << mod->fileinfo().fileName() << "to the jar.";
|
qCritical() << "Failed to add unknown mod type" << mod.filename().fileName() << "to the jar.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -268,7 +269,7 @@ bool MMCZip::findFilesInZip(QuaZip * zip, const QString & what, QStringList & re
|
|||||||
|
|
||||||
|
|
||||||
// ours
|
// ours
|
||||||
std::optional<QStringList> MMCZip::extractSubDir(QuaZip *zip, const QString & subdir, const QString &target)
|
nonstd::optional<QStringList> MMCZip::extractSubDir(QuaZip *zip, const QString & subdir, const QString &target)
|
||||||
{
|
{
|
||||||
QDir directory(target);
|
QDir directory(target);
|
||||||
QStringList extracted;
|
QStringList extracted;
|
||||||
@ -277,7 +278,7 @@ std::optional<QStringList> MMCZip::extractSubDir(QuaZip *zip, const QString & su
|
|||||||
auto numEntries = zip->getEntriesCount();
|
auto numEntries = zip->getEntriesCount();
|
||||||
if(numEntries < 0) {
|
if(numEntries < 0) {
|
||||||
qWarning() << "Failed to enumerate files in archive";
|
qWarning() << "Failed to enumerate files in archive";
|
||||||
return std::nullopt;
|
return nonstd::nullopt;
|
||||||
}
|
}
|
||||||
else if(numEntries == 0) {
|
else if(numEntries == 0) {
|
||||||
qDebug() << "Extracting empty archives seems odd...";
|
qDebug() << "Extracting empty archives seems odd...";
|
||||||
@ -286,7 +287,7 @@ std::optional<QStringList> MMCZip::extractSubDir(QuaZip *zip, const QString & su
|
|||||||
else if (!zip->goToFirstFile())
|
else if (!zip->goToFirstFile())
|
||||||
{
|
{
|
||||||
qWarning() << "Failed to seek to first file in zip";
|
qWarning() << "Failed to seek to first file in zip";
|
||||||
return std::nullopt;
|
return nonstd::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
do
|
do
|
||||||
@ -304,7 +305,7 @@ std::optional<QStringList> MMCZip::extractSubDir(QuaZip *zip, const QString & su
|
|||||||
QString path;
|
QString path;
|
||||||
if(name.contains('/') && !name.endsWith('/')){
|
if(name.contains('/') && !name.endsWith('/')){
|
||||||
path = name.section('/', 0, -2) + "/";
|
path = name.section('/', 0, -2) + "/";
|
||||||
FS::ensureFolderPathExists(FS::PathCombine(target, path));
|
FS::ensureFolderPathExists(path);
|
||||||
|
|
||||||
name = name.split('/').last();
|
name = name.split('/').last();
|
||||||
}
|
}
|
||||||
@ -323,7 +324,7 @@ std::optional<QStringList> MMCZip::extractSubDir(QuaZip *zip, const QString & su
|
|||||||
{
|
{
|
||||||
qWarning() << "Failed to extract file" << original_name << "to" << absFilePath;
|
qWarning() << "Failed to extract file" << original_name << "to" << absFilePath;
|
||||||
JlCompress::removeFile(extracted);
|
JlCompress::removeFile(extracted);
|
||||||
return std::nullopt;
|
return nonstd::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
extracted.append(absFilePath);
|
extracted.append(absFilePath);
|
||||||
@ -341,7 +342,7 @@ bool MMCZip::extractRelFile(QuaZip *zip, const QString &file, const QString &tar
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ours
|
// ours
|
||||||
std::optional<QStringList> MMCZip::extractDir(QString fileCompressed, QString dir)
|
nonstd::optional<QStringList> MMCZip::extractDir(QString fileCompressed, QString dir)
|
||||||
{
|
{
|
||||||
QuaZip zip(fileCompressed);
|
QuaZip zip(fileCompressed);
|
||||||
if (!zip.open(QuaZip::mdUnzip))
|
if (!zip.open(QuaZip::mdUnzip))
|
||||||
@ -352,13 +353,13 @@ std::optional<QStringList> MMCZip::extractDir(QString fileCompressed, QString di
|
|||||||
return QStringList();
|
return QStringList();
|
||||||
}
|
}
|
||||||
qWarning() << "Could not open archive for unzipping:" << fileCompressed << "Error:" << zip.getZipError();;
|
qWarning() << "Could not open archive for unzipping:" << fileCompressed << "Error:" << zip.getZipError();;
|
||||||
return std::nullopt;
|
return nonstd::nullopt;
|
||||||
}
|
}
|
||||||
return MMCZip::extractSubDir(&zip, "", dir);
|
return MMCZip::extractSubDir(&zip, "", dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ours
|
// ours
|
||||||
std::optional<QStringList> MMCZip::extractDir(QString fileCompressed, QString subdir, QString dir)
|
nonstd::optional<QStringList> MMCZip::extractDir(QString fileCompressed, QString subdir, QString dir)
|
||||||
{
|
{
|
||||||
QuaZip zip(fileCompressed);
|
QuaZip zip(fileCompressed);
|
||||||
if (!zip.open(QuaZip::mdUnzip))
|
if (!zip.open(QuaZip::mdUnzip))
|
||||||
@ -369,7 +370,7 @@ std::optional<QStringList> MMCZip::extractDir(QString fileCompressed, QString su
|
|||||||
return QStringList();
|
return QStringList();
|
||||||
}
|
}
|
||||||
qWarning() << "Could not open archive for unzipping:" << fileCompressed << "Error:" << zip.getZipError();;
|
qWarning() << "Could not open archive for unzipping:" << fileCompressed << "Error:" << zip.getZipError();;
|
||||||
return std::nullopt;
|
return nonstd::nullopt;
|
||||||
}
|
}
|
||||||
return MMCZip::extractSubDir(&zip, subdir, dir);
|
return MMCZip::extractSubDir(&zip, subdir, dir);
|
||||||
}
|
}
|
||||||
@ -420,7 +421,7 @@ bool MMCZip::collectFileListRecursively(const QString& rootDir, const QString& s
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
files->append(e); // we want the original paths for MMCZip::compressDirFiles
|
files->append(e.filePath()); // we want the original paths for MMCZip::compressDirFiles
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
#include <quazip/JlCompress.h>
|
#include <quazip/JlCompress.h>
|
||||||
#include <optional>
|
#include <nonstd/optional>
|
||||||
|
|
||||||
namespace MMCZip
|
namespace MMCZip
|
||||||
{
|
{
|
||||||
@ -75,7 +75,7 @@ namespace MMCZip
|
|||||||
/**
|
/**
|
||||||
* take a source jar, add mods to it, resulting in target jar
|
* take a source jar, add mods to it, resulting in target jar
|
||||||
*/
|
*/
|
||||||
bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<Mod*>& mods);
|
bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<Mod>& mods);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a single file in archive by file name (not path)
|
* Find a single file in archive by file name (not path)
|
||||||
@ -95,7 +95,7 @@ namespace MMCZip
|
|||||||
/**
|
/**
|
||||||
* Extract a subdirectory from an archive
|
* Extract a subdirectory from an archive
|
||||||
*/
|
*/
|
||||||
std::optional<QStringList> extractSubDir(QuaZip *zip, const QString & subdir, const QString &target);
|
nonstd::optional<QStringList> extractSubDir(QuaZip *zip, const QString & subdir, const QString &target);
|
||||||
|
|
||||||
bool extractRelFile(QuaZip *zip, const QString & file, const QString &target);
|
bool extractRelFile(QuaZip *zip, const QString & file, const QString &target);
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ namespace MMCZip
|
|||||||
* \param dir The directory to extract to, the current directory if left empty.
|
* \param dir The directory to extract to, the current directory if left empty.
|
||||||
* \return The list of the full paths of the files extracted, empty on failure.
|
* \return The list of the full paths of the files extracted, empty on failure.
|
||||||
*/
|
*/
|
||||||
std::optional<QStringList> extractDir(QString fileCompressed, QString dir);
|
nonstd::optional<QStringList> extractDir(QString fileCompressed, QString dir);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract a subdirectory from an archive
|
* Extract a subdirectory from an archive
|
||||||
@ -116,7 +116,7 @@ namespace MMCZip
|
|||||||
* \param dir The directory to extract to, the current directory if left empty.
|
* \param dir The directory to extract to, the current directory if left empty.
|
||||||
* \return The list of the full paths of the files extracted, empty on failure.
|
* \return The list of the full paths of the files extracted, empty on failure.
|
||||||
*/
|
*/
|
||||||
std::optional<QStringList> extractDir(QString fileCompressed, QString subdir, QString dir);
|
nonstd::optional<QStringList> extractDir(QString fileCompressed, QString subdir, QString dir);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract a single file from an archive into a directory
|
* Extract a single file from an archive into a directory
|
||||||
|
@ -1,56 +1,25 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
/*
|
|
||||||
* PolyMC - Minecraft Launcher
|
|
||||||
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
|
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "ModDownloadTask.h"
|
#include "ModDownloadTask.h"
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "minecraft/mod/ModFolderModel.h"
|
|
||||||
|
|
||||||
ModDownloadTask::ModDownloadTask(ModPlatform::IndexedPack mod, ModPlatform::IndexedVersion version, const std::shared_ptr<ModFolderModel> mods, bool is_indexed)
|
ModDownloadTask::ModDownloadTask(const QUrl sourceUrl,const QString filename, const std::shared_ptr<ModFolderModel> mods)
|
||||||
: m_mod(mod), m_mod_version(version), mods(mods)
|
: m_sourceUrl(sourceUrl), mods(mods), filename(filename) {
|
||||||
{
|
}
|
||||||
if (is_indexed) {
|
|
||||||
m_update_task.reset(new LocalModUpdateTask(mods->indexDir(), m_mod, m_mod_version));
|
|
||||||
connect(m_update_task.get(), &LocalModUpdateTask::hasOldMod, this, &ModDownloadTask::hasOldMod);
|
|
||||||
|
|
||||||
addTask(m_update_task);
|
void ModDownloadTask::executeTask() {
|
||||||
}
|
setStatus(tr("Downloading mod:\n%1").arg(m_sourceUrl.toString()));
|
||||||
|
|
||||||
m_filesNetJob.reset(new NetJob(tr("Mod download"), APPLICATION->network()));
|
m_filesNetJob.reset(new NetJob(tr("Mod download"), APPLICATION->network()));
|
||||||
m_filesNetJob->setStatus(tr("Downloading mod:\n%1").arg(m_mod_version.downloadUrl));
|
m_filesNetJob->addNetAction(Net::Download::makeFile(m_sourceUrl, mods->dir().absoluteFilePath(filename)));
|
||||||
|
|
||||||
m_filesNetJob->addNetAction(Net::Download::makeFile(m_mod_version.downloadUrl, mods->dir().absoluteFilePath(getFilename())));
|
|
||||||
connect(m_filesNetJob.get(), &NetJob::succeeded, this, &ModDownloadTask::downloadSucceeded);
|
connect(m_filesNetJob.get(), &NetJob::succeeded, this, &ModDownloadTask::downloadSucceeded);
|
||||||
connect(m_filesNetJob.get(), &NetJob::progress, this, &ModDownloadTask::downloadProgressChanged);
|
connect(m_filesNetJob.get(), &NetJob::progress, this, &ModDownloadTask::downloadProgressChanged);
|
||||||
connect(m_filesNetJob.get(), &NetJob::failed, this, &ModDownloadTask::downloadFailed);
|
connect(m_filesNetJob.get(), &NetJob::failed, this, &ModDownloadTask::downloadFailed);
|
||||||
|
m_filesNetJob->start();
|
||||||
addTask(m_filesNetJob);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModDownloadTask::downloadSucceeded()
|
void ModDownloadTask::downloadSucceeded()
|
||||||
{
|
{
|
||||||
|
emitSucceeded();
|
||||||
m_filesNetJob.reset();
|
m_filesNetJob.reset();
|
||||||
auto name = std::get<0>(to_delete);
|
|
||||||
auto filename = std::get<1>(to_delete);
|
|
||||||
if (!name.isEmpty() && filename != m_mod_version.fileName) {
|
|
||||||
mods->uninstallMod(filename, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModDownloadTask::downloadFailed(QString reason)
|
void ModDownloadTask::downloadFailed(QString reason)
|
||||||
@ -64,9 +33,7 @@ void ModDownloadTask::downloadProgressChanged(qint64 current, qint64 total)
|
|||||||
emit progress(current, total);
|
emit progress(current, total);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This indirection is done so that we don't delete a mod before being sure it was
|
bool ModDownloadTask::abort() {
|
||||||
// downloaded successfully!
|
return m_filesNetJob->abort();
|
||||||
void ModDownloadTask::hasOldMod(QString name, QString filename)
|
|
||||||
{
|
|
||||||
to_delete = {name, filename};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,56 +1,34 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
/*
|
|
||||||
* PolyMC - Minecraft Launcher
|
|
||||||
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
|
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include "QObjectPtr.h"
|
||||||
|
#include "tasks/Task.h"
|
||||||
|
#include "minecraft/mod/ModFolderModel.h"
|
||||||
#include "net/NetJob.h"
|
#include "net/NetJob.h"
|
||||||
#include "tasks/SequentialTask.h"
|
#include <QUrl>
|
||||||
|
|
||||||
#include "modplatform/ModIndex.h"
|
|
||||||
#include "minecraft/mod/tasks/LocalModUpdateTask.h"
|
|
||||||
|
|
||||||
class ModFolderModel;
|
class ModDownloadTask : public Task {
|
||||||
|
|
||||||
class ModDownloadTask : public SequentialTask {
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit ModDownloadTask(ModPlatform::IndexedPack mod, ModPlatform::IndexedVersion version, const std::shared_ptr<ModFolderModel> mods, bool is_indexed = true);
|
explicit ModDownloadTask(const QUrl sourceUrl, const QString filename, const std::shared_ptr<ModFolderModel> mods);
|
||||||
const QString& getFilename() const { return m_mod_version.fileName; }
|
const QString& getFilename() const { return filename; }
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
bool abort() override;
|
||||||
|
protected:
|
||||||
|
//! Entry point for tasks.
|
||||||
|
void executeTask() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ModPlatform::IndexedPack m_mod;
|
QUrl m_sourceUrl;
|
||||||
ModPlatform::IndexedVersion m_mod_version;
|
|
||||||
const std::shared_ptr<ModFolderModel> mods;
|
|
||||||
|
|
||||||
NetJob::Ptr m_filesNetJob;
|
NetJob::Ptr m_filesNetJob;
|
||||||
LocalModUpdateTask::Ptr m_update_task;
|
const std::shared_ptr<ModFolderModel> mods;
|
||||||
|
const QString filename;
|
||||||
|
|
||||||
void downloadProgressChanged(qint64 current, qint64 total);
|
void downloadProgressChanged(qint64 current, qint64 total);
|
||||||
|
|
||||||
void downloadFailed(QString reason);
|
void downloadFailed(QString reason);
|
||||||
|
|
||||||
void downloadSucceeded();
|
void downloadSucceeded();
|
||||||
|
|
||||||
std::tuple<QString, QString> to_delete {"", ""};
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void hasOldMod(QString name, QString filename);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,38 +1,3 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
/*
|
|
||||||
* PolyMC - Minecraft Launcher
|
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* This file incorporates work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Copyright 2013-2021 MultiMC Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "BaseInstance.h"
|
#include "BaseInstance.h"
|
||||||
#include "launch/LaunchTask.h"
|
#include "launch/LaunchTask.h"
|
||||||
@ -50,10 +15,6 @@ public:
|
|||||||
void saveNow() override
|
void saveNow() override
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
void loadSpecificSettings() override
|
|
||||||
{
|
|
||||||
setSpecificSettingsLoaded(true);
|
|
||||||
}
|
|
||||||
QString getStatusbarDescription() override
|
QString getStatusbarDescription() override
|
||||||
{
|
{
|
||||||
return tr("Unknown instance type");
|
return tr("Unknown instance type");
|
||||||
@ -78,11 +39,7 @@ public:
|
|||||||
{
|
{
|
||||||
return QProcessEnvironment();
|
return QProcessEnvironment();
|
||||||
}
|
}
|
||||||
QProcessEnvironment createLaunchEnvironment() override
|
QMap<QString, QString> getVariables() const override
|
||||||
{
|
|
||||||
return QProcessEnvironment();
|
|
||||||
}
|
|
||||||
QMap<QString, QString> getVariables() override
|
|
||||||
{
|
{
|
||||||
return QMap<QString, QString>();
|
return QMap<QString, QString>();
|
||||||
}
|
}
|
||||||
@ -119,8 +76,4 @@ public:
|
|||||||
QString modsRoot() const override {
|
QString modsRoot() const override {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
void updateRuntimeContext()
|
|
||||||
{
|
|
||||||
// NOOP
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
@ -1,37 +1,89 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QSharedPointer>
|
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
namespace details
|
||||||
|
{
|
||||||
|
struct DeleteQObjectLater
|
||||||
|
{
|
||||||
|
void operator()(QObject *obj) const
|
||||||
|
{
|
||||||
|
obj->deleteLater();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* A unique pointer class with unique pointer semantics intended for derivates of QObject
|
* A unique pointer class with unique pointer semantics intended for derivates of QObject
|
||||||
* Calls deleteLater() instead of destroying the contained object immediately
|
* Calls deleteLater() instead of destroying the contained object immediately
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template<typename T> using unique_qobject_ptr = std::unique_ptr<T, details::DeleteQObjectLater>;
|
||||||
using unique_qobject_ptr = QScopedPointer<T, QScopedPointerDeleteLater>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A shared pointer class with shared pointer semantics intended for derivates of QObject
|
* A shared pointer class with shared pointer semantics intended for derivates of QObject
|
||||||
* Calls deleteLater() instead of destroying the contained object immediately
|
* Calls deleteLater() instead of destroying the contained object immediately
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class shared_qobject_ptr : public QSharedPointer<T> {
|
class shared_qobject_ptr
|
||||||
public:
|
{
|
||||||
constexpr shared_qobject_ptr() : QSharedPointer<T>() {}
|
public:
|
||||||
constexpr shared_qobject_ptr(T* ptr) : QSharedPointer<T>(ptr, &QObject::deleteLater) {}
|
shared_qobject_ptr(){}
|
||||||
constexpr shared_qobject_ptr(std::nullptr_t null_ptr) : QSharedPointer<T>(null_ptr, &QObject::deleteLater) {}
|
shared_qobject_ptr(T * wrap)
|
||||||
|
|
||||||
template <typename Derived>
|
|
||||||
constexpr shared_qobject_ptr(const shared_qobject_ptr<Derived>& other) : QSharedPointer<T>(other)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void reset() { QSharedPointer<T>::reset(); }
|
|
||||||
void reset(const shared_qobject_ptr<T>& other)
|
|
||||||
{
|
{
|
||||||
shared_qobject_ptr<T> t(other);
|
reset(wrap);
|
||||||
this->swap(t);
|
|
||||||
}
|
}
|
||||||
|
shared_qobject_ptr(const shared_qobject_ptr<T>& other)
|
||||||
|
{
|
||||||
|
m_ptr = other.m_ptr;
|
||||||
|
}
|
||||||
|
template<typename Derived>
|
||||||
|
shared_qobject_ptr(const shared_qobject_ptr<Derived> &other)
|
||||||
|
{
|
||||||
|
m_ptr = other.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
void reset(T * wrap)
|
||||||
|
{
|
||||||
|
using namespace std::placeholders;
|
||||||
|
m_ptr.reset(wrap, std::bind(&QObject::deleteLater, _1));
|
||||||
|
}
|
||||||
|
void reset(const shared_qobject_ptr<T> &other)
|
||||||
|
{
|
||||||
|
m_ptr = other.m_ptr;
|
||||||
|
}
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
m_ptr.reset();
|
||||||
|
}
|
||||||
|
T * get() const
|
||||||
|
{
|
||||||
|
return m_ptr.get();
|
||||||
|
}
|
||||||
|
T * operator->() const
|
||||||
|
{
|
||||||
|
return m_ptr.get();
|
||||||
|
}
|
||||||
|
T & operator*() const
|
||||||
|
{
|
||||||
|
return *m_ptr.get();
|
||||||
|
}
|
||||||
|
operator bool() const
|
||||||
|
{
|
||||||
|
return m_ptr.get() != nullptr;
|
||||||
|
}
|
||||||
|
const std::shared_ptr <T> unwrap() const
|
||||||
|
{
|
||||||
|
return m_ptr;
|
||||||
|
}
|
||||||
|
bool operator==(const shared_qobject_ptr<T>& other) {
|
||||||
|
return m_ptr == other.m_ptr;
|
||||||
|
}
|
||||||
|
bool operator!=(const shared_qobject_ptr<T>& other) {
|
||||||
|
return m_ptr != other.m_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr <T> m_ptr;
|
||||||
};
|
};
|
||||||
|
@ -1,88 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
/*
|
|
||||||
* PolyMC - Minecraft Launcher
|
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QSet>
|
|
||||||
#include <QString>
|
|
||||||
#include "settings/SettingsObject.h"
|
|
||||||
|
|
||||||
struct RuntimeContext {
|
|
||||||
QString javaArchitecture;
|
|
||||||
QString javaRealArchitecture;
|
|
||||||
QString javaPath;
|
|
||||||
QString system;
|
|
||||||
|
|
||||||
QString mappedJavaRealArchitecture() const
|
|
||||||
{
|
|
||||||
if (javaRealArchitecture == "amd64")
|
|
||||||
return "x86_64";
|
|
||||||
if (javaRealArchitecture == "i386" || javaRealArchitecture == "i686")
|
|
||||||
return "x86";
|
|
||||||
if (javaRealArchitecture == "aarch64")
|
|
||||||
return "arm64";
|
|
||||||
if (javaRealArchitecture == "arm" || javaRealArchitecture == "armhf")
|
|
||||||
return "arm32";
|
|
||||||
return javaRealArchitecture;
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateFromInstanceSettings(SettingsObjectPtr instanceSettings)
|
|
||||||
{
|
|
||||||
javaArchitecture = instanceSettings->get("JavaArchitecture").toString();
|
|
||||||
javaRealArchitecture = instanceSettings->get("JavaRealArchitecture").toString();
|
|
||||||
javaPath = instanceSettings->get("JavaPath").toString();
|
|
||||||
system = currentSystem();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString getClassifier() const { return system + "-" + mappedJavaRealArchitecture(); }
|
|
||||||
|
|
||||||
// "Legacy" refers to the fact that Mojang assumed that these are the only two architectures
|
|
||||||
bool isLegacyArch() const
|
|
||||||
{
|
|
||||||
const QString mapped = mappedJavaRealArchitecture();
|
|
||||||
return mapped == "x86_64" || mapped == "x86";
|
|
||||||
}
|
|
||||||
|
|
||||||
bool classifierMatches(QString target) const
|
|
||||||
{
|
|
||||||
// try to match precise classifier "[os]-[arch]"
|
|
||||||
bool x = target == getClassifier();
|
|
||||||
// try to match imprecise classifier on legacy architectures "[os]"
|
|
||||||
if (!x && isLegacyArch())
|
|
||||||
x = target == system;
|
|
||||||
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
static QString currentSystem()
|
|
||||||
{
|
|
||||||
#if defined(Q_OS_LINUX)
|
|
||||||
return "linux";
|
|
||||||
#elif defined(Q_OS_MACOS)
|
|
||||||
return "osx";
|
|
||||||
#elif defined(Q_OS_WINDOWS)
|
|
||||||
return "windows";
|
|
||||||
#elif defined(Q_OS_FREEBSD)
|
|
||||||
return "freebsd";
|
|
||||||
#elif defined(Q_OS_OPENBSD)
|
|
||||||
return "openbsd";
|
|
||||||
#else
|
|
||||||
return "unknown";
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
};
|
|
@ -93,7 +93,7 @@ void UpdateController::installUpdates()
|
|||||||
qDebug() << "Installing updates.";
|
qDebug() << "Installing updates.";
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
QString finishCmd = QApplication::applicationFilePath();
|
QString finishCmd = QApplication::applicationFilePath();
|
||||||
#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined (Q_OS_OPENBSD)
|
#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||||
QString finishCmd = FS::PathCombine(m_root, BuildConfig.LAUNCHER_NAME);
|
QString finishCmd = FS::PathCombine(m_root, BuildConfig.LAUNCHER_NAME);
|
||||||
#elif defined Q_OS_MAC
|
#elif defined Q_OS_MAC
|
||||||
QString finishCmd = QApplication::applicationFilePath();
|
QString finishCmd = QApplication::applicationFilePath();
|
||||||
@ -358,7 +358,7 @@ void UpdateController::fail()
|
|||||||
msg = QObject::tr(
|
msg = QObject::tr(
|
||||||
"Couldn't replace file %1. Changes will be reverted.\n"
|
"Couldn't replace file %1. Changes will be reverted.\n"
|
||||||
"See the %2 log file for details."
|
"See the %2 log file for details."
|
||||||
).arg(m_failedFile, BuildConfig.LAUNCHER_DISPLAYNAME);
|
).arg(m_failedFile, BuildConfig.LAUNCHER_NAME);
|
||||||
doRollback = true;
|
doRollback = true;
|
||||||
QMessageBox::critical(m_parent, failTitle, msg);
|
QMessageBox::critical(m_parent, failTitle, msg);
|
||||||
break;
|
break;
|
||||||
@ -368,7 +368,7 @@ void UpdateController::fail()
|
|||||||
msg = QObject::tr(
|
msg = QObject::tr(
|
||||||
"Couldn't remove file %1. Changes will be reverted.\n"
|
"Couldn't remove file %1. Changes will be reverted.\n"
|
||||||
"See the %2 log file for details."
|
"See the %2 log file for details."
|
||||||
).arg(m_failedFile, BuildConfig.LAUNCHER_DISPLAYNAME);
|
).arg(m_failedFile, BuildConfig.LAUNCHER_NAME);
|
||||||
doRollback = true;
|
doRollback = true;
|
||||||
QMessageBox::critical(m_parent, failTitle, msg);
|
QMessageBox::critical(m_parent, failTitle, msg);
|
||||||
break;
|
break;
|
||||||
@ -399,7 +399,7 @@ void UpdateController::fail()
|
|||||||
{
|
{
|
||||||
msg = QObject::tr("The rollback failed too.\n"
|
msg = QObject::tr("The rollback failed too.\n"
|
||||||
"You will have to repair %1 manually.\n"
|
"You will have to repair %1 manually.\n"
|
||||||
"Please let us know why and how this happened.").arg(BuildConfig.LAUNCHER_DISPLAYNAME);
|
"Please let us know why and how this happened.").arg(BuildConfig.LAUNCHER_NAME);
|
||||||
QMessageBox::critical(m_parent, rollFailTitle, msg);
|
QMessageBox::critical(m_parent, rollFailTitle, msg);
|
||||||
qApp->quit();
|
qApp->quit();
|
||||||
}
|
}
|
||||||
|
@ -1,42 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
/*
|
|
||||||
* PolyMC - Minecraft Launcher
|
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* This file incorporates work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Copyright 2013-2021 MultiMC Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringView>
|
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
|
||||||
class QUrl;
|
class QUrl;
|
||||||
@ -75,21 +39,13 @@ private:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
|
||||||
auto numPart = QStringView{m_fullString}.left(cutoff);
|
|
||||||
#else
|
|
||||||
auto numPart = m_fullString.leftRef(cutoff);
|
auto numPart = m_fullString.leftRef(cutoff);
|
||||||
#endif
|
|
||||||
if(numPart.size())
|
if(numPart.size())
|
||||||
{
|
{
|
||||||
numValid = true;
|
numValid = true;
|
||||||
m_numPart = numPart.toInt();
|
m_numPart = numPart.toInt();
|
||||||
}
|
}
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
|
||||||
auto stringPart = QStringView{m_fullString}.mid(cutoff);
|
|
||||||
#else
|
|
||||||
auto stringPart = m_fullString.midRef(cutoff);
|
auto stringPart = m_fullString.midRef(cutoff);
|
||||||
#endif
|
|
||||||
if(stringPart.size())
|
if(stringPart.size())
|
||||||
{
|
{
|
||||||
m_stringPart = stringPart.toString();
|
m_stringPart = stringPart.toString();
|
||||||
|
@ -1,38 +1,3 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
/*
|
|
||||||
* PolyMC - Minecraft Launcher
|
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
*
|
|
||||||
* 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 "VersionProxyModel.h"
|
#include "VersionProxyModel.h"
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
@ -243,8 +208,7 @@ QVariant VersionProxyModel::data(const QModelIndex &index, int role) const
|
|||||||
{
|
{
|
||||||
return APPLICATION->getThemedIcon("bug");
|
return APPLICATION->getThemedIcon("bug");
|
||||||
}
|
}
|
||||||
QPixmap pixmap;
|
auto pixmap = QPixmapCache::find("placeholder");
|
||||||
QPixmapCache::find("placeholder", &pixmap);
|
|
||||||
if(!pixmap)
|
if(!pixmap)
|
||||||
{
|
{
|
||||||
QPixmap px(16,16);
|
QPixmap px(16,16);
|
||||||
@ -252,7 +216,7 @@ QVariant VersionProxyModel::data(const QModelIndex &index, int role) const
|
|||||||
QPixmapCache::insert("placeholder", px);
|
QPixmapCache::insert("placeholder", px);
|
||||||
return px;
|
return px;
|
||||||
}
|
}
|
||||||
return pixmap;
|
return *pixmap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
#include <QTest>
|
#include <QTest>
|
||||||
|
|
||||||
#include <TestUtil.h>
|
#include "TestUtil.h"
|
||||||
#include <Version.h>
|
#include <Version.h>
|
||||||
|
|
||||||
class ModUtilsTest : public QObject
|
class ModUtilsTest : public QObject
|
@ -1,36 +1,16 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
/* Copyright 2013-2021 MultiMC Contributors
|
||||||
/*
|
|
||||||
* PolyMC - Minecraft Launcher
|
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* it under the terms of the GNU General Public License as published by
|
* you may not use this file except in compliance with the License.
|
||||||
* the Free Software Foundation, version 3.
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
* 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
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
*
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* This file incorporates work covered by the following copyright and
|
* See the License for the specific language governing permissions and
|
||||||
* permission notice:
|
* limitations under the License.
|
||||||
*
|
|
||||||
* 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 "IconList.h"
|
#include "IconList.h"
|
||||||
@ -106,11 +86,7 @@ void IconList::directoryChanged(const QString &path)
|
|||||||
QString &foo = (*it);
|
QString &foo = (*it);
|
||||||
foo = m_dir.filePath(foo);
|
foo = m_dir.filePath(foo);
|
||||||
}
|
}
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
|
||||||
QSet<QString> new_set(new_list.begin(), new_list.end());
|
|
||||||
#else
|
|
||||||
auto new_set = new_list.toSet();
|
auto new_set = new_list.toSet();
|
||||||
#endif
|
|
||||||
QList<QString> current_list;
|
QList<QString> current_list;
|
||||||
for (auto &it : icons)
|
for (auto &it : icons)
|
||||||
{
|
{
|
||||||
@ -118,11 +94,7 @@ void IconList::directoryChanged(const QString &path)
|
|||||||
continue;
|
continue;
|
||||||
current_list.push_back(it.m_images[IconType::FileBased].filename);
|
current_list.push_back(it.m_images[IconType::FileBased].filename);
|
||||||
}
|
}
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
|
||||||
QSet<QString> current_set(current_list.begin(), current_list.end());
|
|
||||||
#else
|
|
||||||
QSet<QString> current_set = current_list.toSet();
|
QSet<QString> current_set = current_list.toSet();
|
||||||
#endif
|
|
||||||
|
|
||||||
QSet<QString> to_remove = current_set;
|
QSet<QString> to_remove = current_set;
|
||||||
to_remove -= new_set;
|
to_remove -= new_set;
|
||||||
|
@ -1,41 +1,21 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
/* Copyright 2013-2021 MultiMC Contributors
|
||||||
/*
|
|
||||||
* PolyMC - Minecraft Launcher
|
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* it under the terms of the GNU General Public License as published by
|
* you may not use this file except in compliance with the License.
|
||||||
* the Free Software Foundation, version 3.
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
* 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
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
*
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* This file incorporates work covered by the following copyright and
|
* See the License for the specific language governing permissions and
|
||||||
* permission notice:
|
* limitations under the License.
|
||||||
*
|
|
||||||
* 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 "MMCIcon.h"
|
#include "MMCIcon.h"
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QIcon>
|
#include <xdgicon.h>
|
||||||
|
|
||||||
IconType operator--(IconType &t, int)
|
IconType operator--(IconType &t, int)
|
||||||
{
|
{
|
||||||
@ -83,7 +63,7 @@ QIcon MMCIcon::icon() const
|
|||||||
if(!icon.isNull())
|
if(!icon.isNull())
|
||||||
return icon;
|
return icon;
|
||||||
// FIXME: inject this.
|
// FIXME: inject this.
|
||||||
return QIcon::fromTheme(m_images[m_current_type].key);
|
return XdgIcon::fromTheme(m_images[m_current_type].key);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MMCIcon::remove(IconType rm_type)
|
void MMCIcon::remove(IconType rm_type)
|
||||||
|
@ -1,38 +1,3 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
/*
|
|
||||||
* PolyMC - Minecraft Launcher
|
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
*
|
|
||||||
* 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 "JavaChecker.h"
|
#include "JavaChecker.h"
|
||||||
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
@ -51,13 +16,7 @@ JavaChecker::JavaChecker(QObject *parent) : QObject(parent)
|
|||||||
|
|
||||||
void JavaChecker::performCheck()
|
void JavaChecker::performCheck()
|
||||||
{
|
{
|
||||||
QString checkerJar = JavaUtils::getJavaCheckPath();
|
QString checkerJar = FS::PathCombine(APPLICATION->getJarsPath(), "JavaCheck.jar");
|
||||||
|
|
||||||
if (checkerJar.isEmpty())
|
|
||||||
{
|
|
||||||
qDebug() << "Java checker library could not be found. Please check your installation.";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList args;
|
QStringList args;
|
||||||
|
|
||||||
@ -88,11 +47,7 @@ void JavaChecker::performCheck()
|
|||||||
qDebug() << "Running java checker: " + m_path + args.join(" ");;
|
qDebug() << "Running java checker: " + m_path + args.join(" ");;
|
||||||
|
|
||||||
connect(process.get(), SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(finished(int, QProcess::ExitStatus)));
|
connect(process.get(), SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(finished(int, QProcess::ExitStatus)));
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
|
||||||
connect(process.get(), SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(error(QProcess::ProcessError)));
|
|
||||||
#else
|
|
||||||
connect(process.get(), SIGNAL(error(QProcess::ProcessError)), this, SLOT(error(QProcess::ProcessError)));
|
connect(process.get(), SIGNAL(error(QProcess::ProcessError)), this, SLOT(error(QProcess::ProcessError)));
|
||||||
#endif
|
|
||||||
connect(process.get(), SIGNAL(readyReadStandardOutput()), this, SLOT(stdoutReady()));
|
connect(process.get(), SIGNAL(readyReadStandardOutput()), this, SLOT(stdoutReady()));
|
||||||
connect(process.get(), SIGNAL(readyReadStandardError()), this, SLOT(stderrReady()));
|
connect(process.get(), SIGNAL(readyReadStandardError()), this, SLOT(stderrReady()));
|
||||||
connect(&killTimer, SIGNAL(timeout()), SLOT(timeout()));
|
connect(&killTimer, SIGNAL(timeout()), SLOT(timeout()));
|
||||||
@ -144,12 +99,7 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
|
|||||||
bool success = true;
|
bool success = true;
|
||||||
|
|
||||||
QMap<QString, QString> results;
|
QMap<QString, QString> results;
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
|
||||||
QStringList lines = m_stdout.split("\n", Qt::SkipEmptyParts);
|
|
||||||
#else
|
|
||||||
QStringList lines = m_stdout.split("\n", QString::SkipEmptyParts);
|
QStringList lines = m_stdout.split("\n", QString::SkipEmptyParts);
|
||||||
#endif
|
|
||||||
for(QString line : lines)
|
for(QString line : lines)
|
||||||
{
|
{
|
||||||
line = line.trimmed();
|
line = line.trimmed();
|
||||||
@ -158,11 +108,7 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
|
||||||
auto parts = line.split('=', Qt::SkipEmptyParts);
|
|
||||||
#else
|
|
||||||
auto parts = line.split('=', QString::SkipEmptyParts);
|
auto parts = line.split('=', QString::SkipEmptyParts);
|
||||||
#endif
|
|
||||||
if(parts.size() != 2 || parts[0].isEmpty() || parts[1].isEmpty())
|
if(parts.size() != 2 || parts[0].isEmpty() || parts[1].isEmpty())
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -1,40 +1,21 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
/* Copyright 2013-2021 MultiMC Contributors
|
||||||
/*
|
|
||||||
* PolyMC - Minecraft Launcher
|
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* it under the terms of the GNU General Public License as published by
|
* you may not use this file except in compliance with the License.
|
||||||
* the Free Software Foundation, version 3.
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
* 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
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
*
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* This file incorporates work covered by the following copyright and
|
* See the License for the specific language governing permissions and
|
||||||
* permission notice:
|
* limitations under the License.
|
||||||
*
|
|
||||||
* 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 <QtNetwork>
|
#include <QtNetwork>
|
||||||
#include <QtXml>
|
#include <QtXml>
|
||||||
|
#include <QRegExp>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
@ -100,7 +81,7 @@ QVariant JavaInstallList::data(const QModelIndex &index, int role) const
|
|||||||
switch (role)
|
switch (role)
|
||||||
{
|
{
|
||||||
case VersionPointerRole:
|
case VersionPointerRole:
|
||||||
return QVariant::fromValue(m_vlist[index.row()]);
|
return qVariantFromValue(m_vlist[index.row()]);
|
||||||
case VersionIdRole:
|
case VersionIdRole:
|
||||||
return version->descriptor();
|
return version->descriptor();
|
||||||
case VersionRole:
|
case VersionRole:
|
||||||
|
@ -1,36 +1,16 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
/* Copyright 2013-2021 MultiMC Contributors
|
||||||
/*
|
|
||||||
* PolyMC - Minecraft Launcher
|
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* it under the terms of the GNU General Public License as published by
|
* you may not use this file except in compliance with the License.
|
||||||
* the Free Software Foundation, version 3.
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
* 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
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
*
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* This file incorporates work covered by the following copyright and
|
* See the License for the specific language governing permissions and
|
||||||
* permission notice:
|
* limitations under the License.
|
||||||
*
|
|
||||||
* 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 <QStringList>
|
#include <QStringList>
|
||||||
@ -44,7 +24,6 @@
|
|||||||
#include "java/JavaUtils.h"
|
#include "java/JavaUtils.h"
|
||||||
#include "java/JavaInstallList.h"
|
#include "java/JavaInstallList.h"
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include "Application.h"
|
|
||||||
|
|
||||||
#define IBUS "@im=ibus"
|
#define IBUS "@im=ibus"
|
||||||
|
|
||||||
@ -52,24 +31,25 @@ JavaUtils::JavaUtils()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
QString stripVariableEntries(QString name, QString target, QString remove)
|
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||||
|
static QString processLD_LIBRARY_PATH(const QString & LD_LIBRARY_PATH)
|
||||||
{
|
{
|
||||||
char delimiter = ':';
|
QDir mmcBin(QCoreApplication::applicationDirPath());
|
||||||
#ifdef Q_OS_WIN32
|
auto items = LD_LIBRARY_PATH.split(':');
|
||||||
delimiter = ';';
|
QStringList final;
|
||||||
#endif
|
for(auto & item: items)
|
||||||
|
{
|
||||||
auto targetItems = target.split(delimiter);
|
QDir test(item);
|
||||||
auto toRemove = remove.split(delimiter);
|
if(test == mmcBin)
|
||||||
|
{
|
||||||
for (QString item : toRemove) {
|
qDebug() << "Env:LD_LIBRARY_PATH ignoring path" << item;
|
||||||
bool removed = targetItems.removeOne(item);
|
continue;
|
||||||
if (!removed)
|
}
|
||||||
qWarning() << "Entry" << item
|
final.append(item);
|
||||||
<< "could not be stripped from variable" << name;
|
|
||||||
}
|
}
|
||||||
return targetItems.join(delimiter);
|
return final.join(':');
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
QProcessEnvironment CleanEnviroment()
|
QProcessEnvironment CleanEnviroment()
|
||||||
{
|
{
|
||||||
@ -88,16 +68,6 @@ QProcessEnvironment CleanEnviroment()
|
|||||||
"JAVA_OPTIONS",
|
"JAVA_OPTIONS",
|
||||||
"JAVA_TOOL_OPTIONS"
|
"JAVA_TOOL_OPTIONS"
|
||||||
};
|
};
|
||||||
|
|
||||||
QStringList stripped =
|
|
||||||
{
|
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
|
||||||
"LD_LIBRARY_PATH",
|
|
||||||
"LD_PRELOAD",
|
|
||||||
#endif
|
|
||||||
"QT_PLUGIN_PATH",
|
|
||||||
"QT_FONTPATH"
|
|
||||||
};
|
|
||||||
for(auto key: rawenv.keys())
|
for(auto key: rawenv.keys())
|
||||||
{
|
{
|
||||||
auto value = rawenv.value(key);
|
auto value = rawenv.value(key);
|
||||||
@ -107,22 +77,19 @@ QProcessEnvironment CleanEnviroment()
|
|||||||
qDebug() << "Env: ignoring" << key << value;
|
qDebug() << "Env: ignoring" << key << value;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// filter PolyMC-related things
|
||||||
// These are used to strip the original variables
|
if(key.startsWith("QT_"))
|
||||||
// If there is "LD_LIBRARY_PATH" and "LAUNCHER_LD_LIBRARY_PATH", we want to
|
|
||||||
// remove all values in "LAUNCHER_LD_LIBRARY_PATH" from "LD_LIBRARY_PATH"
|
|
||||||
if(key.startsWith("LAUNCHER_"))
|
|
||||||
{
|
{
|
||||||
qDebug() << "Env: ignoring" << key << value;
|
qDebug() << "Env: ignoring" << key << value;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(stripped.contains(key))
|
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||||
|
// Do not pass LD_* variables to java. They were intended for PolyMC
|
||||||
|
if(key.startsWith("LD_"))
|
||||||
{
|
{
|
||||||
QString newValue = stripVariableEntries(key, value, rawenv.value("LAUNCHER_" + key));
|
qDebug() << "Env: ignoring" << key << value;
|
||||||
|
continue;
|
||||||
qDebug() << "Env: stripped" << key << value << "to" << newValue;
|
|
||||||
}
|
}
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
|
||||||
// Strip IBus
|
// Strip IBus
|
||||||
// IBus is a Linux IME framework. For some reason, it breaks MC?
|
// IBus is a Linux IME framework. For some reason, it breaks MC?
|
||||||
if (key == "XMODIFIERS" && value.contains(IBUS))
|
if (key == "XMODIFIERS" && value.contains(IBUS))
|
||||||
@ -131,12 +98,22 @@ QProcessEnvironment CleanEnviroment()
|
|||||||
value.replace(IBUS, "");
|
value.replace(IBUS, "");
|
||||||
qDebug() << "Env: stripped" << IBUS << "from" << save << ":" << value;
|
qDebug() << "Env: stripped" << IBUS << "from" << save << ":" << value;
|
||||||
}
|
}
|
||||||
|
if(key == "GAME_PRELOAD")
|
||||||
|
{
|
||||||
|
env.insert("LD_PRELOAD", value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(key == "GAME_LIBRARY_PATH")
|
||||||
|
{
|
||||||
|
env.insert("LD_LIBRARY_PATH", processLD_LIBRARY_PATH(value));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
// qDebug() << "Env: " << key << value;
|
// qDebug() << "Env: " << key << value;
|
||||||
env.insert(key, value);
|
env.insert(key, value);
|
||||||
}
|
}
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
// HACK: Workaround for QTBUG-42500
|
// HACK: Workaround for QTBUG42500
|
||||||
if(!env.contains("LD_LIBRARY_PATH"))
|
if(!env.contains("LD_LIBRARY_PATH"))
|
||||||
{
|
{
|
||||||
env.insert("LD_LIBRARY_PATH", "");
|
env.insert("LD_LIBRARY_PATH", "");
|
||||||
@ -174,17 +151,11 @@ JavaInstallPtr JavaUtils::GetDefaultJava()
|
|||||||
|
|
||||||
QStringList addJavasFromEnv(QList<QString> javas)
|
QStringList addJavasFromEnv(QList<QString> javas)
|
||||||
{
|
{
|
||||||
auto env = qEnvironmentVariable("PRISMLAUNCHER_JAVA_PATHS"); // FIXME: use launcher name from buildconfig
|
QByteArray env = qgetenv("POLYMC_JAVA_PATHS");
|
||||||
#if defined(Q_OS_WIN32)
|
#if defined(Q_OS_WIN32)
|
||||||
QList<QString> javaPaths = env.replace("\\", "/").split(QLatin1String(";"));
|
QList<QString> javaPaths = QString::fromLocal8Bit(env).replace("\\", "/").split(QLatin1String(";"));
|
||||||
|
|
||||||
auto envPath = qEnvironmentVariable("PATH");
|
|
||||||
QList<QString> javaPathsfromPath = envPath.replace("\\", "/").split(QLatin1String(";"));
|
|
||||||
for (QString string : javaPathsfromPath) {
|
|
||||||
javaPaths.append(string + "/javaw.exe");
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
QList<QString> javaPaths = env.split(QLatin1String(":"));
|
QList<QString> javaPaths = QString::fromLocal8Bit(env).split(QLatin1String(":"));
|
||||||
#endif
|
#endif
|
||||||
for(QString i : javaPaths)
|
for(QString i : javaPaths)
|
||||||
{
|
{
|
||||||
@ -205,17 +176,25 @@ QList<JavaInstallPtr> JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString
|
|||||||
archType = "32";
|
archType = "32";
|
||||||
|
|
||||||
HKEY jreKey;
|
HKEY jreKey;
|
||||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keyName.toStdWString().c_str(), 0,
|
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, keyName.toStdString().c_str(), 0,
|
||||||
KEY_READ | keyType | KEY_ENUMERATE_SUB_KEYS, &jreKey) == ERROR_SUCCESS)
|
KEY_READ | keyType | KEY_ENUMERATE_SUB_KEYS, &jreKey) == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
// Read the current type version from the registry.
|
// Read the current type version from the registry.
|
||||||
// This will be used to find any key that contains the JavaHome value.
|
// This will be used to find any key that contains the JavaHome value.
|
||||||
|
char *value = new char[0];
|
||||||
|
DWORD valueSz = 0;
|
||||||
|
if (RegQueryValueExA(jreKey, "CurrentVersion", NULL, NULL, (BYTE *)value, &valueSz) ==
|
||||||
|
ERROR_MORE_DATA)
|
||||||
|
{
|
||||||
|
value = new char[valueSz];
|
||||||
|
RegQueryValueExA(jreKey, "CurrentVersion", NULL, NULL, (BYTE *)value, &valueSz);
|
||||||
|
}
|
||||||
|
|
||||||
WCHAR subKeyName[255];
|
TCHAR subKeyName[255];
|
||||||
DWORD subKeyNameSize, numSubKeys, retCode;
|
DWORD subKeyNameSize, numSubKeys, retCode;
|
||||||
|
|
||||||
// Get the number of subkeys
|
// Get the number of subkeys
|
||||||
RegQueryInfoKeyW(jreKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL, NULL, NULL, NULL,
|
RegQueryInfoKey(jreKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL, NULL, NULL, NULL,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
|
|
||||||
// Iterate until RegEnumKeyEx fails
|
// Iterate until RegEnumKeyEx fails
|
||||||
@ -224,37 +203,34 @@ QList<JavaInstallPtr> JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString
|
|||||||
for (DWORD i = 0; i < numSubKeys; i++)
|
for (DWORD i = 0; i < numSubKeys; i++)
|
||||||
{
|
{
|
||||||
subKeyNameSize = 255;
|
subKeyNameSize = 255;
|
||||||
retCode = RegEnumKeyExW(jreKey, i, subKeyName, &subKeyNameSize, NULL, NULL, NULL,
|
retCode = RegEnumKeyEx(jreKey, i, subKeyName, &subKeyNameSize, NULL, NULL, NULL,
|
||||||
NULL);
|
NULL);
|
||||||
QString newSubkeyName = QString::fromWCharArray(subKeyName);
|
|
||||||
if (retCode == ERROR_SUCCESS)
|
if (retCode == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
// Now open the registry key for the version that we just got.
|
// Now open the registry key for the version that we just got.
|
||||||
QString newKeyName = keyName + "\\" + newSubkeyName + subkeySuffix;
|
QString newKeyName = keyName + "\\" + subKeyName + subkeySuffix;
|
||||||
|
|
||||||
HKEY newKey;
|
HKEY newKey;
|
||||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, newKeyName.toStdWString().c_str(), 0,
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, newKeyName.toStdString().c_str(), 0,
|
||||||
KEY_READ | KEY_WOW64_64KEY, &newKey) == ERROR_SUCCESS)
|
KEY_READ | KEY_WOW64_64KEY, &newKey) == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
// Read the JavaHome value to find where Java is installed.
|
// Read the JavaHome value to find where Java is installed.
|
||||||
DWORD valueSz = 0;
|
value = new char[0];
|
||||||
if (RegQueryValueExW(newKey, keyJavaDir.toStdWString().c_str(), NULL, NULL, NULL,
|
valueSz = 0;
|
||||||
&valueSz) == ERROR_SUCCESS)
|
if (RegQueryValueEx(newKey, keyJavaDir.toStdString().c_str(), NULL, NULL, (BYTE *)value,
|
||||||
|
&valueSz) == ERROR_MORE_DATA)
|
||||||
{
|
{
|
||||||
WCHAR *value = new WCHAR[valueSz];
|
value = new char[valueSz];
|
||||||
RegQueryValueExW(newKey, keyJavaDir.toStdWString().c_str(), NULL, NULL, (BYTE *)value,
|
RegQueryValueEx(newKey, keyJavaDir.toStdString().c_str(), NULL, NULL, (BYTE *)value,
|
||||||
&valueSz);
|
&valueSz);
|
||||||
|
|
||||||
QString newValue = QString::fromWCharArray(value);
|
|
||||||
delete [] value;
|
|
||||||
|
|
||||||
// Now, we construct the version object and add it to the list.
|
// Now, we construct the version object and add it to the list.
|
||||||
JavaInstallPtr javaVersion(new JavaInstall());
|
JavaInstallPtr javaVersion(new JavaInstall());
|
||||||
|
|
||||||
javaVersion->id = newSubkeyName;
|
javaVersion->id = subKeyName;
|
||||||
javaVersion->arch = archType;
|
javaVersion->arch = archType;
|
||||||
javaVersion->path =
|
javaVersion->path =
|
||||||
QDir(FS::PathCombine(newValue, "bin")).absoluteFilePath("javaw.exe");
|
QDir(FS::PathCombine(value, "bin")).absoluteFilePath("javaw.exe");
|
||||||
javas.append(javaVersion);
|
javas.append(javaVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -441,7 +417,7 @@ QList<QString> JavaUtils::FindJavaPaths()
|
|||||||
scanJavaDir("/usr/lib/jvm");
|
scanJavaDir("/usr/lib/jvm");
|
||||||
scanJavaDir("/usr/lib64/jvm");
|
scanJavaDir("/usr/lib64/jvm");
|
||||||
scanJavaDir("/usr/lib32/jvm");
|
scanJavaDir("/usr/lib32/jvm");
|
||||||
// javas stored in Prism Launcher's folder
|
// javas stored in PolyMC's folder
|
||||||
scanJavaDir("java");
|
scanJavaDir("java");
|
||||||
// manually installed JDKs in /opt
|
// manually installed JDKs in /opt
|
||||||
scanJavaDir("/opt/jdk");
|
scanJavaDir("/opt/jdk");
|
||||||
@ -461,8 +437,3 @@ QList<QString> JavaUtils::FindJavaPaths()
|
|||||||
return addJavasFromEnv(javas);
|
return addJavasFromEnv(javas);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QString JavaUtils::getJavaCheckPath()
|
|
||||||
{
|
|
||||||
return APPLICATION->getJarPath("JavaCheck.jar");
|
|
||||||
}
|
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QString stripVariableEntries(QString name, QString target, QString remove);
|
|
||||||
QProcessEnvironment CleanEnviroment();
|
QProcessEnvironment CleanEnviroment();
|
||||||
|
|
||||||
class JavaUtils : public QObject
|
class JavaUtils : public QObject
|
||||||
@ -40,6 +39,4 @@ public:
|
|||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
QList<JavaInstallPtr> FindJavaFromRegistryKey(DWORD keyType, QString keyName, QString keyJavaDir, QString subkeySuffix = "");
|
QList<JavaInstallPtr> FindJavaFromRegistryKey(DWORD keyType, QString keyName, QString keyJavaDir, QString subkeySuffix = "");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static QString getJavaCheckPath();
|
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <QTest>
|
#include <QTest>
|
||||||
|
#include "TestUtil.h"
|
||||||
|
|
||||||
#include <java/JavaVersion.h>
|
#include "java/JavaVersion.h"
|
||||||
|
|
||||||
class JavaVersionTest : public QObject
|
class JavaVersionTest : public QObject
|
||||||
{
|
{
|
@ -282,22 +282,18 @@ void LaunchTask::emitFailed(QString reason)
|
|||||||
Task::emitFailed(reason);
|
Task::emitFailed(reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaunchTask::substituteVariables(QStringList &args) const
|
QString LaunchTask::substituteVariables(const QString &cmd) const
|
||||||
{
|
{
|
||||||
auto env = m_instance->createEnvironment();
|
QString out = cmd;
|
||||||
|
auto variables = m_instance->getVariables();
|
||||||
for (auto key : env.keys())
|
for (auto it = variables.begin(); it != variables.end(); ++it)
|
||||||
{
|
{
|
||||||
args.replaceInStrings("$" + key, env.value(key));
|
out.replace("$" + it.key(), it.value());
|
||||||
}
|
}
|
||||||
}
|
auto env = QProcessEnvironment::systemEnvironment();
|
||||||
|
for (auto var : env.keys())
|
||||||
void LaunchTask::substituteVariables(QString &cmd) const
|
|
||||||
{
|
|
||||||
auto env = m_instance->createEnvironment();
|
|
||||||
|
|
||||||
for (auto key : env.keys())
|
|
||||||
{
|
{
|
||||||
cmd.replace("$" + key, env.value(key));
|
out.replace("$" + var, env.value(var));
|
||||||
}
|
}
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
@ -1,38 +1,18 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
/* Copyright 2013-2021 MultiMC Contributors
|
||||||
/*
|
|
||||||
* PolyMC - Minecraft Launcher
|
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
|
||||||
* 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,
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* you may not use this file except in compliance with the License.
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* You may obtain a copy of the License at
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
*
|
||||||
* This file incorporates work covered by the following copyright and
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* permission notice:
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
*
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* Copyright 2013-2021 MultiMC Contributors
|
* See the License for the specific language governing permissions and
|
||||||
*
|
* limitations under the License.
|
||||||
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
|
|
||||||
*
|
|
||||||
* 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
|
||||||
@ -105,8 +85,7 @@ public: /* methods */
|
|||||||
shared_qobject_ptr<LogModel> getLogModel();
|
shared_qobject_ptr<LogModel> getLogModel();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void substituteVariables(QStringList &args) const;
|
QString substituteVariables(const QString &cmd) const;
|
||||||
void substituteVariables(QString &cmd) const;
|
|
||||||
QString censorPrivateInfo(QString in);
|
QString censorPrivateInfo(QString in);
|
||||||
|
|
||||||
protected: /* methods */
|
protected: /* methods */
|
||||||
|
@ -34,7 +34,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CheckJava.h"
|
#include "CheckJava.h"
|
||||||
#include "java/JavaUtils.h"
|
|
||||||
#include <launch/LaunchTask.h>
|
#include <launch/LaunchTask.h>
|
||||||
#include <FileSystem.h>
|
#include <FileSystem.h>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
@ -72,26 +71,15 @@ void CheckJava::executeTask()
|
|||||||
emit logLine("Java path is:\n" + m_javaPath + "\n\n", MessageLevel::Launcher);
|
emit logLine("Java path is:\n" + m_javaPath + "\n\n", MessageLevel::Launcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JavaUtils::getJavaCheckPath().isEmpty())
|
|
||||||
{
|
|
||||||
const char *reason = QT_TR_NOOP("Java checker library could not be found. Please check your installation.");
|
|
||||||
emit logLine(tr(reason), MessageLevel::Fatal);
|
|
||||||
emitFailed(tr(reason));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QFileInfo javaInfo(realJavaPath);
|
QFileInfo javaInfo(realJavaPath);
|
||||||
qlonglong javaUnixTime = javaInfo.lastModified().toMSecsSinceEpoch();
|
qlonglong javaUnixTime = javaInfo.lastModified().toMSecsSinceEpoch();
|
||||||
auto storedUnixTime = settings->get("JavaTimestamp").toLongLong();
|
auto storedUnixTime = settings->get("JavaTimestamp").toLongLong();
|
||||||
auto storedArchitecture = settings->get("JavaArchitecture").toString();
|
auto storedArchitecture = settings->get("JavaArchitecture").toString();
|
||||||
auto storedRealArchitecture = settings->get("JavaRealArchitecture").toString();
|
|
||||||
auto storedVersion = settings->get("JavaVersion").toString();
|
auto storedVersion = settings->get("JavaVersion").toString();
|
||||||
auto storedVendor = settings->get("JavaVendor").toString();
|
auto storedVendor = settings->get("JavaVendor").toString();
|
||||||
m_javaUnixTime = javaUnixTime;
|
m_javaUnixTime = javaUnixTime;
|
||||||
// if timestamps are not the same, or something is missing, check!
|
// if timestamps are not the same, or something is missing, check!
|
||||||
if (javaUnixTime != storedUnixTime || storedVersion.size() == 0
|
if (javaUnixTime != storedUnixTime || storedVersion.size() == 0 || storedArchitecture.size() == 0 || storedVendor.size() == 0)
|
||||||
|| storedArchitecture.size() == 0 || storedRealArchitecture.size() == 0
|
|
||||||
|| storedVendor.size() == 0)
|
|
||||||
{
|
{
|
||||||
m_JavaChecker = new JavaChecker();
|
m_JavaChecker = new JavaChecker();
|
||||||
emit logLine(QString("Checking Java version..."), MessageLevel::Launcher);
|
emit logLine(QString("Checking Java version..."), MessageLevel::Launcher);
|
||||||
@ -104,9 +92,8 @@ void CheckJava::executeTask()
|
|||||||
{
|
{
|
||||||
auto verString = instance->settings()->get("JavaVersion").toString();
|
auto verString = instance->settings()->get("JavaVersion").toString();
|
||||||
auto archString = instance->settings()->get("JavaArchitecture").toString();
|
auto archString = instance->settings()->get("JavaArchitecture").toString();
|
||||||
auto realArchString = settings->get("JavaRealArchitecture").toString();
|
|
||||||
auto vendorString = instance->settings()->get("JavaVendor").toString();
|
auto vendorString = instance->settings()->get("JavaVendor").toString();
|
||||||
printJavaInfo(verString, archString, realArchString, vendorString);
|
printJavaInfo(verString, archString, vendorString);
|
||||||
}
|
}
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
}
|
}
|
||||||
@ -121,6 +108,7 @@ void CheckJava::checkJavaFinished(JavaCheckResult result)
|
|||||||
emit logLine(QString("Could not start java:"), MessageLevel::Error);
|
emit logLine(QString("Could not start java:"), MessageLevel::Error);
|
||||||
emit logLines(result.errorLog.split('\n'), MessageLevel::Error);
|
emit logLines(result.errorLog.split('\n'), MessageLevel::Error);
|
||||||
emit logLine(QString("\nCheck your Java settings."), MessageLevel::Launcher);
|
emit logLine(QString("\nCheck your Java settings."), MessageLevel::Launcher);
|
||||||
|
printSystemInfo(false, false);
|
||||||
emitFailed(QString("Could not start java!"));
|
emitFailed(QString("Could not start java!"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -129,16 +117,17 @@ void CheckJava::checkJavaFinished(JavaCheckResult result)
|
|||||||
emit logLine(QString("Java checker returned some invalid data we don't understand:"), MessageLevel::Error);
|
emit logLine(QString("Java checker returned some invalid data we don't understand:"), MessageLevel::Error);
|
||||||
emit logLines(result.outLog.split('\n'), MessageLevel::Warning);
|
emit logLines(result.outLog.split('\n'), MessageLevel::Warning);
|
||||||
emit logLine("\nMinecraft might not start properly.", MessageLevel::Launcher);
|
emit logLine("\nMinecraft might not start properly.", MessageLevel::Launcher);
|
||||||
|
printSystemInfo(false, false);
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case JavaCheckResult::Validity::Valid:
|
case JavaCheckResult::Validity::Valid:
|
||||||
{
|
{
|
||||||
auto instance = m_parent->instance();
|
auto instance = m_parent->instance();
|
||||||
printJavaInfo(result.javaVersion.toString(), result.mojangPlatform, result.realPlatform, result.javaVendor);
|
printJavaInfo(result.javaVersion.toString(), result.realPlatform, result.javaVendor);
|
||||||
|
printSystemInfo(true, result.is_64bit);
|
||||||
instance->settings()->set("JavaVersion", result.javaVersion.toString());
|
instance->settings()->set("JavaVersion", result.javaVersion.toString());
|
||||||
instance->settings()->set("JavaArchitecture", result.mojangPlatform);
|
instance->settings()->set("JavaArchitecture", result.mojangPlatform);
|
||||||
instance->settings()->set("JavaRealArchitecture", result.realPlatform);
|
|
||||||
instance->settings()->set("JavaVendor", result.javaVendor);
|
instance->settings()->set("JavaVendor", result.javaVendor);
|
||||||
instance->settings()->set("JavaTimestamp", m_javaUnixTime);
|
instance->settings()->set("JavaTimestamp", m_javaUnixTime);
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
@ -147,8 +136,24 @@ void CheckJava::checkJavaFinished(JavaCheckResult result)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckJava::printJavaInfo(const QString& version, const QString& architecture, const QString& realArchitecture, const QString & vendor)
|
void CheckJava::printJavaInfo(const QString& version, const QString& architecture, const QString & vendor)
|
||||||
{
|
{
|
||||||
emit logLine(QString("Java is version %1, using %2 (%3) architecture, from %4.\n\n")
|
emit logLine(QString("Java is version %1, using %2 architecture, from %3.\n\n").arg(version, architecture, vendor), MessageLevel::Launcher);
|
||||||
.arg(version, architecture, realArchitecture, vendor), MessageLevel::Launcher);
|
}
|
||||||
|
|
||||||
|
void CheckJava::printSystemInfo(bool javaIsKnown, bool javaIs64bit)
|
||||||
|
{
|
||||||
|
auto cpu64 = Sys::isCPU64bit();
|
||||||
|
auto system64 = Sys::isSystem64bit();
|
||||||
|
if(cpu64 != system64)
|
||||||
|
{
|
||||||
|
emit logLine(QString("Your CPU architecture is not matching your system architecture. You might want to install a 64bit Operating System.\n\n"), MessageLevel::Error);
|
||||||
|
}
|
||||||
|
if(javaIsKnown)
|
||||||
|
{
|
||||||
|
if(javaIs64bit != system64)
|
||||||
|
{
|
||||||
|
emit logLine(QString("Your Java architecture is not matching your system architecture. You might want to install a 64bit Java version.\n\n"), MessageLevel::Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ private slots:
|
|||||||
void checkJavaFinished(JavaCheckResult result);
|
void checkJavaFinished(JavaCheckResult result);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void printJavaInfo(const QString & version, const QString & architecture, const QString & realArchitecture, const QString & vendor);
|
void printJavaInfo(const QString & version, const QString & architecture, const QString & vendor);
|
||||||
void printSystemInfo(bool javaIsKnown, bool javaIs64bit);
|
void printSystemInfo(bool javaIsKnown, bool javaIs64bit);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -1,36 +1,16 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
/* Copyright 2013-2021 MultiMC Contributors
|
||||||
/*
|
|
||||||
* PolyMC - Minecraft Launcher
|
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* it under the terms of the GNU General Public License as published by
|
* you may not use this file except in compliance with the License.
|
||||||
* the Free Software Foundation, version 3.
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
* 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
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
*
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* This file incorporates work covered by the following copyright and
|
* See the License for the specific language governing permissions and
|
||||||
* permission notice:
|
* limitations under the License.
|
||||||
*
|
|
||||||
* 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 "PostLaunchCommand.h"
|
#include "PostLaunchCommand.h"
|
||||||
@ -47,20 +27,9 @@ PostLaunchCommand::PostLaunchCommand(LaunchTask *parent) : LaunchStep(parent)
|
|||||||
|
|
||||||
void PostLaunchCommand::executeTask()
|
void PostLaunchCommand::executeTask()
|
||||||
{
|
{
|
||||||
//FIXME: where to put this?
|
QString postlaunch_cmd = m_parent->substituteVariables(m_command);
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
emit logLine(tr("Running Post-Launch command: %1").arg(postlaunch_cmd), MessageLevel::Launcher);
|
||||||
auto args = QProcess::splitCommand(m_command);
|
m_process.start(postlaunch_cmd);
|
||||||
m_parent->substituteVariables(args);
|
|
||||||
|
|
||||||
emit logLine(tr("Running Post-Launch command: %1").arg(args.join(' ')), MessageLevel::Launcher);
|
|
||||||
const QString program = args.takeFirst();
|
|
||||||
m_process.start(program, args);
|
|
||||||
#else
|
|
||||||
m_parent->substituteVariables(m_command);
|
|
||||||
|
|
||||||
emit logLine(tr("Running Post-Launch command: %1").arg(m_command), MessageLevel::Launcher);
|
|
||||||
m_process.start(m_command);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PostLaunchCommand::on_state(LoggedProcess::State state)
|
void PostLaunchCommand::on_state(LoggedProcess::State state)
|
||||||
|
@ -1,36 +1,16 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
/* Copyright 2013-2021 MultiMC Contributors
|
||||||
/*
|
|
||||||
* PolyMC - Minecraft Launcher
|
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* it under the terms of the GNU General Public License as published by
|
* you may not use this file except in compliance with the License.
|
||||||
* the Free Software Foundation, version 3.
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
* 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
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
*
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* This file incorporates work covered by the following copyright and
|
* See the License for the specific language governing permissions and
|
||||||
* permission notice:
|
* limitations under the License.
|
||||||
*
|
|
||||||
* 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 "PreLaunchCommand.h"
|
#include "PreLaunchCommand.h"
|
||||||
@ -48,19 +28,9 @@ PreLaunchCommand::PreLaunchCommand(LaunchTask *parent) : LaunchStep(parent)
|
|||||||
void PreLaunchCommand::executeTask()
|
void PreLaunchCommand::executeTask()
|
||||||
{
|
{
|
||||||
//FIXME: where to put this?
|
//FIXME: where to put this?
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
QString prelaunch_cmd = m_parent->substituteVariables(m_command);
|
||||||
auto args = QProcess::splitCommand(m_command);
|
emit logLine(tr("Running Pre-Launch command: %1").arg(prelaunch_cmd), MessageLevel::Launcher);
|
||||||
m_parent->substituteVariables(args);
|
m_process.start(prelaunch_cmd);
|
||||||
|
|
||||||
emit logLine(tr("Running Pre-Launch command: %1").arg(args.join(' ')), MessageLevel::Launcher);
|
|
||||||
const QString program = args.takeFirst();
|
|
||||||
m_process.start(program, args);
|
|
||||||
#else
|
|
||||||
m_parent->substituteVariables(m_command);
|
|
||||||
|
|
||||||
emit logLine(tr("Running Pre-Launch command: %1").arg(m_command), MessageLevel::Launcher);
|
|
||||||
m_process.start(m_command);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PreLaunchCommand::on_state(LoggedProcess::State state)
|
void PreLaunchCommand::on_state(LoggedProcess::State state)
|
||||||
|
@ -1,38 +1,3 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
/*
|
|
||||||
* PolyMC - Minecraft Launcher
|
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
*
|
|
||||||
* 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 "Application.h"
|
#include "Application.h"
|
||||||
|
|
||||||
// #define BREAK_INFINITE_LOOP
|
// #define BREAK_INFINITE_LOOP
|
||||||
@ -59,10 +24,8 @@ int main(int argc, char *argv[])
|
|||||||
return 42;
|
return 42;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if QT_VERSION <= QT_VERSION_CHECK(6, 0, 0)
|
|
||||||
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||||
QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||||
#endif
|
|
||||||
|
|
||||||
// initialize Qt
|
// initialize Qt
|
||||||
Application app(argc, argv);
|
Application app(argc, argv);
|
||||||
@ -75,7 +38,7 @@ int main(int argc, char *argv[])
|
|||||||
Q_INIT_RESOURCE(multimc);
|
Q_INIT_RESOURCE(multimc);
|
||||||
Q_INIT_RESOURCE(backgrounds);
|
Q_INIT_RESOURCE(backgrounds);
|
||||||
Q_INIT_RESOURCE(documents);
|
Q_INIT_RESOURCE(documents);
|
||||||
Q_INIT_RESOURCE(prismlauncher);
|
Q_INIT_RESOURCE(polymc);
|
||||||
|
|
||||||
Q_INIT_RESOURCE(pe_dark);
|
Q_INIT_RESOURCE(pe_dark);
|
||||||
Q_INIT_RESOURCE(pe_light);
|
Q_INIT_RESOURCE(pe_light);
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
#include <QTest>
|
#include <QTest>
|
||||||
|
#include "TestUtil.h"
|
||||||
|
|
||||||
#include <meta/Index.h>
|
#include "meta/Index.h"
|
||||||
#include <meta/VersionList.h>
|
#include "meta/VersionList.h"
|
||||||
|
|
||||||
class IndexTest : public QObject
|
class IndexTest : public QObject
|
||||||
{
|
{
|
@ -140,13 +140,6 @@ VersionPtr VersionList::getVersion(const QString &version)
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VersionList::hasVersion(QString version) const
|
|
||||||
{
|
|
||||||
auto ver = std::find_if(m_versions.constBegin(), m_versions.constEnd(),
|
|
||||||
[&](Meta::VersionPtr const& a){ return a->version() == version; });
|
|
||||||
return (ver != m_versions.constEnd());
|
|
||||||
}
|
|
||||||
|
|
||||||
void VersionList::setName(const QString &name)
|
void VersionList::setName(const QString &name)
|
||||||
{
|
{
|
||||||
m_name = name;
|
m_name = name;
|
||||||
|
@ -66,7 +66,6 @@ public:
|
|||||||
QString humanReadable() const;
|
QString humanReadable() const;
|
||||||
|
|
||||||
VersionPtr getVersion(const QString &version);
|
VersionPtr getVersion(const QString &version);
|
||||||
bool hasVersion(QString version) const;
|
|
||||||
|
|
||||||
QVector<VersionPtr> versions() const
|
QVector<VersionPtr> versions() const
|
||||||
{
|
{
|
||||||
|
@ -1,38 +1,3 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
/*
|
|
||||||
* PolyMC - Minecraft Launcher
|
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
*
|
|
||||||
* 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 <meta/VersionList.h>
|
#include <meta/VersionList.h>
|
||||||
#include <meta/Index.h>
|
#include <meta/Index.h>
|
||||||
#include "Component.h"
|
#include "Component.h"
|
||||||
@ -95,7 +60,7 @@ void Component::applyTo(LaunchProfile* profile)
|
|||||||
auto vfile = getVersionFile();
|
auto vfile = getVersionFile();
|
||||||
if(vfile)
|
if(vfile)
|
||||||
{
|
{
|
||||||
vfile->applyTo(profile, m_parent->runtimeContext());
|
vfile->applyTo(profile);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -197,10 +197,6 @@ void ComponentUpdateTask::loadComponents()
|
|||||||
{
|
{
|
||||||
remoteLoadFailed(taskIndex, error);
|
remoteLoadFailed(taskIndex, error);
|
||||||
});
|
});
|
||||||
connect(indexLoadTask.get(), &Task::aborted, [=]()
|
|
||||||
{
|
|
||||||
remoteLoadFailed(taskIndex, tr("Aborted"));
|
|
||||||
});
|
|
||||||
taskIndex++;
|
taskIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -247,10 +243,6 @@ void ComponentUpdateTask::loadComponents()
|
|||||||
{
|
{
|
||||||
remoteLoadFailed(taskIndex, error);
|
remoteLoadFailed(taskIndex, error);
|
||||||
});
|
});
|
||||||
connect(loadTask.get(), &Task::aborted, [=]()
|
|
||||||
{
|
|
||||||
remoteLoadFailed(taskIndex, tr("Aborted"));
|
|
||||||
});
|
|
||||||
RemoteLoadStatus status;
|
RemoteLoadStatus status;
|
||||||
status.type = loadType;
|
status.type = loadType;
|
||||||
status.PackProfileIndex = componentIndex;
|
status.PackProfileIndex = componentIndex;
|
||||||
|
@ -1,43 +1,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
/*
|
|
||||||
* PolyMC - Minecraft Launcher
|
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* This file incorporates work covered by the following copyright and
|
|
||||||
* permission notice:
|
|
||||||
*
|
|
||||||
* Copyright 2013-2021 MultiMC Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QRegularExpression>
|
|
||||||
#include "DefaultVariable.h"
|
#include "DefaultVariable.h"
|
||||||
|
|
||||||
struct GradleSpecifier
|
struct GradleSpecifier
|
||||||
@ -61,21 +25,20 @@ struct GradleSpecifier
|
|||||||
4 "jdk15"
|
4 "jdk15"
|
||||||
5 "jar"
|
5 "jar"
|
||||||
*/
|
*/
|
||||||
QRegularExpression matcher(QRegularExpression::anchoredPattern("([^:@]+):([^:@]+):([^:@]+)" "(?::([^:@]+))?" "(?:@([^:@]+))?"));
|
QRegExp matcher("([^:@]+):([^:@]+):([^:@]+)" "(?::([^:@]+))?" "(?:@([^:@]+))?");
|
||||||
QRegularExpressionMatch match = matcher.match(value);
|
m_valid = matcher.exactMatch(value);
|
||||||
m_valid = match.hasMatch();
|
|
||||||
if(!m_valid) {
|
if(!m_valid) {
|
||||||
m_invalidValue = value;
|
m_invalidValue = value;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
auto elements = match.captured();
|
auto elements = matcher.capturedTexts();
|
||||||
m_groupId = match.captured(1);
|
m_groupId = elements[1];
|
||||||
m_artifactId = match.captured(2);
|
m_artifactId = elements[2];
|
||||||
m_version = match.captured(3);
|
m_version = elements[3];
|
||||||
m_classifier = match.captured(4);
|
m_classifier = elements[4];
|
||||||
if(match.lastCapturedIndex() >= 5)
|
if(!elements[5].isEmpty())
|
||||||
{
|
{
|
||||||
m_extension = match.captured(5);
|
m_extension = elements[5];
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <QTest>
|
#include <QTest>
|
||||||
|
#include "TestUtil.h"
|
||||||
|
|
||||||
#include <minecraft/GradleSpecifier.h>
|
#include "minecraft/GradleSpecifier.h"
|
||||||
|
|
||||||
class GradleSpecifierTest : public QObject
|
class GradleSpecifierTest : public QObject
|
||||||
{
|
{
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user