Compare commits
49 Commits
Author | SHA1 | Date | |
---|---|---|---|
790e077ca8 | |||
10ac6cb266 | |||
4c9859b16e | |||
4b2c7a8a64 | |||
0120d170b7 | |||
79617d0c50 | |||
6e58635bfb | |||
3aee1d60d8 | |||
a1fbf2b137 | |||
0b98a0884e | |||
1582bb57ed | |||
d8044ababe | |||
32b526b729 | |||
7f6515dbe4 | |||
a39390b8b4 | |||
63a3dd1919 | |||
7a5a4de6ea | |||
664d4e701e | |||
a4ba8d8288 | |||
392bf7a97b | |||
34687049b1 | |||
9337ec6706 | |||
5bcb6962c4 | |||
0617b43190 | |||
ed28234cfb | |||
9c4455ca03 | |||
9ec7837275 | |||
549b5a6488 | |||
2652f37453 | |||
0eaff22145 | |||
2f5393b9d0 | |||
e28480a8e4 | |||
fcef6321fc | |||
35e792c5de | |||
c08b632b51 | |||
cac800bfd8 | |||
2eb8173951 | |||
75abf2c124 | |||
d40a18d6c5 | |||
a74fdc588c | |||
25b0ec6eff | |||
04e8982d33 | |||
58bd449db8 | |||
c984e9b5d6 | |||
ddd319369a | |||
de3c336213 | |||
6e94e9bff1 | |||
93b8d9e454 | |||
6d46081864 |
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@ -1 +1 @@
|
|||||||
open_collective: prismlauncher
|
open_collective: polymc
|
||||||
|
12
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
12
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -8,9 +8,9 @@ body:
|
|||||||
If you need help with running Minecraft, please visit us on our Discord before making a bug report.
|
If you need help with running Minecraft, please visit us on our Discord before making a bug report.
|
||||||
|
|
||||||
Before submitting a bug report, please make sure you have read this *entire* form, and that:
|
Before submitting a bug report, please make sure you have read this *entire* form, and that:
|
||||||
* You have read the [Prism Launcher wiki](https://prismlauncher.org/wiki/) and it has not answered your question.
|
* You have read the [PolyMC wiki](https://polymc.org/wiki/) and it has not answered your question.
|
||||||
* Your bug is not caused by Minecraft or any mods you have installed.
|
* Your bug is not caused by Minecraft or any mods you have installed.
|
||||||
* Your issue has not been reported before, [make sure to use the search function!](https://github.com/PrismLauncher/PrismLauncher/issues)
|
* Your issue has not been reported before, [make sure to use the search function!](https://github.com/PolyMC/PolyMC/issues)
|
||||||
|
|
||||||
**Do not forget to give your issue a descriptive title.** "Bug in the instance screen" makes it hard to distinguish issues at a glance.
|
**Do not forget to give your issue a descriptive title.** "Bug in the instance screen" makes it hard to distinguish issues at a glance.
|
||||||
- type: dropdown
|
- type: dropdown
|
||||||
@ -25,15 +25,15 @@ body:
|
|||||||
- Other
|
- Other
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: Version of Prism Launcher
|
label: Version of PolyMC
|
||||||
description: The version of Prism Launcher used in the bug report.
|
description: The version of PolyMC used in the bug report.
|
||||||
placeholder: Prism Launcher 5.0
|
placeholder: PolyMC 1.4.1
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: Version of Qt
|
label: Version of Qt
|
||||||
description: The version of Qt used in the bug report. You can find it in Help -> About Prism Launcher -> About 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
|
placeholder: Qt 6.3.0
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
4
.github/ISSUE_TEMPLATE/config.yml
vendored
4
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -1,5 +1,5 @@
|
|||||||
blank_issues_enabled: true
|
blank_issues_enabled: true
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: Prism Launcher Matrix Support Room
|
- name: PolyMC Matrix Support Room
|
||||||
url: https://matrix.to/#/#prism-support:matrix.org
|
url: https://matrix.to/#/#support:polymc.org
|
||||||
about: Please ask for support here before opening an issue.
|
about: Please ask for support here before opening an issue.
|
||||||
|
4
.github/ISSUE_TEMPLATE/rfc.yml
vendored
4
.github/ISSUE_TEMPLATE/rfc.yml
vendored
@ -6,7 +6,7 @@ body:
|
|||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
### Use this form to suggest a larger change for Prism Launcher.
|
### Use this form to suggest a larger change for PolyMC.
|
||||||
- type: textarea
|
- type: textarea
|
||||||
attributes:
|
attributes:
|
||||||
label: Goal
|
label: Goal
|
||||||
@ -18,7 +18,7 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
label: Motivation
|
label: Motivation
|
||||||
description: |
|
description: |
|
||||||
Introduce the topic. If this is a not-well-known section of Prism Launcher, a detailed explanation of the background is recommended.
|
Introduce the topic. If this is a not-well-known section of PolyMC, a detailed explanation of the background is recommended.
|
||||||
Some example points of discussion:
|
Some example points of discussion:
|
||||||
- What specific problems are you facing right now that you're trying to address?
|
- What specific problems are you facing right now that you're trying to address?
|
||||||
- Are there any previous discussions? Link to them and summarize them (don't force your readers to read them though!).
|
- Are there any previous discussions? Link to them and summarize them (don't force your readers to read them though!).
|
||||||
|
8
.github/ISSUE_TEMPLATE/suggestion.yml
vendored
8
.github/ISSUE_TEMPLATE/suggestion.yml
vendored
@ -5,25 +5,25 @@ body:
|
|||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
### Use this form to suggest a feature for Prism Launcher.
|
### Use this form to suggest a feature for PolyMC.
|
||||||
- type: input
|
- type: input
|
||||||
attributes:
|
attributes:
|
||||||
label: Role
|
label: Role
|
||||||
description: In what way do you use Prism Launcher that needs this feature?
|
description: In what way do you use PolyMC that needs this feature?
|
||||||
placeholder: I play modded Minecraft.
|
placeholder: I play modded Minecraft.
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: input
|
- type: input
|
||||||
attributes:
|
attributes:
|
||||||
label: Suggestion
|
label: Suggestion
|
||||||
description: What do you want Prism Launcher to do?
|
description: What do you want PolyMC to do?
|
||||||
placeholder: I want the cat button to meow.
|
placeholder: I want the cat button to meow.
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: input
|
- type: input
|
||||||
attributes:
|
attributes:
|
||||||
label: Benefit
|
label: Benefit
|
||||||
description: Why do you need Prism Launcher to do this?
|
description: Why do you need PolyMC to do this?
|
||||||
placeholder: so that I can always hear a cat when I need to.
|
placeholder: so that I can always hear a cat when I need to.
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
9
.github/pull_request_template.md
vendored
9
.github/pull_request_template.md
vendored
@ -1,9 +0,0 @@
|
|||||||
<!--
|
|
||||||
Hey there! Thanks for your contribution.
|
|
||||||
|
|
||||||
Please make sure that your commits are signed off first.
|
|
||||||
If you don't know how that works, check out our contribution guidelines: https://github.com/PrismLauncher/PrismLauncher/blob/develop/CONTRIBUTING.md#signing-your-work
|
|
||||||
If you already created your commits, you can run `git rebase --signoff develop` to retroactively sign-off all your commits and `git push --force` to override what you have pushed already.
|
|
||||||
|
|
||||||
Note that signing and signing-off are two different things!
|
|
||||||
-->
|
|
277
.github/workflows/build.yml
vendored
277
.github/workflows/build.yml
vendored
@ -7,17 +7,10 @@ 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
|
||||||
is_qt_cached:
|
|
||||||
description: Enable Qt caching or not
|
|
||||||
type: string
|
|
||||||
default: true
|
|
||||||
secrets:
|
secrets:
|
||||||
SPARKLE_ED25519_KEY:
|
SPARKLE_ED25519_KEY:
|
||||||
description: Private key for signing Sparkle updates
|
description: Private key for signing Sparkle updates
|
||||||
required: false
|
required: false
|
||||||
CACHIX_AUTH_TOKEN:
|
|
||||||
description: Private token for authenticating against Cachix cache
|
|
||||||
required: false
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@ -32,60 +25,26 @@ jobs:
|
|||||||
- os: ubuntu-20.04
|
- os: ubuntu-20.04
|
||||||
qt_ver: 6
|
qt_ver: 6
|
||||||
qt_host: linux
|
qt_host: linux
|
||||||
qt_arch: ''
|
|
||||||
qt_version: '6.2.4'
|
qt_version: '6.2.4'
|
||||||
qt_modules: 'qt5compat qtimageformats'
|
qt_modules: 'qt5compat qtimageformats'
|
||||||
qt_tools: ''
|
|
||||||
|
|
||||||
- os: windows-2022
|
- os: windows-2022
|
||||||
name: "Windows-MinGW-w64"
|
name: "Windows-Legacy"
|
||||||
msystem: clang64
|
msystem: clang32
|
||||||
|
|
||||||
- os: windows-2022
|
|
||||||
name: "Windows-MSVC-Legacy"
|
|
||||||
msystem: ''
|
|
||||||
architecture: 'win32'
|
|
||||||
vcvars_arch: 'amd64_x86'
|
|
||||||
qt_ver: 5
|
qt_ver: 5
|
||||||
qt_host: windows
|
|
||||||
qt_arch: 'win32_msvc2019'
|
|
||||||
qt_version: '5.15.2'
|
|
||||||
qt_modules: ''
|
|
||||||
qt_tools: 'tools_openssl_x86'
|
|
||||||
|
|
||||||
- os: windows-2022
|
- os: windows-2022
|
||||||
name: "Windows-MSVC"
|
name: "Windows"
|
||||||
msystem: ''
|
msystem: clang64
|
||||||
architecture: 'x64'
|
|
||||||
vcvars_arch: 'amd64'
|
|
||||||
qt_ver: 6
|
qt_ver: 6
|
||||||
qt_host: windows
|
|
||||||
qt_arch: ''
|
|
||||||
qt_version: '6.4.2'
|
|
||||||
qt_modules: 'qt5compat qtimageformats'
|
|
||||||
qt_tools: ''
|
|
||||||
|
|
||||||
- os: windows-2022
|
|
||||||
name: "Windows-MSVC-arm64"
|
|
||||||
msystem: ''
|
|
||||||
architecture: 'arm64'
|
|
||||||
vcvars_arch: 'amd64_arm64'
|
|
||||||
qt_ver: 6
|
|
||||||
qt_host: windows
|
|
||||||
qt_arch: 'win64_msvc2019_arm64'
|
|
||||||
qt_version: '6.4.2'
|
|
||||||
qt_modules: 'qt5compat qtimageformats'
|
|
||||||
qt_tools: ''
|
|
||||||
|
|
||||||
- os: macos-12
|
- os: macos-12
|
||||||
name: macOS
|
name: macOS
|
||||||
macosx_deployment_target: 10.15
|
macosx_deployment_target: 10.15
|
||||||
qt_ver: 6
|
qt_ver: 6
|
||||||
qt_host: mac
|
qt_host: mac
|
||||||
qt_arch: ''
|
|
||||||
qt_version: '6.3.0'
|
qt_version: '6.3.0'
|
||||||
qt_modules: 'qt5compat qtimageformats'
|
qt_modules: 'qt5compat qtimageformats'
|
||||||
qt_tools: ''
|
|
||||||
|
|
||||||
- os: macos-12
|
- os: macos-12
|
||||||
name: macOS-Legacy
|
name: macOS-Legacy
|
||||||
@ -94,7 +53,6 @@ jobs:
|
|||||||
qt_host: mac
|
qt_host: mac
|
||||||
qt_version: '5.15.2'
|
qt_version: '5.15.2'
|
||||||
qt_modules: ''
|
qt_modules: ''
|
||||||
qt_tools: ''
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
@ -105,7 +63,6 @@ jobs:
|
|||||||
INSTALL_APPIMAGE_DIR: "install-appdir"
|
INSTALL_APPIMAGE_DIR: "install-appdir"
|
||||||
BUILD_DIR: "build"
|
BUILD_DIR: "build"
|
||||||
CCACHE_VAR: ""
|
CCACHE_VAR: ""
|
||||||
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
##
|
##
|
||||||
@ -116,8 +73,16 @@ 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' && matrix.msystem != ''
|
if: runner.os == 'Windows'
|
||||||
uses: msys2/setup-msys2@v2
|
uses: msys2/setup-msys2@v2
|
||||||
with:
|
with:
|
||||||
msystem: ${{ matrix.msystem }}
|
msystem: ${{ matrix.msystem }}
|
||||||
@ -130,26 +95,21 @@ jobs:
|
|||||||
cmake:p
|
cmake:p
|
||||||
extra-cmake-modules:p
|
extra-cmake-modules:p
|
||||||
ninja:p
|
ninja:p
|
||||||
qt6-base:p
|
qt${{ matrix.qt_ver }}-base:p
|
||||||
qt6-svg:p
|
qt${{ matrix.qt_ver }}-svg:p
|
||||||
qt6-imageformats:p
|
qt${{ matrix.qt_ver }}-imageformats:p
|
||||||
quazip-qt6:p
|
quazip-qt${{ matrix.qt_ver }}:p
|
||||||
ccache:p
|
ccache:p
|
||||||
qt6-5compat:p
|
${{ matrix.qt_ver == 6 && 'qt6-5compat:p' || '' }}
|
||||||
|
|
||||||
- name: Force newer ccache
|
|
||||||
if: runner.os == 'Windows' && matrix.msystem == '' && inputs.build_type == 'Debug'
|
|
||||||
run: |
|
|
||||||
choco install ccache --version 4.7.1
|
|
||||||
|
|
||||||
- name: Setup ccache
|
- name: Setup ccache
|
||||||
if: (runner.os != 'Windows' || matrix.msystem == '') && inputs.build_type == 'Debug'
|
if: runner.os != 'Windows' && inputs.build_type == 'Debug'
|
||||||
uses: hendrikmuhs/ccache-action@v1.2.5
|
uses: hendrikmuhs/ccache-action@v1.2.3
|
||||||
with:
|
with:
|
||||||
key: ${{ matrix.os }}-qt${{ matrix.qt_ver }}-${{ matrix.architecture }}
|
key: ${{ matrix.os }}-qt${{ matrix.qt_ver }}
|
||||||
|
|
||||||
- name: Setup ccache (Windows MinGW-w64)
|
- name: Setup ccache (Windows)
|
||||||
if: runner.os == 'Windows' && matrix.msystem != '' && inputs.build_type == 'Debug'
|
if: runner.os == 'Windows' && inputs.build_type == 'Debug'
|
||||||
shell: msys2 {0}
|
shell: msys2 {0}
|
||||||
run: |
|
run: |
|
||||||
ccache --set-config=cache_dir='${{ github.workspace }}\.ccache'
|
ccache --set-config=cache_dir='${{ github.workspace }}\.ccache'
|
||||||
@ -164,14 +124,14 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
echo "CCACHE_VAR=ccache" >> $GITHUB_ENV
|
echo "CCACHE_VAR=ccache" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Retrieve ccache cache (Windows MinGW-w64)
|
- name: Retrieve ccache cache (Windows)
|
||||||
if: runner.os == 'Windows' && matrix.msystem != '' && inputs.build_type == 'Debug'
|
if: runner.os == 'Windows' && inputs.build_type == 'Debug'
|
||||||
uses: actions/cache@v3.0.11
|
uses: actions/cache@v3.0.11
|
||||||
with:
|
with:
|
||||||
path: '${{ github.workspace }}\.ccache'
|
path: '${{ github.workspace }}\.ccache'
|
||||||
key: ${{ matrix.os }}-mingw-w64
|
key: ${{ matrix.os }}-qt${{ matrix.qt_ver }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ matrix.os }}-mingw-w64
|
${{ matrix.os }}-qt${{ matrix.qt_ver }}
|
||||||
|
|
||||||
- name: Set short version
|
- name: Set short version
|
||||||
shell: bash
|
shell: bash
|
||||||
@ -196,39 +156,16 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
sudo apt-get -y install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5
|
sudo apt-get -y install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5
|
||||||
|
|
||||||
- name: Install host Qt (Windows MSVC arm64)
|
- name: Install Qt (macOS and AppImage)
|
||||||
if: runner.os == 'Windows' && matrix.architecture == 'arm64'
|
if: runner.os == 'Linux' && matrix.qt_ver == 6 || runner.os == 'macOS'
|
||||||
uses: jurplel/install-qt-action@v3
|
|
||||||
with:
|
|
||||||
version: ${{ matrix.qt_version }}
|
|
||||||
host: 'windows'
|
|
||||||
target: 'desktop'
|
|
||||||
arch: ''
|
|
||||||
modules: ${{ matrix.qt_modules }}
|
|
||||||
tools: ${{ matrix.qt_tools }}
|
|
||||||
cache: ${{ inputs.is_qt_cached }}
|
|
||||||
cache-key-prefix: host-qt-arm64-windows
|
|
||||||
dir: ${{ github.workspace }}\HostQt
|
|
||||||
set-env: false
|
|
||||||
|
|
||||||
- name: Install Qt (macOS, Linux, Qt 6 & Windows MSVC)
|
|
||||||
if: runner.os == 'Linux' && matrix.qt_ver == 6 || runner.os == 'macOS' || (runner.os == 'Windows' && matrix.msystem == '')
|
|
||||||
uses: jurplel/install-qt-action@v3
|
uses: jurplel/install-qt-action@v3
|
||||||
with:
|
with:
|
||||||
version: ${{ matrix.qt_version }}
|
version: ${{ matrix.qt_version }}
|
||||||
host: ${{ matrix.qt_host }}
|
host: ${{ matrix.qt_host }}
|
||||||
target: 'desktop'
|
target: 'desktop'
|
||||||
arch: ${{ matrix.qt_arch }}
|
|
||||||
modules: ${{ matrix.qt_modules }}
|
modules: ${{ matrix.qt_modules }}
|
||||||
tools: ${{ matrix.qt_tools }}
|
cache: true
|
||||||
cache: ${{ inputs.is_qt_cached }}
|
cache-key-prefix: ${{ matrix.qt_host }}-${{ matrix.qt_version }}-"${{ matrix.qt_modules }}"-qt_cache
|
||||||
|
|
||||||
- name: Install MSVC (Windows MSVC)
|
|
||||||
if: runner.os == 'Windows' && matrix.msystem == ''
|
|
||||||
uses: ilammy/msvc-dev-cmd@v1
|
|
||||||
with:
|
|
||||||
vsversion: 2022
|
|
||||||
arch: ${{ matrix.vcvars_arch }}
|
|
||||||
|
|
||||||
- name: Prepare AppImage (Linux)
|
- name: Prepare AppImage (Linux)
|
||||||
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
if: runner.os == 'Linux' && matrix.qt_ver != 5
|
||||||
@ -239,11 +176,6 @@ jobs:
|
|||||||
|
|
||||||
${{ github.workspace }}/.github/scripts/prepare_JREs.sh
|
${{ github.workspace }}/.github/scripts/prepare_JREs.sh
|
||||||
|
|
||||||
- name: Add QT_HOST_PATH var (Windows MSVC arm64)
|
|
||||||
if: runner.os == 'Windows' && matrix.architecture == 'arm64'
|
|
||||||
run: |
|
|
||||||
echo "QT_HOST_PATH=${{ github.workspace }}\HostQt\Qt\${{ matrix.qt_version }}\msvc2019_64" >> $env:GITHUB_ENV
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# CONFIGURE
|
# CONFIGURE
|
||||||
##
|
##
|
||||||
@ -258,26 +190,11 @@ jobs:
|
|||||||
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 }} -DMACOSX_SPARKLE_UPDATE_PUBLIC_KEY="" -DMACOSX_SPARKLE_UPDATE_FEED_URL="" -G Ninja
|
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_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 MinGW-w64)
|
- name: Configure CMake (Windows)
|
||||||
if: runner.os == 'Windows' && matrix.msystem != ''
|
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=6 -DCMAKE_OBJDUMP=/mingw64/bin/objdump.exe -G Ninja
|
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=${{ matrix.name }} -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_OBJDUMP=/mingw64/bin/objdump.exe -G Ninja
|
||||||
|
|
||||||
- name: Configure CMake (Windows MSVC)
|
|
||||||
if: runner.os == 'Windows' && matrix.msystem == ''
|
|
||||||
run: |
|
|
||||||
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=${{ matrix.name }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_MSVC_RUNTIME_LIBRARY="MultiThreadedDLL" -A${{ matrix.architecture}} -DLauncher_FORCE_BUNDLED_LIBS=ON
|
|
||||||
# https://github.com/ccache/ccache/wiki/MS-Visual-Studio (I coudn't figure out the compiler prefix)
|
|
||||||
if ("${{ env.CCACHE_VAR }}")
|
|
||||||
{
|
|
||||||
Copy-Item C:/ProgramData/chocolatey/lib/ccache/tools/ccache-4.7.1-windows-x86_64/ccache.exe -Destination C:/ProgramData/chocolatey/lib/ccache/tools/ccache-4.7.1-windows-x86_64/cl.exe
|
|
||||||
echo "CLToolExe=cl.exe" >> $env:GITHUB_ENV
|
|
||||||
echo "CLToolPath=C:/ProgramData/chocolatey/lib/ccache/tools/ccache-4.7.1-windows-x86_64/" >> $env:GITHUB_ENV
|
|
||||||
echo "TrackFileAccess=false" >> $env:GITHUB_ENV
|
|
||||||
}
|
|
||||||
# Needed for ccache, but also speeds up compile
|
|
||||||
echo "UseMultiToolTask=true" >> $env:GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Configure CMake (Linux)
|
- name: Configure CMake (Linux)
|
||||||
if: runner.os == 'Linux'
|
if: runner.os == 'Linux'
|
||||||
@ -293,17 +210,12 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cmake --build ${{ env.BUILD_DIR }}
|
cmake --build ${{ env.BUILD_DIR }}
|
||||||
|
|
||||||
- name: Build (Windows MinGW-w64)
|
- name: Build (Windows)
|
||||||
if: runner.os == 'Windows' && matrix.msystem != ''
|
if: runner.os == 'Windows'
|
||||||
shell: msys2 {0}
|
shell: msys2 {0}
|
||||||
run: |
|
run: |
|
||||||
cmake --build ${{ env.BUILD_DIR }}
|
cmake --build ${{ env.BUILD_DIR }}
|
||||||
|
|
||||||
- name: Build (Windows MSVC)
|
|
||||||
if: runner.os == 'Windows' && matrix.msystem == ''
|
|
||||||
run: |
|
|
||||||
cmake --build ${{ env.BUILD_DIR }} --config ${{ inputs.build_type }}
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# TEST
|
# TEST
|
||||||
##
|
##
|
||||||
@ -311,18 +223,21 @@ jobs:
|
|||||||
- name: Test
|
- name: Test
|
||||||
if: runner.os != 'Windows'
|
if: runner.os != 'Windows'
|
||||||
run: |
|
run: |
|
||||||
ctest -E "^example64|example$" --test-dir build --output-on-failure
|
ctest --test-dir build --output-on-failure
|
||||||
|
|
||||||
- name: Test (Windows MinGW-w64)
|
- name: Test (Windows)
|
||||||
if: runner.os == 'Windows' && matrix.msystem != ''
|
if: runner.os == 'Windows'
|
||||||
shell: msys2 {0}
|
shell: msys2 {0}
|
||||||
run: |
|
run: |
|
||||||
ctest -E "^example64|example$" --test-dir build --output-on-failure
|
ctest --test-dir build --output-on-failure
|
||||||
|
|
||||||
- name: Test (Windows MSVC)
|
##
|
||||||
if: runner.os == 'Windows' && matrix.msystem == '' && matrix.architecture != 'arm64'
|
# CODE SCAN
|
||||||
run: |
|
##
|
||||||
ctest -E "^example64|example$" --test-dir build --output-on-failure -C ${{ inputs.build_type }}
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
if: runner.os == 'Linux' && matrix.qt_ver == 6
|
||||||
|
uses: github/codeql-action/analyze@v2
|
||||||
|
|
||||||
##
|
##
|
||||||
# PACKAGE BUILDS
|
# PACKAGE BUILDS
|
||||||
@ -358,37 +273,24 @@ jobs:
|
|||||||
EOF
|
EOF
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Package (Windows MinGW-w64)
|
- name: Package (Windows)
|
||||||
if: runner.os == 'Windows' && matrix.msystem != ''
|
if: runner.os == 'Windows'
|
||||||
shell: msys2 {0}
|
shell: msys2 {0}
|
||||||
run: |
|
run: |
|
||||||
cmake --install ${{ env.BUILD_DIR }}
|
cmake --install ${{ env.BUILD_DIR }}
|
||||||
|
|
||||||
- name: Package (Windows MSVC)
|
|
||||||
if: runner.os == 'Windows' && matrix.msystem == ''
|
|
||||||
run: |
|
|
||||||
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build_type }}
|
|
||||||
|
|
||||||
cd ${{ env.INSTALL_DIR }}
|
cd ${{ env.INSTALL_DIR }}
|
||||||
if ("${{ matrix.qt_ver }}" -eq "5")
|
if [ "${{ matrix.qt_ver }}" == "5" ]; then
|
||||||
{
|
cp /clang32/bin/libcrypto-1_1.dll /clang32/bin/libssl-1_1.dll ./
|
||||||
Copy-Item D:/a/PrismLauncher/Qt/Tools/OpenSSL/Win_x86/bin/libcrypto-1_1.dll -Destination libcrypto-1_1.dll
|
fi
|
||||||
Copy-Item D:/a/PrismLauncher/Qt/Tools/OpenSSL/Win_x86/bin/libssl-1_1.dll -Destination libssl-1_1.dll
|
|
||||||
}
|
|
||||||
|
|
||||||
- name: Package (Windows MinGW-w64, portable)
|
- name: Package (Windows, portable)
|
||||||
if: runner.os == 'Windows' && matrix.msystem != ''
|
if: runner.os == 'Windows'
|
||||||
shell: msys2 {0}
|
shell: msys2 {0}
|
||||||
run: |
|
run: |
|
||||||
cp -r ${{ env.INSTALL_DIR }} ${{ env.INSTALL_PORTABLE_DIR }} # cmake install on Windows is slow, let's just copy instead
|
cp -r ${{ env.INSTALL_DIR }} ${{ env.INSTALL_PORTABLE_DIR }} # cmake install on Windows is slow, let's just copy instead
|
||||||
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable
|
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable
|
||||||
|
|
||||||
- name: Package (Windows MSVC, portable)
|
|
||||||
if: runner.os == 'Windows' && matrix.msystem == ''
|
|
||||||
run: |
|
|
||||||
cp -r ${{ env.INSTALL_DIR }} ${{ env.INSTALL_PORTABLE_DIR }} # cmake install on Windows is slow, let's just copy instead
|
|
||||||
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable
|
|
||||||
|
|
||||||
- name: Package (Windows, installer)
|
- name: Package (Windows, installer)
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
run: |
|
run: |
|
||||||
@ -509,76 +411,5 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
|
name: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
|
||||||
path: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
|
path: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
|
||||||
snap:
|
|
||||||
runs-on: ubuntu-20.04
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
if: inputs.build_type == 'Debug'
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
submodules: 'true'
|
|
||||||
- name: Set short version
|
|
||||||
shell: bash
|
|
||||||
if: inputs.build_type == 'Debug'
|
|
||||||
run: |
|
|
||||||
ver_short=`git rev-parse --short HEAD`
|
|
||||||
echo "VERSION=$ver_short" >> $GITHUB_ENV
|
|
||||||
- name: Package Snap (Linux)
|
|
||||||
id: snapcraft
|
|
||||||
if: inputs.build_type == 'Debug'
|
|
||||||
uses: snapcore/action-build@v1
|
|
||||||
- name: Upload Snap (Linux)
|
|
||||||
if: inputs.build_type == 'Debug'
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: prismlauncher_${{ env.VERSION }}_amd64.snap
|
|
||||||
path: ${{ steps.snapcraft.outputs.snap }}
|
|
||||||
|
|
||||||
flatpak:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
container:
|
|
||||||
image: bilelmoussaoui/flatpak-github-actions:kde-5.15-22.08
|
|
||||||
options: --privileged
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
if: inputs.build_type == 'Debug'
|
|
||||||
with:
|
|
||||||
submodules: 'true'
|
|
||||||
- name: Build Flatpak (Linux)
|
|
||||||
if: inputs.build_type == 'Debug'
|
|
||||||
uses: flatpak/flatpak-github-actions/flatpak-builder@v4
|
|
||||||
with:
|
|
||||||
bundle: "Prism Launcher.flatpak"
|
|
||||||
manifest-path: flatpak/org.prismlauncher.PrismLauncher.yml
|
|
||||||
cache-key: flatpak-${{ github.sha }}-x86_64
|
|
||||||
|
|
||||||
nix:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
package:
|
|
||||||
- prismlauncher
|
|
||||||
- prismlauncher-qt5
|
|
||||||
steps:
|
|
||||||
- name: Clone repository
|
|
||||||
if: inputs.build_type == 'Debug'
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
submodules: 'true'
|
|
||||||
- name: Install nix
|
|
||||||
if: inputs.build_type == 'Debug'
|
|
||||||
uses: cachix/install-nix-action@v18
|
|
||||||
with:
|
|
||||||
install_url: https://nixos.org/nix/install
|
|
||||||
extra_nix_config: |
|
|
||||||
auto-optimise-store = true
|
|
||||||
experimental-features = nix-command flakes
|
|
||||||
- uses: cachix/cachix-action@v12
|
|
||||||
if: inputs.build_type == 'Debug'
|
|
||||||
with:
|
|
||||||
name: prismlauncher
|
|
||||||
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
|
||||||
- name: Build
|
|
||||||
if: inputs.build_type == 'Debug'
|
|
||||||
run: nix build .#${{ matrix.package }} --print-build-logs
|
|
||||||
|
35
.github/workflows/codeql.yml
vendored
35
.github/workflows/codeql.yml
vendored
@ -1,35 +0,0 @@
|
|||||||
name: "CodeQL Code Scanning"
|
|
||||||
|
|
||||||
on: [ push, pull_request, workflow_dispatch ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
CodeQL:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
submodules: 'true'
|
|
||||||
|
|
||||||
- name: Initialize CodeQL
|
|
||||||
uses: github/codeql-action/init@v2
|
|
||||||
with:
|
|
||||||
config-file: ./.github/codeql/codeql-config.yml
|
|
||||||
queries: security-and-quality
|
|
||||||
languages: cpp, java
|
|
||||||
|
|
||||||
- name: Install Dependencies
|
|
||||||
run:
|
|
||||||
sudo apt-get -y update
|
|
||||||
|
|
||||||
sudo apt-get -y install ninja-build extra-cmake-modules scdoc qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5
|
|
||||||
|
|
||||||
- name: Configure and Build
|
|
||||||
run: |
|
|
||||||
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=/usr -DLauncher_QT_VERSION_MAJOR=5 -G Ninja
|
|
||||||
|
|
||||||
cmake --build build
|
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
|
||||||
uses: github/codeql-action/analyze@v2
|
|
6
.github/workflows/trigger_builds.yml
vendored
6
.github/workflows/trigger_builds.yml
vendored
@ -3,11 +3,12 @@ name: Build Application
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches-ignore:
|
branches-ignore:
|
||||||
- 'renovate/**'
|
- 'stable'
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '**.md'
|
- '**.md'
|
||||||
- '**/LICENSE'
|
- '**/LICENSE'
|
||||||
- 'flake.lock'
|
- 'flake.lock'
|
||||||
|
- '**.nix'
|
||||||
- 'packages/**'
|
- 'packages/**'
|
||||||
- '.github/ISSUE_TEMPLATE/**'
|
- '.github/ISSUE_TEMPLATE/**'
|
||||||
- '.markdownlint**'
|
- '.markdownlint**'
|
||||||
@ -16,6 +17,7 @@ on:
|
|||||||
- '**.md'
|
- '**.md'
|
||||||
- '**/LICENSE'
|
- '**/LICENSE'
|
||||||
- 'flake.lock'
|
- 'flake.lock'
|
||||||
|
- '**.nix'
|
||||||
- 'packages/**'
|
- 'packages/**'
|
||||||
- '.github/ISSUE_TEMPLATE/**'
|
- '.github/ISSUE_TEMPLATE/**'
|
||||||
- '.markdownlint**'
|
- '.markdownlint**'
|
||||||
@ -28,7 +30,5 @@ jobs:
|
|||||||
uses: ./.github/workflows/build.yml
|
uses: ./.github/workflows/build.yml
|
||||||
with:
|
with:
|
||||||
build_type: Debug
|
build_type: Debug
|
||||||
is_qt_cached: true
|
|
||||||
secrets:
|
secrets:
|
||||||
SPARKLE_ED25519_KEY: ${{ secrets.SPARKLE_ED25519_KEY }}
|
SPARKLE_ED25519_KEY: ${{ secrets.SPARKLE_ED25519_KEY }}
|
||||||
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
|
||||||
|
36
.github/workflows/trigger_release.yml
vendored
36
.github/workflows/trigger_release.yml
vendored
@ -12,7 +12,6 @@ jobs:
|
|||||||
uses: ./.github/workflows/build.yml
|
uses: ./.github/workflows/build.yml
|
||||||
with:
|
with:
|
||||||
build_type: Release
|
build_type: Release
|
||||||
is_qt_cached: false
|
|
||||||
secrets:
|
secrets:
|
||||||
SPARKLE_ED25519_KEY: ${{ secrets.SPARKLE_ED25519_KEY }}
|
SPARKLE_ED25519_KEY: ${{ secrets.SPARKLE_ED25519_KEY }}
|
||||||
|
|
||||||
@ -46,26 +45,13 @@ jobs:
|
|||||||
|
|
||||||
tar -czf PrismLauncher-${{ env.VERSION }}.tar.gz PrismLauncher-${{ env.VERSION }}
|
tar -czf PrismLauncher-${{ env.VERSION }}.tar.gz PrismLauncher-${{ env.VERSION }}
|
||||||
|
|
||||||
for d in PrismLauncher-Windows-MSVC*; do
|
for d in PrismLauncher-Windows-*; do
|
||||||
cd "${d}" || continue
|
cd "${d}" || continue
|
||||||
LEGACY="$(echo -n ${d} | grep -o Legacy || true)"
|
LEGACY="$(echo -n ${d} | grep -o Legacy || true)"
|
||||||
ARM64="$(echo -n ${d} | grep -o arm64 || true)"
|
|
||||||
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-MSVC"
|
NAME="PrismLauncher-Windows"
|
||||||
test -z "${LEGACY}" || NAME="${NAME}-Legacy"
|
test -z "${LEGACY}" || NAME="${NAME}-Legacy"
|
||||||
test -z "${ARM64}" || NAME="${NAME}-arm64"
|
|
||||||
test -z "${PORT}" || NAME="${NAME}-Portable"
|
|
||||||
test -z "${INST}" || mv PrismLauncher-*.exe ../${NAME}-Setup-${{ env.VERSION }}.exe
|
|
||||||
test -n "${INST}" || zip -r -9 "../${NAME}-${{ env.VERSION }}.zip" *
|
|
||||||
cd ..
|
|
||||||
done
|
|
||||||
|
|
||||||
for d in PrismLauncher-Windows-MinGW-w64*; do
|
|
||||||
cd "${d}" || continue
|
|
||||||
INST="$(echo -n ${d} | grep -o Setup || true)"
|
|
||||||
PORT="$(echo -n ${d} | grep -o Portable || true)"
|
|
||||||
NAME="PrismLauncher-Windows-MinGW-w64"
|
|
||||||
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 PrismLauncher-*.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" *
|
||||||
@ -86,20 +72,14 @@ jobs:
|
|||||||
PrismLauncher-Linux-${{ env.VERSION }}.tar.gz
|
PrismLauncher-Linux-${{ env.VERSION }}.tar.gz
|
||||||
PrismLauncher-Linux-Portable-${{ env.VERSION }}.tar.gz
|
PrismLauncher-Linux-Portable-${{ env.VERSION }}.tar.gz
|
||||||
PrismLauncher-Linux-${{ env.VERSION }}-x86_64.AppImage
|
PrismLauncher-Linux-${{ env.VERSION }}-x86_64.AppImage
|
||||||
|
PrismLauncher-Windows-Legacy-${{ env.VERSION }}.zip
|
||||||
PrismLauncher-Linux-Qt6-${{ env.VERSION }}.tar.gz
|
PrismLauncher-Linux-Qt6-${{ env.VERSION }}.tar.gz
|
||||||
PrismLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz
|
PrismLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz
|
||||||
PrismLauncher-Windows-MinGW-w64-${{ env.VERSION }}.zip
|
PrismLauncher-Windows-Legacy-Portable-${{ env.VERSION }}.zip
|
||||||
PrismLauncher-Windows-MinGW-w64-Portable-${{ env.VERSION }}.zip
|
PrismLauncher-Windows-Legacy-Setup-${{ env.VERSION }}.exe
|
||||||
PrismLauncher-Windows-MinGW-w64-Setup-${{ env.VERSION }}.exe
|
PrismLauncher-Windows-${{ env.VERSION }}.zip
|
||||||
PrismLauncher-Windows-MSVC-Legacy-${{ env.VERSION }}.zip
|
PrismLauncher-Windows-Portable-${{ env.VERSION }}.zip
|
||||||
PrismLauncher-Windows-MSVC-Legacy-Portable-${{ env.VERSION }}.zip
|
PrismLauncher-Windows-Setup-${{ env.VERSION }}.exe
|
||||||
PrismLauncher-Windows-MSVC-Legacy-Setup-${{ env.VERSION }}.exe
|
|
||||||
PrismLauncher-Windows-MSVC-arm64-${{ env.VERSION }}.zip
|
|
||||||
PrismLauncher-Windows-MSVC-arm64-Portable-${{ env.VERSION }}.zip
|
|
||||||
PrismLauncher-Windows-MSVC-arm64-Setup-${{ env.VERSION }}.exe
|
|
||||||
PrismLauncher-Windows-MSVC-${{ env.VERSION }}.zip
|
|
||||||
PrismLauncher-Windows-MSVC-Portable-${{ env.VERSION }}.zip
|
|
||||||
PrismLauncher-Windows-MSVC-Setup-${{ env.VERSION }}.exe
|
|
||||||
PrismLauncher-macOS-${{ env.VERSION }}.tar.gz
|
PrismLauncher-macOS-${{ env.VERSION }}.tar.gz
|
||||||
PrismLauncher-macOS-Legacy-${{ env.VERSION }}.tar.gz
|
PrismLauncher-macOS-Legacy-${{ env.VERSION }}.tar.gz
|
||||||
PrismLauncher-${{ env.VERSION }}.tar.gz
|
PrismLauncher-${{ env.VERSION }}.tar.gz
|
||||||
|
2
.github/workflows/winget.yml
vendored
2
.github/workflows/winget.yml
vendored
@ -11,5 +11,5 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
identifier: PrismLauncher.PrismLauncher
|
identifier: PrismLauncher.PrismLauncher
|
||||||
version: ${{ github.event.release.tag_name }}
|
version: ${{ github.event.release.tag_name }}
|
||||||
installers-regex: 'PrismLauncher-Windows-MSVC(:?-arm64|-Legacy)?-Setup-.+\.exe$'
|
installers-regex: 'PrismLauncher-Windows-Setup-.+\.exe$'
|
||||||
token: ${{ secrets.WINGET_TOKEN }}
|
token: ${{ secrets.WINGET_TOKEN }}
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -47,6 +47,3 @@ result/
|
|||||||
# Flatpak
|
# Flatpak
|
||||||
.flatpak-builder
|
.flatpak-builder
|
||||||
flatbuild
|
flatbuild
|
||||||
|
|
||||||
# Snap
|
|
||||||
*.snap
|
|
||||||
|
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -10,9 +10,3 @@
|
|||||||
[submodule "libraries/libnbtplusplus"]
|
[submodule "libraries/libnbtplusplus"]
|
||||||
path = libraries/libnbtplusplus
|
path = libraries/libnbtplusplus
|
||||||
url = https://github.com/PrismLauncher/libnbtplusplus.git
|
url = https://github.com/PrismLauncher/libnbtplusplus.git
|
||||||
[submodule "libraries/zlib"]
|
|
||||||
path = libraries/zlib
|
|
||||||
url = https://github.com/madler/zlib.git
|
|
||||||
[submodule "libraries/extra-cmake-modules"]
|
|
||||||
path = libraries/extra-cmake-modules
|
|
||||||
url = https://github.com/KDE/extra-cmake-modules
|
|
||||||
|
164
CMakeLists.txt
164
CMakeLists.txt
@ -1,5 +1,10 @@
|
|||||||
cmake_minimum_required(VERSION 3.15) # minimum version required by QuaZip
|
cmake_minimum_required(VERSION 3.15) # minimum version required by QuaZip
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
# In Qt 5.1+ we have our own main() function, don't autolink to qtmain on Windows
|
||||||
|
cmake_policy(SET CMP0020 OLD)
|
||||||
|
endif()
|
||||||
|
|
||||||
project(Launcher)
|
project(Launcher)
|
||||||
|
|
||||||
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)
|
||||||
@ -27,51 +32,11 @@ set(CMAKE_C_STANDARD_REQUIRED true)
|
|||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_C_STANDARD 11)
|
set(CMAKE_C_STANDARD 11)
|
||||||
include(GenerateExportHeader)
|
include(GenerateExportHeader)
|
||||||
if(MSVC)
|
set(CMAKE_CXX_FLAGS "-Wall -pedantic -fstack-protector-strong --param=ssp-buffer-size=4 ${CMAKE_CXX_FLAGS}")
|
||||||
# /GS Adds buffer security checks, default on but incuded anyway to mirror gcc's fstack-protector flag
|
|
||||||
# /permissive- specify standards-conforming compiler behavior, also enabled by Qt6, default on with std:c++20
|
|
||||||
# Use /W4 as /Wall includes unnesserey warnings such as added padding to structs
|
|
||||||
set(CMAKE_CXX_FLAGS "/GS /permissive- /W4 ${CMAKE_CXX_FLAGS}")
|
|
||||||
|
|
||||||
# LINK accepts /SUBSYSTEM whics sets if we are a WINDOWS (gui) or a CONSOLE programs
|
# ATL's packlist needs more than the default 1 Mib stack on windows
|
||||||
# This implicitly selects an entrypoint specific to the subsystem selected
|
if(WIN32)
|
||||||
# qtmain/QtEntryPointLib provides the correct entrypoint (wWinMain) for gui programs
|
set(CMAKE_EXE_LINKER_FLAGS "-Wl,--stack,8388608 ${CMAKE_EXE_LINKER_FLAGS}")
|
||||||
# Additinaly LINK autodetects we use a GUI so we can omit /SUBSYSTEM
|
|
||||||
# This allows tests to still use have console without using seperate linker flags
|
|
||||||
# /LTCG allows for linking wholy optimizated programs
|
|
||||||
# /MANIFEST:NO disables generating a manifest file, we instead provide our own
|
|
||||||
# /STACK sets the stack reserve size, ATL's pack list needs 3-4 MiB as of November 2022, provide 8 MiB
|
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "/LTCG /MANIFEST:NO /STACK:8388608 ${CMAKE_EXE_LINKER_FLAGS}")
|
|
||||||
|
|
||||||
# /GL enables whole program optimizations
|
|
||||||
# /Gw helps reduce binary size
|
|
||||||
# /Gy allows the compiler to package individual functions
|
|
||||||
# /guard:cf enables control flow guard
|
|
||||||
foreach(lang C CXX)
|
|
||||||
set("CMAKE_${lang}_FLAGS_RELEASE" "/GL /Gw /Gy /guard:cf")
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
# See https://github.com/ccache/ccache/issues/1040
|
|
||||||
# Note, CMake 3.25 replaces this with CMAKE_MSVC_DEBUG_INFORMATION_FORMAT
|
|
||||||
# See https://cmake.org/cmake/help/v3.25/variable/CMAKE_MSVC_DEBUG_INFORMATION_FORMAT.html
|
|
||||||
foreach(config DEBUG RELWITHDEBINFO)
|
|
||||||
foreach(lang C CXX)
|
|
||||||
set(flags_var "CMAKE_${lang}_FLAGS_${config}")
|
|
||||||
string(REGEX REPLACE "/Z[Ii]" "/Z7" ${flags_var} "${${flags_var}}")
|
|
||||||
endforeach()
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
if(CMAKE_MSVC_RUNTIME_LIBRARY STREQUAL "MultiThreadedDLL")
|
|
||||||
set(CMAKE_MAP_IMPORTED_CONFIG_DEBUG Release "")
|
|
||||||
set(CMAKE_MAP_IMPORTED_CONFIG_RELWITHDEBINFO Release "")
|
|
||||||
endif()
|
|
||||||
else()
|
|
||||||
set(CMAKE_CXX_FLAGS "-Wall -pedantic -fstack-protector-strong --param=ssp-buffer-size=4 ${CMAKE_CXX_FLAGS}")
|
|
||||||
|
|
||||||
# ATL's pack list needs more than the default 1 Mib stack on windows
|
|
||||||
if(WIN32)
|
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "-Wl,--stack,8388608 ${CMAKE_EXE_LINKER_FLAGS}")
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Fix build with Qt 5.13
|
# Fix build with Qt 5.13
|
||||||
@ -79,9 +44,6 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_NO_DEPRECATED_WARNINGS=Y")
|
|||||||
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_DISABLE_DEPRECATED_BEFORE=0x050C00")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_DISABLE_DEPRECATED_BEFORE=0x050C00")
|
||||||
|
|
||||||
# Fix aarch64 build for toml++
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DTOML_ENABLE_FLOAT16=0")
|
|
||||||
|
|
||||||
# set CXXFLAGS for build targets
|
# set CXXFLAGS for build targets
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -D_FORTIFY_SOURCE=2 ${CMAKE_CXX_FLAGS_RELEASE}")
|
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -D_FORTIFY_SOURCE=2 ${CMAKE_CXX_FLAGS_RELEASE}")
|
||||||
|
|
||||||
@ -91,18 +53,11 @@ if(ENABLE_LTO)
|
|||||||
include(CheckIPOSupported)
|
include(CheckIPOSupported)
|
||||||
check_ipo_supported(RESULT ipo_supported OUTPUT ipo_error)
|
check_ipo_supported(RESULT ipo_supported OUTPUT ipo_error)
|
||||||
|
|
||||||
if(ipo_supported)
|
if(ipo_supported AND (CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "MinSizeRel"))
|
||||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE)
|
message(STATUS "IPO / LTO enabled")
|
||||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_MINSIZEREL TRUE)
|
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||||
if(CMAKE_BUILD_TYPE)
|
elseif(ipo_supported)
|
||||||
if(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
|
message(STATUS "Not enabling IPO / LTO on debug builds")
|
||||||
message(STATUS "IPO / LTO enabled")
|
|
||||||
else()
|
|
||||||
message(STATUS "Not enabling IPO / LTO on debug builds")
|
|
||||||
endif()
|
|
||||||
else()
|
|
||||||
message(STATUS "IPO / LTO will only be enabled for release builds")
|
|
||||||
endif()
|
|
||||||
else()
|
else()
|
||||||
message(STATUS "IPO / LTO not supported: <${ipo_error}>")
|
message(STATUS "IPO / LTO not supported: <${ipo_error}>")
|
||||||
endif()
|
endif()
|
||||||
@ -110,20 +65,8 @@ endif()
|
|||||||
|
|
||||||
option(BUILD_TESTING "Build the testing tree." ON)
|
option(BUILD_TESTING "Build the testing tree." ON)
|
||||||
|
|
||||||
find_package(ECM QUIET NO_MODULE)
|
find_package(ECM REQUIRED NO_MODULE)
|
||||||
if(NOT ECM_FOUND)
|
set(CMAKE_MODULE_PATH "${ECM_MODULE_PATH};${CMAKE_MODULE_PATH}")
|
||||||
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/libraries/extra-cmake-modules/CMakeLists.txt")
|
|
||||||
message(STATUS "Using bundled ECM")
|
|
||||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/libraries/extra-cmake-modules/modules;${CMAKE_MODULE_PATH}")
|
|
||||||
else()
|
|
||||||
message(FATAL_ERROR
|
|
||||||
" Could not find ECM\n \n"
|
|
||||||
" Either install ECM using the system package manager or clone submodules\n"
|
|
||||||
" Submodules can be cloned with 'git submodule update --init --recursive'")
|
|
||||||
endif()
|
|
||||||
else()
|
|
||||||
set(CMAKE_MODULE_PATH "${ECM_MODULE_PATH};${CMAKE_MODULE_PATH}")
|
|
||||||
endif()
|
|
||||||
include(CTest)
|
include(CTest)
|
||||||
include(ECMAddTests)
|
include(ECMAddTests)
|
||||||
if(BUILD_TESTING)
|
if(BUILD_TESTING)
|
||||||
@ -138,8 +81,8 @@ set(Launcher_NEWS_OPEN_URL "https://prismlauncher.org/news" CACHE STRING "URL th
|
|||||||
set(Launcher_HELP_URL "https://prismlauncher.org/wiki/help-pages/%1" CACHE STRING "URL (with arg %1 to be substituted with page-id) that gets opened when the user requests help")
|
set(Launcher_HELP_URL "https://prismlauncher.org/wiki/help-pages/%1" CACHE STRING "URL (with arg %1 to be substituted with page-id) that gets opened when the user requests help")
|
||||||
|
|
||||||
######## Set version numbers ########
|
######## Set version numbers ########
|
||||||
set(Launcher_VERSION_MAJOR 6)
|
set(Launcher_VERSION_MAJOR 5)
|
||||||
set(Launcher_VERSION_MINOR 3)
|
set(Launcher_VERSION_MINOR 2)
|
||||||
|
|
||||||
set(Launcher_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}")
|
set(Launcher_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}")
|
||||||
set(Launcher_VERSION_NAME4 "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.0.0")
|
set(Launcher_VERSION_NAME4 "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.0.0")
|
||||||
@ -208,16 +151,6 @@ set(Launcher_BUILD_TIMESTAMP "${TODAY}")
|
|||||||
|
|
||||||
################################ 3rd Party Libs ################################
|
################################ 3rd Party Libs ################################
|
||||||
|
|
||||||
# Successive configurations of cmake without cleaning the build dir will cause zlib fallback to fail due to cached values
|
|
||||||
# Record when fallback triggered and skip this find_package
|
|
||||||
if(NOT Launcher_FORCE_BUNDLED_LIBS AND NOT FORCE_BUNDLED_ZLIB)
|
|
||||||
find_package(ZLIB QUIET)
|
|
||||||
endif()
|
|
||||||
if(NOT ZLIB_FOUND)
|
|
||||||
set(FORCE_BUNDLED_ZLIB TRUE CACHE BOOL "")
|
|
||||||
mark_as_advanced(FORCE_BUNDLED_ZLIB)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Find the required Qt parts
|
# Find the required Qt parts
|
||||||
include(QtVersionlessBackport)
|
include(QtVersionlessBackport)
|
||||||
if(Launcher_QT_VERSION_MAJOR EQUAL 5)
|
if(Launcher_QT_VERSION_MAJOR EQUAL 5)
|
||||||
@ -236,7 +169,7 @@ if(Launcher_QT_VERSION_MAJOR EQUAL 5)
|
|||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUNICODE -D_UNICODE")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUNICODE -D_UNICODE")
|
||||||
elseif(Launcher_QT_VERSION_MAJOR EQUAL 6)
|
elseif(Launcher_QT_VERSION_MAJOR EQUAL 6)
|
||||||
set(QT_VERSION_MAJOR 6)
|
set(QT_VERSION_MAJOR 6)
|
||||||
find_package(Qt6 REQUIRED COMPONENTS Core CoreTools Widgets Concurrent Network Test Xml Core5Compat)
|
find_package(Qt6 REQUIRED COMPONENTS Core Widgets Concurrent Network Test Xml Core5Compat)
|
||||||
list(APPEND Launcher_QT_LIBS Qt6::Core5Compat)
|
list(APPEND Launcher_QT_LIBS Qt6::Core5Compat)
|
||||||
|
|
||||||
if(NOT Launcher_FORCE_BUNDLED_LIBS)
|
if(NOT Launcher_FORCE_BUNDLED_LIBS)
|
||||||
@ -250,16 +183,12 @@ else()
|
|||||||
message(FATAL_ERROR "Qt version ${Launcher_QT_VERSION_MAJOR} is not supported")
|
message(FATAL_ERROR "Qt version ${Launcher_QT_VERSION_MAJOR} is not supported")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(Launcher_QT_VERSION_MAJOR EQUAL 5)
|
include(ECMQueryQt)
|
||||||
include(ECMQueryQt)
|
ecm_query_qt(QT_PLUGINS_DIR QT_INSTALL_PLUGINS)
|
||||||
ecm_query_qt(QT_PLUGINS_DIR QT_INSTALL_PLUGINS)
|
ecm_query_qt(QT_LIBS_DIR QT_INSTALL_LIBS)
|
||||||
ecm_query_qt(QT_LIBS_DIR QT_INSTALL_LIBS)
|
ecm_query_qt(QT_LIBEXECS_DIR QT_INSTALL_LIBEXECS)
|
||||||
ecm_query_qt(QT_LIBEXECS_DIR QT_INSTALL_LIBEXECS)
|
ecm_query_qt(QT_DATA_DIR QT_HOST_DATA)
|
||||||
else()
|
set(QT_MKSPECS_DIR ${QT_DATA_DIR}/mkspecs)
|
||||||
set(QT_PLUGINS_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_PLUGINS})
|
|
||||||
set(QT_LIBS_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_LIBS})
|
|
||||||
set(QT_LIBEXECS_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_LIBEXECS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# NOTE: Qt 6 already sets this by default
|
# NOTE: Qt 6 already sets this by default
|
||||||
if (Qt5_POSITION_INDEPENDENT_CODE)
|
if (Qt5_POSITION_INDEPENDENT_CODE)
|
||||||
@ -274,8 +203,6 @@ if(NOT Launcher_FORCE_BUNDLED_LIBS)
|
|||||||
find_package(ghc_filesystem QUIET)
|
find_package(ghc_filesystem QUIET)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include(ECMQtDeclareLoggingCategory)
|
|
||||||
|
|
||||||
####################################### Program Info #######################################
|
####################################### Program Info #######################################
|
||||||
|
|
||||||
set(Launcher_APP_BINARY_NAME "prismlauncher" CACHE STRING "Name of the Launcher binary")
|
set(Launcher_APP_BINARY_NAME "prismlauncher" CACHE STRING "Name of the Launcher binary")
|
||||||
@ -325,11 +252,13 @@ if(UNIX AND APPLE)
|
|||||||
install(FILES ${Launcher_Branding_ICNS} DESTINATION ${RESOURCES_DEST_DIR} RENAME ${Launcher_Name}.icns)
|
install(FILES ${Launcher_Branding_ICNS} DESTINATION ${RESOURCES_DEST_DIR} RENAME ${Launcher_Name}.icns)
|
||||||
|
|
||||||
elseif(UNIX)
|
elseif(UNIX)
|
||||||
include(KDEInstallDirs)
|
|
||||||
|
|
||||||
set(BINARY_DEST_DIR "bin")
|
set(BINARY_DEST_DIR "bin")
|
||||||
set(LIBRARY_DEST_DIR "lib${LIB_SUFFIX}")
|
set(LIBRARY_DEST_DIR "lib${LIB_SUFFIX}")
|
||||||
set(JARS_DEST_DIR "share/${Launcher_APP_BINARY_NAME}")
|
set(JARS_DEST_DIR "share/${Launcher_APP_BINARY_NAME}")
|
||||||
|
set(LAUNCHER_DESKTOP_DEST_DIR "share/applications" CACHE STRING "Path to the desktop file directory")
|
||||||
|
set(LAUNCHER_METAINFO_DEST_DIR "share/metainfo" CACHE STRING "Path to the metainfo directory")
|
||||||
|
set(LAUNCHER_ICON_DEST_DIR "share/icons/hicolor/scalable/apps" CACHE STRING "Path to the scalable icon directory")
|
||||||
|
set(LAUNCHER_MAN_DEST_DIR "share/man/man6" CACHE STRING "Path to the man page directory")
|
||||||
|
|
||||||
# install as bundle with no dependencies included
|
# install as bundle with no dependencies included
|
||||||
set(INSTALL_BUNDLE "nodeps")
|
set(INSTALL_BUNDLE "nodeps")
|
||||||
@ -337,13 +266,12 @@ elseif(UNIX)
|
|||||||
# Set RPATH
|
# Set RPATH
|
||||||
SET(Launcher_BINARY_RPATH "$ORIGIN/")
|
SET(Launcher_BINARY_RPATH "$ORIGIN/")
|
||||||
|
|
||||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_Desktop} DESTINATION ${KDE_INSTALL_APPDIR})
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_Desktop} DESTINATION ${LAUNCHER_DESKTOP_DEST_DIR})
|
||||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_MetaInfo} DESTINATION ${KDE_INSTALL_METAINFODIR})
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_MetaInfo} DESTINATION ${LAUNCHER_METAINFO_DEST_DIR})
|
||||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_SVG} DESTINATION "${KDE_INSTALL_ICONDIR}/hicolor/scalable/apps")
|
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_SVG} DESTINATION ${LAUNCHER_ICON_DEST_DIR})
|
||||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_mrpack_MIMEInfo} DESTINATION ${KDE_INSTALL_MIMEDIR})
|
|
||||||
|
|
||||||
if(Launcher_ManPage)
|
if(Launcher_ManPage)
|
||||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_ManPage} DESTINATION "${KDE_INSTALL_MANDIR}/man6")
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_ManPage} DESTINATION ${LAUNCHER_MAN_DEST_DIR})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Install basic runner script if component "portable" is selected
|
# Install basic runner script if component "portable" is selected
|
||||||
@ -383,32 +311,6 @@ 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
|
||||||
if(FORCE_BUNDLED_ZLIB)
|
|
||||||
message(STATUS "Using bundled zlib")
|
|
||||||
|
|
||||||
set(CMAKE_POLICY_DEFAULT_CMP0069 NEW) # Suppress cmake warnings and allow INTERPROCEDURAL_OPTIMIZATION for zlib
|
|
||||||
set(SKIP_INSTALL_ALL ON)
|
|
||||||
add_subdirectory(libraries/zlib EXCLUDE_FROM_ALL)
|
|
||||||
|
|
||||||
# On OS where unistd.h exists, zlib's generated header defines `Z_HAVE_UNISTD_H`, while the included header does not.
|
|
||||||
# We cannot safely undo the rename on those systems, and they generally have packages for zlib anyway.
|
|
||||||
check_include_file(unistd.h NEED_GENERATED_ZCONF)
|
|
||||||
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/libraries/zlib/zconf.h.included" AND NOT NEED_GENERATED_ZCONF)
|
|
||||||
# zlib's cmake script renames a file, dirtying the submodule, see https://github.com/madler/zlib/issues/162
|
|
||||||
message(STATUS "Undoing Rename")
|
|
||||||
message(STATUS " ${CMAKE_CURRENT_SOURCE_DIR}/libraries/zlib/zconf.h")
|
|
||||||
file(RENAME "${CMAKE_CURRENT_SOURCE_DIR}/libraries/zlib/zconf.h.included" "${CMAKE_CURRENT_SOURCE_DIR}/libraries/zlib/zconf.h")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(ZLIB_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/libraries/zlib" "${CMAKE_CURRENT_SOURCE_DIR}/libraries/zlib" CACHE STRING "" FORCE)
|
|
||||||
set_target_properties(zlibstatic PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${ZLIB_INCLUDE_DIR}")
|
|
||||||
add_library(ZLIB::ZLIB ALIAS zlibstatic)
|
|
||||||
set(ZLIB_LIBRARY ZLIB::ZLIB CACHE STRING "zlib library name")
|
|
||||||
|
|
||||||
find_package(ZLIB REQUIRED)
|
|
||||||
else()
|
|
||||||
message(STATUS "Using system zlib")
|
|
||||||
endif()
|
|
||||||
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.
|
||||||
|
44
COPYING.md
44
COPYING.md
@ -1,7 +1,7 @@
|
|||||||
## Prism Launcher
|
## Prism Launcher
|
||||||
|
|
||||||
Prism Launcher - Minecraft Launcher
|
Prism Launcher - Minecraft Launcher
|
||||||
Copyright (C) 2022-2023 Prism Launcher Contributors
|
Copyright (C) 2022 Prism Launcher Contributors
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@ -398,45 +398,3 @@
|
|||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
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
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
|
|
||||||
## Breeze icons
|
|
||||||
|
|
||||||
Copyright (C) 2014 Uri Herrera <uri_herrera@nitrux.in> and others
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 3 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library 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
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
## Oxygen Icons
|
|
||||||
|
|
||||||
The Oxygen Icon Theme
|
|
||||||
Copyright (C) 2007 Nuno Pinheiro <nuno@oxygen-icons.org>
|
|
||||||
Copyright (C) 2007 David Vignoni <david@icon-king.com>
|
|
||||||
Copyright (C) 2007 David Miller <miller@oxygen-icons.org>
|
|
||||||
Copyright (C) 2007 Johann Ollivier Lapeyre <johann@oxygen-icons.org>
|
|
||||||
Copyright (C) 2007 Kenneth Wimer <kwwii@bootsplash.org>
|
|
||||||
Copyright (C) 2007 Riccardo Iaconelli <riccardo@oxygen-icons.org>
|
|
||||||
|
|
||||||
and others
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Lesser General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 3 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library 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
|
|
||||||
Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
|
||||||
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
91
README.md
91
README.md
@ -1,102 +1,29 @@
|
|||||||
<p align="left">
|
<p align="center">
|
||||||
<picture>
|
<img src="./program_info/org.prismlauncher.PrismLauncher.logo.svg#gh-light-mode-only" alt="Prism Launcher logo" width="50%"/>
|
||||||
<source media="(prefers-color-scheme: dark)" srcset="/program_info/org.prismlauncher.PrismLauncher.logo-darkmode.svg">
|
<img src="./program_info/org.prismlauncher.PrismLauncher.logo-darkmode.svg#gh-dark-mode-only" alt="Prism Launcher logo" width="50%"/>
|
||||||
<source media="(prefers-color-scheme: light)" srcset="/program_info/org.prismlauncher.PrismLauncher.logo.svg">
|
|
||||||
<img alt="Prism Launcher" src="/program_info/org.prismlauncher.PrismLauncher.logo.svg" width="50%">
|
|
||||||
</picture>
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
Prism Launcher is a custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once.
|
Prism Launcher is a custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once.
|
||||||
|
|
||||||
This is a **fork** of the MultiMC Launcher and is not endorsed by MultiMC.
|
We are working on a website and other media, for more info we have a [Discord server](https://discord.gg/prismlauncher).
|
||||||
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
<a href="https://repology.org/project/prismlauncher/versions">
|
- All downloads and instructions for Prism Launcher will soon be available.
|
||||||
<img src="https://repology.org/badge/vertical-allrepos/prismlauncher.svg" alt="Packaging status" align="right">
|
- Last build status can be found [here](https://github.com/PrismLauncher/PrismLauncher/actions).
|
||||||
</a>
|
|
||||||
|
|
||||||
- All downloads and instructions for Prism Launcher can be found on our [Website](https://prismlauncher.org/download/).
|
|
||||||
- Last build status can be found in the [GitHub Actions](https://github.com/PrismLauncher/PrismLauncher/actions).
|
|
||||||
|
|
||||||
### Development Builds
|
### Development Builds
|
||||||
|
|
||||||
There are development builds available [here](https://github.com/PrismLauncher/PrismLauncher/actions). These have debug information in the binaries, so their file sizes are relatively larger.
|
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.
|
||||||
|
|
||||||
Prebuilt Development builds are provided for **Linux**, **Windows** and **macOS**.
|
Portable builds are provided for AppImage on Linux, Windows, and macOS.
|
||||||
|
|
||||||
For **Arch**, **Debian**, **Fedora**, **OpenSUSE (Tumbleweed)** and **Gentoo**, respectively, you can use these packages for the latest development versions:
|
## Help & Support
|
||||||
|
|
||||||
[](https://aur.archlinux.org/packages/prismlauncher-git/) [](https://aur.archlinux.org/packages/prismlauncher-qt5-git/) [](https://mpr.makedeb.org/packages/prismlauncher-git) [](https://copr.fedorainfracloud.org/coprs/g3tchoo/prismlauncher/) [](https://build.opensuse.org/project/show/home:getchoo) [](https://packages.gentoo.org/packages/games-action/prismlauncher)
|
|
||||||
|
|
||||||
## Community & Support
|
[](https://discord.gg/hX4g537UNE)
|
||||||
|
|
||||||
Feel free to create a GitHub issue if you find a bug or want to suggest a new feature. We have multiple community spaces where other community members can help you.
|
|
||||||
|
|
||||||
#### Join our Discord server:
|
|
||||||
[](https://discord.gg/prismlauncher)
|
|
||||||
|
|
||||||
#### Join our Matrix space:
|
|
||||||
[](https://matrix.to/#/#prismlauncher:matrix.org)
|
|
||||||
|
|
||||||
#### Join our Subreddit:
|
|
||||||
[](https://www.reddit.com/r/PrismLauncher/)
|
|
||||||
|
|
||||||
## Building
|
|
||||||
|
|
||||||
If you want to build Prism Launcher yourself, check the [Build Instructions](https://prismlauncher.org/wiki/development/build-instructions/).
|
|
||||||
|
|
||||||
## Translations
|
|
||||||
|
|
||||||
The translation effort for PrismLauncher is hosted on [Weblate](https://hosted.weblate.org/projects/prismlauncher/launcher/) and information about translating Prism Launcher is available at <https://github.com/PrismLauncher/Translations>
|
|
||||||
|
|
||||||
## Forking/Redistributing/Custom builds policy
|
|
||||||
|
|
||||||
We don't care what you do with your fork/custom build as long as you follow the terms of the [license](LICENSE) (this is a legal responsibility), and if you made code changes rather than just packaging a custom build, please do the following as a basic courtesy:
|
|
||||||
|
|
||||||
- Make it clear that your fork is not PrismLauncher and is not endorsed by or affiliated with the PrismLauncher project (<https://prismlauncher.org>).
|
|
||||||
- Go through [CMakeLists.txt](CMakeLists.txt) and change PrismLauncher's API keys to your own or set them to empty strings (`""`) to disable them (this way the program will still compile but the functionality requiring those keys will be disabled).
|
|
||||||
|
|
||||||
If you have any questions or want any clarification on the above conditions please make an issue and ask us.
|
|
||||||
|
|
||||||
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 by setting them to an empty string (`""`).
|
|
||||||
|
|
||||||
## Sponsors & Partners
|
|
||||||
|
|
||||||
We thank all the wonderful backers over at Open Collective! Support Prism Launcher by [becoming a backer](https://opencollective.com/prismlauncher).
|
|
||||||
|
|
||||||
[](https://opencollective.com/prismlauncher#backers)
|
|
||||||
|
|
||||||
Thanks to JetBrains for providing us a few licenses for all their products, as part of their [Open Source program](https://www.jetbrains.com/opensource/).
|
|
||||||
|
|
||||||
[](https://www.jetbrains.com/opensource/)
|
|
||||||
|
|
||||||
Thanks to Weblate for hosting our translation efforts.
|
|
||||||
|
|
||||||
<a href="https://hosted.weblate.org/engage/prismlauncher/">
|
|
||||||
<img src="https://hosted.weblate.org/widgets/prismlauncher/-/open-graph.png" alt="Translation status" width="300" />
|
|
||||||
</a>
|
|
||||||
|
|
||||||
Thanks to Netlify for providing us their excellent web services, as part of their [Open Source program](https://www.netlify.com/open-source/)
|
|
||||||
|
|
||||||
<a href="https://www.netlify.com"> <img src="https://www.netlify.com/v3/img/components/netlify-color-accent.svg" alt="Deploys by Netlify" /> </a>
|
|
||||||
|
|
||||||
Thanks to the awesome people over at [MacStadium](https://www.macstadium.com/), for providing M1-Macs for development purposes!
|
|
||||||
|
|
||||||
<a href="https://www.macstadium.com"><img src="https://uploads-ssl.webflow.com/5ac3c046c82724970fc60918/5c019d917bba312af7553b49_MacStadium-developerlogo.png" alt="Powered by MacStadium" width="300"></a>
|
|
||||||
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
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.
|
|
||||||
|
@ -76,9 +76,7 @@ Config::Config()
|
|||||||
|
|
||||||
// Assume that builds outside of Git repos are "stable"
|
// Assume that builds outside of Git repos are "stable"
|
||||||
if (GIT_REFSPEC == QStringLiteral("GITDIR-NOTFOUND")
|
if (GIT_REFSPEC == QStringLiteral("GITDIR-NOTFOUND")
|
||||||
|| GIT_TAG == QStringLiteral("GITDIR-NOTFOUND")
|
|| GIT_TAG == QStringLiteral("GITDIR-NOTFOUND"))
|
||||||
|| GIT_REFSPEC == QStringLiteral("")
|
|
||||||
|| GIT_TAG == QStringLiteral("GIT-NOTFOUND"))
|
|
||||||
{
|
{
|
||||||
GIT_REFSPEC = "refs/heads/stable";
|
GIT_REFSPEC = "refs/heads/stable";
|
||||||
GIT_TAG = versionString();
|
GIT_TAG = versionString();
|
||||||
|
@ -161,8 +161,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 FLAME_BASE_URL = "https://api.curseforge.com/v1";
|
|
||||||
|
|
||||||
QString versionString() const;
|
QString versionString() const;
|
||||||
/**
|
/**
|
||||||
* \brief Converts the Version to a string.
|
* \brief Converts the Version to a string.
|
||||||
|
@ -44,28 +44,5 @@
|
|||||||
<string>${MACOSX_SPARKLE_UPDATE_PUBLIC_KEY}</string>
|
<string>${MACOSX_SPARKLE_UPDATE_PUBLIC_KEY}</string>
|
||||||
<key>SUFeedURL</key>
|
<key>SUFeedURL</key>
|
||||||
<string>${MACOSX_SPARKLE_UPDATE_FEED_URL}</string>
|
<string>${MACOSX_SPARKLE_UPDATE_FEED_URL}</string>
|
||||||
<key>CFBundleDocumentTypes</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleTypeExtensions</key>
|
|
||||||
<array>
|
|
||||||
<string>zip</string>
|
|
||||||
<string>mrpack</string>
|
|
||||||
</array>
|
|
||||||
<key>CFBundleTypeName</key>
|
|
||||||
<string>Prism Launcher instance</string>
|
|
||||||
<key>CFBundleTypeOSTypes</key>
|
|
||||||
<array>
|
|
||||||
<string>TEXT</string>
|
|
||||||
<string>utxt</string>
|
|
||||||
<string>TUTX</string>
|
|
||||||
<string>****</string>
|
|
||||||
</array>
|
|
||||||
<key>CFBundleTypeRole</key>
|
|
||||||
<string>Viewer</string>
|
|
||||||
<key>LSHandlerRank</key>
|
|
||||||
<string>Alternate</string>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
31
flake.lock
generated
31
flake.lock
generated
@ -3,11 +3,11 @@
|
|||||||
"flake-compat": {
|
"flake-compat": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1668681692,
|
"lastModified": 1650374568,
|
||||||
"narHash": "sha256-Ht91NGdewz8IQLtWZ9LCeNXMSXHUss+9COoqu6JLmXU=",
|
"narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=",
|
||||||
"owner": "edolstra",
|
"owner": "edolstra",
|
||||||
"repo": "flake-compat",
|
"repo": "flake-compat",
|
||||||
"rev": "009399224d5e398d03b22badca40a37ac85412a1",
|
"rev": "b4a34015c698c7793d592d66adbab377907a2be8",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -34,11 +34,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1671417167,
|
"lastModified": 1666057921,
|
||||||
"narHash": "sha256-JkHam6WQOwZN1t2C2sbp1TqMv3TVRjzrdoejqfefwrM=",
|
"narHash": "sha256-VpQqtXdj6G7cH//SvoprjR7XT3KS7p+tCVebGK1N6tE=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "bb31220cca6d044baa6dc2715b07497a2a7c4bc7",
|
"rev": "88eab1e431cabd0ed621428d8b40d425a07af39f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -52,7 +52,24 @@
|
|||||||
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -5,9 +5,10 @@
|
|||||||
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:PrismLauncher/libnbtplusplus"; flake = false; };
|
||||||
|
tomlplusplus = { url = "github:marzer/tomlplusplus"; flake = false; };
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = { self, nixpkgs, libnbtplusplus, ... }:
|
outputs = { self, nixpkgs, libnbtplusplus, tomlplusplus, ... }:
|
||||||
let
|
let
|
||||||
# User-friendly version number.
|
# User-friendly version number.
|
||||||
version = builtins.substring 0 8 self.lastModifiedDate;
|
version = builtins.substring 0 8 self.lastModifiedDate;
|
||||||
@ -22,8 +23,8 @@
|
|||||||
pkgs = forAllSystems (system: nixpkgs.legacyPackages.${system});
|
pkgs = forAllSystems (system: nixpkgs.legacyPackages.${system});
|
||||||
|
|
||||||
packagesFn = pkgs: rec {
|
packagesFn = pkgs: rec {
|
||||||
prismlauncher-qt5 = pkgs.libsForQt5.callPackage ./nix { inherit version self libnbtplusplus; };
|
prismlauncher = pkgs.libsForQt5.callPackage ./nix { inherit version self libnbtplusplus tomlplusplus; };
|
||||||
prismlauncher = pkgs.qt6Packages.callPackage ./nix { inherit version self libnbtplusplus; };
|
prismlauncher-qt6 = pkgs.qt6Packages.callPackage ./nix { inherit version self libnbtplusplus tomlplusplus; };
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
@ -1,83 +0,0 @@
|
|||||||
id: org.prismlauncher.PrismLauncher
|
|
||||||
runtime: org.kde.Platform
|
|
||||||
runtime-version: "5.15-22.08"
|
|
||||||
sdk: org.kde.Sdk
|
|
||||||
sdk-extensions:
|
|
||||||
- org.freedesktop.Sdk.Extension.openjdk17
|
|
||||||
- org.freedesktop.Sdk.Extension.openjdk8
|
|
||||||
add-extensions:
|
|
||||||
com.valvesoftware.Steam.Utility.gamescope:
|
|
||||||
version: stable
|
|
||||||
add-ld-path: lib
|
|
||||||
no-autodownload: true
|
|
||||||
autodelete: false
|
|
||||||
directory: utils/gamescope
|
|
||||||
|
|
||||||
command: prismlauncher
|
|
||||||
finish-args:
|
|
||||||
- --share=ipc
|
|
||||||
- --socket=x11
|
|
||||||
- --socket=wayland
|
|
||||||
- --device=all
|
|
||||||
- --share=network
|
|
||||||
- --socket=pulseaudio
|
|
||||||
# for Discord RPC mods
|
|
||||||
- --filesystem=xdg-run/app/com.discordapp.Discord:create
|
|
||||||
# Mod drag&drop
|
|
||||||
- --filesystem=xdg-download:ro
|
|
||||||
|
|
||||||
modules:
|
|
||||||
- name: prismlauncher
|
|
||||||
buildsystem: cmake-ninja
|
|
||||||
config-opts:
|
|
||||||
- -DLauncher_BUILD_PLATFORM=flatpak
|
|
||||||
- -DCMAKE_BUILD_TYPE=Debug
|
|
||||||
build-options:
|
|
||||||
env:
|
|
||||||
JAVA_HOME: /usr/lib/sdk/openjdk17/jvm/openjdk-17
|
|
||||||
JAVA_COMPILER: /usr/lib/sdk/openjdk17/jvm/openjdk-17/bin/javac
|
|
||||||
sources:
|
|
||||||
- type: dir
|
|
||||||
path: ../
|
|
||||||
- name: openjdk
|
|
||||||
buildsystem: simple
|
|
||||||
build-commands:
|
|
||||||
- mkdir -p /app/jdk/
|
|
||||||
- /usr/lib/sdk/openjdk17/install.sh
|
|
||||||
- mv /app/jre /app/jdk/17
|
|
||||||
- /usr/lib/sdk/openjdk8/install.sh
|
|
||||||
- mv /app/jre /app/jdk/8
|
|
||||||
cleanup: [/jre]
|
|
||||||
- name: xrandr
|
|
||||||
buildsystem: autotools
|
|
||||||
sources:
|
|
||||||
- type: archive
|
|
||||||
url: https://xorg.freedesktop.org/archive/individual/app/xrandr-1.5.1.tar.xz
|
|
||||||
sha256: 7bc76daf9d72f8aff885efad04ce06b90488a1a169d118dea8a2b661832e8762
|
|
||||||
cleanup: [/share/man, /bin/xkeystone]
|
|
||||||
- name: gamemode
|
|
||||||
buildsystem: meson
|
|
||||||
config-opts:
|
|
||||||
- -Dwith-sd-bus-provider=no-daemon
|
|
||||||
- -Dwith-examples=false
|
|
||||||
post-install:
|
|
||||||
# gamemoderun is installed for users who want to use wrapper commands
|
|
||||||
# post-install is running inside the build dir, we need it from the source though
|
|
||||||
- install -Dm755 ../data/gamemoderun -t /app/bin
|
|
||||||
sources:
|
|
||||||
- type: git
|
|
||||||
url: https://github.com/FeralInteractive/gamemode
|
|
||||||
tag: "1.7"
|
|
||||||
commit: 4dc99dff76218718763a6b07fc1900fa6d1dafd9
|
|
||||||
- name: enhance
|
|
||||||
buildsystem: simple
|
|
||||||
build-commands:
|
|
||||||
- mkdir -p /app/utils/gamescope
|
|
||||||
- install -Dm755 prime-run /app/bin/prime-run
|
|
||||||
- mv /app/bin/prismlauncher /app/bin/prismrun
|
|
||||||
- install -Dm755 prismlauncher /app/bin/prismlauncher
|
|
||||||
sources:
|
|
||||||
- type: file
|
|
||||||
path: ../flatpak/prime-run
|
|
||||||
- type: file
|
|
||||||
path: ../flatpak/prismlauncher
|
|
@ -1,4 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
export __NV_PRIME_RENDER_OFFLOAD=1 __VK_LAYER_NV_optimus=NVIDIA_only __GLX_VENDOR_LIBRARY_NAME=nvidia
|
|
||||||
exec "$@"
|
|
@ -1,11 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# discord RPC
|
|
||||||
for i in {0..9}; do
|
|
||||||
test -S "$XDG_RUNTIME_DIR"/discord-ipc-"$i" || ln -sf {app/com.discordapp.Discord,"$XDG_RUNTIME_DIR"}/discord-ipc-"$i";
|
|
||||||
done
|
|
||||||
|
|
||||||
export PATH="${PATH}${PATH:+:}/app/utils/gamescope/bin:/usr/lib/extensions/vulkan/MangoHud/bin"
|
|
||||||
export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}${LD_LIBRARY_PATH:+:}/usr/lib/extensions/vulkan/MangoHud/\$LIB/"
|
|
||||||
|
|
||||||
exec /app/bin/prismrun "$@"
|
|
@ -1,12 +1,8 @@
|
|||||||
// SPDX-FileCopyrightText: 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-only AND Apache-2.0
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prism Launcher - Minecraft Launcher
|
* PolyMC - Minecraft Launcher
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
* Copyright (C) 2022 Lenny McLennington <lenny@sneed.church>
|
* Copyright (C) 2022 Lenny McLennington <lenny@sneed.church>
|
||||||
* Copyright (C) 2022 Tayou <tayou@gmx.net>
|
|
||||||
*
|
*
|
||||||
* 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
|
||||||
@ -41,14 +37,10 @@
|
|||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "BuildConfig.h"
|
#include "BuildConfig.h"
|
||||||
|
|
||||||
#include "DataMigrationTask.h"
|
|
||||||
#include "net/PasteUpload.h"
|
#include "net/PasteUpload.h"
|
||||||
#include "pathmatcher/MultiMatcher.h"
|
|
||||||
#include "pathmatcher/SimplePrefixMatcher.h"
|
|
||||||
#include "ui/MainWindow.h"
|
#include "ui/MainWindow.h"
|
||||||
#include "ui/InstanceWindow.h"
|
#include "ui/InstanceWindow.h"
|
||||||
|
|
||||||
#include "ui/dialogs/ProgressDialog.h"
|
|
||||||
#include "ui/instanceview/AccessibleInstanceView.h"
|
#include "ui/instanceview/AccessibleInstanceView.h"
|
||||||
|
|
||||||
#include "ui/pages/BasePageProvider.h"
|
#include "ui/pages/BasePageProvider.h"
|
||||||
@ -62,6 +54,17 @@
|
|||||||
#include "ui/pages/global/APIPage.h"
|
#include "ui/pages/global/APIPage.h"
|
||||||
#include "ui/pages/global/CustomCommandsPage.h"
|
#include "ui/pages/global/CustomCommandsPage.h"
|
||||||
|
|
||||||
|
#include "ui/themes/ITheme.h"
|
||||||
|
#include "ui/themes/SystemTheme.h"
|
||||||
|
#include "ui/themes/DarkTheme.h"
|
||||||
|
#include "ui/themes/BrightTheme.h"
|
||||||
|
#include "ui/themes/CustomTheme.h"
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
#include "ui/WinDarkmode.h"
|
||||||
|
#include <versionhelpers.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"
|
||||||
@ -71,8 +74,6 @@
|
|||||||
|
|
||||||
#include "ui/pagedialog/PageDialog.h"
|
#include "ui/pagedialog/PageDialog.h"
|
||||||
|
|
||||||
#include "ui/themes/ThemeManager.h"
|
|
||||||
|
|
||||||
#include "ApplicationMessage.h"
|
#include "ApplicationMessage.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@ -92,7 +93,6 @@
|
|||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
|
|
||||||
#include "InstanceList.h"
|
#include "InstanceList.h"
|
||||||
#include "MTPixmapCache.h"
|
|
||||||
|
|
||||||
#include <minecraft/auth/AccountList.h>
|
#include <minecraft/auth/AccountList.h>
|
||||||
#include "icons/IconList.h"
|
#include "icons/IconList.h"
|
||||||
@ -121,7 +121,6 @@
|
|||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include "gamemode_client.h"
|
#include "gamemode_client.h"
|
||||||
#include "MangoHud.h"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@ -138,15 +137,20 @@
|
|||||||
|
|
||||||
static const QLatin1String liveCheckFile("live.check");
|
static const QLatin1String liveCheckFile("live.check");
|
||||||
|
|
||||||
PixmapCache* PixmapCache::s_instance = nullptr;
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
/** This is used so that we can output to the log file in addition to the CLI. */
|
|
||||||
void appDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
|
void appDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
|
||||||
{
|
{
|
||||||
QString out = qFormatLogMessage(type, context, msg);
|
const char *levels = "DWCFIS";
|
||||||
out += QChar::LineFeed;
|
const QString format("%1 %2 %3\n");
|
||||||
|
|
||||||
|
qint64 msecstotal = APPLICATION->timeSinceStart();
|
||||||
|
qint64 seconds = msecstotal / 1000;
|
||||||
|
qint64 msecs = msecstotal % 1000;
|
||||||
|
QString foo;
|
||||||
|
char buf[1025] = {0};
|
||||||
|
::snprintf(buf, 1024, "%5lld.%03lld", seconds, msecs);
|
||||||
|
|
||||||
|
QString out = format.arg(buf).arg(levels[type]).arg(msg);
|
||||||
|
|
||||||
APPLICATION->logFile->write(out.toUtf8());
|
APPLICATION->logFile->write(out.toUtf8());
|
||||||
APPLICATION->logFile->flush();
|
APPLICATION->logFile->flush();
|
||||||
@ -225,7 +229,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
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(QString("%1 %2").arg(BuildConfig.LAUNCHER_DISPLAYNAME, BuildConfig.printableVersionString()));
|
||||||
setApplicationVersion(BuildConfig.printableVersionString() + "\n" + BuildConfig.GIT_COMMIT);
|
setApplicationVersion(BuildConfig.printableVersionString());
|
||||||
setDesktopFileName(BuildConfig.LAUNCHER_DESKTOPFILENAME);
|
setDesktopFileName(BuildConfig.LAUNCHER_DESKTOPFILENAME);
|
||||||
startTime = QDateTime::currentDateTime();
|
startTime = QDateTime::currentDateTime();
|
||||||
|
|
||||||
@ -242,8 +246,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
{{"s", "server"}, "Join the specified server on launch (only valid in combination with --launch)", "address"},
|
{{"s", "server"}, "Join the specified server on launch (only valid in combination with --launch)", "address"},
|
||||||
{{"a", "profile"}, "Use the account specified by its profile name (only valid in combination with --launch)", "profile"},
|
{{"a", "profile"}, "Use the account specified by its profile name (only valid in combination with --launch)", "profile"},
|
||||||
{"alive", "Write a small '" + liveCheckFile + "' file after the launcher starts"},
|
{"alive", "Write a small '" + liveCheckFile + "' file after the launcher starts"},
|
||||||
{{"I", "import"}, "Import instance from specified zip (local path or URL)", "file"},
|
{{"I", "import"}, "Import instance from specified zip (local path or URL)", "file"}
|
||||||
{"show", "Opens the window for the specified instance (by instance ID)", "show"}
|
|
||||||
});
|
});
|
||||||
parser.addHelpOption();
|
parser.addHelpOption();
|
||||||
parser.addVersionOption();
|
parser.addVersionOption();
|
||||||
@ -255,7 +258,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
m_profileToUse = parser.value("profile");
|
m_profileToUse = parser.value("profile");
|
||||||
m_liveCheck = parser.isSet("alive");
|
m_liveCheck = parser.isSet("alive");
|
||||||
m_zipToImport = parser.value("import");
|
m_zipToImport = parser.value("import");
|
||||||
m_instanceIdToShowWindowOf = parser.value("show");
|
|
||||||
|
|
||||||
// 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())
|
||||||
@ -300,6 +302,22 @@ 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
|
||||||
|
// TODO: this should be removed in a future version
|
||||||
|
// TODO: provide a migration path similar to macOS migration
|
||||||
|
QDir bar(FS::PathCombine(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation), "polymc"));
|
||||||
|
if (bar.exists()) {
|
||||||
|
dataPath = bar.absolutePath();
|
||||||
|
adjustedBy = "Legacy data path";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef Q_OS_MACOS
|
#ifndef Q_OS_MACOS
|
||||||
if (QFile::exists(FS::PathCombine(m_rootPath, "portable.txt"))) {
|
if (QFile::exists(FS::PathCombine(m_rootPath, "portable.txt"))) {
|
||||||
dataPath = m_rootPath;
|
dataPath = m_rootPath;
|
||||||
@ -419,26 +437,9 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
qInstallMessageHandler(appDebugOutput);
|
qInstallMessageHandler(appDebugOutput);
|
||||||
|
|
||||||
qSetMessagePattern(
|
|
||||||
"%{time process}" " "
|
|
||||||
"%{if-debug}D%{endif}" "%{if-info}I%{endif}" "%{if-warning}W%{endif}" "%{if-critical}C%{endif}" "%{if-fatal}F%{endif}"
|
|
||||||
" " "|" " "
|
|
||||||
"%{if-category}[%{category}]: %{endif}"
|
|
||||||
"%{message}");
|
|
||||||
|
|
||||||
qDebug() << "<> Log initialized.";
|
qDebug() << "<> Log initialized.";
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
bool migrated = false;
|
|
||||||
|
|
||||||
if (!migrated)
|
|
||||||
migrated = handleDataMigration(dataPath, FS::PathCombine(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation), "../../PolyMC"), "PolyMC", "polymc.cfg");
|
|
||||||
if (!migrated)
|
|
||||||
migrated = handleDataMigration(dataPath, FS::PathCombine(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation), "../../multimc"), "MultiMC", "multimc.cfg");
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
qDebug() << BuildConfig.LAUNCHER_DISPLAYNAME << ", (c) 2013-2021 " << BuildConfig.LAUNCHER_COPYRIGHT;
|
qDebug() << BuildConfig.LAUNCHER_DISPLAYNAME << ", (c) 2013-2021 " << BuildConfig.LAUNCHER_COPYRIGHT;
|
||||||
@ -498,7 +499,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
// Theming
|
// Theming
|
||||||
m_settings->registerSetting("IconTheme", QString("pe_colored"));
|
m_settings->registerSetting("IconTheme", QString("pe_colored"));
|
||||||
m_settings->registerSetting("ApplicationTheme", QString("system"));
|
m_settings->registerSetting("ApplicationTheme", QString("system"));
|
||||||
m_settings->registerSetting("BackgroundCat", QString("kitteh"));
|
|
||||||
|
|
||||||
// Remembered state
|
// Remembered state
|
||||||
m_settings->registerSetting("LastUsedGroupForNewInstance", QString());
|
m_settings->registerSetting("LastUsedGroupForNewInstance", QString());
|
||||||
@ -563,7 +563,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
|
|
||||||
// Memory
|
// Memory
|
||||||
m_settings->registerSetting({"MinMemAlloc", "MinMemoryAlloc"}, 512);
|
m_settings->registerSetting({"MinMemAlloc", "MinMemoryAlloc"}, 512);
|
||||||
m_settings->registerSetting({"MaxMemAlloc", "MaxMemoryAlloc"}, suitableMaxMem());
|
m_settings->registerSetting({"MaxMemAlloc", "MaxMemoryAlloc"}, 4096);
|
||||||
m_settings->registerSetting("PermGen", 128);
|
m_settings->registerSetting("PermGen", 128);
|
||||||
|
|
||||||
// Java Settings
|
// Java Settings
|
||||||
@ -611,8 +611,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
// The cat
|
// The cat
|
||||||
m_settings->registerSetting("TheCat", false);
|
m_settings->registerSetting("TheCat", false);
|
||||||
|
|
||||||
m_settings->registerSetting("ToolbarsLocked", false);
|
|
||||||
|
|
||||||
m_settings->registerSetting("InstSortMode", "Name");
|
m_settings->registerSetting("InstSortMode", "Name");
|
||||||
m_settings->registerSetting("SelectedInstance", QString());
|
m_settings->registerSetting("SelectedInstance", QString());
|
||||||
|
|
||||||
@ -693,9 +691,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
m_globalSettingsProvider->addPage<AccountListPage>();
|
m_globalSettingsProvider->addPage<AccountListPage>();
|
||||||
m_globalSettingsProvider->addPage<APIPage>();
|
m_globalSettingsProvider->addPage<APIPage>();
|
||||||
}
|
}
|
||||||
|
|
||||||
PixmapCache::setInstance(new PixmapCache(this));
|
|
||||||
|
|
||||||
qDebug() << "<> Settings loaded.";
|
qDebug() << "<> Settings loaded.";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -752,8 +747,29 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
qDebug() << "<> Instance icons intialized.";
|
qDebug() << "<> Instance icons intialized.";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Themes
|
// Icon themes
|
||||||
m_themeManager = std::make_unique<ThemeManager>(m_mainWindow);
|
{
|
||||||
|
// TODO: icon themes and instance icons do not mesh well together. Rearrange and fix discrepancies!
|
||||||
|
// set icon theme search path!
|
||||||
|
auto searchPaths = QIcon::themeSearchPaths();
|
||||||
|
searchPaths.append("iconthemes");
|
||||||
|
QIcon::setThemeSearchPaths(searchPaths);
|
||||||
|
qDebug() << "<> Icon themes initialized.";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize widget themes
|
||||||
|
{
|
||||||
|
auto insertTheme = [this](ITheme * theme)
|
||||||
|
{
|
||||||
|
m_themes.insert(std::make_pair(theme->id(), std::unique_ptr<ITheme>(theme)));
|
||||||
|
};
|
||||||
|
auto darkTheme = new DarkTheme();
|
||||||
|
insertTheme(new SystemTheme());
|
||||||
|
insertTheme(darkTheme);
|
||||||
|
insertTheme(new BrightTheme());
|
||||||
|
insertTheme(new CustomTheme(darkTheme, "custom"));
|
||||||
|
qDebug() << "<> Widget themes initialized.";
|
||||||
|
}
|
||||||
|
|
||||||
// initialize and load all instances
|
// initialize and load all instances
|
||||||
{
|
{
|
||||||
@ -918,24 +934,18 @@ bool Application::createSetupWizard()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Application::event(QEvent* event)
|
bool Application::event(QEvent* event) {
|
||||||
{
|
|
||||||
#ifdef Q_OS_MACOS
|
#ifdef Q_OS_MACOS
|
||||||
if (event->type() == QEvent::ApplicationStateChange) {
|
if (event->type() == QEvent::ApplicationStateChange) {
|
||||||
auto ev = static_cast<QApplicationStateChangeEvent*>(event);
|
auto ev = static_cast<QApplicationStateChangeEvent*>(event);
|
||||||
|
|
||||||
if (m_prevAppState == Qt::ApplicationActive && ev->applicationState() == Qt::ApplicationActive) {
|
if (m_prevAppState == Qt::ApplicationActive
|
||||||
|
&& ev->applicationState() == Qt::ApplicationActive) {
|
||||||
emit clickedOnDock();
|
emit clickedOnDock();
|
||||||
}
|
}
|
||||||
m_prevAppState = ev->applicationState();
|
m_prevAppState = ev->applicationState();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (event->type() == QEvent::FileOpen) {
|
|
||||||
auto ev = static_cast<QFileOpenEvent*>(event);
|
|
||||||
m_mainWindow->droppedURLs({ ev->url() });
|
|
||||||
}
|
|
||||||
|
|
||||||
return QApplication::event(event);
|
return QApplication::event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -977,16 +987,6 @@ void Application::performMainStartupAction()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!m_instanceIdToShowWindowOf.isEmpty())
|
|
||||||
{
|
|
||||||
auto inst = instances()->getInstanceById(m_instanceIdToShowWindowOf);
|
|
||||||
if(inst)
|
|
||||||
{
|
|
||||||
qDebug() << "<> Showing window of instance " << m_instanceIdToShowWindowOf;
|
|
||||||
showInstanceWindow(inst);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!m_mainWindow)
|
if(!m_mainWindow)
|
||||||
{
|
{
|
||||||
// normal main window
|
// normal main window
|
||||||
@ -1113,19 +1113,45 @@ std::shared_ptr<JavaInstallList> Application::javalist()
|
|||||||
return m_javalist;
|
return m_javalist;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<ITheme*> Application::getValidApplicationThemes()
|
std::vector<ITheme *> Application::getValidApplicationThemes()
|
||||||
{
|
{
|
||||||
return m_themeManager->getValidApplicationThemes();
|
std::vector<ITheme *> ret;
|
||||||
|
auto iter = m_themes.cbegin();
|
||||||
|
while (iter != m_themes.cend())
|
||||||
|
{
|
||||||
|
ret.push_back((*iter).second.get());
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::setApplicationTheme(const QString& name, bool initial)
|
void Application::setApplicationTheme(const QString& name, bool initial)
|
||||||
{
|
{
|
||||||
m_themeManager->setApplicationTheme(name, initial);
|
auto systemPalette = qApp->palette();
|
||||||
|
auto themeIter = m_themes.find(name);
|
||||||
|
if(themeIter != m_themes.end())
|
||||||
|
{
|
||||||
|
auto & theme = (*themeIter).second;
|
||||||
|
theme->apply(initial);
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
if (m_mainWindow && IsWindows10OrGreater()) {
|
||||||
|
if (QString::compare(theme->id(), "dark") == 0) {
|
||||||
|
WinDarkmode::setDarkWinTitlebar(m_mainWindow->winId(), true);
|
||||||
|
} else {
|
||||||
|
WinDarkmode::setDarkWinTitlebar(m_mainWindow->winId(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qWarning() << "Tried to set invalid theme:" << name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::setIconTheme(const QString& name)
|
void Application::setIconTheme(const QString& name)
|
||||||
{
|
{
|
||||||
m_themeManager->setIconTheme(name);
|
QIcon::setThemeName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
QIcon Application::getThemedIcon(const QString& name)
|
QIcon Application::getThemedIcon(const QString& name)
|
||||||
@ -1348,7 +1374,16 @@ 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 (IsWindows10OrGreater())
|
||||||
|
{
|
||||||
|
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();
|
||||||
@ -1513,8 +1548,17 @@ void Application::updateCapabilities()
|
|||||||
if (gamemode_query_status() >= 0)
|
if (gamemode_query_status() >= 0)
|
||||||
m_capabilities |= SupportsGameMode;
|
m_capabilities |= SupportsGameMode;
|
||||||
|
|
||||||
if (!MangoHud::getLibraryString().isEmpty())
|
{
|
||||||
m_capabilities |= SupportsMangoHud;
|
void *dummy = dlopen("libMangoHud_dlsym.so", RTLD_LAZY);
|
||||||
|
// try normal variant as well
|
||||||
|
if (dummy == NULL)
|
||||||
|
dummy = dlopen("libMangoHud.so", RTLD_LAZY);
|
||||||
|
|
||||||
|
if (dummy != NULL) {
|
||||||
|
dlclose(dummy);
|
||||||
|
m_capabilities |= SupportsMangoHud;
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1525,8 +1569,7 @@ QString Application::getJarPath(QString jarFile)
|
|||||||
FS::PathCombine(m_rootPath, "share/" + BuildConfig.LAUNCHER_APP_BINARY_NAME),
|
FS::PathCombine(m_rootPath, "share/" + BuildConfig.LAUNCHER_APP_BINARY_NAME),
|
||||||
#endif
|
#endif
|
||||||
FS::PathCombine(m_rootPath, "jars"),
|
FS::PathCombine(m_rootPath, "jars"),
|
||||||
FS::PathCombine(applicationDirPath(), "jars"),
|
FS::PathCombine(applicationDirPath(), "jars")
|
||||||
FS::PathCombine(applicationDirPath(), "..", "jars") // from inside build dir, for debuging
|
|
||||||
};
|
};
|
||||||
for(QString p : potentialPaths)
|
for(QString p : potentialPaths)
|
||||||
{
|
{
|
||||||
@ -1577,102 +1620,3 @@ QString Application::getUserAgentUncached()
|
|||||||
|
|
||||||
return BuildConfig.USER_AGENT_UNCACHED;
|
return BuildConfig.USER_AGENT_UNCACHED;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Application::suitableMaxMem()
|
|
||||||
{
|
|
||||||
float totalRAM = (float)Sys::getSystemRam() / (float)Sys::mebibyte;
|
|
||||||
int maxMemoryAlloc;
|
|
||||||
|
|
||||||
// If totalRAM < 6GB, use (totalRAM / 1.5), else 4GB
|
|
||||||
if (totalRAM < (4096 * 1.5))
|
|
||||||
maxMemoryAlloc = (int) (totalRAM / 1.5);
|
|
||||||
else
|
|
||||||
maxMemoryAlloc = 4096;
|
|
||||||
|
|
||||||
return maxMemoryAlloc;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Application::handleDataMigration(const QString& currentData,
|
|
||||||
const QString& oldData,
|
|
||||||
const QString& name,
|
|
||||||
const QString& configFile) const
|
|
||||||
{
|
|
||||||
QString nomigratePath = FS::PathCombine(currentData, name + "_nomigrate.txt");
|
|
||||||
QStringList configPaths = { FS::PathCombine(oldData, configFile), FS::PathCombine(oldData, BuildConfig.LAUNCHER_CONFIGFILE) };
|
|
||||||
|
|
||||||
QLocale locale;
|
|
||||||
|
|
||||||
// Is there a valid config at the old location?
|
|
||||||
bool configExists = false;
|
|
||||||
for (QString configPath : configPaths) {
|
|
||||||
configExists |= QFileInfo::exists(configPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!configExists || QFileInfo::exists(nomigratePath)) {
|
|
||||||
qDebug() << "<> No migration needed from" << name;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString message;
|
|
||||||
bool currentExists = QFileInfo::exists(FS::PathCombine(currentData, BuildConfig.LAUNCHER_CONFIGFILE));
|
|
||||||
|
|
||||||
if (currentExists) {
|
|
||||||
message = tr("Old data from %1 was found, but you already have existing data for %2. Sadly you will need to migrate yourself. Do "
|
|
||||||
"you want to be reminded of the pending data migration next time you start %2?")
|
|
||||||
.arg(name, BuildConfig.LAUNCHER_DISPLAYNAME);
|
|
||||||
} else {
|
|
||||||
message = tr("It looks like you used %1 before. Do you want to migrate your data to the new location of %2?")
|
|
||||||
.arg(name, BuildConfig.LAUNCHER_DISPLAYNAME);
|
|
||||||
|
|
||||||
QFileInfo logInfo(FS::PathCombine(oldData, name + "-0.log"));
|
|
||||||
if (logInfo.exists()) {
|
|
||||||
QString lastModified = logInfo.lastModified().toString(locale.dateFormat());
|
|
||||||
message = tr("It looks like you used %1 on %2 before. Do you want to migrate your data to the new location of %3?")
|
|
||||||
.arg(name, lastModified, BuildConfig.LAUNCHER_DISPLAYNAME);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QMessageBox::StandardButton askMoveDialogue =
|
|
||||||
QMessageBox::question(nullptr, BuildConfig.LAUNCHER_DISPLAYNAME, message, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
|
||||||
|
|
||||||
auto setDoNotMigrate = [&nomigratePath] {
|
|
||||||
QFile file(nomigratePath);
|
|
||||||
file.open(QIODevice::WriteOnly);
|
|
||||||
};
|
|
||||||
|
|
||||||
// create no-migrate file if user doesn't want to migrate
|
|
||||||
if (askMoveDialogue != QMessageBox::Yes) {
|
|
||||||
qDebug() << "<> Migration declined for" << name;
|
|
||||||
setDoNotMigrate();
|
|
||||||
return currentExists; // cancel further migrations, if we already have a data directory
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!currentExists) {
|
|
||||||
// Migrate!
|
|
||||||
auto matcher = std::make_shared<MultiMatcher>();
|
|
||||||
matcher->add(std::make_shared<SimplePrefixMatcher>(configFile));
|
|
||||||
matcher->add(std::make_shared<SimplePrefixMatcher>(
|
|
||||||
BuildConfig.LAUNCHER_CONFIGFILE)); // it's possible that we already used that directory before
|
|
||||||
matcher->add(std::make_shared<SimplePrefixMatcher>("accounts.json"));
|
|
||||||
matcher->add(std::make_shared<SimplePrefixMatcher>("accounts/"));
|
|
||||||
matcher->add(std::make_shared<SimplePrefixMatcher>("assets/"));
|
|
||||||
matcher->add(std::make_shared<SimplePrefixMatcher>("icons/"));
|
|
||||||
matcher->add(std::make_shared<SimplePrefixMatcher>("instances/"));
|
|
||||||
matcher->add(std::make_shared<SimplePrefixMatcher>("libraries/"));
|
|
||||||
matcher->add(std::make_shared<SimplePrefixMatcher>("mods/"));
|
|
||||||
matcher->add(std::make_shared<SimplePrefixMatcher>("themes/"));
|
|
||||||
|
|
||||||
ProgressDialog diag;
|
|
||||||
DataMigrationTask task(nullptr, oldData, currentData, matcher);
|
|
||||||
if (diag.execWithTask(&task)) {
|
|
||||||
qDebug() << "<> Migration succeeded";
|
|
||||||
setDoNotMigrate();
|
|
||||||
} else {
|
|
||||||
QString reason = task.failReason();
|
|
||||||
QMessageBox::critical(nullptr, BuildConfig.LAUNCHER_DISPLAYNAME, tr("Migration failed! Reason: %1").arg(reason));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
qWarning() << "<> Migration was skipped, due to existing data";
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
/*
|
/*
|
||||||
* Prism Launcher - Minecraft Launcher
|
* PolyMC - Minecraft Launcher
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
* Copyright (C) 2022 Tayou <tayou@gmx.net>
|
|
||||||
*
|
*
|
||||||
* 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
|
||||||
@ -69,7 +68,6 @@ class BaseDetachedToolFactory;
|
|||||||
class TranslationsModel;
|
class TranslationsModel;
|
||||||
class ITheme;
|
class ITheme;
|
||||||
class MCEditTool;
|
class MCEditTool;
|
||||||
class ThemeManager;
|
|
||||||
|
|
||||||
namespace Meta {
|
namespace Meta {
|
||||||
class Index;
|
class Index;
|
||||||
@ -120,7 +118,7 @@ public:
|
|||||||
|
|
||||||
void setIconTheme(const QString& name);
|
void setIconTheme(const QString& name);
|
||||||
|
|
||||||
QList<ITheme*> getValidApplicationThemes();
|
std::vector<ITheme *> getValidApplicationThemes();
|
||||||
|
|
||||||
void setApplicationTheme(const QString& name, bool initial);
|
void setApplicationTheme(const QString& name, bool initial);
|
||||||
|
|
||||||
@ -200,8 +198,6 @@ public:
|
|||||||
|
|
||||||
void ShowGlobalSettings(class QWidget * parent, QString open_page = QString());
|
void ShowGlobalSettings(class QWidget * parent, QString open_page = QString());
|
||||||
|
|
||||||
int suitableMaxMem();
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void updateAllowedChanged(bool status);
|
void updateAllowedChanged(bool status);
|
||||||
void globalSettingsAboutToOpen();
|
void globalSettingsAboutToOpen();
|
||||||
@ -231,7 +227,6 @@ private slots:
|
|||||||
void setupWizardFinished(int status);
|
void setupWizardFinished(int status);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool handleDataMigration(const QString & currentData, const QString & oldData, const QString & name, const QString & configFile) const;
|
|
||||||
bool createSetupWizard();
|
bool createSetupWizard();
|
||||||
void performMainStartupAction();
|
void performMainStartupAction();
|
||||||
|
|
||||||
@ -260,9 +255,9 @@ private:
|
|||||||
std::shared_ptr<JavaInstallList> m_javalist;
|
std::shared_ptr<JavaInstallList> m_javalist;
|
||||||
std::shared_ptr<TranslationsModel> m_translations;
|
std::shared_ptr<TranslationsModel> m_translations;
|
||||||
std::shared_ptr<GenericPageProvider> m_globalSettingsProvider;
|
std::shared_ptr<GenericPageProvider> m_globalSettingsProvider;
|
||||||
|
std::map<QString, std::unique_ptr<ITheme>> m_themes;
|
||||||
std::unique_ptr<MCEditTool> m_mcedit;
|
std::unique_ptr<MCEditTool> m_mcedit;
|
||||||
QSet<QString> m_features;
|
QSet<QString> m_features;
|
||||||
std::unique_ptr<ThemeManager> m_themeManager;
|
|
||||||
|
|
||||||
QMap<QString, std::shared_ptr<BaseProfilerFactory>> m_profilers;
|
QMap<QString, std::shared_ptr<BaseProfilerFactory>> m_profilers;
|
||||||
|
|
||||||
@ -304,7 +299,6 @@ public:
|
|||||||
QString m_profileToUse;
|
QString m_profileToUse;
|
||||||
bool m_liveCheck = false;
|
bool m_liveCheck = false;
|
||||||
QUrl m_zipToImport;
|
QUrl m_zipToImport;
|
||||||
QString m_instanceIdToShowWindowOf;
|
|
||||||
std::unique_ptr<QFile> logFile;
|
std::unique_ptr<QFile> logFile;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -47,8 +47,8 @@ void ApplicationMessage::parse(const QByteArray & input) {
|
|||||||
args.clear();
|
args.clear();
|
||||||
|
|
||||||
auto parsedArgs = root.value("args").toObject();
|
auto parsedArgs = root.value("args").toObject();
|
||||||
for(auto iter = parsedArgs.constBegin(); iter != parsedArgs.constEnd(); iter++) {
|
for(auto iter = parsedArgs.begin(); iter != parsedArgs.end(); iter++) {
|
||||||
args.insert(iter.key(), iter.value().toString());
|
args[iter.key()] = iter.value().toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,8 +56,8 @@ QByteArray ApplicationMessage::serialize() {
|
|||||||
QJsonObject root;
|
QJsonObject root;
|
||||||
root.insert("command", command);
|
root.insert("command", command);
|
||||||
QJsonObject outArgs;
|
QJsonObject outArgs;
|
||||||
for (auto iter = args.constBegin(); iter != args.constEnd(); iter++) {
|
for (auto iter = args.begin(); iter != args.end(); iter++) {
|
||||||
outArgs.insert(iter.key(), iter.value());
|
outArgs[iter.key()] = iter.value();
|
||||||
}
|
}
|
||||||
root.insert("args", outArgs);
|
root.insert("args", outArgs);
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QHash>
|
#include <QMap>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
|
|
||||||
struct ApplicationMessage {
|
struct ApplicationMessage {
|
||||||
QString command;
|
QString command;
|
||||||
QHash<QString, QString> args;
|
QMap<QString, QString> args;
|
||||||
|
|
||||||
QByteArray serialize();
|
QByteArray serialize();
|
||||||
void parse(const QByteArray & input);
|
void parse(const QByteArray & input);
|
||||||
|
@ -151,7 +151,7 @@ public:
|
|||||||
void copyManagedPack(BaseInstance& other);
|
void copyManagedPack(BaseInstance& other);
|
||||||
|
|
||||||
/// guess log level from a line of game log
|
/// guess log level from a line of game log
|
||||||
virtual MessageLevel::Enum guessLevel([[maybe_unused]] const QString &line, MessageLevel::Enum level)
|
virtual MessageLevel::Enum guessLevel(const QString &line, MessageLevel::Enum level)
|
||||||
{
|
{
|
||||||
return level;
|
return level;
|
||||||
};
|
};
|
||||||
|
@ -95,12 +95,12 @@ BaseVersionList::RoleList BaseVersionList::providesRoles() const
|
|||||||
int BaseVersionList::rowCount(const QModelIndex &parent) const
|
int BaseVersionList::rowCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
// Return count
|
// Return count
|
||||||
return parent.isValid() ? 0 : count();
|
return count();
|
||||||
}
|
}
|
||||||
|
|
||||||
int BaseVersionList::columnCount(const QModelIndex &parent) const
|
int BaseVersionList::columnCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
return parent.isValid() ? 0 : 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
QHash<int, QByteArray> BaseVersionList::roleNames() const
|
QHash<int, QByteArray> BaseVersionList::roleNames() const
|
||||||
|
@ -31,8 +31,6 @@ set(CORE_SOURCES
|
|||||||
# Basic instance manipulation tasks (derived from InstanceTask)
|
# Basic instance manipulation tasks (derived from InstanceTask)
|
||||||
InstanceCreationTask.h
|
InstanceCreationTask.h
|
||||||
InstanceCreationTask.cpp
|
InstanceCreationTask.cpp
|
||||||
InstanceCopyPrefs.h
|
|
||||||
InstanceCopyPrefs.cpp
|
|
||||||
InstanceCopyTask.h
|
InstanceCopyTask.h
|
||||||
InstanceCopyTask.cpp
|
InstanceCopyTask.cpp
|
||||||
InstanceImportTask.h
|
InstanceImportTask.h
|
||||||
@ -89,18 +87,7 @@ set(CORE_SOURCES
|
|||||||
# Time
|
# Time
|
||||||
MMCTime.h
|
MMCTime.h
|
||||||
MMCTime.cpp
|
MMCTime.cpp
|
||||||
|
|
||||||
MTPixmapCache.h
|
|
||||||
)
|
)
|
||||||
if (UNIX AND NOT CYGWIN AND NOT APPLE)
|
|
||||||
set(CORE_SOURCES
|
|
||||||
${CORE_SOURCES}
|
|
||||||
|
|
||||||
# MangoHud
|
|
||||||
MangoHud.h
|
|
||||||
MangoHud.cpp
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(PATHMATCHER_SOURCES
|
set(PATHMATCHER_SOURCES
|
||||||
# Path matchers
|
# Path matchers
|
||||||
@ -108,7 +95,6 @@ set(PATHMATCHER_SOURCES
|
|||||||
pathmatcher/IPathMatcher.h
|
pathmatcher/IPathMatcher.h
|
||||||
pathmatcher/MultiMatcher.h
|
pathmatcher/MultiMatcher.h
|
||||||
pathmatcher/RegexpMatcher.h
|
pathmatcher/RegexpMatcher.h
|
||||||
pathmatcher/SimplePrefixMatcher.h
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(NET_SOURCES
|
set(NET_SOURCES
|
||||||
@ -551,26 +537,11 @@ set(ATLAUNCHER_SOURCES
|
|||||||
modplatform/atlauncher/ATLShareCode.h
|
modplatform/atlauncher/ATLShareCode.h
|
||||||
)
|
)
|
||||||
|
|
||||||
######## Logging categories ########
|
|
||||||
|
|
||||||
ecm_qt_declare_logging_category(CORE_SOURCES
|
|
||||||
HEADER Logging.h
|
|
||||||
IDENTIFIER authCredentials
|
|
||||||
CATEGORY_NAME "launcher.auth.credentials"
|
|
||||||
DEFAULT_SEVERITY Warning
|
|
||||||
DESCRIPTION "Secrets and credentials for debugging purposes"
|
|
||||||
EXPORT "${Launcher_Name}"
|
|
||||||
)
|
|
||||||
|
|
||||||
if(KDE_INSTALL_LOGGINGCATEGORIESDIR) # only install if there is a standard path for this
|
|
||||||
ecm_qt_install_logging_categories(
|
|
||||||
EXPORT "${Launcher_Name}"
|
|
||||||
DESTINATION "${KDE_INSTALL_LOGGINGCATEGORIESDIR}"
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
################################ COMPILE ################################
|
################################ COMPILE ################################
|
||||||
|
|
||||||
|
# we need zlib
|
||||||
|
find_package(ZLIB REQUIRED)
|
||||||
|
|
||||||
set(LOGIC_SOURCES
|
set(LOGIC_SOURCES
|
||||||
${CORE_SOURCES}
|
${CORE_SOURCES}
|
||||||
${PATHMATCHER_SOURCES}
|
${PATHMATCHER_SOURCES}
|
||||||
@ -605,8 +576,6 @@ SET(LAUNCHER_SOURCES
|
|||||||
# Application base
|
# Application base
|
||||||
Application.h
|
Application.h
|
||||||
Application.cpp
|
Application.cpp
|
||||||
DataMigrationTask.h
|
|
||||||
DataMigrationTask.cpp
|
|
||||||
UpdateController.cpp
|
UpdateController.cpp
|
||||||
UpdateController.h
|
UpdateController.h
|
||||||
ApplicationMessage.h
|
ApplicationMessage.h
|
||||||
@ -630,12 +599,9 @@ SET(LAUNCHER_SOURCES
|
|||||||
resources/pe_light/pe_light.qrc
|
resources/pe_light/pe_light.qrc
|
||||||
resources/pe_colored/pe_colored.qrc
|
resources/pe_colored/pe_colored.qrc
|
||||||
resources/pe_blue/pe_blue.qrc
|
resources/pe_blue/pe_blue.qrc
|
||||||
resources/breeze_dark/breeze_dark.qrc
|
|
||||||
resources/breeze_light/breeze_light.qrc
|
|
||||||
resources/OSX/OSX.qrc
|
resources/OSX/OSX.qrc
|
||||||
resources/iOS/iOS.qrc
|
resources/iOS/iOS.qrc
|
||||||
resources/flat/flat.qrc
|
resources/flat/flat.qrc
|
||||||
resources/flat_white/flat_white.qrc
|
|
||||||
resources/documents/documents.qrc
|
resources/documents/documents.qrc
|
||||||
../${Launcher_Branding_LogoQRC}
|
../${Launcher_Branding_LogoQRC}
|
||||||
|
|
||||||
@ -683,8 +649,6 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/themes/ITheme.h
|
ui/themes/ITheme.h
|
||||||
ui/themes/SystemTheme.cpp
|
ui/themes/SystemTheme.cpp
|
||||||
ui/themes/SystemTheme.h
|
ui/themes/SystemTheme.h
|
||||||
ui/themes/ThemeManager.cpp
|
|
||||||
ui/themes/ThemeManager.h
|
|
||||||
|
|
||||||
# Processes
|
# Processes
|
||||||
LaunchController.h
|
LaunchController.h
|
||||||
@ -709,8 +673,6 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/pages/instance/GameOptionsPage.h
|
ui/pages/instance/GameOptionsPage.h
|
||||||
ui/pages/instance/VersionPage.cpp
|
ui/pages/instance/VersionPage.cpp
|
||||||
ui/pages/instance/VersionPage.h
|
ui/pages/instance/VersionPage.h
|
||||||
ui/pages/instance/ManagedPackPage.cpp
|
|
||||||
ui/pages/instance/ManagedPackPage.h
|
|
||||||
ui/pages/instance/TexturePackPage.h
|
ui/pages/instance/TexturePackPage.h
|
||||||
ui/pages/instance/ResourcePackPage.h
|
ui/pages/instance/ResourcePackPage.h
|
||||||
ui/pages/instance/ShaderPackPage.h
|
ui/pages/instance/ShaderPackPage.h
|
||||||
@ -827,8 +789,6 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/dialogs/ExportInstanceDialog.h
|
ui/dialogs/ExportInstanceDialog.h
|
||||||
ui/dialogs/IconPickerDialog.cpp
|
ui/dialogs/IconPickerDialog.cpp
|
||||||
ui/dialogs/IconPickerDialog.h
|
ui/dialogs/IconPickerDialog.h
|
||||||
ui/dialogs/ImportResourcePackDialog.cpp
|
|
||||||
ui/dialogs/ImportResourcePackDialog.h
|
|
||||||
ui/dialogs/LoginDialog.cpp
|
ui/dialogs/LoginDialog.cpp
|
||||||
ui/dialogs/LoginDialog.h
|
ui/dialogs/LoginDialog.h
|
||||||
ui/dialogs/MSALoginDialog.cpp
|
ui/dialogs/MSALoginDialog.cpp
|
||||||
@ -923,6 +883,16 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/instanceview/VisualGroup.h
|
ui/instanceview/VisualGroup.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
set(LAUNCHER_SOURCES
|
||||||
|
${LAUNCHER_SOURCES}
|
||||||
|
|
||||||
|
# GUI - dark titlebar for Windows 10/11
|
||||||
|
ui/WinDarkmode.h
|
||||||
|
ui/WinDarkmode.cpp
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
qt_wrap_ui(LAUNCHER_UI
|
qt_wrap_ui(LAUNCHER_UI
|
||||||
ui/setupwizard/PasteWizardPage.ui
|
ui/setupwizard/PasteWizardPage.ui
|
||||||
ui/pages/global/AccountListPage.ui
|
ui/pages/global/AccountListPage.ui
|
||||||
@ -940,7 +910,6 @@ qt_wrap_ui(LAUNCHER_UI
|
|||||||
ui/pages/instance/OtherLogsPage.ui
|
ui/pages/instance/OtherLogsPage.ui
|
||||||
ui/pages/instance/InstanceSettingsPage.ui
|
ui/pages/instance/InstanceSettingsPage.ui
|
||||||
ui/pages/instance/VersionPage.ui
|
ui/pages/instance/VersionPage.ui
|
||||||
ui/pages/instance/ManagedPackPage.ui
|
|
||||||
ui/pages/instance/WorldListPage.ui
|
ui/pages/instance/WorldListPage.ui
|
||||||
ui/pages/instance/ScreenshotsPage.ui
|
ui/pages/instance/ScreenshotsPage.ui
|
||||||
ui/pages/modplatform/atlauncher/AtlOptionalModDialog.ui
|
ui/pages/modplatform/atlauncher/AtlOptionalModDialog.ui
|
||||||
@ -968,7 +937,6 @@ qt_wrap_ui(LAUNCHER_UI
|
|||||||
ui/dialogs/SkinUploadDialog.ui
|
ui/dialogs/SkinUploadDialog.ui
|
||||||
ui/dialogs/ExportInstanceDialog.ui
|
ui/dialogs/ExportInstanceDialog.ui
|
||||||
ui/dialogs/IconPickerDialog.ui
|
ui/dialogs/IconPickerDialog.ui
|
||||||
ui/dialogs/ImportResourcePackDialog.ui
|
|
||||||
ui/dialogs/MSALoginDialog.ui
|
ui/dialogs/MSALoginDialog.ui
|
||||||
ui/dialogs/OfflineLoginDialog.ui
|
ui/dialogs/OfflineLoginDialog.ui
|
||||||
ui/dialogs/AboutDialog.ui
|
ui/dialogs/AboutDialog.ui
|
||||||
@ -987,8 +955,6 @@ qt_add_resources(LAUNCHER_RESOURCES
|
|||||||
resources/pe_light/pe_light.qrc
|
resources/pe_light/pe_light.qrc
|
||||||
resources/pe_colored/pe_colored.qrc
|
resources/pe_colored/pe_colored.qrc
|
||||||
resources/pe_blue/pe_blue.qrc
|
resources/pe_blue/pe_blue.qrc
|
||||||
resources/breeze_dark/breeze_dark.qrc
|
|
||||||
resources/breeze_light/breeze_light.qrc
|
|
||||||
resources/OSX/OSX.qrc
|
resources/OSX/OSX.qrc
|
||||||
resources/iOS/iOS.qrc
|
resources/iOS/iOS.qrc
|
||||||
resources/flat/flat.qrc
|
resources/flat/flat.qrc
|
||||||
@ -1095,99 +1061,96 @@ if(INSTALL_BUNDLE STREQUAL "full")
|
|||||||
COMPONENT Runtime
|
COMPONENT Runtime
|
||||||
)
|
)
|
||||||
# Bundle plugins
|
# Bundle plugins
|
||||||
# Image formats
|
if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
|
||||||
install(
|
# Image formats
|
||||||
DIRECTORY "${QT_PLUGINS_DIR}/imageformats"
|
|
||||||
CONFIGURATIONS Debug RelWithDebInfo ""
|
|
||||||
DESTINATION ${PLUGIN_DEST_DIR}
|
|
||||||
COMPONENT Runtime
|
|
||||||
REGEX "tga|tiff|mng" EXCLUDE
|
|
||||||
)
|
|
||||||
install(
|
|
||||||
DIRECTORY "${QT_PLUGINS_DIR}/imageformats"
|
|
||||||
CONFIGURATIONS Release MinSizeRel
|
|
||||||
DESTINATION ${PLUGIN_DEST_DIR}
|
|
||||||
COMPONENT Runtime
|
|
||||||
REGEX "tga|tiff|mng" EXCLUDE
|
|
||||||
REGEX "d\\." EXCLUDE
|
|
||||||
REGEX "_debug\\." EXCLUDE
|
|
||||||
REGEX "\\.dSYM" EXCLUDE
|
|
||||||
)
|
|
||||||
# Icon engines
|
|
||||||
install(
|
|
||||||
DIRECTORY "${QT_PLUGINS_DIR}/iconengines"
|
|
||||||
CONFIGURATIONS Debug RelWithDebInfo ""
|
|
||||||
DESTINATION ${PLUGIN_DEST_DIR}
|
|
||||||
COMPONENT Runtime
|
|
||||||
REGEX "fontawesome" EXCLUDE
|
|
||||||
)
|
|
||||||
install(
|
|
||||||
DIRECTORY "${QT_PLUGINS_DIR}/iconengines"
|
|
||||||
CONFIGURATIONS Release MinSizeRel
|
|
||||||
DESTINATION ${PLUGIN_DEST_DIR}
|
|
||||||
COMPONENT Runtime
|
|
||||||
REGEX "fontawesome" EXCLUDE
|
|
||||||
REGEX "d\\." EXCLUDE
|
|
||||||
REGEX "_debug\\." EXCLUDE
|
|
||||||
REGEX "\\.dSYM" EXCLUDE
|
|
||||||
)
|
|
||||||
# Platform plugins
|
|
||||||
install(
|
|
||||||
DIRECTORY "${QT_PLUGINS_DIR}/platforms"
|
|
||||||
CONFIGURATIONS Debug RelWithDebInfo ""
|
|
||||||
DESTINATION ${PLUGIN_DEST_DIR}
|
|
||||||
COMPONENT Runtime
|
|
||||||
REGEX "minimal|linuxfb|offscreen" EXCLUDE
|
|
||||||
)
|
|
||||||
install(
|
|
||||||
DIRECTORY "${QT_PLUGINS_DIR}/platforms"
|
|
||||||
CONFIGURATIONS Release MinSizeRel
|
|
||||||
DESTINATION ${PLUGIN_DEST_DIR}
|
|
||||||
COMPONENT Runtime
|
|
||||||
REGEX "minimal|linuxfb|offscreen" EXCLUDE
|
|
||||||
REGEX "[^2]d\\." EXCLUDE
|
|
||||||
REGEX "_debug\\." EXCLUDE
|
|
||||||
REGEX "\\.dSYM" EXCLUDE
|
|
||||||
)
|
|
||||||
# Style plugins
|
|
||||||
if(EXISTS "${QT_PLUGINS_DIR}/styles")
|
|
||||||
install(
|
install(
|
||||||
DIRECTORY "${QT_PLUGINS_DIR}/styles"
|
DIRECTORY "${QT_PLUGINS_DIR}/imageformats"
|
||||||
CONFIGURATIONS Debug RelWithDebInfo ""
|
|
||||||
DESTINATION ${PLUGIN_DEST_DIR}
|
DESTINATION ${PLUGIN_DEST_DIR}
|
||||||
COMPONENT Runtime
|
COMPONENT Runtime
|
||||||
|
REGEX "tga|tiff|mng" EXCLUDE
|
||||||
)
|
)
|
||||||
|
# Icon engines
|
||||||
install(
|
install(
|
||||||
DIRECTORY "${QT_PLUGINS_DIR}/styles"
|
DIRECTORY "${QT_PLUGINS_DIR}/iconengines"
|
||||||
CONFIGURATIONS Release MinSizeRel
|
|
||||||
DESTINATION ${PLUGIN_DEST_DIR}
|
DESTINATION ${PLUGIN_DEST_DIR}
|
||||||
COMPONENT Runtime
|
COMPONENT Runtime
|
||||||
|
REGEX "fontawesome" EXCLUDE
|
||||||
|
)
|
||||||
|
# Platform plugins
|
||||||
|
install(
|
||||||
|
DIRECTORY "${QT_PLUGINS_DIR}/platforms"
|
||||||
|
DESTINATION ${PLUGIN_DEST_DIR}
|
||||||
|
COMPONENT Runtime
|
||||||
|
REGEX "minimal|linuxfb|offscreen" EXCLUDE
|
||||||
|
)
|
||||||
|
# Style plugins
|
||||||
|
if(EXISTS "${QT_PLUGINS_DIR}/styles")
|
||||||
|
install(
|
||||||
|
DIRECTORY "${QT_PLUGINS_DIR}/styles"
|
||||||
|
DESTINATION ${PLUGIN_DEST_DIR}
|
||||||
|
COMPONENT Runtime
|
||||||
|
)
|
||||||
|
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()
|
||||||
|
# Image formats
|
||||||
|
install(
|
||||||
|
DIRECTORY "${QT_PLUGINS_DIR}/imageformats"
|
||||||
|
DESTINATION ${PLUGIN_DEST_DIR}
|
||||||
|
COMPONENT Runtime
|
||||||
|
REGEX "tga|tiff|mng" EXCLUDE
|
||||||
REGEX "d\\." EXCLUDE
|
REGEX "d\\." EXCLUDE
|
||||||
REGEX "_debug\\." EXCLUDE
|
REGEX "_debug\\." EXCLUDE
|
||||||
REGEX "\\.dSYM" EXCLUDE
|
REGEX "\\.dSYM" EXCLUDE
|
||||||
)
|
)
|
||||||
endif()
|
# Icon engines
|
||||||
# TLS plugins (Qt 6 only)
|
|
||||||
if(EXISTS "${QT_PLUGINS_DIR}/tls")
|
|
||||||
install(
|
install(
|
||||||
DIRECTORY "${QT_PLUGINS_DIR}/tls"
|
DIRECTORY "${QT_PLUGINS_DIR}/iconengines"
|
||||||
CONFIGURATIONS Debug RelWithDebInfo ""
|
|
||||||
DESTINATION ${PLUGIN_DEST_DIR}
|
DESTINATION ${PLUGIN_DEST_DIR}
|
||||||
COMPONENT Runtime
|
COMPONENT Runtime
|
||||||
PATTERN "*qopensslbackend*" EXCLUDE
|
REGEX "fontawesome" EXCLUDE
|
||||||
PATTERN "*qcertonlybackend*" EXCLUDE
|
REGEX "d\\." EXCLUDE
|
||||||
)
|
|
||||||
install(
|
|
||||||
DIRECTORY "${QT_PLUGINS_DIR}/tls"
|
|
||||||
CONFIGURATIONS Release MinSizeRel
|
|
||||||
DESTINATION ${PLUGIN_DEST_DIR}
|
|
||||||
COMPONENT Runtime
|
|
||||||
REGEX "dd\\." EXCLUDE
|
|
||||||
REGEX "_debug\\." EXCLUDE
|
REGEX "_debug\\." EXCLUDE
|
||||||
REGEX "\\.dSYM" EXCLUDE
|
REGEX "\\.dSYM" EXCLUDE
|
||||||
PATTERN "*qopensslbackend*" EXCLUDE
|
|
||||||
PATTERN "*qcertonlybackend*" EXCLUDE
|
|
||||||
)
|
)
|
||||||
|
# Platform plugins
|
||||||
|
install(
|
||||||
|
DIRECTORY "${QT_PLUGINS_DIR}/platforms"
|
||||||
|
DESTINATION ${PLUGIN_DEST_DIR}
|
||||||
|
COMPONENT Runtime
|
||||||
|
REGEX "minimal|linuxfb|offscreen" EXCLUDE
|
||||||
|
REGEX "d\\." EXCLUDE
|
||||||
|
REGEX "_debug\\." EXCLUDE
|
||||||
|
REGEX "\\.dSYM" EXCLUDE
|
||||||
|
)
|
||||||
|
# Style plugins
|
||||||
|
if(EXISTS "${QT_PLUGINS_DIR}/styles")
|
||||||
|
install(
|
||||||
|
DIRECTORY "${QT_PLUGINS_DIR}/styles"
|
||||||
|
DESTINATION ${PLUGIN_DEST_DIR}
|
||||||
|
COMPONENT Runtime
|
||||||
|
REGEX "d\\." EXCLUDE
|
||||||
|
REGEX "_debug\\." EXCLUDE
|
||||||
|
REGEX "\\.dSYM" EXCLUDE
|
||||||
|
)
|
||||||
|
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,96 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
|
|
||||||
#include "DataMigrationTask.h"
|
|
||||||
|
|
||||||
#include "FileSystem.h"
|
|
||||||
|
|
||||||
#include <QDirIterator>
|
|
||||||
#include <QFileInfo>
|
|
||||||
#include <QMap>
|
|
||||||
|
|
||||||
#include <QtConcurrent>
|
|
||||||
|
|
||||||
DataMigrationTask::DataMigrationTask(QObject* parent,
|
|
||||||
const QString& sourcePath,
|
|
||||||
const QString& targetPath,
|
|
||||||
const IPathMatcher::Ptr pathMatcher)
|
|
||||||
: Task(parent), m_sourcePath(sourcePath), m_targetPath(targetPath), m_pathMatcher(pathMatcher), m_copy(sourcePath, targetPath)
|
|
||||||
{
|
|
||||||
m_copy.matcher(m_pathMatcher.get()).whitelist(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataMigrationTask::executeTask()
|
|
||||||
{
|
|
||||||
setStatus(tr("Scanning files..."));
|
|
||||||
|
|
||||||
// 1. Scan
|
|
||||||
// Check how many files we gotta copy
|
|
||||||
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [&] {
|
|
||||||
return m_copy(true); // dry run to collect amount of files
|
|
||||||
});
|
|
||||||
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::dryRunFinished);
|
|
||||||
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &DataMigrationTask::dryRunAborted);
|
|
||||||
m_copyFutureWatcher.setFuture(m_copyFuture);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataMigrationTask::dryRunFinished()
|
|
||||||
{
|
|
||||||
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::dryRunFinished);
|
|
||||||
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &DataMigrationTask::dryRunAborted);
|
|
||||||
|
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
|
||||||
if (!m_copyFuture.isValid() || !m_copyFuture.result()) {
|
|
||||||
#else
|
|
||||||
if (!m_copyFuture.result()) {
|
|
||||||
#endif
|
|
||||||
emitFailed(tr("Failed to scan source path."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Copy
|
|
||||||
// Actually copy all files now.
|
|
||||||
m_toCopy = m_copy.totalCopied();
|
|
||||||
connect(&m_copy, &FS::copy::fileCopied, [&, this](const QString& relativeName) {
|
|
||||||
QString shortenedName = relativeName;
|
|
||||||
// shorten the filename to hopefully fit into one line
|
|
||||||
if (shortenedName.length() > 50)
|
|
||||||
shortenedName = relativeName.left(20) + "…" + relativeName.right(29);
|
|
||||||
setProgress(m_copy.totalCopied(), m_toCopy);
|
|
||||||
setStatus(tr("Copying %1…").arg(shortenedName));
|
|
||||||
});
|
|
||||||
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [&] {
|
|
||||||
return m_copy(false); // actually copy now
|
|
||||||
});
|
|
||||||
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::copyFinished);
|
|
||||||
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &DataMigrationTask::copyAborted);
|
|
||||||
m_copyFutureWatcher.setFuture(m_copyFuture);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataMigrationTask::dryRunAborted()
|
|
||||||
{
|
|
||||||
emitFailed(tr("Aborted"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataMigrationTask::copyFinished()
|
|
||||||
{
|
|
||||||
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::copyFinished);
|
|
||||||
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &DataMigrationTask::copyAborted);
|
|
||||||
|
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
|
||||||
if (!m_copyFuture.isValid() || !m_copyFuture.result()) {
|
|
||||||
#else
|
|
||||||
if (!m_copyFuture.result()) {
|
|
||||||
#endif
|
|
||||||
emitFailed(tr("Some paths could not be copied!"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
emitSucceeded();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DataMigrationTask::copyAborted()
|
|
||||||
{
|
|
||||||
emitFailed(tr("Aborted"));
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "FileSystem.h"
|
|
||||||
#include "pathmatcher/IPathMatcher.h"
|
|
||||||
#include "tasks/Task.h"
|
|
||||||
|
|
||||||
#include <QFuture>
|
|
||||||
#include <QFutureWatcher>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Migrate existing data from other MMC-like launchers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class DataMigrationTask : public Task {
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit DataMigrationTask(QObject* parent, const QString& sourcePath, const QString& targetPath, const IPathMatcher::Ptr pathmatcher);
|
|
||||||
~DataMigrationTask() override = default;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void executeTask() override;
|
|
||||||
|
|
||||||
protected slots:
|
|
||||||
void dryRunFinished();
|
|
||||||
void dryRunAborted();
|
|
||||||
void copyFinished();
|
|
||||||
void copyAborted();
|
|
||||||
|
|
||||||
private:
|
|
||||||
const QString& m_sourcePath;
|
|
||||||
const QString& m_targetPath;
|
|
||||||
const IPathMatcher::Ptr m_pathMatcher;
|
|
||||||
|
|
||||||
FS::copy m_copy;
|
|
||||||
int m_toCopy = 0;
|
|
||||||
QFuture<bool> m_copyFuture;
|
|
||||||
QFutureWatcher<bool> m_copyFutureWatcher;
|
|
||||||
};
|
|
@ -49,14 +49,12 @@
|
|||||||
#include "StringUtils.h"
|
#include "StringUtils.h"
|
||||||
|
|
||||||
#if defined Q_OS_WIN32
|
#if defined Q_OS_WIN32
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#include <objbase.h>
|
#include <objbase.h>
|
||||||
#include <objidl.h>
|
#include <objidl.h>
|
||||||
#include <shlguid.h>
|
#include <shlguid.h>
|
||||||
#include <shlobj.h>
|
#include <shlobj.h>
|
||||||
#include <shobjidl.h>
|
#include <shobjidl.h>
|
||||||
#include <sys/utime.h>
|
#include <sys/utime.h>
|
||||||
#include <versionhelpers.h>
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <winnls.h>
|
#include <winnls.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -151,13 +149,9 @@ bool ensureFolderPathExists(QString foldernamepath)
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Copies a directory and it's contents from src to dest
|
bool copy::operator()(const QString& offset)
|
||||||
/// @param offset subdirectory form src to copy to dest
|
|
||||||
/// @return if there was an error during the filecopy
|
|
||||||
bool copy::operator()(const QString& offset, bool dryRun)
|
|
||||||
{
|
{
|
||||||
using copy_opts = fs::copy_options;
|
using copy_opts = fs::copy_options;
|
||||||
m_copied = 0; // reset counter
|
|
||||||
|
|
||||||
// NOTE always deep copy on windows. the alternatives are too messy.
|
// NOTE always deep copy on windows. the alternatives are too messy.
|
||||||
#if defined Q_OS_WIN32
|
#if defined Q_OS_WIN32
|
||||||
@ -177,21 +171,18 @@ bool copy::operator()(const QString& offset, bool dryRun)
|
|||||||
|
|
||||||
// Function that'll do the actual copying
|
// Function that'll do the actual copying
|
||||||
auto copy_file = [&](QString src_path, QString relative_dst_path) {
|
auto copy_file = [&](QString src_path, QString relative_dst_path) {
|
||||||
if (m_matcher && (m_matcher->matches(relative_dst_path) != m_whitelist))
|
if (m_blacklist && m_blacklist->matches(relative_dst_path))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto dst_path = PathCombine(dst, relative_dst_path);
|
auto dst_path = PathCombine(dst, relative_dst_path);
|
||||||
if (!dryRun) {
|
ensureFilePathExists(dst_path);
|
||||||
ensureFilePathExists(dst_path);
|
|
||||||
fs::copy(StringUtils::toStdString(src_path), StringUtils::toStdString(dst_path), opt, err);
|
fs::copy(StringUtils::toStdString(src_path), StringUtils::toStdString(dst_path), opt, err);
|
||||||
}
|
|
||||||
if (err) {
|
if (err) {
|
||||||
qWarning() << "Failed to copy files:" << QString::fromStdString(err.message());
|
qWarning() << "Failed to copy files:" << QString::fromStdString(err.message());
|
||||||
qDebug() << "Source file:" << src_path;
|
qDebug() << "Source file:" << src_path;
|
||||||
qDebug() << "Destination file:" << dst_path;
|
qDebug() << "Destination file:" << dst_path;
|
||||||
}
|
}
|
||||||
m_copied++;
|
|
||||||
emit fileCopied(relative_dst_path);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// We can't use copy_opts::recursive because we need to take into account the
|
// We can't use copy_opts::recursive because we need to take into account the
|
||||||
@ -235,10 +226,6 @@ bool trash(QString path, QString *pathInTrash = nullptr)
|
|||||||
// FIXME: Figure out trash in Flatpak. Qt seemingly doesn't use the Trash portal
|
// FIXME: Figure out trash in Flatpak. Qt seemingly doesn't use the Trash portal
|
||||||
if (DesktopServices::isFlatpak())
|
if (DesktopServices::isFlatpak())
|
||||||
return false;
|
return false;
|
||||||
#if defined Q_OS_WIN32
|
|
||||||
if (IsWindowsServer())
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
return QFile::moveToTrash(path, pathInTrash);
|
return QFile::moveToTrash(path, pathInTrash);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -349,35 +336,12 @@ QString getDesktopDir()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cross-platform Shortcut creation
|
// Cross-platform Shortcut creation
|
||||||
bool createShortcut(QString destination, QString target, QStringList args, QString name, QString icon)
|
bool createShortCut(QString location, QString dest, QStringList args, QString name, QString icon)
|
||||||
{
|
{
|
||||||
#if defined(Q_OS_MACOS)
|
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||||
destination += ".command";
|
location = PathCombine(location, name + ".desktop");
|
||||||
|
|
||||||
QFile f(destination);
|
QFile f(location);
|
||||||
f.open(QIODevice::WriteOnly | QIODevice::Text);
|
|
||||||
QTextStream stream(&f);
|
|
||||||
|
|
||||||
QString argstring;
|
|
||||||
if (!args.empty())
|
|
||||||
argstring = " \"" + args.join("\" \"") + "\"";
|
|
||||||
|
|
||||||
stream << "#!/bin/bash"
|
|
||||||
<< "\n";
|
|
||||||
stream << "\""
|
|
||||||
<< target
|
|
||||||
<< "\" "
|
|
||||||
<< argstring
|
|
||||||
<< "\n";
|
|
||||||
|
|
||||||
stream.flush();
|
|
||||||
f.close();
|
|
||||||
|
|
||||||
f.setPermissions(f.permissions() | QFileDevice::ExeOwner | QFileDevice::ExeGroup | QFileDevice::ExeOther);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
|
||||||
QFile f(destination);
|
|
||||||
f.open(QIODevice::WriteOnly | QIODevice::Text);
|
f.open(QIODevice::WriteOnly | QIODevice::Text);
|
||||||
QTextStream stream(&f);
|
QTextStream stream(&f);
|
||||||
|
|
||||||
@ -389,12 +353,10 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
|
|||||||
<< "\n";
|
<< "\n";
|
||||||
stream << "Type=Application"
|
stream << "Type=Application"
|
||||||
<< "\n";
|
<< "\n";
|
||||||
stream << "Exec=\"" << target.toLocal8Bit() << "\"" << argstring.toLocal8Bit() << "\n";
|
stream << "TryExec=" << dest.toLocal8Bit() << "\n";
|
||||||
|
stream << "Exec=" << dest.toLocal8Bit() << argstring.toLocal8Bit() << "\n";
|
||||||
stream << "Name=" << name.toLocal8Bit() << "\n";
|
stream << "Name=" << name.toLocal8Bit() << "\n";
|
||||||
if (!icon.isEmpty())
|
stream << "Icon=" << icon.toLocal8Bit() << "\n";
|
||||||
{
|
|
||||||
stream << "Icon=" << icon.toLocal8Bit() << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.flush();
|
stream.flush();
|
||||||
f.close();
|
f.close();
|
||||||
@ -402,132 +364,25 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
|
|||||||
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
|
||||||
QFileInfo targetInfo(target);
|
// TODO: Fix
|
||||||
|
// QFile file(PathCombine(location, name + ".lnk"));
|
||||||
|
// WCHAR *file_w;
|
||||||
|
// WCHAR *dest_w;
|
||||||
|
// WCHAR *args_w;
|
||||||
|
// file.fileName().toWCharArray(file_w);
|
||||||
|
// dest.toWCharArray(dest_w);
|
||||||
|
|
||||||
if (!targetInfo.exists())
|
// QString argStr;
|
||||||
{
|
// for (int i = 0; i < args.count(); i++)
|
||||||
qWarning() << "Target file does not exist!";
|
// {
|
||||||
return false;
|
// argStr.append(args[i]);
|
||||||
}
|
// argStr.append(" ");
|
||||||
|
// }
|
||||||
|
// argStr.toWCharArray(args_w);
|
||||||
|
|
||||||
target = targetInfo.absoluteFilePath();
|
// return SUCCEEDED(CreateLink(file_w, dest_w, args_w));
|
||||||
|
return false;
|
||||||
if (target.length() >= MAX_PATH)
|
|
||||||
{
|
|
||||||
qWarning() << "Target file path is too long!";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!icon.isEmpty() && icon.length() >= MAX_PATH)
|
|
||||||
{
|
|
||||||
qWarning() << "Icon path is too long!";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
destination += ".lnk";
|
|
||||||
|
|
||||||
if (destination.length() >= MAX_PATH)
|
|
||||||
{
|
|
||||||
qWarning() << "Destination path is too long!";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString argStr;
|
|
||||||
int argCount = args.count();
|
|
||||||
for (int i = 0; i < argCount; i++)
|
|
||||||
{
|
|
||||||
if (args[i].contains(' '))
|
|
||||||
{
|
|
||||||
argStr.append('"').append(args[i]).append('"');
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
argStr.append(args[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i < argCount - 1)
|
|
||||||
{
|
|
||||||
argStr.append(" ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argStr.length() >= MAX_PATH)
|
|
||||||
{
|
|
||||||
qWarning() << "Arguments string is too long!";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
HRESULT hres;
|
|
||||||
|
|
||||||
// ...yes, you need to initialize the entire COM stack just to make a shortcut
|
|
||||||
hres = CoInitialize(nullptr);
|
|
||||||
if (FAILED(hres))
|
|
||||||
{
|
|
||||||
qWarning() << "Failed to initialize COM!";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
WCHAR wsz[MAX_PATH];
|
|
||||||
|
|
||||||
IShellLink* psl;
|
|
||||||
|
|
||||||
// create an IShellLink instance - this stores the shortcut's attributes
|
|
||||||
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl);
|
|
||||||
if (SUCCEEDED(hres))
|
|
||||||
{
|
|
||||||
wmemset(wsz, 0, MAX_PATH);
|
|
||||||
target.toWCharArray(wsz);
|
|
||||||
psl->SetPath(wsz);
|
|
||||||
|
|
||||||
wmemset(wsz, 0, MAX_PATH);
|
|
||||||
argStr.toWCharArray(wsz);
|
|
||||||
psl->SetArguments(wsz);
|
|
||||||
|
|
||||||
wmemset(wsz, 0, MAX_PATH);
|
|
||||||
targetInfo.absolutePath().toWCharArray(wsz);
|
|
||||||
psl->SetWorkingDirectory(wsz); // "Starts in" attribute
|
|
||||||
|
|
||||||
if (!icon.isEmpty())
|
|
||||||
{
|
|
||||||
wmemset(wsz, 0, MAX_PATH);
|
|
||||||
icon.toWCharArray(wsz);
|
|
||||||
psl->SetIconLocation(wsz, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// query an IPersistFile interface from our IShellLink instance
|
|
||||||
// this is the interface that will actually let us save the shortcut to disk!
|
|
||||||
IPersistFile* ppf;
|
|
||||||
hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf);
|
|
||||||
if (SUCCEEDED(hres))
|
|
||||||
{
|
|
||||||
wmemset(wsz, 0, MAX_PATH);
|
|
||||||
destination.toWCharArray(wsz);
|
|
||||||
hres = ppf->Save(wsz, TRUE);
|
|
||||||
if (FAILED(hres))
|
|
||||||
{
|
|
||||||
qWarning() << "IPresistFile->Save() failed";
|
|
||||||
qWarning() << "hres = " << hres;
|
|
||||||
}
|
|
||||||
ppf->Release();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
qWarning() << "Failed to query IPersistFile interface from IShellLink instance";
|
|
||||||
qWarning() << "hres = " << hres;
|
|
||||||
}
|
|
||||||
psl->Release();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
qWarning() << "Failed to create IShellLink instance";
|
|
||||||
qWarning() << "hres = " << hres;
|
|
||||||
}
|
|
||||||
|
|
||||||
// go away COM, nobody likes you
|
|
||||||
CoUninitialize();
|
|
||||||
|
|
||||||
return SUCCEEDED(hres);
|
|
||||||
#else
|
#else
|
||||||
qWarning("Desktop Shortcuts not supported on your platform!");
|
qWarning("Desktop Shortcuts not supported on your platform!");
|
||||||
return false;
|
return false;
|
||||||
|
@ -40,7 +40,6 @@
|
|||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFlags>
|
#include <QFlags>
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
namespace FS {
|
namespace FS {
|
||||||
|
|
||||||
@ -76,11 +75,9 @@ bool ensureFilePathExists(QString filenamepath);
|
|||||||
*/
|
*/
|
||||||
bool ensureFolderPathExists(QString filenamepath);
|
bool ensureFolderPathExists(QString filenamepath);
|
||||||
|
|
||||||
/// @brief Copies a directory and it's contents from src to dest
|
class copy {
|
||||||
class copy : public QObject {
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
public:
|
||||||
copy(const QString& src, const QString& dst, QObject* parent = nullptr) : QObject(parent)
|
copy(const QString& src, const QString& dst)
|
||||||
{
|
{
|
||||||
m_src.setPath(src);
|
m_src.setPath(src);
|
||||||
m_dst.setPath(dst);
|
m_dst.setPath(dst);
|
||||||
@ -90,35 +87,21 @@ class copy : public QObject {
|
|||||||
m_followSymlinks = follow;
|
m_followSymlinks = follow;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
copy& matcher(const IPathMatcher* filter)
|
copy& blacklist(const IPathMatcher* filter)
|
||||||
{
|
{
|
||||||
m_matcher = filter;
|
m_blacklist = filter;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
copy& whitelist(bool whitelist)
|
bool operator()() { return operator()(QString()); }
|
||||||
{
|
|
||||||
m_whitelist = whitelist;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator()(bool dryRun = false) { return operator()(QString(), dryRun); }
|
|
||||||
|
|
||||||
int totalCopied() { return m_copied; }
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void fileCopied(const QString& relativeName);
|
|
||||||
// TODO: maybe add a "shouldCopy" signal in the future?
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool operator()(const QString& offset, bool dryRun = false);
|
bool operator()(const QString& offset);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_followSymlinks = true;
|
bool m_followSymlinks = true;
|
||||||
const IPathMatcher* m_matcher = nullptr;
|
const IPathMatcher* m_blacklist = nullptr;
|
||||||
bool m_whitelist = false;
|
|
||||||
QDir m_src;
|
QDir m_src;
|
||||||
QDir m_dst;
|
QDir m_dst;
|
||||||
int m_copied;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -172,9 +155,4 @@ QString getDesktopDir();
|
|||||||
// 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);
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a shortcut to the specified target file at the specified destination path.
|
|
||||||
*/
|
|
||||||
bool createShortcut(QString destination, QString target, QStringList args, QString name, QString icon);
|
|
||||||
}
|
}
|
||||||
|
@ -1,135 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by marcelohdez on 10/22/22.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "InstanceCopyPrefs.h"
|
|
||||||
|
|
||||||
bool InstanceCopyPrefs::allTrue() const
|
|
||||||
{
|
|
||||||
return copySaves &&
|
|
||||||
keepPlaytime &&
|
|
||||||
copyGameOptions &&
|
|
||||||
copyResourcePacks &&
|
|
||||||
copyShaderPacks &&
|
|
||||||
copyServers &&
|
|
||||||
copyMods &&
|
|
||||||
copyScreenshots;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns a single RegEx string of the selected folders/files to filter out (ex: ".minecraft/saves|.minecraft/server.dat")
|
|
||||||
QString InstanceCopyPrefs::getSelectedFiltersAsRegex() const
|
|
||||||
{
|
|
||||||
QStringList filters;
|
|
||||||
|
|
||||||
if(!copySaves)
|
|
||||||
filters << "saves";
|
|
||||||
|
|
||||||
if(!copyGameOptions)
|
|
||||||
filters << "options.txt";
|
|
||||||
|
|
||||||
if(!copyResourcePacks)
|
|
||||||
filters << "resourcepacks" << "texturepacks";
|
|
||||||
|
|
||||||
if(!copyShaderPacks)
|
|
||||||
filters << "shaderpacks";
|
|
||||||
|
|
||||||
if(!copyServers)
|
|
||||||
filters << "servers.dat" << "servers.dat_old" << "server-resource-packs";
|
|
||||||
|
|
||||||
if(!copyMods)
|
|
||||||
filters << "coremods" << "mods" << "config";
|
|
||||||
|
|
||||||
if(!copyScreenshots)
|
|
||||||
filters << "screenshots";
|
|
||||||
|
|
||||||
// If we have any filters to add, join them as a single regex string to return:
|
|
||||||
if (!filters.isEmpty()) {
|
|
||||||
const QString MC_ROOT = "[.]?minecraft/";
|
|
||||||
// Ensure first filter starts with root, then join other filters with OR regex before root (ex: ".minecraft/saves|.minecraft/mods"):
|
|
||||||
return MC_ROOT + filters.join("|" + MC_ROOT);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// ======= Getters =======
|
|
||||||
bool InstanceCopyPrefs::isCopySavesEnabled() const
|
|
||||||
{
|
|
||||||
return copySaves;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool InstanceCopyPrefs::isKeepPlaytimeEnabled() const
|
|
||||||
{
|
|
||||||
return keepPlaytime;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool InstanceCopyPrefs::isCopyGameOptionsEnabled() const
|
|
||||||
{
|
|
||||||
return copyGameOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool InstanceCopyPrefs::isCopyResourcePacksEnabled() const
|
|
||||||
{
|
|
||||||
return copyResourcePacks;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool InstanceCopyPrefs::isCopyShaderPacksEnabled() const
|
|
||||||
{
|
|
||||||
return copyShaderPacks;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool InstanceCopyPrefs::isCopyServersEnabled() const
|
|
||||||
{
|
|
||||||
return copyServers;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool InstanceCopyPrefs::isCopyModsEnabled() const
|
|
||||||
{
|
|
||||||
return copyMods;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool InstanceCopyPrefs::isCopyScreenshotsEnabled() const
|
|
||||||
{
|
|
||||||
return copyScreenshots;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ======= Setters =======
|
|
||||||
void InstanceCopyPrefs::enableCopySaves(bool b)
|
|
||||||
{
|
|
||||||
copySaves = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InstanceCopyPrefs::enableKeepPlaytime(bool b)
|
|
||||||
{
|
|
||||||
keepPlaytime = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InstanceCopyPrefs::enableCopyGameOptions(bool b)
|
|
||||||
{
|
|
||||||
copyGameOptions = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InstanceCopyPrefs::enableCopyResourcePacks(bool b)
|
|
||||||
{
|
|
||||||
copyResourcePacks = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InstanceCopyPrefs::enableCopyShaderPacks(bool b)
|
|
||||||
{
|
|
||||||
copyShaderPacks = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InstanceCopyPrefs::enableCopyServers(bool b)
|
|
||||||
{
|
|
||||||
copyServers = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InstanceCopyPrefs::enableCopyMods(bool b)
|
|
||||||
{
|
|
||||||
copyMods = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InstanceCopyPrefs::enableCopyScreenshots(bool b)
|
|
||||||
{
|
|
||||||
copyScreenshots = b;
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by marcelohdez on 10/22/22.
|
|
||||||
//
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QStringList>
|
|
||||||
|
|
||||||
struct InstanceCopyPrefs {
|
|
||||||
public:
|
|
||||||
[[nodiscard]] bool allTrue() const;
|
|
||||||
[[nodiscard]] QString getSelectedFiltersAsRegex() const;
|
|
||||||
// Getters
|
|
||||||
[[nodiscard]] bool isCopySavesEnabled() const;
|
|
||||||
[[nodiscard]] bool isKeepPlaytimeEnabled() const;
|
|
||||||
[[nodiscard]] bool isCopyGameOptionsEnabled() const;
|
|
||||||
[[nodiscard]] bool isCopyResourcePacksEnabled() const;
|
|
||||||
[[nodiscard]] bool isCopyShaderPacksEnabled() const;
|
|
||||||
[[nodiscard]] bool isCopyServersEnabled() const;
|
|
||||||
[[nodiscard]] bool isCopyModsEnabled() const;
|
|
||||||
[[nodiscard]] bool isCopyScreenshotsEnabled() const;
|
|
||||||
// Setters
|
|
||||||
void enableCopySaves(bool b);
|
|
||||||
void enableKeepPlaytime(bool b);
|
|
||||||
void enableCopyGameOptions(bool b);
|
|
||||||
void enableCopyResourcePacks(bool b);
|
|
||||||
void enableCopyShaderPacks(bool b);
|
|
||||||
void enableCopyServers(bool b);
|
|
||||||
void enableCopyMods(bool b);
|
|
||||||
void enableCopyScreenshots(bool b);
|
|
||||||
|
|
||||||
protected: // data
|
|
||||||
bool copySaves = true;
|
|
||||||
bool keepPlaytime = true;
|
|
||||||
bool copyGameOptions = true;
|
|
||||||
bool copyResourcePacks = true;
|
|
||||||
bool copyShaderPacks = true;
|
|
||||||
bool copyServers = true;
|
|
||||||
bool copyMods = true;
|
|
||||||
bool copyScreenshots = true;
|
|
||||||
};
|
|
@ -5,17 +5,15 @@
|
|||||||
#include "pathmatcher/RegexpMatcher.h"
|
#include "pathmatcher/RegexpMatcher.h"
|
||||||
#include <QtConcurrentRun>
|
#include <QtConcurrentRun>
|
||||||
|
|
||||||
InstanceCopyTask::InstanceCopyTask(InstancePtr origInstance, const InstanceCopyPrefs& prefs)
|
InstanceCopyTask::InstanceCopyTask(InstancePtr origInstance, bool copySaves, bool keepPlaytime)
|
||||||
{
|
{
|
||||||
m_origInstance = origInstance;
|
m_origInstance = origInstance;
|
||||||
m_keepPlaytime = prefs.isKeepPlaytimeEnabled();
|
m_keepPlaytime = keepPlaytime;
|
||||||
|
|
||||||
QString filters = prefs.getSelectedFiltersAsRegex();
|
if(!copySaves)
|
||||||
if (!filters.isEmpty())
|
|
||||||
{
|
{
|
||||||
// Set regex filter:
|
|
||||||
// FIXME: get this from the original instance type...
|
// FIXME: get this from the original instance type...
|
||||||
auto matcherReal = new RegexpMatcher(filters);
|
auto matcherReal = new RegexpMatcher("[.]?minecraft/saves");
|
||||||
matcherReal->caseSensitive(false);
|
matcherReal->caseSensitive(false);
|
||||||
m_matcher.reset(matcherReal);
|
m_matcher.reset(matcherReal);
|
||||||
}
|
}
|
||||||
@ -25,12 +23,10 @@ void InstanceCopyTask::executeTask()
|
|||||||
{
|
{
|
||||||
setStatus(tr("Copying instance %1").arg(m_origInstance->name()));
|
setStatus(tr("Copying instance %1").arg(m_origInstance->name()));
|
||||||
|
|
||||||
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [this]{
|
FS::copy folderCopy(m_origInstance->instanceRoot(), m_stagingPath);
|
||||||
FS::copy folderCopy(m_origInstance->instanceRoot(), m_stagingPath);
|
folderCopy.followSymlinks(false).blacklist(m_matcher.get());
|
||||||
folderCopy.followSymlinks(false).matcher(m_matcher.get());
|
|
||||||
|
|
||||||
return folderCopy();
|
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), folderCopy);
|
||||||
});
|
|
||||||
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &InstanceCopyTask::copyFinished);
|
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &InstanceCopyTask::copyFinished);
|
||||||
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &InstanceCopyTask::copyAborted);
|
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &InstanceCopyTask::copyAborted);
|
||||||
m_copyFutureWatcher.setFuture(m_copyFuture);
|
m_copyFutureWatcher.setFuture(m_copyFuture);
|
||||||
|
@ -1,21 +1,20 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "tasks/Task.h"
|
||||||
|
#include "net/NetJob.h"
|
||||||
|
#include <QUrl>
|
||||||
#include <QFuture>
|
#include <QFuture>
|
||||||
#include <QFutureWatcher>
|
#include <QFutureWatcher>
|
||||||
#include <QUrl>
|
|
||||||
#include "BaseInstance.h"
|
|
||||||
#include "BaseVersion.h"
|
|
||||||
#include "InstanceCopyPrefs.h"
|
|
||||||
#include "InstanceTask.h"
|
|
||||||
#include "net/NetJob.h"
|
|
||||||
#include "settings/SettingsObject.h"
|
#include "settings/SettingsObject.h"
|
||||||
#include "tasks/Task.h"
|
#include "BaseVersion.h"
|
||||||
|
#include "BaseInstance.h"
|
||||||
|
#include "InstanceTask.h"
|
||||||
|
|
||||||
class InstanceCopyTask : public InstanceTask
|
class InstanceCopyTask : public InstanceTask
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit InstanceCopyTask(InstancePtr origInstance, const InstanceCopyPrefs& prefs);
|
explicit InstanceCopyTask(InstancePtr origInstance, bool copySaves, bool keepPlaytime);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//! Entry point for tasks.
|
//! Entry point for tasks.
|
||||||
@ -23,8 +22,7 @@ protected:
|
|||||||
void copyFinished();
|
void copyFinished();
|
||||||
void copyAborted();
|
void copyAborted();
|
||||||
|
|
||||||
private:
|
private: /* data */
|
||||||
/* data */
|
|
||||||
InstancePtr m_origInstance;
|
InstancePtr m_origInstance;
|
||||||
QFuture<bool> m_copyFuture;
|
QFuture<bool> m_copyFuture;
|
||||||
QFutureWatcher<bool> m_copyFutureWatcher;
|
QFutureWatcher<bool> m_copyFutureWatcher;
|
||||||
|
@ -25,13 +25,9 @@ void InstanceCreationTask::executeTask()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
qWarning() << "Instance creation failed!";
|
qWarning() << "Instance creation failed!";
|
||||||
if (!m_error_message.isEmpty()) {
|
if (!m_error_message.isEmpty())
|
||||||
qWarning() << "Reason: " << m_error_message;
|
qWarning() << "Reason: " << m_error_message;
|
||||||
emitFailed(tr("Error while creating new instance:\n%1").arg(m_error_message));
|
emitFailed(tr("Error while creating new instance."));
|
||||||
} else {
|
|
||||||
emitFailed(tr("Error while creating new instance."));
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,9 +55,11 @@
|
|||||||
|
|
||||||
#include <quazip/quazipdir.h>
|
#include <quazip/quazipdir.h>
|
||||||
|
|
||||||
InstanceImportTask::InstanceImportTask(const QUrl sourceUrl, QWidget* parent, QMap<QString, QString>&& extra_info)
|
InstanceImportTask::InstanceImportTask(const QUrl sourceUrl, QWidget* parent)
|
||||||
: m_sourceUrl(sourceUrl), m_extra_info(extra_info), m_parent(parent)
|
{
|
||||||
{}
|
m_sourceUrl = sourceUrl;
|
||||||
|
m_parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
bool InstanceImportTask::abort()
|
bool InstanceImportTask::abort()
|
||||||
{
|
{
|
||||||
@ -162,14 +164,18 @@ void InstanceImportTask::processZipPack()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QStringList paths_to_ignore { "overrides/" };
|
QString mmcRoot = MMCZip::findFolderOfFileInZip(m_packZip.get(), "instance.cfg");
|
||||||
|
QString flameRoot = MMCZip::findFolderOfFileInZip(m_packZip.get(), "manifest.json");
|
||||||
|
|
||||||
if (QString mmcRoot = MMCZip::findFolderOfFileInZip(m_packZip.get(), "instance.cfg", paths_to_ignore); !mmcRoot.isNull()) {
|
if (!mmcRoot.isNull())
|
||||||
|
{
|
||||||
// process as MultiMC instance/pack
|
// process as MultiMC instance/pack
|
||||||
qDebug() << "MultiMC:" << mmcRoot;
|
qDebug() << "MultiMC:" << mmcRoot;
|
||||||
root = mmcRoot;
|
root = mmcRoot;
|
||||||
m_modpackType = ModpackType::MultiMC;
|
m_modpackType = ModpackType::MultiMC;
|
||||||
} else if (QString flameRoot = MMCZip::findFolderOfFileInZip(m_packZip.get(), "manifest.json", paths_to_ignore); !flameRoot.isNull()) {
|
}
|
||||||
|
else if(!flameRoot.isNull())
|
||||||
|
{
|
||||||
// process as Flame pack
|
// process as Flame pack
|
||||||
qDebug() << "Flame:" << flameRoot;
|
qDebug() << "Flame:" << flameRoot;
|
||||||
root = flameRoot;
|
root = flameRoot;
|
||||||
@ -257,34 +263,14 @@ void InstanceImportTask::extractAborted()
|
|||||||
|
|
||||||
void InstanceImportTask::processFlame()
|
void InstanceImportTask::processFlame()
|
||||||
{
|
{
|
||||||
FlameCreationTask* inst_creation_task = nullptr;
|
auto* inst_creation_task = new FlameCreationTask(m_stagingPath, m_globalSettings, m_parent);
|
||||||
if (!m_extra_info.isEmpty()) {
|
|
||||||
auto pack_id_it = m_extra_info.constFind("pack_id");
|
|
||||||
Q_ASSERT(pack_id_it != m_extra_info.constEnd());
|
|
||||||
auto pack_id = pack_id_it.value();
|
|
||||||
|
|
||||||
auto pack_version_id_it = m_extra_info.constFind("pack_version_id");
|
|
||||||
Q_ASSERT(pack_version_id_it != m_extra_info.constEnd());
|
|
||||||
auto pack_version_id = pack_version_id_it.value();
|
|
||||||
|
|
||||||
QString original_instance_id;
|
|
||||||
auto original_instance_id_it = m_extra_info.constFind("original_instance_id");
|
|
||||||
if (original_instance_id_it != m_extra_info.constEnd())
|
|
||||||
original_instance_id = original_instance_id_it.value();
|
|
||||||
|
|
||||||
inst_creation_task = new FlameCreationTask(m_stagingPath, m_globalSettings, m_parent, pack_id, pack_version_id, original_instance_id);
|
|
||||||
} else {
|
|
||||||
// FIXME: Find a way to get IDs in directly imported ZIPs
|
|
||||||
inst_creation_task = new FlameCreationTask(m_stagingPath, m_globalSettings, m_parent, {}, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
inst_creation_task->setName(*this);
|
inst_creation_task->setName(*this);
|
||||||
inst_creation_task->setIcon(m_instIcon);
|
inst_creation_task->setIcon(m_instIcon);
|
||||||
inst_creation_task->setGroup(m_instGroup);
|
inst_creation_task->setGroup(m_instGroup);
|
||||||
inst_creation_task->setConfirmUpdate(shouldConfirmUpdate());
|
|
||||||
|
|
||||||
connect(inst_creation_task, &Task::succeeded, this, [this, inst_creation_task] {
|
connect(inst_creation_task, &Task::succeeded, this, [this, inst_creation_task] {
|
||||||
setOverride(inst_creation_task->shouldOverride(), inst_creation_task->originalInstanceID());
|
setOverride(inst_creation_task->shouldOverride());
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
});
|
});
|
||||||
connect(inst_creation_task, &Task::failed, this, &InstanceImportTask::emitFailed);
|
connect(inst_creation_task, &Task::failed, this, &InstanceImportTask::emitFailed);
|
||||||
@ -341,41 +327,14 @@ void InstanceImportTask::processMultiMC()
|
|||||||
|
|
||||||
void InstanceImportTask::processModrinth()
|
void InstanceImportTask::processModrinth()
|
||||||
{
|
{
|
||||||
ModrinthCreationTask* inst_creation_task = nullptr;
|
auto* inst_creation_task = new ModrinthCreationTask(m_stagingPath, m_globalSettings, m_parent, m_sourceUrl.toString());
|
||||||
if (!m_extra_info.isEmpty()) {
|
|
||||||
auto pack_id_it = m_extra_info.constFind("pack_id");
|
|
||||||
Q_ASSERT(pack_id_it != m_extra_info.constEnd());
|
|
||||||
auto pack_id = pack_id_it.value();
|
|
||||||
|
|
||||||
QString pack_version_id;
|
|
||||||
auto pack_version_id_it = m_extra_info.constFind("pack_version_id");
|
|
||||||
if (pack_version_id_it != m_extra_info.constEnd())
|
|
||||||
pack_version_id = pack_version_id_it.value();
|
|
||||||
|
|
||||||
QString original_instance_id;
|
|
||||||
auto original_instance_id_it = m_extra_info.constFind("original_instance_id");
|
|
||||||
if (original_instance_id_it != m_extra_info.constEnd())
|
|
||||||
original_instance_id = original_instance_id_it.value();
|
|
||||||
|
|
||||||
inst_creation_task = new ModrinthCreationTask(m_stagingPath, m_globalSettings, m_parent, pack_id, pack_version_id, original_instance_id);
|
|
||||||
} else {
|
|
||||||
QString pack_id;
|
|
||||||
if (!m_sourceUrl.isEmpty()) {
|
|
||||||
QRegularExpression regex(R"(data\/(.*)\/versions)");
|
|
||||||
pack_id = regex.match(m_sourceUrl.toString()).captured(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: Find a way to get the ID in directly imported ZIPs
|
|
||||||
inst_creation_task = new ModrinthCreationTask(m_stagingPath, m_globalSettings, m_parent, pack_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
inst_creation_task->setName(*this);
|
inst_creation_task->setName(*this);
|
||||||
inst_creation_task->setIcon(m_instIcon);
|
inst_creation_task->setIcon(m_instIcon);
|
||||||
inst_creation_task->setGroup(m_instGroup);
|
inst_creation_task->setGroup(m_instGroup);
|
||||||
inst_creation_task->setConfirmUpdate(shouldConfirmUpdate());
|
|
||||||
|
|
||||||
connect(inst_creation_task, &Task::succeeded, this, [this, inst_creation_task] {
|
connect(inst_creation_task, &Task::succeeded, this, [this, inst_creation_task] {
|
||||||
setOverride(inst_creation_task->shouldOverride(), inst_creation_task->originalInstanceID());
|
setOverride(inst_creation_task->shouldOverride());
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
});
|
});
|
||||||
connect(inst_creation_task, &Task::failed, this, &InstanceImportTask::emitFailed);
|
connect(inst_creation_task, &Task::failed, this, &InstanceImportTask::emitFailed);
|
||||||
|
@ -56,7 +56,7 @@ class InstanceImportTask : public InstanceTask
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit InstanceImportTask(const QUrl sourceUrl, QWidget* parent = nullptr, QMap<QString, QString>&& extra_info = {});
|
explicit InstanceImportTask(const QUrl sourceUrl, QWidget* parent = nullptr);
|
||||||
|
|
||||||
bool abort() override;
|
bool abort() override;
|
||||||
const QVector<Flame::File> &getBlockedFiles() const
|
const QVector<Flame::File> &getBlockedFiles() const
|
||||||
@ -101,10 +101,6 @@ private: /* data */
|
|||||||
Modrinth,
|
Modrinth,
|
||||||
} m_modpackType = ModpackType::Unknown;
|
} m_modpackType = ModpackType::Unknown;
|
||||||
|
|
||||||
// Extra info we might need, that's available before, but can't be derived from
|
|
||||||
// the source URL / the resource it points to alone.
|
|
||||||
QMap<QString, QString> m_extra_info;
|
|
||||||
|
|
||||||
//FIXME: nuke
|
//FIXME: nuke
|
||||||
QWidget* m_parent;
|
QWidget* m_parent;
|
||||||
};
|
};
|
||||||
|
@ -816,7 +816,7 @@ class InstanceStaging : public Task {
|
|||||||
void childSucceded()
|
void childSucceded()
|
||||||
{
|
{
|
||||||
unsigned sleepTime = backoff();
|
unsigned sleepTime = backoff();
|
||||||
if (m_parent->commitStagedInstance(m_stagingPath, m_instance_name, m_groupName, *m_child.get()))
|
if (m_parent->commitStagedInstance(m_stagingPath, m_instance_name, m_groupName, m_child->shouldOverride()))
|
||||||
{
|
{
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
return;
|
return;
|
||||||
@ -880,22 +880,25 @@ QString InstanceList::getStagedInstancePath()
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InstanceList::commitStagedInstance(const QString& path, InstanceName const& instanceName, const QString& groupName, InstanceTask const& commiting)
|
bool InstanceList::commitStagedInstance(const QString& path, InstanceName const& instanceName, const QString& groupName, bool should_override)
|
||||||
{
|
{
|
||||||
QDir dir;
|
QDir dir;
|
||||||
QString instID;
|
QString instID;
|
||||||
InstancePtr inst;
|
InstancePtr inst;
|
||||||
|
|
||||||
auto should_override = commiting.shouldOverride();
|
|
||||||
|
|
||||||
if (should_override) {
|
if (should_override) {
|
||||||
instID = commiting.originalInstanceID();
|
// This is to avoid problems when the instance folder gets manually renamed
|
||||||
|
if ((inst = getInstanceByManagedName(instanceName.originalName()))) {
|
||||||
|
instID = QFileInfo(inst->instanceRoot()).fileName();
|
||||||
|
} else if ((inst = getInstanceByManagedName(instanceName.modifiedName()))) {
|
||||||
|
instID = QFileInfo(inst->instanceRoot()).fileName();
|
||||||
|
} else {
|
||||||
|
instID = FS::RemoveInvalidFilenameChars(instanceName.modifiedName(), '-');
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
instID = FS::DirNameFromString(instanceName.modifiedName(), m_instDir);
|
instID = FS::DirNameFromString(instanceName.modifiedName(), m_instDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_ASSERT(!instID.isEmpty());
|
|
||||||
|
|
||||||
{
|
{
|
||||||
WatchLock lock(m_watcher, m_instDir);
|
WatchLock lock(m_watcher, m_instDir);
|
||||||
QString destination = FS::PathCombine(m_instDir, instID);
|
QString destination = FS::PathCombine(m_instDir, instID);
|
||||||
|
@ -133,7 +133,7 @@ public:
|
|||||||
* should_override is used when another similar instance already exists, and we want to override it
|
* should_override is used when another similar instance already exists, and we want to override it
|
||||||
* - for instance, when updating it.
|
* - for instance, when updating it.
|
||||||
*/
|
*/
|
||||||
bool commitStagedInstance(const QString& keyPath, const InstanceName& instanceName, const QString& groupName, const InstanceTask&);
|
bool commitStagedInstance(const QString& keyPath, const InstanceName& instanceName, const QString& groupName, bool should_override);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
#include "ui/pages/BasePageProvider.h"
|
#include "ui/pages/BasePageProvider.h"
|
||||||
#include "ui/pages/instance/LogPage.h"
|
#include "ui/pages/instance/LogPage.h"
|
||||||
#include "ui/pages/instance/VersionPage.h"
|
#include "ui/pages/instance/VersionPage.h"
|
||||||
#include "ui/pages/instance/ManagedPackPage.h"
|
|
||||||
#include "ui/pages/instance/ModFolderPage.h"
|
#include "ui/pages/instance/ModFolderPage.h"
|
||||||
#include "ui/pages/instance/ResourcePackPage.h"
|
#include "ui/pages/instance/ResourcePackPage.h"
|
||||||
#include "ui/pages/instance/TexturePackPage.h"
|
#include "ui/pages/instance/TexturePackPage.h"
|
||||||
@ -34,7 +33,6 @@ 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()));
|
||||||
values.append(ManagedPackPage::createPage(onesix.get()));
|
|
||||||
auto modsPage = new ModFolderPage(onesix.get(), onesix->loaderModList());
|
auto modsPage = new ModFolderPage(onesix.get(), onesix->loaderModList());
|
||||||
modsPage->setFilter("%1 (*.zip *.jar *.litemod)");
|
modsPage->setFilter("%1 (*.zip *.jar *.litemod)");
|
||||||
values.append(modsPage);
|
values.append(modsPage);
|
||||||
|
@ -18,29 +18,6 @@ InstanceNameChange askForChangingInstanceName(QWidget* parent, const QString& ol
|
|||||||
return InstanceNameChange::ShouldKeep;
|
return InstanceNameChange::ShouldKeep;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShouldUpdate askIfShouldUpdate(QWidget *parent, QString original_version_name)
|
|
||||||
{
|
|
||||||
auto info = CustomMessageBox::selectable(
|
|
||||||
parent, QObject::tr("Similar modpack was found!"),
|
|
||||||
QObject::tr("One or more of your instances are from this same modpack%1. Do you want to create a "
|
|
||||||
"separate instance, or update the existing one?\n\nNOTE: Make sure you made a backup of your important instance data before "
|
|
||||||
"updating, as worlds can be corrupted and some configuration may be lost (due to pack overrides).")
|
|
||||||
.arg(original_version_name),
|
|
||||||
QMessageBox::Information, QMessageBox::Ok | QMessageBox::Reset | QMessageBox::Abort);
|
|
||||||
info->setButtonText(QMessageBox::Ok, QObject::tr("Update existing instance"));
|
|
||||||
info->setButtonText(QMessageBox::Abort, QObject::tr("Create new instance"));
|
|
||||||
info->setButtonText(QMessageBox::Reset, QObject::tr("Cancel"));
|
|
||||||
|
|
||||||
info->exec();
|
|
||||||
|
|
||||||
if (info->clickedButton() == info->button(QMessageBox::Ok))
|
|
||||||
return ShouldUpdate::Update;
|
|
||||||
if (info->clickedButton() == info->button(QMessageBox::Abort))
|
|
||||||
return ShouldUpdate::SkipUpdating;
|
|
||||||
return ShouldUpdate::Cancel;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
QString InstanceName::name() const
|
QString InstanceName::name() const
|
||||||
{
|
{
|
||||||
if (!m_modified_name.isEmpty())
|
if (!m_modified_name.isEmpty())
|
||||||
|
@ -6,8 +6,6 @@
|
|||||||
/* Helpers */
|
/* Helpers */
|
||||||
enum class InstanceNameChange { ShouldChange, ShouldKeep };
|
enum class InstanceNameChange { ShouldChange, ShouldKeep };
|
||||||
[[nodiscard]] InstanceNameChange askForChangingInstanceName(QWidget* parent, const QString& old_name, const QString& new_name);
|
[[nodiscard]] InstanceNameChange askForChangingInstanceName(QWidget* parent, const QString& old_name, const QString& new_name);
|
||||||
enum class ShouldUpdate { Update, SkipUpdating, Cancel };
|
|
||||||
[[nodiscard]] ShouldUpdate askIfShouldUpdate(QWidget* parent, QString original_version_name);
|
|
||||||
|
|
||||||
struct InstanceName {
|
struct InstanceName {
|
||||||
public:
|
public:
|
||||||
@ -44,20 +42,10 @@ class InstanceTask : public Task, public InstanceName {
|
|||||||
void setGroup(const QString& group) { m_instGroup = group; }
|
void setGroup(const QString& group) { m_instGroup = group; }
|
||||||
QString group() const { return m_instGroup; }
|
QString group() const { return m_instGroup; }
|
||||||
|
|
||||||
[[nodiscard]] bool shouldConfirmUpdate() const { return m_confirm_update; }
|
|
||||||
void setConfirmUpdate(bool confirm) { m_confirm_update = confirm; }
|
|
||||||
|
|
||||||
bool shouldOverride() const { return m_override_existing; }
|
bool shouldOverride() const { return m_override_existing; }
|
||||||
|
|
||||||
[[nodiscard]] QString originalInstanceID() const { return m_original_instance_id; };
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void setOverride(bool override, QString instance_id_to_override = {})
|
void setOverride(bool override) { m_override_existing = override; }
|
||||||
{
|
|
||||||
m_override_existing = override;
|
|
||||||
if (!instance_id_to_override.isEmpty())
|
|
||||||
m_original_instance_id = instance_id_to_override;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected: /* data */
|
protected: /* data */
|
||||||
SettingsObjectPtr m_globalSettings;
|
SettingsObjectPtr m_globalSettings;
|
||||||
@ -66,7 +54,4 @@ class InstanceTask : public Task, public InstanceName {
|
|||||||
QString m_stagingPath;
|
QString m_stagingPath;
|
||||||
|
|
||||||
bool m_override_existing = false;
|
bool m_override_existing = false;
|
||||||
bool m_confirm_update = true;
|
|
||||||
|
|
||||||
QString m_original_instance_id;
|
|
||||||
};
|
};
|
||||||
|
@ -28,11 +28,11 @@ QString Time::prettifyDuration(int64_t duration) {
|
|||||||
int days = (int) (duration / 24);
|
int days = (int) (duration / 24);
|
||||||
if((hours == 0)&&(days == 0))
|
if((hours == 0)&&(days == 0))
|
||||||
{
|
{
|
||||||
return QObject::tr("%1min %2s").arg(minutes).arg(seconds);
|
return QObject::tr("%1m %2s").arg(minutes).arg(seconds);
|
||||||
}
|
}
|
||||||
if (days == 0)
|
if (days == 0)
|
||||||
{
|
{
|
||||||
return QObject::tr("%1h %2min").arg(hours).arg(minutes);
|
return QObject::tr("%1h %2m").arg(hours).arg(minutes);
|
||||||
}
|
}
|
||||||
return QObject::tr("%1d %2h %3min").arg(days).arg(hours).arg(minutes);
|
return QObject::tr("%1d %2h %3m").arg(days).arg(hours).arg(minutes);
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,6 @@
|
|||||||
#include "MMCZip.h"
|
#include "MMCZip.h"
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
|
|
||||||
#include <QCoreApplication>
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
// ours
|
// ours
|
||||||
@ -229,27 +228,23 @@ bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ours
|
// ours
|
||||||
QString MMCZip::findFolderOfFileInZip(QuaZip* zip, const QString& what, const QStringList& ignore_paths, const QString& root)
|
QString MMCZip::findFolderOfFileInZip(QuaZip * zip, const QString & what, const QString &root)
|
||||||
{
|
{
|
||||||
QuaZipDir rootDir(zip, root);
|
QuaZipDir rootDir(zip, root);
|
||||||
for (auto&& fileName : rootDir.entryList(QDir::Files)) {
|
for(auto fileName: rootDir.entryList(QDir::Files))
|
||||||
if (fileName == what)
|
{
|
||||||
|
if(fileName == what)
|
||||||
return root;
|
return root;
|
||||||
|
|
||||||
QCoreApplication::processEvents();
|
|
||||||
}
|
}
|
||||||
|
for(auto fileName: rootDir.entryList(QDir::Dirs))
|
||||||
// Recurse the search to non-ignored subfolders
|
{
|
||||||
for (auto&& fileName : rootDir.entryList(QDir::Dirs)) {
|
QString result = findFolderOfFileInZip(zip, what, root + fileName);
|
||||||
if (ignore_paths.contains(fileName))
|
if(!result.isEmpty())
|
||||||
continue;
|
{
|
||||||
|
|
||||||
QString result = findFolderOfFileInZip(zip, what, ignore_paths, root + fileName);
|
|
||||||
if (!result.isEmpty())
|
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return QString();
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ours
|
// ours
|
||||||
|
@ -80,11 +80,9 @@ namespace MMCZip
|
|||||||
/**
|
/**
|
||||||
* Find a single file in archive by file name (not path)
|
* Find a single file in archive by file name (not path)
|
||||||
*
|
*
|
||||||
* \param ignore_paths paths to skip when recursing the search
|
|
||||||
*
|
|
||||||
* \return the path prefix where the file is
|
* \return the path prefix where the file is
|
||||||
*/
|
*/
|
||||||
QString findFolderOfFileInZip(QuaZip * zip, const QString & what, const QStringList& ignore_paths = {}, const QString &root = QString(""));
|
QString findFolderOfFileInZip(QuaZip * zip, const QString & what, const QString &root = QString(""));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a multiple files of the same name in archive by file name
|
* Find a multiple files of the same name in archive by file name
|
||||||
|
@ -1,95 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QCoreApplication>
|
|
||||||
#include <QPixmapCache>
|
|
||||||
#include <QThread>
|
|
||||||
|
|
||||||
#define GET_TYPE() \
|
|
||||||
Qt::ConnectionType type; \
|
|
||||||
if (QThread::currentThread() != QCoreApplication::instance()->thread()) \
|
|
||||||
type = Qt::BlockingQueuedConnection; \
|
|
||||||
else \
|
|
||||||
type = Qt::DirectConnection;
|
|
||||||
|
|
||||||
#define DEFINE_FUNC_NO_PARAM(NAME, RET_TYPE) \
|
|
||||||
static RET_TYPE NAME() \
|
|
||||||
{ \
|
|
||||||
RET_TYPE ret; \
|
|
||||||
GET_TYPE() \
|
|
||||||
QMetaObject::invokeMethod(s_instance, "_" #NAME, type, Q_RETURN_ARG(RET_TYPE, ret)); \
|
|
||||||
return ret; \
|
|
||||||
}
|
|
||||||
#define DEFINE_FUNC_ONE_PARAM(NAME, RET_TYPE, PARAM_1_TYPE) \
|
|
||||||
static RET_TYPE NAME(PARAM_1_TYPE p1) \
|
|
||||||
{ \
|
|
||||||
RET_TYPE ret; \
|
|
||||||
GET_TYPE() \
|
|
||||||
QMetaObject::invokeMethod(s_instance, "_" #NAME, type, Q_RETURN_ARG(RET_TYPE, ret), Q_ARG(PARAM_1_TYPE, p1)); \
|
|
||||||
return ret; \
|
|
||||||
}
|
|
||||||
#define DEFINE_FUNC_TWO_PARAM(NAME, RET_TYPE, PARAM_1_TYPE, PARAM_2_TYPE) \
|
|
||||||
static RET_TYPE NAME(PARAM_1_TYPE p1, PARAM_2_TYPE p2) \
|
|
||||||
{ \
|
|
||||||
RET_TYPE ret; \
|
|
||||||
GET_TYPE() \
|
|
||||||
QMetaObject::invokeMethod(s_instance, "_" #NAME, type, Q_RETURN_ARG(RET_TYPE, ret), Q_ARG(PARAM_1_TYPE, p1), \
|
|
||||||
Q_ARG(PARAM_2_TYPE, p2)); \
|
|
||||||
return ret; \
|
|
||||||
}
|
|
||||||
|
|
||||||
/** A wrapper around QPixmapCache with thread affinity with the main thread.
|
|
||||||
*/
|
|
||||||
class PixmapCache final : public QObject {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
PixmapCache(QObject* parent) : QObject(parent) {}
|
|
||||||
~PixmapCache() override = default;
|
|
||||||
|
|
||||||
static PixmapCache& instance() { return *s_instance; }
|
|
||||||
static void setInstance(PixmapCache* i) { s_instance = i; }
|
|
||||||
|
|
||||||
public:
|
|
||||||
DEFINE_FUNC_NO_PARAM(cacheLimit, int)
|
|
||||||
DEFINE_FUNC_NO_PARAM(clear, bool)
|
|
||||||
DEFINE_FUNC_TWO_PARAM(find, bool, const QString&, QPixmap*)
|
|
||||||
DEFINE_FUNC_TWO_PARAM(find, bool, const QPixmapCache::Key&, QPixmap*)
|
|
||||||
DEFINE_FUNC_TWO_PARAM(insert, bool, const QString&, const QPixmap&)
|
|
||||||
DEFINE_FUNC_ONE_PARAM(insert, QPixmapCache::Key, const QPixmap&)
|
|
||||||
DEFINE_FUNC_ONE_PARAM(remove, bool, const QString&)
|
|
||||||
DEFINE_FUNC_ONE_PARAM(remove, bool, const QPixmapCache::Key&)
|
|
||||||
DEFINE_FUNC_TWO_PARAM(replace, bool, const QPixmapCache::Key&, const QPixmap&)
|
|
||||||
DEFINE_FUNC_ONE_PARAM(setCacheLimit, bool, int)
|
|
||||||
|
|
||||||
// NOTE: Every function returns something non-void to simplify the macros.
|
|
||||||
private slots:
|
|
||||||
int _cacheLimit() { return QPixmapCache::cacheLimit(); }
|
|
||||||
bool _clear()
|
|
||||||
{
|
|
||||||
QPixmapCache::clear();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool _find(const QString& key, QPixmap* pixmap) { return QPixmapCache::find(key, pixmap); }
|
|
||||||
bool _find(const QPixmapCache::Key& key, QPixmap* pixmap) { return QPixmapCache::find(key, pixmap); }
|
|
||||||
bool _insert(const QString& key, const QPixmap& pixmap) { return QPixmapCache::insert(key, pixmap); }
|
|
||||||
QPixmapCache::Key _insert(const QPixmap& pixmap) { return QPixmapCache::insert(pixmap); }
|
|
||||||
bool _remove(const QString& key)
|
|
||||||
{
|
|
||||||
QPixmapCache::remove(key);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool _remove(const QPixmapCache::Key& key)
|
|
||||||
{
|
|
||||||
QPixmapCache::remove(key);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool _replace(const QPixmapCache::Key& key, const QPixmap& pixmap) { return QPixmapCache::replace(key, pixmap); }
|
|
||||||
bool _setCacheLimit(int n)
|
|
||||||
{
|
|
||||||
QPixmapCache::setCacheLimit(n);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static PixmapCache* s_instance;
|
|
||||||
};
|
|
@ -1,90 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
/*
|
|
||||||
* PrismLauncher - Minecraft Launcher
|
|
||||||
* Copyright (C) 2022 Jan Drögehoff <sentrycraft123@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <QStringList>
|
|
||||||
#include <QDir>
|
|
||||||
#include <QString>
|
|
||||||
#include <QtGlobal>
|
|
||||||
|
|
||||||
#include "MangoHud.h"
|
|
||||||
#include "FileSystem.h"
|
|
||||||
#include "Json.h"
|
|
||||||
|
|
||||||
namespace MangoHud {
|
|
||||||
|
|
||||||
QString getLibraryString()
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Check for vulkan layers in this order:
|
|
||||||
*
|
|
||||||
* $VK_LAYER_PATH
|
|
||||||
* $XDG_DATA_DIRS (/usr/local/share/:/usr/share/)
|
|
||||||
* $XDG_DATA_HOME (~/.local/share)
|
|
||||||
* /etc
|
|
||||||
* $XDG_CONFIG_DIRS (/etc/xdg)
|
|
||||||
* $XDG_CONFIG_HOME (~/.config)
|
|
||||||
*/
|
|
||||||
|
|
||||||
QStringList vkLayerList;
|
|
||||||
{
|
|
||||||
QString home = QDir::homePath();
|
|
||||||
|
|
||||||
QString vkLayerPath = qEnvironmentVariable("VK_LAYER_PATH");
|
|
||||||
if (!vkLayerPath.isEmpty()) {
|
|
||||||
vkLayerList << vkLayerPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList xdgDataDirs = qEnvironmentVariable("XDG_DATA_DIRS", "/usr/local/share/:/usr/share/").split(QLatin1String(":"));
|
|
||||||
for (QString dir : xdgDataDirs) {
|
|
||||||
vkLayerList << FS::PathCombine(dir, "vulkan", "implicit_layer.d");
|
|
||||||
}
|
|
||||||
|
|
||||||
QString xdgDataHome = qEnvironmentVariable("XDG_DATA_HOME");
|
|
||||||
if (xdgDataHome.isEmpty()) {
|
|
||||||
xdgDataHome = FS::PathCombine(home, ".local", "share");
|
|
||||||
}
|
|
||||||
vkLayerList << FS::PathCombine(xdgDataHome, "vulkan", "implicit_layer.d");
|
|
||||||
|
|
||||||
vkLayerList << "/etc";
|
|
||||||
|
|
||||||
QStringList xdgConfigDirs = qEnvironmentVariable("XDG_CONFIG_DIRS", "/etc/xdg").split(QLatin1String(":"));
|
|
||||||
for (QString dir : xdgConfigDirs) {
|
|
||||||
vkLayerList << FS::PathCombine(dir, "vulkan", "implicit_layer.d");
|
|
||||||
}
|
|
||||||
|
|
||||||
QString xdgConfigHome = qEnvironmentVariable("XDG_CONFIG_HOME");
|
|
||||||
if (xdgConfigHome.isEmpty()) {
|
|
||||||
xdgConfigHome = FS::PathCombine(home, ".config");
|
|
||||||
}
|
|
||||||
vkLayerList << FS::PathCombine(xdgConfigHome, "vulkan", "implicit_layer.d");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (QString vkLayer : vkLayerList) {
|
|
||||||
QString filePath = FS::PathCombine(vkLayer, "MangoHud.json");
|
|
||||||
if (!QFile::exists(filePath))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
auto conf = Json::requireDocument(filePath, vkLayer);
|
|
||||||
auto confObject = Json::requireObject(conf, vkLayer);
|
|
||||||
auto layer = Json::ensureObject(confObject, "layer");
|
|
||||||
return Json::ensureString(layer, "library_path");
|
|
||||||
}
|
|
||||||
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
} // namespace MangoHud
|
|
@ -1,27 +0,0 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
/*
|
|
||||||
* PrismLauncher - Minecraft Launcher
|
|
||||||
* Copyright (C) 2022 Jan Drögehoff <sentrycraft123@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, version 3.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QString>
|
|
||||||
#include <QStringList>
|
|
||||||
|
|
||||||
namespace MangoHud {
|
|
||||||
|
|
||||||
QString getLibraryString();
|
|
||||||
}
|
|
@ -311,14 +311,14 @@ QModelIndex VersionProxyModel::index(int row, int column, const QModelIndex &par
|
|||||||
|
|
||||||
int VersionProxyModel::columnCount(const QModelIndex &parent) const
|
int VersionProxyModel::columnCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
return parent.isValid() ? 0 : m_columns.size();
|
return m_columns.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
int VersionProxyModel::rowCount(const QModelIndex &parent) const
|
int VersionProxyModel::rowCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
if(sourceModel())
|
if(sourceModel())
|
||||||
{
|
{
|
||||||
return sourceModel()->rowCount(parent);
|
return sourceModel()->rowCount();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -242,7 +242,7 @@ Qt::DropActions IconList::supportedDropActions() const
|
|||||||
return Qt::CopyAction;
|
return Qt::CopyAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IconList::dropMimeData(const QMimeData *data, Qt::DropAction action, [[maybe_unused]] int row, [[maybe_unused]] int column, [[maybe_unused]] const QModelIndex &parent)
|
bool IconList::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
|
||||||
{
|
{
|
||||||
if (action == Qt::IgnoreAction)
|
if (action == Qt::IgnoreAction)
|
||||||
return true;
|
return true;
|
||||||
@ -302,7 +302,7 @@ QVariant IconList::data(const QModelIndex &index, int role) const
|
|||||||
|
|
||||||
int IconList::rowCount(const QModelIndex &parent) const
|
int IconList::rowCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
return parent.isValid() ? 0 : icons.size();
|
return icons.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IconList::installIcons(const QStringList &iconFiles)
|
void IconList::installIcons(const QStringList &iconFiles)
|
||||||
|
@ -439,28 +439,19 @@ QList<QString> JavaUtils::FindJavaPaths()
|
|||||||
javas.append(FS::PathCombine(prefix, "bin/java"));
|
javas.append(FS::PathCombine(prefix, "bin/java"));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// java installed in a snap is installed in the standard directory, but underneath $SNAP
|
|
||||||
auto snap = qEnvironmentVariable("SNAP");
|
|
||||||
auto scanJavaDirs = [&](const QString & dirPath)
|
|
||||||
{
|
|
||||||
scanJavaDir(dirPath);
|
|
||||||
if (!snap.isNull()) {
|
|
||||||
scanJavaDir(snap + dirPath);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// oracle RPMs
|
// oracle RPMs
|
||||||
scanJavaDirs("/usr/java");
|
scanJavaDir("/usr/java");
|
||||||
// general locations used by distro packaging
|
// general locations used by distro packaging
|
||||||
scanJavaDirs("/usr/lib/jvm");
|
scanJavaDir("/usr/lib/jvm");
|
||||||
scanJavaDirs("/usr/lib64/jvm");
|
scanJavaDir("/usr/lib64/jvm");
|
||||||
scanJavaDirs("/usr/lib32/jvm");
|
scanJavaDir("/usr/lib32/jvm");
|
||||||
// javas stored in Prism Launcher's folder
|
// javas stored in Prism Launcher's folder
|
||||||
scanJavaDirs("java");
|
scanJavaDir("java");
|
||||||
// manually installed JDKs in /opt
|
// manually installed JDKs in /opt
|
||||||
scanJavaDirs("/opt/jdk");
|
scanJavaDir("/opt/jdk");
|
||||||
scanJavaDirs("/opt/jdks");
|
scanJavaDir("/opt/jdks");
|
||||||
// flatpak
|
// flatpak
|
||||||
scanJavaDirs("/app/jdk");
|
scanJavaDir("/app/jdk");
|
||||||
javas = addJavasFromEnv(javas);
|
javas = addJavasFromEnv(javas);
|
||||||
javas.removeDuplicates();
|
javas.removeDuplicates();
|
||||||
return javas;
|
return javas;
|
||||||
|
@ -81,12 +81,9 @@ int main(int argc, char *argv[])
|
|||||||
Q_INIT_RESOURCE(pe_light);
|
Q_INIT_RESOURCE(pe_light);
|
||||||
Q_INIT_RESOURCE(pe_blue);
|
Q_INIT_RESOURCE(pe_blue);
|
||||||
Q_INIT_RESOURCE(pe_colored);
|
Q_INIT_RESOURCE(pe_colored);
|
||||||
Q_INIT_RESOURCE(breeze_dark);
|
|
||||||
Q_INIT_RESOURCE(breeze_light);
|
|
||||||
Q_INIT_RESOURCE(OSX);
|
Q_INIT_RESOURCE(OSX);
|
||||||
Q_INIT_RESOURCE(iOS);
|
Q_INIT_RESOURCE(iOS);
|
||||||
Q_INIT_RESOURCE(flat);
|
Q_INIT_RESOURCE(flat);
|
||||||
Q_INIT_RESOURCE(flat_white);
|
|
||||||
return app.exec();
|
return app.exec();
|
||||||
}
|
}
|
||||||
case Application::Failed:
|
case Application::Failed:
|
||||||
|
@ -58,11 +58,11 @@ QVariant Index::data(const QModelIndex &index, int role) const
|
|||||||
}
|
}
|
||||||
int Index::rowCount(const QModelIndex &parent) const
|
int Index::rowCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
return parent.isValid() ? 0 : m_lists.size();
|
return m_lists.size();
|
||||||
}
|
}
|
||||||
int Index::columnCount(const QModelIndex &parent) const
|
int Index::columnCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
return parent.isValid() ? 0 : 1;
|
return 1;
|
||||||
}
|
}
|
||||||
QVariant Index::headerData(int section, Qt::Orientation orientation, int role) const
|
QVariant Index::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
{
|
{
|
||||||
|
@ -60,6 +60,11 @@ struct Require
|
|||||||
QString suggests;
|
QString suggests;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline Q_DECL_PURE_FUNCTION uint qHash(const Require &key, uint seed = 0) Q_DECL_NOTHROW
|
||||||
|
{
|
||||||
|
return qHash(key.uid, seed);
|
||||||
|
}
|
||||||
|
|
||||||
using RequireSet = std::set<Require>;
|
using RequireSet = std::set<Require>;
|
||||||
|
|
||||||
void parseIndex(const QJsonObject &obj, Index *ptr);
|
void parseIndex(const QJsonObject &obj, Index *ptr);
|
||||||
|
@ -10,7 +10,7 @@ typedef std::shared_ptr<Agent> AgentPtr;
|
|||||||
|
|
||||||
class Agent {
|
class Agent {
|
||||||
public:
|
public:
|
||||||
Agent(LibraryPtr library, const QString &argument)
|
Agent(LibraryPtr library, QString &argument)
|
||||||
{
|
{
|
||||||
m_library = library;
|
m_library = library;
|
||||||
m_argument = argument;
|
m_argument = argument;
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
/*
|
/*
|
||||||
* Prism Launcher - 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>
|
* Copyright (C) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||||
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
|
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -88,10 +87,6 @@
|
|||||||
#include "minecraft/gameoptions/GameOptions.h"
|
#include "minecraft/gameoptions/GameOptions.h"
|
||||||
#include "minecraft/update/FoldersTask.h"
|
#include "minecraft/update/FoldersTask.h"
|
||||||
|
|
||||||
#ifdef Q_OS_LINUX
|
|
||||||
#include "MangoHud.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define IBUS "@im=ibus"
|
#define IBUS "@im=ibus"
|
||||||
|
|
||||||
// all of this because keeping things compatible with deprecated old settings
|
// all of this because keeping things compatible with deprecated old settings
|
||||||
@ -441,17 +436,6 @@ QStringList MinecraftInstance::javaArguments()
|
|||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MinecraftInstance::getLauncher()
|
|
||||||
{
|
|
||||||
auto profile = m_components->getProfile();
|
|
||||||
|
|
||||||
// use legacy launcher if the traits are set
|
|
||||||
if (profile->getTraits().contains("legacyLaunch") || profile->getTraits().contains("alphaLaunch"))
|
|
||||||
return "legacy";
|
|
||||||
|
|
||||||
return "standard";
|
|
||||||
}
|
|
||||||
|
|
||||||
QMap<QString, QString> MinecraftInstance::getVariables()
|
QMap<QString, QString> MinecraftInstance::getVariables()
|
||||||
{
|
{
|
||||||
QMap<QString, QString> out;
|
QMap<QString, QString> out;
|
||||||
@ -486,22 +470,9 @@ QProcessEnvironment MinecraftInstance::createLaunchEnvironment()
|
|||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
if (settings()->get("EnableMangoHud").toBool() && APPLICATION->capabilities() & Application::SupportsMangoHud)
|
if (settings()->get("EnableMangoHud").toBool() && APPLICATION->capabilities() & Application::SupportsMangoHud)
|
||||||
{
|
{
|
||||||
|
auto preload = env.value("LD_PRELOAD", "") + ":libMangoHud_dlsym.so:libMangoHud.so";
|
||||||
|
|
||||||
auto preloadList = env.value("LD_PRELOAD").split(QLatin1String(":"));
|
env.insert("LD_PRELOAD", preload);
|
||||||
auto libPaths = env.value("LD_LIBRARY_PATH").split(QLatin1String(":"));
|
|
||||||
|
|
||||||
auto mangoHudLibString = MangoHud::getLibraryString();
|
|
||||||
if (!mangoHudLibString.isEmpty())
|
|
||||||
{
|
|
||||||
QFileInfo mangoHudLib(mangoHudLibString);
|
|
||||||
|
|
||||||
// dlsym variant is only needed for OpenGL and not included in the vulkan layer
|
|
||||||
preloadList << "libMangoHud_dlsym.so" << mangoHudLib.fileName();
|
|
||||||
libPaths << mangoHudLib.absolutePath();
|
|
||||||
}
|
|
||||||
|
|
||||||
env.insert("LD_PRELOAD", preloadList.join(QLatin1String(":")));
|
|
||||||
env.insert("LD_LIBRARY_PATH", libPaths.join(QLatin1String(":")));
|
|
||||||
env.insert("MANGOHUD", "1");
|
env.insert("MANGOHUD", "1");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -656,13 +627,26 @@ QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftS
|
|||||||
launchScript += "sessionId " + session->session + "\n";
|
launchScript += "sessionId " + session->session + "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// libraries and class path.
|
||||||
|
{
|
||||||
|
QStringList jars, nativeJars;
|
||||||
|
profile->getLibraryFiles(runtimeContext(), jars, nativeJars, getLocalLibraryPath(), binRoot());
|
||||||
|
for(auto file: jars)
|
||||||
|
{
|
||||||
|
launchScript += "cp " + file + "\n";
|
||||||
|
}
|
||||||
|
for(auto file: nativeJars)
|
||||||
|
{
|
||||||
|
launchScript += "ext " + file + "\n";
|
||||||
|
}
|
||||||
|
launchScript += "natives " + getNativePath() + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
for (auto trait : profile->getTraits())
|
for (auto trait : profile->getTraits())
|
||||||
{
|
{
|
||||||
launchScript += "traits " + trait + "\n";
|
launchScript += "traits " + trait + "\n";
|
||||||
}
|
}
|
||||||
|
launchScript += "launcher onesix\n";
|
||||||
launchScript += "launcher " + getLauncher() + "\n";
|
|
||||||
|
|
||||||
// qDebug() << "Generated launch script:" << launchScript;
|
// qDebug() << "Generated launch script:" << launchScript;
|
||||||
return launchScript;
|
return launchScript;
|
||||||
}
|
}
|
||||||
@ -798,8 +782,6 @@ QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, Minecr
|
|||||||
out << "Window size: " + QString::number(width) + " x " + QString::number(height);
|
out << "Window size: " + QString::number(width) + " x " + QString::number(height);
|
||||||
}
|
}
|
||||||
out << "";
|
out << "";
|
||||||
out << "Launcher: " + getLauncher();
|
|
||||||
out << "";
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1127,6 +1109,8 @@ std::shared_ptr<ResourcePackFolderModel> MinecraftInstance::resourcePackList() c
|
|||||||
if (!m_resource_pack_list)
|
if (!m_resource_pack_list)
|
||||||
{
|
{
|
||||||
m_resource_pack_list.reset(new ResourcePackFolderModel(resourcePacksDir()));
|
m_resource_pack_list.reset(new ResourcePackFolderModel(resourcePacksDir()));
|
||||||
|
m_resource_pack_list->enableInteraction(!isRunning());
|
||||||
|
connect(this, &BaseInstance::runningStatusChanged, m_resource_pack_list.get(), &ResourcePackFolderModel::disableInteraction);
|
||||||
}
|
}
|
||||||
return m_resource_pack_list;
|
return m_resource_pack_list;
|
||||||
}
|
}
|
||||||
@ -1136,6 +1120,8 @@ std::shared_ptr<TexturePackFolderModel> MinecraftInstance::texturePackList() con
|
|||||||
if (!m_texture_pack_list)
|
if (!m_texture_pack_list)
|
||||||
{
|
{
|
||||||
m_texture_pack_list.reset(new TexturePackFolderModel(texturePacksDir()));
|
m_texture_pack_list.reset(new TexturePackFolderModel(texturePacksDir()));
|
||||||
|
m_texture_pack_list->disableInteraction(isRunning());
|
||||||
|
connect(this, &BaseInstance::runningStatusChanged, m_texture_pack_list.get(), &ModFolderModel::disableInteraction);
|
||||||
}
|
}
|
||||||
return m_texture_pack_list;
|
return m_texture_pack_list;
|
||||||
}
|
}
|
||||||
@ -1145,6 +1131,8 @@ std::shared_ptr<ShaderPackFolderModel> MinecraftInstance::shaderPackList() const
|
|||||||
if (!m_shader_pack_list)
|
if (!m_shader_pack_list)
|
||||||
{
|
{
|
||||||
m_shader_pack_list.reset(new ShaderPackFolderModel(shaderPacksDir()));
|
m_shader_pack_list.reset(new ShaderPackFolderModel(shaderPacksDir()));
|
||||||
|
m_shader_pack_list->disableInteraction(isRunning());
|
||||||
|
connect(this, &BaseInstance::runningStatusChanged, m_shader_pack_list.get(), &ModFolderModel::disableInteraction);
|
||||||
}
|
}
|
||||||
return m_shader_pack_list;
|
return m_shader_pack_list;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
/*
|
/*
|
||||||
* Prism Launcher - Minecraft Launcher
|
* PolyMC - Minecraft Launcher
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
|
|
||||||
*
|
*
|
||||||
* 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
|
||||||
@ -131,7 +130,6 @@ public:
|
|||||||
QString createLaunchScript(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin);
|
QString createLaunchScript(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin);
|
||||||
/// get arguments passed to java
|
/// get arguments passed to java
|
||||||
QStringList javaArguments();
|
QStringList javaArguments();
|
||||||
QString getLauncher();
|
|
||||||
|
|
||||||
/// get variables for launch command variable substitution/environment
|
/// get variables for launch command variable substitution/environment
|
||||||
QMap<QString, QString> getVariables() override;
|
QMap<QString, QString> getVariables() override;
|
||||||
|
@ -135,7 +135,7 @@ QJsonObject libDownloadInfoToJson(MojangLibraryDownloadInfo::Ptr libinfo)
|
|||||||
{
|
{
|
||||||
out.insert("artifact", downloadInfoToJson(libinfo->artifact));
|
out.insert("artifact", downloadInfoToJson(libinfo->artifact));
|
||||||
}
|
}
|
||||||
if(!libinfo->classifiers.isEmpty())
|
if(libinfo->classifiers.size())
|
||||||
{
|
{
|
||||||
QJsonObject classifiersOut;
|
QJsonObject classifiersOut;
|
||||||
for(auto iter = libinfo->classifiers.begin(); iter != libinfo->classifiers.end(); iter++)
|
for(auto iter = libinfo->classifiers.begin(); iter != libinfo->classifiers.end(); iter++)
|
||||||
@ -297,7 +297,7 @@ void MojangVersionFormat::writeVersionProperties(const VersionFile* in, QJsonObj
|
|||||||
{
|
{
|
||||||
out.insert("assetIndex", assetIndexToJson(in->mojangAssetIndex));
|
out.insert("assetIndex", assetIndexToJson(in->mojangAssetIndex));
|
||||||
}
|
}
|
||||||
if(!in->mojangDownloads.isEmpty())
|
if(in->mojangDownloads.size())
|
||||||
{
|
{
|
||||||
QJsonObject downloadsOut;
|
QJsonObject downloadsOut;
|
||||||
for(auto iter = in->mojangDownloads.begin(); iter != in->mojangDownloads.end(); iter++)
|
for(auto iter = in->mojangDownloads.begin(); iter != in->mojangDownloads.end(); iter++)
|
||||||
@ -306,15 +306,6 @@ void MojangVersionFormat::writeVersionProperties(const VersionFile* in, QJsonObj
|
|||||||
}
|
}
|
||||||
out.insert("downloads", downloadsOut);
|
out.insert("downloads", downloadsOut);
|
||||||
}
|
}
|
||||||
if(!in->compatibleJavaMajors.isEmpty())
|
|
||||||
{
|
|
||||||
QJsonArray compatibleJavaMajorsOut;
|
|
||||||
for(auto compatibleJavaMajor : in->compatibleJavaMajors)
|
|
||||||
{
|
|
||||||
compatibleJavaMajorsOut.append(compatibleJavaMajor);
|
|
||||||
}
|
|
||||||
out.insert("compatibleJavaMajors", compatibleJavaMajorsOut);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonDocument MojangVersionFormat::versionFileToJson(const VersionFilePtr &patch)
|
QJsonDocument MojangVersionFormat::versionFileToJson(const VersionFilePtr &patch)
|
||||||
@ -405,7 +396,7 @@ QJsonObject MojangVersionFormat::libraryToJson(Library *library)
|
|||||||
iter++;
|
iter++;
|
||||||
}
|
}
|
||||||
libRoot.insert("natives", nativeList);
|
libRoot.insert("natives", nativeList);
|
||||||
if (!library->m_extractExcludes.isEmpty())
|
if (library->m_extractExcludes.size())
|
||||||
{
|
{
|
||||||
QJsonArray excludes;
|
QJsonArray excludes;
|
||||||
QJsonObject extract;
|
QJsonObject extract;
|
||||||
@ -417,7 +408,7 @@ QJsonObject MojangVersionFormat::libraryToJson(Library *library)
|
|||||||
libRoot.insert("extract", extract);
|
libRoot.insert("extract", extract);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!library->m_rules.isEmpty())
|
if (library->m_rules.size())
|
||||||
{
|
{
|
||||||
QJsonArray allRules;
|
QJsonArray allRules;
|
||||||
for (auto &rule : library->m_rules)
|
for (auto &rule : library->m_rules)
|
||||||
|
@ -39,8 +39,6 @@
|
|||||||
#include "minecraft/ParseUtils.h"
|
#include "minecraft/ParseUtils.h"
|
||||||
#include <minecraft/MojangVersionFormat.h>
|
#include <minecraft/MojangVersionFormat.h>
|
||||||
|
|
||||||
#include <QRegularExpression>
|
|
||||||
|
|
||||||
using namespace Json;
|
using namespace Json;
|
||||||
|
|
||||||
static void readString(const QJsonObject &root, const QString &key, QString &variable)
|
static void readString(const QJsonObject &root, const QString &key, QString &variable)
|
||||||
@ -65,13 +63,13 @@ LibraryPtr OneSixVersionFormat::libraryFromJson(ProblemContainer & problems, con
|
|||||||
QJsonObject OneSixVersionFormat::libraryToJson(Library *library)
|
QJsonObject OneSixVersionFormat::libraryToJson(Library *library)
|
||||||
{
|
{
|
||||||
QJsonObject libRoot = MojangVersionFormat::libraryToJson(library);
|
QJsonObject libRoot = MojangVersionFormat::libraryToJson(library);
|
||||||
if (!library->m_absoluteURL.isEmpty())
|
if (library->m_absoluteURL.size())
|
||||||
libRoot.insert("MMC-absoluteUrl", library->m_absoluteURL);
|
libRoot.insert("MMC-absoluteUrl", library->m_absoluteURL);
|
||||||
if (!library->m_hint.isEmpty())
|
if (library->m_hint.size())
|
||||||
libRoot.insert("MMC-hint", library->m_hint);
|
libRoot.insert("MMC-hint", library->m_hint);
|
||||||
if (!library->m_filename.isEmpty())
|
if (library->m_filename.size())
|
||||||
libRoot.insert("MMC-filename", library->m_filename);
|
libRoot.insert("MMC-filename", library->m_filename);
|
||||||
if (!library->m_displayname.isEmpty())
|
if (library->m_displayname.size())
|
||||||
libRoot.insert("MMC-displayname", library->m_displayname);
|
libRoot.insert("MMC-displayname", library->m_displayname);
|
||||||
return libRoot;
|
return libRoot;
|
||||||
}
|
}
|
||||||
@ -123,15 +121,6 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc
|
|||||||
out->uid = root.value("fileId").toString();
|
out->uid = root.value("fileId").toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
const QRegularExpression valid_uid_regex{ QRegularExpression::anchoredPattern(QStringLiteral(R"([a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]+)*)")) };
|
|
||||||
if (!valid_uid_regex.match(out->uid).hasMatch()) {
|
|
||||||
qCritical() << "The component's 'uid' contains illegal characters! UID:" << out->uid;
|
|
||||||
out->addProblem(
|
|
||||||
ProblemSeverity::Error,
|
|
||||||
QObject::tr("The component's 'uid' contains illegal characters! This can cause security issues.")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
out->version = root.value("version").toString();
|
out->version = root.value("version").toString();
|
||||||
|
|
||||||
MojangVersionFormat::readVersionProperties(root, out.get());
|
MojangVersionFormat::readVersionProperties(root, out.get());
|
||||||
@ -236,10 +225,11 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc
|
|||||||
{
|
{
|
||||||
QJsonObject agentObj = requireObject(agentVal);
|
QJsonObject agentObj = requireObject(agentVal);
|
||||||
auto lib = libraryFromJson(*out, agentObj, filename);
|
auto lib = libraryFromJson(*out, agentObj, filename);
|
||||||
|
|
||||||
QString arg = "";
|
QString arg = "";
|
||||||
readString(agentObj, "argument", arg);
|
if (agentObj.contains("argument"))
|
||||||
|
{
|
||||||
|
readString(agentObj, "argument", arg);
|
||||||
|
}
|
||||||
AgentPtr agent(new Agent(lib, arg));
|
AgentPtr agent(new Agent(lib, arg));
|
||||||
out->agents.append(agent);
|
out->agents.append(agent);
|
||||||
}
|
}
|
||||||
@ -342,20 +332,6 @@ QJsonDocument OneSixVersionFormat::versionFileToJson(const VersionFilePtr &patch
|
|||||||
writeString(root, "appletClass", patch->appletClass);
|
writeString(root, "appletClass", patch->appletClass);
|
||||||
writeStringList(root, "+tweakers", patch->addTweakers);
|
writeStringList(root, "+tweakers", patch->addTweakers);
|
||||||
writeStringList(root, "+traits", patch->traits.values());
|
writeStringList(root, "+traits", patch->traits.values());
|
||||||
writeStringList(root, "+jvmArgs", patch->addnJvmArguments);
|
|
||||||
if (!patch->agents.isEmpty())
|
|
||||||
{
|
|
||||||
QJsonArray array;
|
|
||||||
for (auto value: patch->agents)
|
|
||||||
{
|
|
||||||
QJsonObject agentOut = OneSixVersionFormat::libraryToJson(value->library().get());
|
|
||||||
if (!value->argument().isEmpty())
|
|
||||||
agentOut.insert("argument", value->argument());
|
|
||||||
|
|
||||||
array.append(agentOut);
|
|
||||||
}
|
|
||||||
root.insert("+agents", array);
|
|
||||||
}
|
|
||||||
if (!patch->libraries.isEmpty())
|
if (!patch->libraries.isEmpty())
|
||||||
{
|
{
|
||||||
QJsonArray array;
|
QJsonArray array;
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
/*
|
/*
|
||||||
* Prism Launcher - Minecraft Launcher
|
* PolyMC - Minecraft Launcher
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
|
|
||||||
*
|
*
|
||||||
* 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
|
||||||
@ -48,6 +47,7 @@
|
|||||||
#include "Exception.h"
|
#include "Exception.h"
|
||||||
#include "minecraft/OneSixVersionFormat.h"
|
#include "minecraft/OneSixVersionFormat.h"
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
|
#include "meta/Index.h"
|
||||||
#include "minecraft/MinecraftInstance.h"
|
#include "minecraft/MinecraftInstance.h"
|
||||||
#include "Json.h"
|
#include "Json.h"
|
||||||
|
|
||||||
@ -55,6 +55,7 @@
|
|||||||
#include "PackProfile_p.h"
|
#include "PackProfile_p.h"
|
||||||
#include "ComponentUpdateTask.h"
|
#include "ComponentUpdateTask.h"
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
#include "modplatform/ModAPI.h"
|
#include "modplatform/ModAPI.h"
|
||||||
|
|
||||||
static const QMap<QString, ModAPI::ModLoaderType> modloaderMapping{
|
static const QMap<QString, ModAPI::ModLoaderType> modloaderMapping{
|
||||||
@ -612,7 +613,7 @@ QVariant PackProfile::data(const QModelIndex &index, int role) const
|
|||||||
|
|
||||||
bool PackProfile::setData(const QModelIndex& index, const QVariant& value, int role)
|
bool PackProfile::setData(const QModelIndex& index, const QVariant& value, int role)
|
||||||
{
|
{
|
||||||
if (!index.isValid() || index.row() < 0 || index.row() >= rowCount(index.parent()))
|
if (!index.isValid() || index.row() < 0 || index.row() >= rowCount(index))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -674,12 +675,12 @@ Qt::ItemFlags PackProfile::flags(const QModelIndex &index) const
|
|||||||
|
|
||||||
int PackProfile::rowCount(const QModelIndex &parent) const
|
int PackProfile::rowCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
return parent.isValid() ? 0 : d->components.size();
|
return d->components.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
int PackProfile::columnCount(const QModelIndex &parent) const
|
int PackProfile::columnCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
return parent.isValid() ? 0 : NUM_COLUMNS;
|
return NUM_COLUMNS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PackProfile::move(const int index, const MoveDirection direction)
|
void PackProfile::move(const int index, const MoveDirection direction)
|
||||||
@ -737,11 +738,6 @@ void PackProfile::installCustomJar(QString selectedFile)
|
|||||||
installCustomJar_internal(selectedFile);
|
installCustomJar_internal(selectedFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PackProfile::installAgents(QStringList selectedFiles)
|
|
||||||
{
|
|
||||||
installAgents_internal(selectedFiles);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PackProfile::installEmpty(const QString& uid, const QString& name)
|
bool PackProfile::installEmpty(const QString& uid, const QString& name)
|
||||||
{
|
{
|
||||||
QString patchDir = FS::PathCombine(d->m_instance->instanceRoot(), "patches");
|
QString patchDir = FS::PathCombine(d->m_instance->instanceRoot(), "patches");
|
||||||
@ -836,14 +832,18 @@ bool PackProfile::installJarMods_internal(QStringList filepaths)
|
|||||||
for(auto filepath:filepaths)
|
for(auto filepath:filepaths)
|
||||||
{
|
{
|
||||||
QFileInfo sourceInfo(filepath);
|
QFileInfo sourceInfo(filepath);
|
||||||
QString id = QUuid::createUuid().toString(QUuid::WithoutBraces);
|
auto uuid = QUuid::createUuid();
|
||||||
|
QString id = uuid.toString().remove('{').remove('}');
|
||||||
QString target_filename = id + ".jar";
|
QString target_filename = id + ".jar";
|
||||||
QString target_id = "custom.jarmod." + id;
|
QString target_id = "org.multimc.jarmod." + id;
|
||||||
QString target_name = sourceInfo.completeBaseName() + " (jar mod)";
|
QString target_name = sourceInfo.completeBaseName() + " (jar mod)";
|
||||||
QString finalPath = FS::PathCombine(d->m_instance->jarModsDir(), target_filename);
|
QString finalPath = FS::PathCombine(d->m_instance->jarModsDir(), target_filename);
|
||||||
|
|
||||||
QFileInfo targetInfo(finalPath);
|
QFileInfo targetInfo(finalPath);
|
||||||
Q_ASSERT(!targetInfo.exists());
|
if(targetInfo.exists())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!QFile::copy(sourceInfo.absoluteFilePath(),QFileInfo(finalPath).absoluteFilePath()))
|
if (!QFile::copy(sourceInfo.absoluteFilePath(),QFileInfo(finalPath).absoluteFilePath()))
|
||||||
{
|
{
|
||||||
@ -852,7 +852,7 @@ bool PackProfile::installJarMods_internal(QStringList filepaths)
|
|||||||
|
|
||||||
auto f = std::make_shared<VersionFile>();
|
auto f = std::make_shared<VersionFile>();
|
||||||
auto jarMod = std::make_shared<Library>();
|
auto jarMod = std::make_shared<Library>();
|
||||||
jarMod->setRawName(GradleSpecifier("custom.jarmods:" + id + ":1"));
|
jarMod->setRawName(GradleSpecifier("org.multimc.jarmods:" + id + ":1"));
|
||||||
jarMod->setFilename(target_filename);
|
jarMod->setFilename(target_filename);
|
||||||
jarMod->setDisplayName(sourceInfo.completeBaseName());
|
jarMod->setDisplayName(sourceInfo.completeBaseName());
|
||||||
jarMod->setHint("local");
|
jarMod->setHint("local");
|
||||||
@ -892,7 +892,7 @@ bool PackProfile::installCustomJar_internal(QString filepath)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto specifier = GradleSpecifier("custom:customjar:1");
|
auto specifier = GradleSpecifier("org.multimc:customjar:1");
|
||||||
QFileInfo sourceInfo(filepath);
|
QFileInfo sourceInfo(filepath);
|
||||||
QString target_filename = specifier.getFileName();
|
QString target_filename = specifier.getFileName();
|
||||||
QString target_id = specifier.artifactId();
|
QString target_id = specifier.artifactId();
|
||||||
@ -939,64 +939,6 @@ bool PackProfile::installCustomJar_internal(QString filepath)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PackProfile::installAgents_internal(QStringList filepaths)
|
|
||||||
{
|
|
||||||
// FIXME code duplication
|
|
||||||
const QString patchDir = FS::PathCombine(d->m_instance->instanceRoot(), "patches");
|
|
||||||
if (!FS::ensureFolderPathExists(patchDir))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const QString libDir = d->m_instance->getLocalLibraryPath();
|
|
||||||
if (!FS::ensureFolderPathExists(libDir))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (const QString& source : filepaths) {
|
|
||||||
const QFileInfo sourceInfo(source);
|
|
||||||
const QString id = QUuid::createUuid().toString(QUuid::WithoutBraces);
|
|
||||||
const QString targetBaseName = id + ".jar";
|
|
||||||
const QString targetId = "custom.agent." + id;
|
|
||||||
const QString targetName = sourceInfo.completeBaseName() + " (agent)";
|
|
||||||
const QString target = FS::PathCombine(d->m_instance->getLocalLibraryPath(), targetBaseName);
|
|
||||||
|
|
||||||
const QFileInfo targetInfo(target);
|
|
||||||
Q_ASSERT(!targetInfo.exists());
|
|
||||||
|
|
||||||
if (!QFile::copy(source, target))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto versionFile = std::make_shared<VersionFile>();
|
|
||||||
|
|
||||||
auto agent = std::make_shared<Library>();
|
|
||||||
|
|
||||||
agent->setRawName("custom.agents:" + id + ":1");
|
|
||||||
agent->setFilename(targetBaseName);
|
|
||||||
agent->setDisplayName(sourceInfo.completeBaseName());
|
|
||||||
agent->setHint("local");
|
|
||||||
|
|
||||||
versionFile->agents.append(std::make_shared<Agent>(agent, QString()));
|
|
||||||
|
|
||||||
versionFile->name = targetName;
|
|
||||||
versionFile->uid = targetId;
|
|
||||||
|
|
||||||
QFile patchFile(FS::PathCombine(patchDir, targetId + ".json"));
|
|
||||||
|
|
||||||
if (!patchFile.open(QFile::WriteOnly)) {
|
|
||||||
qCritical() << "Error opening" << patchFile.fileName() << "for reading:" << patchFile.errorString();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
patchFile.write(OneSixVersionFormat::versionFileToJson(versionFile).toJson());
|
|
||||||
patchFile.close();
|
|
||||||
|
|
||||||
appendComponent(new Component(this, versionFile->uid, versionFile));
|
|
||||||
}
|
|
||||||
|
|
||||||
scheduleSave();
|
|
||||||
invalidateLaunchProfile();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<LaunchProfile> PackProfile::getProfile() const
|
std::shared_ptr<LaunchProfile> PackProfile::getProfile() const
|
||||||
{
|
{
|
||||||
if(!d->m_profile)
|
if(!d->m_profile)
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
/*
|
/*
|
||||||
* Prism Launcher - Minecraft Launcher
|
* PolyMC - Minecraft Launcher
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
|
|
||||||
*
|
*
|
||||||
* 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
|
||||||
@ -86,9 +85,6 @@ public:
|
|||||||
/// install a jar/zip as a replacement for the main jar
|
/// install a jar/zip as a replacement for the main jar
|
||||||
void installCustomJar(QString selectedFile);
|
void installCustomJar(QString selectedFile);
|
||||||
|
|
||||||
/// install Java agent files
|
|
||||||
void installAgents(QStringList selectedFiles);
|
|
||||||
|
|
||||||
enum MoveDirection { MoveUp, MoveDown };
|
enum MoveDirection { MoveUp, MoveDown };
|
||||||
/// move component file # up or down the list
|
/// move component file # up or down the list
|
||||||
void move(const int index, const MoveDirection direction);
|
void move(const int index, const MoveDirection direction);
|
||||||
@ -171,7 +167,6 @@ private:
|
|||||||
bool load();
|
bool load();
|
||||||
bool installJarMods_internal(QStringList filepaths);
|
bool installJarMods_internal(QStringList filepaths);
|
||||||
bool installCustomJar_internal(QString filepath);
|
bool installCustomJar_internal(QString filepath);
|
||||||
bool installAgents_internal(QStringList filepaths);
|
|
||||||
bool removeComponent_internal(ComponentPtr patch);
|
bool removeComponent_internal(ComponentPtr patch);
|
||||||
|
|
||||||
private: /* data */
|
private: /* data */
|
||||||
|
@ -104,7 +104,7 @@ public:
|
|||||||
class ImplicitRule : public Rule
|
class ImplicitRule : public Rule
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
virtual bool applies(const Library *, [[maybe_unused]] const RuntimeContext & runtimeContext)
|
virtual bool applies(const Library *, const RuntimeContext & runtimeContext)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -173,7 +173,7 @@ bool WorldList::resetIcon(int row)
|
|||||||
|
|
||||||
int WorldList::columnCount(const QModelIndex &parent) const
|
int WorldList::columnCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
return parent.isValid()? 0 : 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant WorldList::data(const QModelIndex &index, int role) const
|
QVariant WorldList::data(const QModelIndex &index, int role) const
|
||||||
@ -398,8 +398,8 @@ void WorldList::installWorld(QFileInfo filename)
|
|||||||
w.install(m_dir.absolutePath());
|
w.install(m_dir.absolutePath());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WorldList::dropMimeData(const QMimeData *data, Qt::DropAction action, [[maybe_unused]] int row, [[maybe_unused]] int column,
|
bool WorldList::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column,
|
||||||
[[maybe_unused]] const QModelIndex &parent)
|
const QModelIndex &parent)
|
||||||
{
|
{
|
||||||
if (action == Qt::IgnoreAction)
|
if (action == Qt::IgnoreAction)
|
||||||
return true;
|
return true;
|
||||||
|
@ -54,7 +54,7 @@ public:
|
|||||||
|
|
||||||
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const
|
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const
|
||||||
{
|
{
|
||||||
return parent.isValid() ? 0 : static_cast<int>(size());
|
return size();
|
||||||
};
|
};
|
||||||
virtual QVariant headerData(int section, Qt::Orientation orientation,
|
virtual QVariant headerData(int section, Qt::Orientation orientation,
|
||||||
int role = Qt::DisplayRole) const;
|
int role = Qt::DisplayRole) const;
|
||||||
|
@ -408,20 +408,20 @@ QVariant AccountList::headerData(int section, Qt::Orientation orientation, int r
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int AccountList::rowCount(const QModelIndex &parent) const
|
int AccountList::rowCount(const QModelIndex &) const
|
||||||
{
|
{
|
||||||
// Return count
|
// Return count
|
||||||
return parent.isValid() ? 0 : count();
|
return count();
|
||||||
}
|
}
|
||||||
|
|
||||||
int AccountList::columnCount(const QModelIndex &parent) const
|
int AccountList::columnCount(const QModelIndex &) const
|
||||||
{
|
{
|
||||||
return parent.isValid() ? 0 : NUM_COLUMNS;
|
return NUM_COLUMNS;
|
||||||
}
|
}
|
||||||
|
|
||||||
Qt::ItemFlags AccountList::flags(const QModelIndex &index) const
|
Qt::ItemFlags AccountList::flags(const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
if (index.row() < 0 || index.row() >= rowCount(index.parent()) || !index.isValid())
|
if (index.row() < 0 || index.row() >= rowCount(index) || !index.isValid())
|
||||||
{
|
{
|
||||||
return Qt::NoItemFlags;
|
return Qt::NoItemFlags;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#include "Parsers.h"
|
#include "Parsers.h"
|
||||||
#include "Json.h"
|
#include "Json.h"
|
||||||
#include "Logging.h"
|
|
||||||
|
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
@ -76,7 +75,9 @@ bool getBool(QJsonValue value, bool & out) {
|
|||||||
|
|
||||||
bool parseXTokenResponse(QByteArray & data, Katabasis::Token &output, QString name) {
|
bool parseXTokenResponse(QByteArray & data, Katabasis::Token &output, QString name) {
|
||||||
qDebug() << "Parsing" << name <<":";
|
qDebug() << "Parsing" << name <<":";
|
||||||
qCDebug(authCredentials()) << data;
|
#ifndef NDEBUG
|
||||||
|
qDebug() << data;
|
||||||
|
#endif
|
||||||
QJsonParseError jsonError;
|
QJsonParseError jsonError;
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
|
QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
|
||||||
if(jsonError.error) {
|
if(jsonError.error) {
|
||||||
@ -136,7 +137,9 @@ bool parseXTokenResponse(QByteArray & data, Katabasis::Token &output, QString na
|
|||||||
|
|
||||||
bool parseMinecraftProfile(QByteArray & data, MinecraftProfile &output) {
|
bool parseMinecraftProfile(QByteArray & data, MinecraftProfile &output) {
|
||||||
qDebug() << "Parsing Minecraft profile...";
|
qDebug() << "Parsing Minecraft profile...";
|
||||||
qCDebug(authCredentials()) << data;
|
#ifndef NDEBUG
|
||||||
|
qDebug() << data;
|
||||||
|
#endif
|
||||||
|
|
||||||
QJsonParseError jsonError;
|
QJsonParseError jsonError;
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
|
QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
|
||||||
@ -272,7 +275,9 @@ decoded base64 "value":
|
|||||||
|
|
||||||
bool parseMinecraftProfileMojang(QByteArray & data, MinecraftProfile &output) {
|
bool parseMinecraftProfileMojang(QByteArray & data, MinecraftProfile &output) {
|
||||||
qDebug() << "Parsing Minecraft profile...";
|
qDebug() << "Parsing Minecraft profile...";
|
||||||
qCDebug(authCredentials()) << data;
|
#ifndef NDEBUG
|
||||||
|
qDebug() << data;
|
||||||
|
#endif
|
||||||
|
|
||||||
QJsonParseError jsonError;
|
QJsonParseError jsonError;
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
|
QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
|
||||||
@ -384,7 +389,9 @@ bool parseMinecraftProfileMojang(QByteArray & data, MinecraftProfile &output) {
|
|||||||
|
|
||||||
bool parseMinecraftEntitlements(QByteArray & data, MinecraftEntitlement &output) {
|
bool parseMinecraftEntitlements(QByteArray & data, MinecraftEntitlement &output) {
|
||||||
qDebug() << "Parsing Minecraft entitlements...";
|
qDebug() << "Parsing Minecraft entitlements...";
|
||||||
qCDebug(authCredentials()) << data;
|
#ifndef NDEBUG
|
||||||
|
qDebug() << data;
|
||||||
|
#endif
|
||||||
|
|
||||||
QJsonParseError jsonError;
|
QJsonParseError jsonError;
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
|
QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
|
||||||
@ -417,7 +424,9 @@ bool parseMinecraftEntitlements(QByteArray & data, MinecraftEntitlement &output)
|
|||||||
|
|
||||||
bool parseRolloutResponse(QByteArray & data, bool& result) {
|
bool parseRolloutResponse(QByteArray & data, bool& result) {
|
||||||
qDebug() << "Parsing Rollout response...";
|
qDebug() << "Parsing Rollout response...";
|
||||||
qCDebug(authCredentials()) << data;
|
#ifndef NDEBUG
|
||||||
|
qDebug() << data;
|
||||||
|
#endif
|
||||||
|
|
||||||
QJsonParseError jsonError;
|
QJsonParseError jsonError;
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
|
QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
|
||||||
@ -446,7 +455,9 @@ bool parseRolloutResponse(QByteArray & data, bool& result) {
|
|||||||
bool parseMojangResponse(QByteArray & data, Katabasis::Token &output) {
|
bool parseMojangResponse(QByteArray & data, Katabasis::Token &output) {
|
||||||
QJsonParseError jsonError;
|
QJsonParseError jsonError;
|
||||||
qDebug() << "Parsing Mojang response...";
|
qDebug() << "Parsing Mojang response...";
|
||||||
qCDebug(authCredentials()) << data;
|
#ifndef NDEBUG
|
||||||
|
qDebug() << data;
|
||||||
|
#endif
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
|
QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
|
||||||
if(jsonError.error) {
|
if(jsonError.error) {
|
||||||
qWarning() << "Failed to parse response from api.minecraftservices.com/launcher/login as JSON: " << jsonError.errorString();
|
qWarning() << "Failed to parse response from api.minecraftservices.com/launcher/login as JSON: " << jsonError.errorString();
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
#include <QNetworkRequest>
|
#include <QNetworkRequest>
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
|
|
||||||
#include "Logging.h"
|
|
||||||
#include "minecraft/auth/AuthRequest.h"
|
#include "minecraft/auth/AuthRequest.h"
|
||||||
#include "minecraft/auth/Parsers.h"
|
#include "minecraft/auth/Parsers.h"
|
||||||
|
|
||||||
@ -42,7 +41,9 @@ void EntitlementsStep::onRequestDone(
|
|||||||
auto requestor = qobject_cast<AuthRequest *>(QObject::sender());
|
auto requestor = qobject_cast<AuthRequest *>(QObject::sender());
|
||||||
requestor->deleteLater();
|
requestor->deleteLater();
|
||||||
|
|
||||||
qCDebug(authCredentials()) << data;
|
#ifndef NDEBUG
|
||||||
|
qDebug() << data;
|
||||||
|
#endif
|
||||||
|
|
||||||
// TODO: check presence of same entitlementsRequestId?
|
// TODO: check presence of same entitlementsRequestId?
|
||||||
// TODO: validate JWTs?
|
// TODO: validate JWTs?
|
||||||
|
@ -2,10 +2,9 @@
|
|||||||
|
|
||||||
#include <QNetworkRequest>
|
#include <QNetworkRequest>
|
||||||
|
|
||||||
#include "Logging.h"
|
|
||||||
#include "minecraft/auth/AccountTask.h"
|
|
||||||
#include "minecraft/auth/AuthRequest.h"
|
#include "minecraft/auth/AuthRequest.h"
|
||||||
#include "minecraft/auth/Parsers.h"
|
#include "minecraft/auth/Parsers.h"
|
||||||
|
#include "minecraft/auth/AccountTask.h"
|
||||||
#include "net/NetUtils.h"
|
#include "net/NetUtils.h"
|
||||||
|
|
||||||
LauncherLoginStep::LauncherLoginStep(AccountData* data) : AuthStep(data) {
|
LauncherLoginStep::LauncherLoginStep(AccountData* data) : AuthStep(data) {
|
||||||
@ -52,10 +51,14 @@ void LauncherLoginStep::onRequestDone(
|
|||||||
auto requestor = qobject_cast<AuthRequest *>(QObject::sender());
|
auto requestor = qobject_cast<AuthRequest *>(QObject::sender());
|
||||||
requestor->deleteLater();
|
requestor->deleteLater();
|
||||||
|
|
||||||
qCDebug(authCredentials()) << data;
|
#ifndef NDEBUG
|
||||||
|
qDebug() << data;
|
||||||
|
#endif
|
||||||
if (error != QNetworkReply::NoError) {
|
if (error != QNetworkReply::NoError) {
|
||||||
qWarning() << "Reply error:" << error;
|
qWarning() << "Reply error:" << error;
|
||||||
qCDebug(authCredentials()) << data;
|
#ifndef NDEBUG
|
||||||
|
qDebug() << data;
|
||||||
|
#endif
|
||||||
if (Net::isApplicationError(error)) {
|
if (Net::isApplicationError(error)) {
|
||||||
emit finished(
|
emit finished(
|
||||||
AccountTaskState::STATE_FAILED_SOFT,
|
AccountTaskState::STATE_FAILED_SOFT,
|
||||||
@ -73,7 +76,9 @@ void LauncherLoginStep::onRequestDone(
|
|||||||
|
|
||||||
if(!Parsers::parseMojangResponse(data, m_data->yggdrasilToken)) {
|
if(!Parsers::parseMojangResponse(data, m_data->yggdrasilToken)) {
|
||||||
qWarning() << "Could not parse login_with_xbox response...";
|
qWarning() << "Could not parse login_with_xbox response...";
|
||||||
qCDebug(authCredentials()) << data;
|
#ifndef NDEBUG
|
||||||
|
qDebug() << data;
|
||||||
|
#endif
|
||||||
emit finished(
|
emit finished(
|
||||||
AccountTaskState::STATE_FAILED_SOFT,
|
AccountTaskState::STATE_FAILED_SOFT,
|
||||||
tr("Failed to parse the Minecraft access token response.")
|
tr("Failed to parse the Minecraft access token response.")
|
||||||
|
@ -42,7 +42,6 @@
|
|||||||
#include "minecraft/auth/Parsers.h"
|
#include "minecraft/auth/Parsers.h"
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "Logging.h"
|
|
||||||
|
|
||||||
using OAuth2 = Katabasis::DeviceFlow;
|
using OAuth2 = Katabasis::DeviceFlow;
|
||||||
using Activity = Katabasis::Activity;
|
using Activity = Katabasis::Activity;
|
||||||
@ -118,12 +117,14 @@ void MSAStep::onOAuthActivityChanged(Katabasis::Activity activity) {
|
|||||||
// Succeeded or did not invalidate tokens
|
// Succeeded or did not invalidate tokens
|
||||||
emit hideVerificationUriAndCode();
|
emit hideVerificationUriAndCode();
|
||||||
QVariantMap extraTokens = m_oauth2->extraTokens();
|
QVariantMap extraTokens = m_oauth2->extraTokens();
|
||||||
|
#ifndef NDEBUG
|
||||||
if (!extraTokens.isEmpty()) {
|
if (!extraTokens.isEmpty()) {
|
||||||
qCDebug(authCredentials()) << "Extra tokens in response:";
|
qDebug() << "Extra tokens in response:";
|
||||||
foreach (QString key, extraTokens.keys()) {
|
foreach (QString key, extraTokens.keys()) {
|
||||||
qCDebug(authCredentials()) << "\t" << key << ":" << extraTokens.value(key);
|
qDebug() << "\t" << key << ":" << extraTokens.value(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
emit finished(AccountTaskState::STATE_WORKING, tr("Got "));
|
emit finished(AccountTaskState::STATE_WORKING, tr("Got "));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include <QNetworkRequest>
|
#include <QNetworkRequest>
|
||||||
|
|
||||||
#include "Logging.h"
|
|
||||||
#include "minecraft/auth/AuthRequest.h"
|
#include "minecraft/auth/AuthRequest.h"
|
||||||
#include "minecraft/auth/Parsers.h"
|
#include "minecraft/auth/Parsers.h"
|
||||||
#include "net/NetUtils.h"
|
#include "net/NetUtils.h"
|
||||||
@ -41,7 +40,9 @@ void MinecraftProfileStep::onRequestDone(
|
|||||||
auto requestor = qobject_cast<AuthRequest *>(QObject::sender());
|
auto requestor = qobject_cast<AuthRequest *>(QObject::sender());
|
||||||
requestor->deleteLater();
|
requestor->deleteLater();
|
||||||
|
|
||||||
qCDebug(authCredentials()) << data;
|
#ifndef NDEBUG
|
||||||
|
qDebug() << data;
|
||||||
|
#endif
|
||||||
if (error == QNetworkReply::ContentNotFoundError) {
|
if (error == QNetworkReply::ContentNotFoundError) {
|
||||||
// NOTE: Succeed even if we do not have a profile. This is a valid account state.
|
// NOTE: Succeed even if we do not have a profile. This is a valid account state.
|
||||||
if(m_data->type == AccountType::Mojang) {
|
if(m_data->type == AccountType::Mojang) {
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include <QNetworkRequest>
|
#include <QNetworkRequest>
|
||||||
|
|
||||||
#include "Logging.h"
|
|
||||||
#include "minecraft/auth/AuthRequest.h"
|
#include "minecraft/auth/AuthRequest.h"
|
||||||
#include "minecraft/auth/Parsers.h"
|
#include "minecraft/auth/Parsers.h"
|
||||||
#include "net/NetUtils.h"
|
#include "net/NetUtils.h"
|
||||||
@ -44,7 +43,9 @@ void MinecraftProfileStepMojang::onRequestDone(
|
|||||||
auto requestor = qobject_cast<AuthRequest *>(QObject::sender());
|
auto requestor = qobject_cast<AuthRequest *>(QObject::sender());
|
||||||
requestor->deleteLater();
|
requestor->deleteLater();
|
||||||
|
|
||||||
qCDebug(authCredentials()) << data;
|
#ifndef NDEBUG
|
||||||
|
qDebug() << data;
|
||||||
|
#endif
|
||||||
if (error == QNetworkReply::ContentNotFoundError) {
|
if (error == QNetworkReply::ContentNotFoundError) {
|
||||||
// NOTE: Succeed even if we do not have a profile. This is a valid account state.
|
// NOTE: Succeed even if we do not have a profile. This is a valid account state.
|
||||||
if(m_data->type == AccountType::Mojang) {
|
if(m_data->type == AccountType::Mojang) {
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
#include <QJsonParseError>
|
#include <QJsonParseError>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
|
|
||||||
#include "Logging.h"
|
|
||||||
#include "minecraft/auth/AuthRequest.h"
|
#include "minecraft/auth/AuthRequest.h"
|
||||||
#include "minecraft/auth/Parsers.h"
|
#include "minecraft/auth/Parsers.h"
|
||||||
#include "net/NetUtils.h"
|
#include "net/NetUtils.h"
|
||||||
@ -59,7 +58,9 @@ void XboxAuthorizationStep::onRequestDone(
|
|||||||
auto requestor = qobject_cast<AuthRequest *>(QObject::sender());
|
auto requestor = qobject_cast<AuthRequest *>(QObject::sender());
|
||||||
requestor->deleteLater();
|
requestor->deleteLater();
|
||||||
|
|
||||||
qCDebug(authCredentials()) << data;
|
#ifndef NDEBUG
|
||||||
|
qDebug() << data;
|
||||||
|
#endif
|
||||||
if (error != QNetworkReply::NoError) {
|
if (error != QNetworkReply::NoError) {
|
||||||
qWarning() << "Reply error:" << error;
|
qWarning() << "Reply error:" << error;
|
||||||
if (Net::isApplicationError(error)) {
|
if (Net::isApplicationError(error)) {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include <QNetworkRequest>
|
#include <QNetworkRequest>
|
||||||
#include <QUrlQuery>
|
#include <QUrlQuery>
|
||||||
|
|
||||||
#include "Logging.h"
|
|
||||||
#include "minecraft/auth/AuthRequest.h"
|
#include "minecraft/auth/AuthRequest.h"
|
||||||
#include "minecraft/auth/Parsers.h"
|
#include "minecraft/auth/Parsers.h"
|
||||||
#include "net/NetUtils.h"
|
#include "net/NetUtils.h"
|
||||||
@ -56,7 +56,9 @@ void XboxProfileStep::onRequestDone(
|
|||||||
|
|
||||||
if (error != QNetworkReply::NoError) {
|
if (error != QNetworkReply::NoError) {
|
||||||
qWarning() << "Reply error:" << error;
|
qWarning() << "Reply error:" << error;
|
||||||
qCDebug(authCredentials()) << data;
|
#ifndef NDEBUG
|
||||||
|
qDebug() << data;
|
||||||
|
#endif
|
||||||
if (Net::isApplicationError(error)) {
|
if (Net::isApplicationError(error)) {
|
||||||
emit finished(
|
emit finished(
|
||||||
AccountTaskState::STATE_FAILED_SOFT,
|
AccountTaskState::STATE_FAILED_SOFT,
|
||||||
@ -72,7 +74,9 @@ void XboxProfileStep::onRequestDone(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qCDebug(authCredentials()) << "XBox profile: " << data;
|
#ifndef NDEBUG
|
||||||
|
qDebug() << "XBox profile: " << data;
|
||||||
|
#endif
|
||||||
|
|
||||||
emit finished(AccountTaskState::STATE_WORKING, tr("Got Xbox profile"));
|
emit finished(AccountTaskState::STATE_WORKING, tr("Got Xbox profile"));
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,7 @@ QVariant ModFolderModel::headerData(int section, Qt::Orientation orientation, in
|
|||||||
|
|
||||||
int ModFolderModel::columnCount(const QModelIndex &parent) const
|
int ModFolderModel::columnCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
return parent.isValid() ? 0 : NUM_COLUMNS;
|
return NUM_COLUMNS;
|
||||||
}
|
}
|
||||||
|
|
||||||
Task* ModFolderModel::createUpdateTask()
|
Task* ModFolderModel::createUpdateTask()
|
||||||
|
@ -20,7 +20,6 @@ ResourceFolderModel::ResourceFolderModel(QDir dir, QObject* parent) : QAbstractL
|
|||||||
m_dir.setSorting(QDir::Name | QDir::IgnoreCase | QDir::LocaleAware);
|
m_dir.setSorting(QDir::Name | QDir::IgnoreCase | QDir::LocaleAware);
|
||||||
|
|
||||||
connect(&m_watcher, &QFileSystemWatcher::directoryChanged, this, &ResourceFolderModel::directoryChanged);
|
connect(&m_watcher, &QFileSystemWatcher::directoryChanged, this, &ResourceFolderModel::directoryChanged);
|
||||||
connect(&m_helper_thread_task, &ConcurrentTask::finished, this, [this]{ m_helper_thread_task.clear(); });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourceFolderModel::~ResourceFolderModel()
|
ResourceFolderModel::~ResourceFolderModel()
|
||||||
@ -260,7 +259,7 @@ void ResourceFolderModel::resolveResource(Resource* res)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Task::Ptr task{ createParseTask(*res) };
|
auto task = createParseTask(*res);
|
||||||
if (!task)
|
if (!task)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -270,17 +269,13 @@ void ResourceFolderModel::resolveResource(Resource* res)
|
|||||||
m_active_parse_tasks.insert(ticket, task);
|
m_active_parse_tasks.insert(ticket, task);
|
||||||
|
|
||||||
connect(
|
connect(
|
||||||
task.get(), &Task::succeeded, this, [=] { onParseSucceeded(ticket, res->internal_id()); }, Qt::ConnectionType::QueuedConnection);
|
task, &Task::succeeded, this, [=] { onParseSucceeded(ticket, res->internal_id()); }, Qt::ConnectionType::QueuedConnection);
|
||||||
connect(
|
connect(
|
||||||
task.get(), &Task::failed, this, [=] { onParseFailed(ticket, res->internal_id()); }, Qt::ConnectionType::QueuedConnection);
|
task, &Task::failed, this, [=] { onParseFailed(ticket, res->internal_id()); }, Qt::ConnectionType::QueuedConnection);
|
||||||
connect(
|
connect(
|
||||||
task.get(), &Task::finished, this, [=] { m_active_parse_tasks.remove(ticket); }, Qt::ConnectionType::QueuedConnection);
|
task, &Task::finished, this, [=] { m_active_parse_tasks.remove(ticket); }, Qt::ConnectionType::QueuedConnection);
|
||||||
|
|
||||||
m_helper_thread_task.addTask(task);
|
QThreadPool::globalInstance()->start(task);
|
||||||
|
|
||||||
if (!m_helper_thread_task.isRunning()) {
|
|
||||||
QThreadPool::globalInstance()->start(&m_helper_thread_task);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResourceFolderModel::onUpdateSucceeded()
|
void ResourceFolderModel::onUpdateSucceeded()
|
||||||
@ -431,7 +426,7 @@ QVariant ResourceFolderModel::data(const QModelIndex& index, int role) const
|
|||||||
bool ResourceFolderModel::setData(const QModelIndex& index, const QVariant& value, int role)
|
bool ResourceFolderModel::setData(const QModelIndex& index, const QVariant& value, int role)
|
||||||
{
|
{
|
||||||
int row = index.row();
|
int row = index.row();
|
||||||
if (row < 0 || row >= rowCount(index.parent()) || !index.isValid())
|
if (row < 0 || row >= rowCount(index) || !index.isValid())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (role == Qt::CheckStateRole)
|
if (role == Qt::CheckStateRole)
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
#include "Resource.h"
|
#include "Resource.h"
|
||||||
|
|
||||||
#include "tasks/Task.h"
|
#include "tasks/Task.h"
|
||||||
#include "tasks/ConcurrentTask.h"
|
|
||||||
|
|
||||||
class QSortFilterProxyModel;
|
class QSortFilterProxyModel;
|
||||||
|
|
||||||
@ -91,8 +90,8 @@ class ResourceFolderModel : public QAbstractListModel {
|
|||||||
/* Basic columns */
|
/* Basic columns */
|
||||||
enum Columns { ACTIVE_COLUMN = 0, NAME_COLUMN, DATE_COLUMN, NUM_COLUMNS };
|
enum Columns { ACTIVE_COLUMN = 0, NAME_COLUMN, DATE_COLUMN, NUM_COLUMNS };
|
||||||
|
|
||||||
[[nodiscard]] int rowCount(const QModelIndex& parent = {}) const override { return parent.isValid() ? 0 : static_cast<int>(size()); }
|
[[nodiscard]] int rowCount(const QModelIndex& = {}) const override { return size(); }
|
||||||
[[nodiscard]] int columnCount(const QModelIndex& parent = {}) const override { return parent.isValid() ? 0 : NUM_COLUMNS; };
|
[[nodiscard]] int columnCount(const QModelIndex& = {}) const override { return NUM_COLUMNS; };
|
||||||
|
|
||||||
[[nodiscard]] Qt::DropActions supportedDropActions() const override;
|
[[nodiscard]] Qt::DropActions supportedDropActions() const override;
|
||||||
|
|
||||||
@ -177,7 +176,7 @@ class ResourceFolderModel : public QAbstractListModel {
|
|||||||
* if the resource is complex and has more stuff to parse.
|
* if the resource is complex and has more stuff to parse.
|
||||||
*/
|
*/
|
||||||
virtual void onParseSucceeded(int ticket, QString resource_id);
|
virtual void onParseSucceeded(int ticket, QString resource_id);
|
||||||
virtual void onParseFailed(int ticket, QString resource_id) { Q_UNUSED(ticket); Q_UNUSED(resource_id); }
|
virtual void onParseFailed(int ticket, QString resource_id) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Represents the relationship between a column's index (represented by the list index), and it's sorting key.
|
// Represents the relationship between a column's index (represented by the list index), and it's sorting key.
|
||||||
@ -198,7 +197,6 @@ class ResourceFolderModel : public QAbstractListModel {
|
|||||||
// Represents the relationship between a resource's internal ID and it's row position on the model.
|
// Represents the relationship between a resource's internal ID and it's row position on the model.
|
||||||
QMap<QString, int> m_resources_index;
|
QMap<QString, int> m_resources_index;
|
||||||
|
|
||||||
ConcurrentTask m_helper_thread_task;
|
|
||||||
QMap<int, Task::Ptr> m_active_parse_tasks;
|
QMap<int, Task::Ptr> m_active_parse_tasks;
|
||||||
std::atomic<int> m_next_resolution_ticket = 0;
|
std::atomic<int> m_next_resolution_ticket = 0;
|
||||||
};
|
};
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
#include "ResourcePack.h"
|
#include "ResourcePack.h"
|
||||||
|
|
||||||
#include <QCoreApplication>
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
|
|
||||||
#include "MTPixmapCache.h"
|
|
||||||
#include "Version.h"
|
#include "Version.h"
|
||||||
|
|
||||||
#include "minecraft/mod/tasks/LocalResourcePackParseTask.h"
|
#include "minecraft/mod/tasks/LocalResourcePackParseTask.h"
|
||||||
@ -17,7 +15,7 @@ static const QMap<int, std::pair<Version, Version>> s_pack_format_versions = {
|
|||||||
{ 3, { Version("1.11"), Version("1.12.2") } }, { 4, { Version("1.13"), Version("1.14.4") } },
|
{ 3, { Version("1.11"), Version("1.12.2") } }, { 4, { Version("1.13"), Version("1.14.4") } },
|
||||||
{ 5, { Version("1.15"), Version("1.16.1") } }, { 6, { Version("1.16.2"), Version("1.16.5") } },
|
{ 5, { Version("1.15"), Version("1.16.1") } }, { 6, { Version("1.16.2"), Version("1.16.5") } },
|
||||||
{ 7, { Version("1.17"), Version("1.17.1") } }, { 8, { Version("1.18"), Version("1.18.2") } },
|
{ 7, { Version("1.17"), Version("1.17.1") } }, { 8, { Version("1.18"), Version("1.18.2") } },
|
||||||
{ 9, { Version("1.19"), Version("1.19.2") } }, { 11, { Version("1.19.3"), Version("1.19.3") } },
|
{ 9, { Version("1.19"), Version("1.19.2") } },
|
||||||
};
|
};
|
||||||
|
|
||||||
void ResourcePack::setPackFormat(int new_format_id)
|
void ResourcePack::setPackFormat(int new_format_id)
|
||||||
@ -45,22 +43,16 @@ void ResourcePack::setImage(QImage new_image)
|
|||||||
Q_ASSERT(!new_image.isNull());
|
Q_ASSERT(!new_image.isNull());
|
||||||
|
|
||||||
if (m_pack_image_cache_key.key.isValid())
|
if (m_pack_image_cache_key.key.isValid())
|
||||||
PixmapCache::instance().remove(m_pack_image_cache_key.key);
|
QPixmapCache::remove(m_pack_image_cache_key.key);
|
||||||
|
|
||||||
m_pack_image_cache_key.key = PixmapCache::instance().insert(QPixmap::fromImage(new_image));
|
m_pack_image_cache_key.key = QPixmapCache::insert(QPixmap::fromImage(new_image));
|
||||||
m_pack_image_cache_key.was_ever_used = true;
|
m_pack_image_cache_key.was_ever_used = true;
|
||||||
|
|
||||||
// This can happen if the pixmap is too big to fit in the cache :c
|
|
||||||
if (!m_pack_image_cache_key.key.isValid()) {
|
|
||||||
qWarning() << "Could not insert a image cache entry! Ignoring it.";
|
|
||||||
m_pack_image_cache_key.was_ever_used = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QPixmap ResourcePack::image(QSize size)
|
QPixmap ResourcePack::image(QSize size)
|
||||||
{
|
{
|
||||||
QPixmap cached_image;
|
QPixmap cached_image;
|
||||||
if (PixmapCache::instance().find(m_pack_image_cache_key.key, &cached_image)) {
|
if (QPixmapCache::find(m_pack_image_cache_key.key, &cached_image)) {
|
||||||
if (size.isNull())
|
if (size.isNull())
|
||||||
return cached_image;
|
return cached_image;
|
||||||
return cached_image.scaled(size);
|
return cached_image.scaled(size);
|
||||||
@ -122,8 +114,3 @@ bool ResourcePack::applyFilter(QRegularExpression filter) const
|
|||||||
|
|
||||||
return Resource::applyFilter(filter);
|
return Resource::applyFilter(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ResourcePack::valid() const
|
|
||||||
{
|
|
||||||
return m_pack_format != 0;
|
|
||||||
}
|
|
||||||
|
@ -42,8 +42,6 @@ class ResourcePack : public Resource {
|
|||||||
/** Thread-safe. */
|
/** Thread-safe. */
|
||||||
void setImage(QImage new_image);
|
void setImage(QImage new_image);
|
||||||
|
|
||||||
bool valid() const override;
|
|
||||||
|
|
||||||
[[nodiscard]] auto compare(Resource const& other, SortType type) const -> std::pair<int, bool> override;
|
[[nodiscard]] auto compare(Resource const& other, SortType type) const -> std::pair<int, bool> override;
|
||||||
[[nodiscard]] bool applyFilter(QRegularExpression filter) const override;
|
[[nodiscard]] bool applyFilter(QRegularExpression filter) const override;
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ QVariant ResourcePackFolderModel::headerData(int section, Qt::Orientation orient
|
|||||||
|
|
||||||
int ResourcePackFolderModel::columnCount(const QModelIndex& parent) const
|
int ResourcePackFolderModel::columnCount(const QModelIndex& parent) const
|
||||||
{
|
{
|
||||||
return parent.isValid() ? 0 : NUM_COLUMNS;
|
return NUM_COLUMNS;
|
||||||
}
|
}
|
||||||
|
|
||||||
Task* ResourcePackFolderModel::createUpdateTask()
|
Task* ResourcePackFolderModel::createUpdateTask()
|
||||||
|
@ -62,8 +62,3 @@ QPixmap TexturePack::image(QSize size)
|
|||||||
TexturePackUtils::process(*this);
|
TexturePackUtils::process(*this);
|
||||||
return image(size);
|
return image(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TexturePack::valid() const
|
|
||||||
{
|
|
||||||
return m_description != nullptr;
|
|
||||||
}
|
|
||||||
|
@ -48,8 +48,6 @@ class TexturePack : public Resource {
|
|||||||
/** Thread-safe. */
|
/** Thread-safe. */
|
||||||
void setImage(QImage new_image);
|
void setImage(QImage new_image);
|
||||||
|
|
||||||
bool valid() const override;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
mutable QMutex m_data_lock;
|
mutable QMutex m_data_lock;
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// NEW format
|
// NEW format
|
||||||
// https://github.com/MinecraftForge/FML/wiki/FML-mod-information-file/c8d8f1929aff9979e322af79a59ce81f3e02db6a
|
// https://github.com/MinecraftForge/FML/wiki/FML-mod-information-file/6f62b37cea040daf350dc253eae6326dd9c822c3
|
||||||
|
|
||||||
// OLD format:
|
// OLD format:
|
||||||
// https://github.com/MinecraftForge/FML/wiki/FML-mod-information-file/5bf6a2d05145ec79387acc0d45c958642fb049fc
|
// https://github.com/MinecraftForge/FML/wiki/FML-mod-information-file/5bf6a2d05145ec79387acc0d45c958642fb049fc
|
||||||
@ -73,11 +73,10 @@ ModDetails ReadMCModInfo(QByteArray contents)
|
|||||||
version = Json::ensureString(val, "").toInt();
|
version = Json::ensureString(val, "").toInt();
|
||||||
|
|
||||||
if (version != 2) {
|
if (version != 2) {
|
||||||
qWarning() << QString(R"(The value of 'modListVersion' is "%1" (expected "2")! The file may be corrupted.)").arg(version);
|
qCritical() << "BAD stuff happened to mod json:";
|
||||||
qWarning() << "The contents of 'mcmod.info' are as follows:";
|
qCritical() << contents;
|
||||||
qWarning() << contents;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto arrVal = jsonDoc.object().value("modlist");
|
auto arrVal = jsonDoc.object().value("modlist");
|
||||||
if (arrVal.isUndefined()) {
|
if (arrVal.isUndefined()) {
|
||||||
arrVal = jsonDoc.object().value("modList");
|
arrVal = jsonDoc.object().value("modList");
|
||||||
@ -122,7 +121,7 @@ ModDetails ReadMCModTOML(QByteArray contents)
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto modsTable = tomlModsTable0->as_table();
|
auto modsTable = tomlModsTable0->as_table();
|
||||||
if (!modsTable) {
|
if (!tomlModsTable0) {
|
||||||
qWarning() << "Corrupted mods.toml? [[mods]] was not a table!";
|
qWarning() << "Corrupted mods.toml? [[mods]] was not a table!";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -28,14 +28,14 @@
|
|||||||
|
|
||||||
namespace ResourcePackUtils {
|
namespace ResourcePackUtils {
|
||||||
|
|
||||||
bool process(ResourcePack& pack, ProcessingLevel level)
|
bool process(ResourcePack& pack)
|
||||||
{
|
{
|
||||||
switch (pack.type()) {
|
switch (pack.type()) {
|
||||||
case ResourceType::FOLDER:
|
case ResourceType::FOLDER:
|
||||||
ResourcePackUtils::processFolder(pack, level);
|
ResourcePackUtils::processFolder(pack);
|
||||||
return true;
|
return true;
|
||||||
case ResourceType::ZIPFILE:
|
case ResourceType::ZIPFILE:
|
||||||
ResourcePackUtils::processZIP(pack, level);
|
ResourcePackUtils::processZIP(pack);
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
qWarning() << "Invalid type for resource pack parse task!";
|
qWarning() << "Invalid type for resource pack parse task!";
|
||||||
@ -43,7 +43,7 @@ bool process(ResourcePack& pack, ProcessingLevel level)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void processFolder(ResourcePack& pack, ProcessingLevel level)
|
void processFolder(ResourcePack& pack)
|
||||||
{
|
{
|
||||||
Q_ASSERT(pack.type() == ResourceType::FOLDER);
|
Q_ASSERT(pack.type() == ResourceType::FOLDER);
|
||||||
|
|
||||||
@ -60,9 +60,6 @@ void processFolder(ResourcePack& pack, ProcessingLevel level)
|
|||||||
mcmeta_file.close();
|
mcmeta_file.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (level == ProcessingLevel::BasicInfoOnly)
|
|
||||||
return;
|
|
||||||
|
|
||||||
QFileInfo image_file_info(FS::PathCombine(pack.fileinfo().filePath(), "pack.png"));
|
QFileInfo image_file_info(FS::PathCombine(pack.fileinfo().filePath(), "pack.png"));
|
||||||
if (image_file_info.isFile()) {
|
if (image_file_info.isFile()) {
|
||||||
QFile mcmeta_file(image_file_info.filePath());
|
QFile mcmeta_file(image_file_info.filePath());
|
||||||
@ -77,7 +74,7 @@ void processFolder(ResourcePack& pack, ProcessingLevel level)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void processZIP(ResourcePack& pack, ProcessingLevel level)
|
void processZIP(ResourcePack& pack)
|
||||||
{
|
{
|
||||||
Q_ASSERT(pack.type() == ResourceType::ZIPFILE);
|
Q_ASSERT(pack.type() == ResourceType::ZIPFILE);
|
||||||
|
|
||||||
@ -101,11 +98,6 @@ void processZIP(ResourcePack& pack, ProcessingLevel level)
|
|||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (level == ProcessingLevel::BasicInfoOnly) {
|
|
||||||
zip.close();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (zip.setCurrentFile("pack.png")) {
|
if (zip.setCurrentFile("pack.png")) {
|
||||||
if (!file.open(QIODevice::ReadOnly)) {
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
qCritical() << "Failed to open file in zip.";
|
qCritical() << "Failed to open file in zip.";
|
||||||
@ -146,13 +138,6 @@ void processPackPNG(ResourcePack& pack, QByteArray&& raw_data)
|
|||||||
qWarning() << "Failed to parse pack.png.";
|
qWarning() << "Failed to parse pack.png.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool validate(QFileInfo file)
|
|
||||||
{
|
|
||||||
ResourcePack rp{ file };
|
|
||||||
return ResourcePackUtils::process(rp, ProcessingLevel::BasicInfoOnly) && rp.valid();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ResourcePackUtils
|
} // namespace ResourcePackUtils
|
||||||
|
|
||||||
LocalResourcePackParseTask::LocalResourcePackParseTask(int token, ResourcePack& rp)
|
LocalResourcePackParseTask::LocalResourcePackParseTask(int token, ResourcePack& rp)
|
||||||
@ -167,6 +152,8 @@ bool LocalResourcePackParseTask::abort()
|
|||||||
|
|
||||||
void LocalResourcePackParseTask::executeTask()
|
void LocalResourcePackParseTask::executeTask()
|
||||||
{
|
{
|
||||||
|
Q_ASSERT(m_resource_pack.valid());
|
||||||
|
|
||||||
if (!ResourcePackUtils::process(m_resource_pack))
|
if (!ResourcePackUtils::process(m_resource_pack))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -26,19 +26,13 @@
|
|||||||
#include "tasks/Task.h"
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
namespace ResourcePackUtils {
|
namespace ResourcePackUtils {
|
||||||
|
bool process(ResourcePack& pack);
|
||||||
|
|
||||||
enum class ProcessingLevel { Full, BasicInfoOnly };
|
void processZIP(ResourcePack& pack);
|
||||||
|
void processFolder(ResourcePack& pack);
|
||||||
bool process(ResourcePack& pack, ProcessingLevel level = ProcessingLevel::Full);
|
|
||||||
|
|
||||||
void processZIP(ResourcePack& pack, ProcessingLevel level = ProcessingLevel::Full);
|
|
||||||
void processFolder(ResourcePack& pack, ProcessingLevel level = ProcessingLevel::Full);
|
|
||||||
|
|
||||||
void processMCMeta(ResourcePack& pack, QByteArray&& raw_data);
|
void processMCMeta(ResourcePack& pack, QByteArray&& raw_data);
|
||||||
void processPackPNG(ResourcePack& pack, QByteArray&& raw_data);
|
void processPackPNG(ResourcePack& pack, QByteArray&& raw_data);
|
||||||
|
|
||||||
/** Checks whether a file is valid as a resource pack or not. */
|
|
||||||
bool validate(QFileInfo file);
|
|
||||||
} // namespace ResourcePackUtils
|
} // namespace ResourcePackUtils
|
||||||
|
|
||||||
class LocalResourcePackParseTask : public Task {
|
class LocalResourcePackParseTask : public Task {
|
||||||
|
@ -28,14 +28,14 @@
|
|||||||
|
|
||||||
namespace TexturePackUtils {
|
namespace TexturePackUtils {
|
||||||
|
|
||||||
bool process(TexturePack& pack, ProcessingLevel level)
|
bool process(TexturePack& pack)
|
||||||
{
|
{
|
||||||
switch (pack.type()) {
|
switch (pack.type()) {
|
||||||
case ResourceType::FOLDER:
|
case ResourceType::FOLDER:
|
||||||
TexturePackUtils::processFolder(pack, level);
|
TexturePackUtils::processFolder(pack);
|
||||||
return true;
|
return true;
|
||||||
case ResourceType::ZIPFILE:
|
case ResourceType::ZIPFILE:
|
||||||
TexturePackUtils::processZIP(pack, level);
|
TexturePackUtils::processZIP(pack);
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
qWarning() << "Invalid type for resource pack parse task!";
|
qWarning() << "Invalid type for resource pack parse task!";
|
||||||
@ -43,7 +43,7 @@ bool process(TexturePack& pack, ProcessingLevel level)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void processFolder(TexturePack& pack, ProcessingLevel level)
|
void processFolder(TexturePack& pack)
|
||||||
{
|
{
|
||||||
Q_ASSERT(pack.type() == ResourceType::FOLDER);
|
Q_ASSERT(pack.type() == ResourceType::FOLDER);
|
||||||
|
|
||||||
@ -60,9 +60,6 @@ void processFolder(TexturePack& pack, ProcessingLevel level)
|
|||||||
mcmeta_file.close();
|
mcmeta_file.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (level == ProcessingLevel::BasicInfoOnly)
|
|
||||||
return;
|
|
||||||
|
|
||||||
QFileInfo image_file_info(FS::PathCombine(pack.fileinfo().filePath(), "pack.png"));
|
QFileInfo image_file_info(FS::PathCombine(pack.fileinfo().filePath(), "pack.png"));
|
||||||
if (image_file_info.isFile()) {
|
if (image_file_info.isFile()) {
|
||||||
QFile mcmeta_file(image_file_info.filePath());
|
QFile mcmeta_file(image_file_info.filePath());
|
||||||
@ -77,7 +74,7 @@ void processFolder(TexturePack& pack, ProcessingLevel level)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void processZIP(TexturePack& pack, ProcessingLevel level)
|
void processZIP(TexturePack& pack)
|
||||||
{
|
{
|
||||||
Q_ASSERT(pack.type() == ResourceType::ZIPFILE);
|
Q_ASSERT(pack.type() == ResourceType::ZIPFILE);
|
||||||
|
|
||||||
@ -101,11 +98,6 @@ void processZIP(TexturePack& pack, ProcessingLevel level)
|
|||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (level == ProcessingLevel::BasicInfoOnly) {
|
|
||||||
zip.close();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (zip.setCurrentFile("pack.png")) {
|
if (zip.setCurrentFile("pack.png")) {
|
||||||
if (!file.open(QIODevice::ReadOnly)) {
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
qCritical() << "Failed to open file in zip.";
|
qCritical() << "Failed to open file in zip.";
|
||||||
@ -137,13 +129,6 @@ void processPackPNG(TexturePack& pack, QByteArray&& raw_data)
|
|||||||
qWarning() << "Failed to parse pack.png.";
|
qWarning() << "Failed to parse pack.png.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool validate(QFileInfo file)
|
|
||||||
{
|
|
||||||
TexturePack rp{ file };
|
|
||||||
return TexturePackUtils::process(rp, ProcessingLevel::BasicInfoOnly) && rp.valid();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace TexturePackUtils
|
} // namespace TexturePackUtils
|
||||||
|
|
||||||
LocalTexturePackParseTask::LocalTexturePackParseTask(int token, TexturePack& rp)
|
LocalTexturePackParseTask::LocalTexturePackParseTask(int token, TexturePack& rp)
|
||||||
@ -158,6 +143,8 @@ bool LocalTexturePackParseTask::abort()
|
|||||||
|
|
||||||
void LocalTexturePackParseTask::executeTask()
|
void LocalTexturePackParseTask::executeTask()
|
||||||
{
|
{
|
||||||
|
Q_ASSERT(m_texture_pack.valid());
|
||||||
|
|
||||||
if (!TexturePackUtils::process(m_texture_pack))
|
if (!TexturePackUtils::process(m_texture_pack))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -27,19 +27,13 @@
|
|||||||
#include "tasks/Task.h"
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
namespace TexturePackUtils {
|
namespace TexturePackUtils {
|
||||||
|
bool process(TexturePack& pack);
|
||||||
|
|
||||||
enum class ProcessingLevel { Full, BasicInfoOnly };
|
void processZIP(TexturePack& pack);
|
||||||
|
void processFolder(TexturePack& pack);
|
||||||
bool process(TexturePack& pack, ProcessingLevel level = ProcessingLevel::Full);
|
|
||||||
|
|
||||||
void processZIP(TexturePack& pack, ProcessingLevel level = ProcessingLevel::Full);
|
|
||||||
void processFolder(TexturePack& pack, ProcessingLevel level = ProcessingLevel::Full);
|
|
||||||
|
|
||||||
void processPackTXT(TexturePack& pack, QByteArray&& raw_data);
|
void processPackTXT(TexturePack& pack, QByteArray&& raw_data);
|
||||||
void processPackPNG(TexturePack& pack, QByteArray&& raw_data);
|
void processPackPNG(TexturePack& pack, QByteArray&& raw_data);
|
||||||
|
|
||||||
/** Checks whether a file is valid as a texture pack or not. */
|
|
||||||
bool validate(QFileInfo file);
|
|
||||||
} // namespace TexturePackUtils
|
} // namespace TexturePackUtils
|
||||||
|
|
||||||
class LocalTexturePackParseTask : public Task {
|
class LocalTexturePackParseTask : public Task {
|
||||||
|
@ -12,7 +12,7 @@ LibrariesTask::LibrariesTask(MinecraftInstance * inst)
|
|||||||
|
|
||||||
void LibrariesTask::executeTask()
|
void LibrariesTask::executeTask()
|
||||||
{
|
{
|
||||||
setStatus(tr("Downloading required library files..."));
|
setStatus(tr("Getting the library files from Mojang..."));
|
||||||
qDebug() << m_inst->name() << ": downloading libraries";
|
qDebug() << m_inst->name() << ": downloading libraries";
|
||||||
MinecraftInstance *inst = (MinecraftInstance *)m_inst;
|
MinecraftInstance *inst = (MinecraftInstance *)m_inst;
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
#include <QList>
|
#include <QList>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
#include "../Version.h"
|
#include "Version.h"
|
||||||
#include "net/NetJob.h"
|
#include "net/NetJob.h"
|
||||||
|
|
||||||
namespace ModPlatform {
|
namespace ModPlatform {
|
||||||
|
@ -42,25 +42,12 @@ void Flame::FileResolvingTask::executeTask()
|
|||||||
void Flame::FileResolvingTask::netJobFinished()
|
void Flame::FileResolvingTask::netJobFinished()
|
||||||
{
|
{
|
||||||
setProgress(1, 3);
|
setProgress(1, 3);
|
||||||
|
int index = 0;
|
||||||
// job to check modrinth for blocked projects
|
// job to check modrinth for blocked projects
|
||||||
m_checkJob = new NetJob("Modrinth check", m_network);
|
m_checkJob = new NetJob("Modrinth check", m_network);
|
||||||
blockedProjects = QMap<File *,QByteArray *>();
|
blockedProjects = QMap<File *,QByteArray *>();
|
||||||
|
auto doc = Json::requireDocument(*result);
|
||||||
QJsonDocument doc;
|
auto array = Json::requireArray(doc.object()["data"]);
|
||||||
QJsonArray array;
|
|
||||||
|
|
||||||
try {
|
|
||||||
doc = Json::requireDocument(*result);
|
|
||||||
array = Json::requireArray(doc.object()["data"]);
|
|
||||||
} catch (Json::JsonException& e) {
|
|
||||||
qCritical() << "Non-JSON data returned from the CF API";
|
|
||||||
qCritical() << e.cause();
|
|
||||||
|
|
||||||
emitFailed(tr("Invalid data returned from the API."));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (QJsonValueRef file : array) {
|
for (QJsonValueRef file : array) {
|
||||||
auto fileid = Json::requireInteger(Json::requireObject(file)["id"]);
|
auto fileid = Json::requireInteger(Json::requireObject(file)["id"]);
|
||||||
auto& out = m_toProcess.files[fileid];
|
auto& out = m_toProcess.files[fileid];
|
||||||
@ -81,6 +68,7 @@ void Flame::FileResolvingTask::netJobFinished()
|
|||||||
blockedProjects.insert(&out, output);
|
blockedProjects.insert(&out, output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
index++;
|
||||||
}
|
}
|
||||||
connect(m_checkJob.get(), &NetJob::finished, this, &Flame::FileResolvingTask::modrinthCheckFinished);
|
connect(m_checkJob.get(), &NetJob::finished, this, &Flame::FileResolvingTask::modrinthCheckFinished);
|
||||||
|
|
||||||
|
@ -1,38 +1,3 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
/*
|
|
||||||
* Prism Launcher - 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 "FlameInstanceCreationTask.h"
|
#include "FlameInstanceCreationTask.h"
|
||||||
|
|
||||||
#include "modplatform/flame/FlameAPI.h"
|
#include "modplatform/flame/FlameAPI.h"
|
||||||
@ -81,19 +46,13 @@ bool FlameCreationTask::updateInstance()
|
|||||||
auto instance_list = APPLICATION->instances();
|
auto instance_list = APPLICATION->instances();
|
||||||
|
|
||||||
// FIXME: How to handle situations when there's more than one install already for a given modpack?
|
// FIXME: How to handle situations when there's more than one install already for a given modpack?
|
||||||
InstancePtr inst;
|
auto inst = instance_list->getInstanceByManagedName(originalName());
|
||||||
if (auto original_id = originalInstanceID(); !original_id.isEmpty()) {
|
|
||||||
inst = instance_list->getInstanceById(original_id);
|
|
||||||
Q_ASSERT(inst);
|
|
||||||
} else {
|
|
||||||
inst = instance_list->getInstanceByManagedName(originalName());
|
|
||||||
|
|
||||||
if (!inst) {
|
if (!inst) {
|
||||||
inst = instance_list->getInstanceById(originalName());
|
inst = instance_list->getInstanceById(originalName());
|
||||||
|
|
||||||
if (!inst)
|
if (!inst)
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString index_path(FS::PathCombine(m_stagingPath, "manifest.json"));
|
QString index_path(FS::PathCombine(m_stagingPath, "manifest.json"));
|
||||||
@ -108,14 +67,24 @@ bool FlameCreationTask::updateInstance()
|
|||||||
auto version_id = inst->getManagedPackVersionName();
|
auto version_id = inst->getManagedPackVersionName();
|
||||||
auto version_str = !version_id.isEmpty() ? tr(" (version %1)").arg(version_id) : "";
|
auto version_str = !version_id.isEmpty() ? tr(" (version %1)").arg(version_id) : "";
|
||||||
|
|
||||||
if (shouldConfirmUpdate()) {
|
auto info = CustomMessageBox::selectable(
|
||||||
auto should_update = askIfShouldUpdate(m_parent, version_str);
|
m_parent, tr("Similar modpack was found!"),
|
||||||
if (should_update == ShouldUpdate::SkipUpdating)
|
tr("One or more of your instances are from this same modpack%1. Do you want to create a "
|
||||||
return false;
|
"separate instance, or update the existing one?\n\nNOTE: Make sure you made a backup of your important instance data before "
|
||||||
if (should_update == ShouldUpdate::Cancel) {
|
"updating, as worlds can be corrupted and some configuration may be lost (due to pack overrides).")
|
||||||
m_abort = true;
|
.arg(version_str), QMessageBox::Information, QMessageBox::Ok | QMessageBox::Reset | QMessageBox::Abort);
|
||||||
return false;
|
info->setButtonText(QMessageBox::Ok, tr("Update existing instance"));
|
||||||
}
|
info->setButtonText(QMessageBox::Abort, tr("Create new instance"));
|
||||||
|
info->setButtonText(QMessageBox::Reset, tr("Cancel"));
|
||||||
|
|
||||||
|
info->exec();
|
||||||
|
|
||||||
|
if (info->clickedButton() == info->button(QMessageBox::Abort))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (info->clickedButton() == info->button(QMessageBox::Reset)) {
|
||||||
|
m_abort = true;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QDir old_inst_dir(inst->instanceRoot());
|
QDir old_inst_dir(inst->instanceRoot());
|
||||||
@ -228,10 +197,10 @@ bool FlameCreationTask::updateInstance()
|
|||||||
m_process_update_file_info_job = nullptr;
|
m_process_update_file_info_job = nullptr;
|
||||||
} else {
|
} else {
|
||||||
// We don't have an old index file, so we may duplicate stuff!
|
// We don't have an old index file, so we may duplicate stuff!
|
||||||
auto dialog = CustomMessageBox::selectable(m_parent, tr("No index file."),
|
auto dialog = CustomMessageBox::selectable(m_parent,
|
||||||
tr("We couldn't find a suitable index file for the older version. This may cause some "
|
tr("No index file."),
|
||||||
"of the files to be duplicated. Do you want to continue?"),
|
tr("We couldn't find a suitable index file for the older version. This may cause some of the files to be duplicated. Do you want to continue?"),
|
||||||
QMessageBox::Warning, QMessageBox::Ok | QMessageBox::Cancel);
|
QMessageBox::Warning, QMessageBox::Ok | QMessageBox::Cancel);
|
||||||
|
|
||||||
if (dialog->exec() == QDialog::DialogCode::Rejected) {
|
if (dialog->exec() == QDialog::DialogCode::Rejected) {
|
||||||
m_abort = true;
|
m_abort = true;
|
||||||
@ -239,7 +208,7 @@ bool FlameCreationTask::updateInstance()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setOverride(true, inst->id());
|
setOverride(true);
|
||||||
qDebug() << "Will override instance!";
|
qDebug() << "Will override instance!";
|
||||||
|
|
||||||
m_instance = inst;
|
m_instance = inst;
|
||||||
@ -361,9 +330,7 @@ bool FlameCreationTask::createInstance()
|
|||||||
FS::deletePath(jarmodsPath);
|
FS::deletePath(jarmodsPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't add managed info to packs without an ID (most likely imported from ZIP)
|
instance.setManagedPack("flame", {}, m_pack.name, {}, m_pack.version);
|
||||||
if (!m_managed_id.isEmpty())
|
|
||||||
instance.setManagedPack("flame", m_managed_id, m_pack.name, m_managed_version_id, m_pack.version);
|
|
||||||
instance.setName(name());
|
instance.setName(name());
|
||||||
|
|
||||||
m_mod_id_resolver = new Flame::FileResolvingTask(APPLICATION->network(), m_pack);
|
m_mod_id_resolver = new Flame::FileResolvingTask(APPLICATION->network(), m_pack);
|
||||||
@ -371,7 +338,6 @@ bool FlameCreationTask::createInstance()
|
|||||||
connect(m_mod_id_resolver.get(), &Flame::FileResolvingTask::failed, [&](QString reason) {
|
connect(m_mod_id_resolver.get(), &Flame::FileResolvingTask::failed, [&](QString reason) {
|
||||||
m_mod_id_resolver.reset();
|
m_mod_id_resolver.reset();
|
||||||
setError(tr("Unable to resolve mod IDs:\n") + reason);
|
setError(tr("Unable to resolve mod IDs:\n") + reason);
|
||||||
loop.quit();
|
|
||||||
});
|
});
|
||||||
connect(m_mod_id_resolver.get(), &Flame::FileResolvingTask::progress, this, &FlameCreationTask::setProgress);
|
connect(m_mod_id_resolver.get(), &Flame::FileResolvingTask::progress, this, &FlameCreationTask::setProgress);
|
||||||
connect(m_mod_id_resolver.get(), &Flame::FileResolvingTask::status, this, &FlameCreationTask::setStatus);
|
connect(m_mod_id_resolver.get(), &Flame::FileResolvingTask::status, this, &FlameCreationTask::setStatus);
|
||||||
@ -387,6 +353,14 @@ bool FlameCreationTask::createInstance()
|
|||||||
setAbortable(false);
|
setAbortable(false);
|
||||||
auto inst = m_instance.value();
|
auto inst = m_instance.value();
|
||||||
|
|
||||||
|
// Only change the name if it didn't use a custom name, so that the previous custom name
|
||||||
|
// is preserved, but if we're using the original one, we update the version string.
|
||||||
|
// NOTE: This needs to come before the copyManagedPack call!
|
||||||
|
if (inst->name().contains(inst->getManagedPackVersionName())) {
|
||||||
|
if (askForChangingInstanceName(m_parent, inst->name(), instance.name()) == InstanceNameChange::ShouldChange)
|
||||||
|
inst->setName(instance.name());
|
||||||
|
}
|
||||||
|
|
||||||
inst->copyManagedPack(instance);
|
inst->copyManagedPack(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,36 +372,27 @@ void FlameCreationTask::idResolverSucceeded(QEventLoop& loop)
|
|||||||
auto results = m_mod_id_resolver->getResults();
|
auto results = m_mod_id_resolver->getResults();
|
||||||
|
|
||||||
// first check for blocked mods
|
// first check for blocked mods
|
||||||
QList<BlockedMod> blocked_mods;
|
QString text;
|
||||||
|
QList<QUrl> urls;
|
||||||
auto anyBlocked = false;
|
auto anyBlocked = false;
|
||||||
for (const auto& result : results.files.values()) {
|
for (const auto& result : results.files.values()) {
|
||||||
if (!result.resolved || result.url.isEmpty()) {
|
if (!result.resolved || result.url.isEmpty()) {
|
||||||
BlockedMod blocked_mod;
|
text += QString("%1: <a href='%2'>%2</a><br/>").arg(result.fileName, result.websiteUrl);
|
||||||
blocked_mod.name = result.fileName;
|
urls.append(QUrl(result.websiteUrl));
|
||||||
blocked_mod.websiteUrl = result.websiteUrl;
|
|
||||||
blocked_mod.hash = result.hash;
|
|
||||||
blocked_mod.matched = false;
|
|
||||||
blocked_mod.localPath = "";
|
|
||||||
blocked_mod.targetFolder = result.targetFolder;
|
|
||||||
|
|
||||||
blocked_mods.append(blocked_mod);
|
|
||||||
|
|
||||||
anyBlocked = true;
|
anyBlocked = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (anyBlocked) {
|
if (anyBlocked) {
|
||||||
qWarning() << "Blocked mods found, displaying mod list";
|
qWarning() << "Blocked mods found, displaying mod list";
|
||||||
|
|
||||||
BlockedModsDialog message_dialog(m_parent, tr("Blocked mods found"),
|
auto message_dialog = new BlockedModsDialog(m_parent, tr("Blocked mods found"),
|
||||||
tr("The following files are not available for download in third party launchers.<br/>"
|
tr("The following mods were blocked on third party launchers.<br/>"
|
||||||
"You will need to manually download them and add them to the instance."),
|
"You will need to manually download them and add them to the modpack"),
|
||||||
blocked_mods);
|
text,
|
||||||
|
urls);
|
||||||
|
message_dialog->setModal(true);
|
||||||
|
|
||||||
message_dialog.setModal(true);
|
if (message_dialog->exec()) {
|
||||||
|
|
||||||
if (message_dialog.exec()) {
|
|
||||||
qDebug() << "Post dialog blocked mods list: " << blocked_mods;
|
|
||||||
copyBlockedMods(blocked_mods);
|
|
||||||
setupDownloadJob(loop);
|
setupDownloadJob(loop);
|
||||||
} else {
|
} else {
|
||||||
m_mod_id_resolver.reset();
|
m_mod_id_resolver.reset();
|
||||||
@ -439,38 +404,6 @@ void FlameCreationTask::idResolverSucceeded(QEventLoop& loop)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief copy the matched blocked mods to the instance staging area
|
|
||||||
/// @param blocked_mods list of the blocked mods and their matched paths
|
|
||||||
void FlameCreationTask::copyBlockedMods(QList<BlockedMod> const& blocked_mods)
|
|
||||||
{
|
|
||||||
setStatus(tr("Copying Blocked Mods..."));
|
|
||||||
setAbortable(false);
|
|
||||||
int i = 0;
|
|
||||||
int total = blocked_mods.length();
|
|
||||||
setProgress(i, total);
|
|
||||||
for (auto const& mod : blocked_mods) {
|
|
||||||
if (!mod.matched) {
|
|
||||||
qDebug() << mod.name << "was not matched to a local file, skipping copy";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto dest_path = FS::PathCombine(m_stagingPath, "minecraft", mod.targetFolder, mod.name);
|
|
||||||
|
|
||||||
setStatus(tr("Copying Blocked Mods (%1 out of %2 are done)").arg(QString::number(i), QString::number(total)));
|
|
||||||
|
|
||||||
qDebug() << "Will try to copy" << mod.localPath << "to" << dest_path;
|
|
||||||
|
|
||||||
if (!FS::copy(mod.localPath, dest_path)()) {
|
|
||||||
qDebug() << "Copy of" << mod.localPath << "to" << dest_path << "Failed";
|
|
||||||
}
|
|
||||||
|
|
||||||
i++;
|
|
||||||
setProgress(i, total);
|
|
||||||
}
|
|
||||||
|
|
||||||
setAbortable(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FlameCreationTask::setupDownloadJob(QEventLoop& loop)
|
void FlameCreationTask::setupDownloadJob(QEventLoop& loop)
|
||||||
{
|
{
|
||||||
m_files_job = new NetJob(tr("Mod download"), APPLICATION->network());
|
m_files_job = new NetJob(tr("Mod download"), APPLICATION->network());
|
||||||
@ -509,12 +442,14 @@ void FlameCreationTask::setupDownloadJob(QEventLoop& loop)
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_mod_id_resolver.reset();
|
m_mod_id_resolver.reset();
|
||||||
connect(m_files_job.get(), &NetJob::succeeded, this, [&]() { m_files_job.reset(); });
|
connect(m_files_job.get(), &NetJob::succeeded, this, [&]() {
|
||||||
|
m_files_job.reset();
|
||||||
|
});
|
||||||
connect(m_files_job.get(), &NetJob::failed, [&](QString reason) {
|
connect(m_files_job.get(), &NetJob::failed, [&](QString reason) {
|
||||||
m_files_job.reset();
|
m_files_job.reset();
|
||||||
setError(reason);
|
setError(reason);
|
||||||
});
|
});
|
||||||
connect(m_files_job.get(), &NetJob::progress, this, &FlameCreationTask::setProgress);
|
connect(m_files_job.get(), &NetJob::progress, [&](qint64 current, qint64 total) { setProgress(current, total); });
|
||||||
connect(m_files_job.get(), &NetJob::finished, &loop, &QEventLoop::quit);
|
connect(m_files_job.get(), &NetJob::finished, &loop, &QEventLoop::quit);
|
||||||
|
|
||||||
setStatus(tr("Downloading mods..."));
|
setStatus(tr("Downloading mods..."));
|
||||||
|
@ -1,38 +1,3 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
|
||||||
/*
|
|
||||||
* Prism Launcher - 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 "InstanceCreationTask.h"
|
#include "InstanceCreationTask.h"
|
||||||
@ -45,27 +10,15 @@
|
|||||||
|
|
||||||
#include "net/NetJob.h"
|
#include "net/NetJob.h"
|
||||||
|
|
||||||
#include "ui/dialogs/BlockedModsDialog.h"
|
|
||||||
|
|
||||||
class FlameCreationTask final : public InstanceCreationTask {
|
class FlameCreationTask final : public InstanceCreationTask {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FlameCreationTask(const QString& staging_path,
|
FlameCreationTask(const QString& staging_path, SettingsObjectPtr global_settings, QWidget* parent)
|
||||||
SettingsObjectPtr global_settings,
|
: InstanceCreationTask(), m_parent(parent)
|
||||||
QWidget* parent,
|
|
||||||
QString id,
|
|
||||||
QString version_id,
|
|
||||||
QString original_instance_id = {})
|
|
||||||
: InstanceCreationTask()
|
|
||||||
, m_parent(parent)
|
|
||||||
, m_managed_id(std::move(id))
|
|
||||||
, m_managed_version_id(std::move(version_id))
|
|
||||||
{
|
{
|
||||||
setStagingPath(staging_path);
|
setStagingPath(staging_path);
|
||||||
setParentSettings(global_settings);
|
setParentSettings(global_settings);
|
||||||
|
|
||||||
m_original_instance_id = std::move(original_instance_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool abort() override;
|
bool abort() override;
|
||||||
@ -76,7 +29,6 @@ class FlameCreationTask final : public InstanceCreationTask {
|
|||||||
private slots:
|
private slots:
|
||||||
void idResolverSucceeded(QEventLoop&);
|
void idResolverSucceeded(QEventLoop&);
|
||||||
void setupDownloadJob(QEventLoop&);
|
void setupDownloadJob(QEventLoop&);
|
||||||
void copyBlockedMods(QList<BlockedMod> const& blocked_mods);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QWidget* m_parent = nullptr;
|
QWidget* m_parent = nullptr;
|
||||||
@ -88,7 +40,5 @@ class FlameCreationTask final : public InstanceCreationTask {
|
|||||||
NetJob* m_process_update_file_info_job = nullptr;
|
NetJob* m_process_update_file_info_job = nullptr;
|
||||||
NetJob::Ptr m_files_job = nullptr;
|
NetJob::Ptr m_files_job = nullptr;
|
||||||
|
|
||||||
QString m_managed_id, m_managed_version_id;
|
|
||||||
|
|
||||||
std::optional<InstancePtr> m_instance;
|
std::optional<InstancePtr> m_instance;
|
||||||
};
|
};
|
||||||
|
@ -36,18 +36,6 @@ Hasher::Ptr createFlameHasher(QString file_path)
|
|||||||
return new FlameHasher(file_path);
|
return new FlameHasher(file_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Hasher::Ptr createBlockedModHasher(QString file_path, ModPlatform::Provider provider)
|
|
||||||
{
|
|
||||||
return new BlockedModHasher(file_path, provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
Hasher::Ptr createBlockedModHasher(QString file_path, ModPlatform::Provider provider, QString type)
|
|
||||||
{
|
|
||||||
auto hasher = new BlockedModHasher(file_path, provider);
|
|
||||||
hasher->useHashType(type);
|
|
||||||
return hasher;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ModrinthHasher::executeTask()
|
void ModrinthHasher::executeTask()
|
||||||
{
|
{
|
||||||
QFile file(m_path);
|
QFile file(m_path);
|
||||||
@ -91,50 +79,4 @@ void FlameHasher::executeTask()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BlockedModHasher::BlockedModHasher(QString file_path, ModPlatform::Provider provider)
|
|
||||||
: Hasher(file_path), provider(provider) {
|
|
||||||
setObjectName(QString("BlockedModHasher: %1").arg(file_path));
|
|
||||||
hash_type = ProviderCaps.hashType(provider).first();
|
|
||||||
}
|
|
||||||
|
|
||||||
void BlockedModHasher::executeTask()
|
|
||||||
{
|
|
||||||
QFile file(m_path);
|
|
||||||
|
|
||||||
try {
|
|
||||||
file.open(QFile::ReadOnly);
|
|
||||||
} catch (FS::FileSystemException& e) {
|
|
||||||
qCritical() << QString("Failed to open JAR file in %1").arg(m_path);
|
|
||||||
qCritical() << QString("Reason: ") << e.cause();
|
|
||||||
|
|
||||||
emitFailed("Failed to open file for hashing.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_hash = ProviderCaps.hash(provider, &file, hash_type);
|
|
||||||
|
|
||||||
file.close();
|
|
||||||
|
|
||||||
if (m_hash.isEmpty()) {
|
|
||||||
emitFailed("Empty hash!");
|
|
||||||
} else {
|
|
||||||
emitSucceeded();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList BlockedModHasher::getHashTypes() {
|
|
||||||
return ProviderCaps.hashType(provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BlockedModHasher::useHashType(QString type) {
|
|
||||||
auto types = ProviderCaps.hashType(provider);
|
|
||||||
if (types.contains(type)) {
|
|
||||||
hash_type = type;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
qDebug() << "Bad hash type " << type << " for provider";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Hashing
|
} // namespace Hashing
|
||||||
|
@ -40,23 +40,8 @@ class ModrinthHasher : public Hasher {
|
|||||||
void executeTask() override;
|
void executeTask() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BlockedModHasher : public Hasher {
|
|
||||||
public:
|
|
||||||
BlockedModHasher(QString file_path, ModPlatform::Provider provider);
|
|
||||||
|
|
||||||
void executeTask() override;
|
|
||||||
|
|
||||||
QStringList getHashTypes();
|
|
||||||
bool useHashType(QString type);
|
|
||||||
private:
|
|
||||||
ModPlatform::Provider provider;
|
|
||||||
QString hash_type;
|
|
||||||
};
|
|
||||||
|
|
||||||
Hasher::Ptr createHasher(QString file_path, ModPlatform::Provider provider);
|
Hasher::Ptr createHasher(QString file_path, ModPlatform::Provider provider);
|
||||||
Hasher::Ptr createFlameHasher(QString file_path);
|
Hasher::Ptr createFlameHasher(QString file_path);
|
||||||
Hasher::Ptr createModrinthHasher(QString file_path);
|
Hasher::Ptr createModrinthHasher(QString file_path);
|
||||||
Hasher::Ptr createBlockedModHasher(QString file_path, ModPlatform::Provider provider);
|
|
||||||
Hasher::Ptr createBlockedModHasher(QString file_path, ModPlatform::Provider provider, QString type);
|
|
||||||
|
|
||||||
} // namespace Hashing
|
} // namespace Hashing
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
/*
|
/*
|
||||||
* Prism Launcher - Minecraft Launcher
|
* PolyMC - Minecraft Launcher
|
||||||
* Copyright (C) 2022 flowln <flowlnlnln@gmail.com>
|
* Copyright (C) 2022 flowln <flowlnlnln@gmail.com>
|
||||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
@ -176,6 +176,8 @@ void PackInstallTask::resolveMods()
|
|||||||
|
|
||||||
void PackInstallTask::onResolveModsSucceeded()
|
void PackInstallTask::onResolveModsSucceeded()
|
||||||
{
|
{
|
||||||
|
QString text;
|
||||||
|
QList<QUrl> urls;
|
||||||
auto anyBlocked = false;
|
auto anyBlocked = false;
|
||||||
|
|
||||||
Flame::Manifest results = m_mod_id_resolver_task->getResults();
|
Flame::Manifest results = m_mod_id_resolver_task->getResults();
|
||||||
@ -189,16 +191,11 @@ void PackInstallTask::onResolveModsSucceeded()
|
|||||||
|
|
||||||
// First check for blocked mods
|
// First check for blocked mods
|
||||||
if (!results_file.resolved || results_file.url.isEmpty()) {
|
if (!results_file.resolved || results_file.url.isEmpty()) {
|
||||||
BlockedMod blocked_mod;
|
QString type(local_file.type);
|
||||||
blocked_mod.name = local_file.name;
|
|
||||||
blocked_mod.websiteUrl = results_file.websiteUrl;
|
|
||||||
blocked_mod.hash = results_file.hash;
|
|
||||||
blocked_mod.matched = false;
|
|
||||||
blocked_mod.localPath = "";
|
|
||||||
blocked_mod.targetFolder = results_file.targetFolder;
|
|
||||||
|
|
||||||
m_blocked_mods.append(blocked_mod);
|
|
||||||
|
|
||||||
|
type[0] = type[0].toUpper();
|
||||||
|
text += QString("%1: %2 - <a href='%3'>%3</a><br/>").arg(type, local_file.name, results_file.websiteUrl);
|
||||||
|
urls.append(QUrl(results_file.websiteUrl));
|
||||||
anyBlocked = true;
|
anyBlocked = true;
|
||||||
} else {
|
} else {
|
||||||
local_file.url = results_file.url.toString();
|
local_file.url = results_file.url.toString();
|
||||||
@ -210,20 +207,16 @@ void PackInstallTask::onResolveModsSucceeded()
|
|||||||
if (anyBlocked) {
|
if (anyBlocked) {
|
||||||
qDebug() << "Blocked files found, displaying file list";
|
qDebug() << "Blocked files found, displaying file list";
|
||||||
|
|
||||||
BlockedModsDialog message_dialog(m_parent, tr("Blocked files found"),
|
auto message_dialog = new BlockedModsDialog(m_parent, tr("Blocked files found"),
|
||||||
tr("The following files are not available for download in third party launchers.<br/>"
|
tr("The following files are not available for download in third party launchers.<br/>"
|
||||||
"You will need to manually download them and add them to the instance."),
|
"You will need to manually download them and add them to the instance."),
|
||||||
m_blocked_mods);
|
text,
|
||||||
|
urls);
|
||||||
|
|
||||||
message_dialog.setModal(true);
|
if (message_dialog->exec() == QDialog::Accepted)
|
||||||
|
|
||||||
if (message_dialog.exec() == QDialog::Accepted) {
|
|
||||||
qDebug() << "Post dialog blocked mods list: " << m_blocked_mods;
|
|
||||||
createInstance();
|
createInstance();
|
||||||
} else {
|
else
|
||||||
abort();
|
abort();
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
createInstance();
|
createInstance();
|
||||||
}
|
}
|
||||||
@ -327,9 +320,6 @@ void PackInstallTask::downloadPack()
|
|||||||
void PackInstallTask::onModDownloadSucceeded()
|
void PackInstallTask::onModDownloadSucceeded()
|
||||||
{
|
{
|
||||||
m_net_job.reset();
|
m_net_job.reset();
|
||||||
if (!m_blocked_mods.isEmpty()) {
|
|
||||||
copyBlockedMods();
|
|
||||||
}
|
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -353,35 +343,4 @@ void PackInstallTask::onModDownloadFailed(QString reason)
|
|||||||
emitFailed(reason);
|
emitFailed(reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief copy the matched blocked mods to the instance staging area
|
|
||||||
void PackInstallTask::copyBlockedMods()
|
|
||||||
{
|
|
||||||
setStatus(tr("Copying Blocked Mods..."));
|
|
||||||
setAbortable(false);
|
|
||||||
int i = 0;
|
|
||||||
int total = m_blocked_mods.length();
|
|
||||||
setProgress(i, total);
|
|
||||||
for (auto const& mod : m_blocked_mods) {
|
|
||||||
if (!mod.matched) {
|
|
||||||
qDebug() << mod.name << "was not matched to a local file, skipping copy";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto dest_path = FS::PathCombine(m_stagingPath, ".minecraft", mod.targetFolder, mod.name);
|
|
||||||
|
|
||||||
setStatus(tr("Copying Blocked Mods (%1 out of %2 are done)").arg(QString::number(i), QString::number(total)));
|
|
||||||
|
|
||||||
qDebug() << "Will try to copy" << mod.localPath << "to" << dest_path;
|
|
||||||
|
|
||||||
if (!FS::copy(mod.localPath, dest_path)()) {
|
|
||||||
qDebug() << "Copy of" << mod.localPath << "to" << dest_path << "Failed";
|
|
||||||
}
|
|
||||||
|
|
||||||
i++;
|
|
||||||
setProgress(i, total);
|
|
||||||
}
|
|
||||||
|
|
||||||
setAbortable(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ModpacksCH
|
} // namespace ModpacksCH
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
/*
|
/*
|
||||||
* Prism Launcher - Minecraft Launcher
|
* PolyMC - Minecraft Launcher
|
||||||
* Copyright (C) 2022 flowln <flowlnlnln@gmail.com>
|
* Copyright (C) 2022 flowln <flowlnlnln@gmail.com>
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
*
|
*
|
||||||
@ -43,7 +43,6 @@
|
|||||||
#include "QObjectPtr.h"
|
#include "QObjectPtr.h"
|
||||||
#include "modplatform/flame/FileResolvingTask.h"
|
#include "modplatform/flame/FileResolvingTask.h"
|
||||||
#include "net/NetJob.h"
|
#include "net/NetJob.h"
|
||||||
#include "ui/dialogs/BlockedModsDialog.h"
|
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
@ -77,7 +76,6 @@ private:
|
|||||||
void resolveMods();
|
void resolveMods();
|
||||||
void createInstance();
|
void createInstance();
|
||||||
void downloadPack();
|
void downloadPack();
|
||||||
void copyBlockedMods();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NetJob::Ptr m_net_job = nullptr;
|
NetJob::Ptr m_net_job = nullptr;
|
||||||
@ -92,7 +90,6 @@ private:
|
|||||||
Version m_version;
|
Version m_version;
|
||||||
|
|
||||||
QMap<QString, QString> m_files_to_copy;
|
QMap<QString, QString> m_files_to_copy;
|
||||||
QList<BlockedMod> m_blocked_mods;
|
|
||||||
|
|
||||||
//FIXME: nuke
|
//FIXME: nuke
|
||||||
QWidget* m_parent;
|
QWidget* m_parent;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user