Merge branch 'release-5.x' of https://github.com/PrismLauncher/PrismLauncher into prism
This commit is contained in:
commit
23e5773094
3
.github/codeql/codeql-config.yml
vendored
Normal file
3
.github/codeql/codeql-config.yml
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
query-filters:
|
||||||
|
- exclude:
|
||||||
|
id: cpp/fixme-comment
|
40
.github/workflows/build.yml
vendored
40
.github/workflows/build.yml
vendored
@ -39,12 +39,21 @@ jobs:
|
|||||||
qt_ver: 6
|
qt_ver: 6
|
||||||
|
|
||||||
- os: macos-12
|
- os: macos-12
|
||||||
|
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_version: '6.3.0'
|
qt_version: '6.3.0'
|
||||||
qt_modules: 'qt5compat qtimageformats'
|
qt_modules: 'qt5compat qtimageformats'
|
||||||
|
|
||||||
|
- os: macos-12
|
||||||
|
name: macOS-Legacy
|
||||||
|
macosx_deployment_target: 10.13
|
||||||
|
qt_ver: 5
|
||||||
|
qt_host: mac
|
||||||
|
qt_version: '5.15.2'
|
||||||
|
qt_modules: ''
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
env:
|
env:
|
||||||
@ -64,6 +73,14 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
submodules: 'true'
|
submodules: 'true'
|
||||||
|
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
if: runner.os == 'Linux' && matrix.qt_ver == 6
|
||||||
|
uses: github/codeql-action/init@v2
|
||||||
|
with:
|
||||||
|
config-file: ./.github/codeql/codeql-config.yml
|
||||||
|
queries: security-and-quality
|
||||||
|
languages: cpp, java
|
||||||
|
|
||||||
- name: 'Setup MSYS2'
|
- name: 'Setup MSYS2'
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
uses: msys2/setup-msys2@v2
|
uses: msys2/setup-msys2@v2
|
||||||
@ -140,7 +157,7 @@ jobs:
|
|||||||
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 Qt (macOS and AppImage)
|
- name: Install Qt (macOS and AppImage)
|
||||||
if: matrix.qt_ver == 6 && runner.os != 'Windows'
|
if: runner.os == 'Linux' && matrix.qt_ver == 6 || runner.os == 'macOS'
|
||||||
uses: jurplel/install-qt-action@v3
|
uses: jurplel/install-qt-action@v3
|
||||||
with:
|
with:
|
||||||
version: ${{ matrix.qt_version }}
|
version: ${{ matrix.qt_version }}
|
||||||
@ -164,9 +181,14 @@ jobs:
|
|||||||
##
|
##
|
||||||
|
|
||||||
- name: Configure CMake (macOS)
|
- name: Configure CMake (macOS)
|
||||||
if: runner.os == 'macOS'
|
if: runner.os == 'macOS' && matrix.qt_ver == 6
|
||||||
run: |
|
run: |
|
||||||
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -DLauncher_BUILD_PLATFORM=macOS -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -G Ninja
|
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=${{ matrix.name }} -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -G Ninja
|
||||||
|
|
||||||
|
- name: Configure CMake (macOS-Legacy)
|
||||||
|
if: runner.os == 'macOS' && matrix.qt_ver == 5
|
||||||
|
run: |
|
||||||
|
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=${{ matrix.name }} -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DMACOSX_SPARKLE_UPDATE_PUBLIC_KEY="" -DMACOSX_SPARKLE_UPDATE_FEED_URL="" -G Ninja
|
||||||
|
|
||||||
- name: Configure CMake (Windows)
|
- name: Configure CMake (Windows)
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
@ -209,6 +231,14 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
ctest --test-dir build --output-on-failure
|
ctest --test-dir build --output-on-failure
|
||||||
|
|
||||||
|
##
|
||||||
|
# CODE SCAN
|
||||||
|
##
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
if: runner.os == 'Linux' && matrix.qt_ver == 6
|
||||||
|
uses: github/codeql-action/analyze@v2
|
||||||
|
|
||||||
##
|
##
|
||||||
# PACKAGE BUILDS
|
# PACKAGE BUILDS
|
||||||
##
|
##
|
||||||
@ -224,7 +254,7 @@ jobs:
|
|||||||
tar -czf ../PollyMC.tar.gz *
|
tar -czf ../PollyMC.tar.gz *
|
||||||
|
|
||||||
- name: Make Sparkle signature (macOS)
|
- name: Make Sparkle signature (macOS)
|
||||||
if: runner.os == 'macOS'
|
if: matrix.name == 'macOS'
|
||||||
run: |
|
run: |
|
||||||
if [ '${{ secrets.SPARKLE_ED25519_KEY }}' != '' ]; then
|
if [ '${{ secrets.SPARKLE_ED25519_KEY }}' != '' ]; then
|
||||||
brew install openssl@3
|
brew install openssl@3
|
||||||
@ -323,7 +353,7 @@ jobs:
|
|||||||
if: runner.os == 'macOS'
|
if: runner.os == 'macOS'
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: PollyMC-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
name: PollyMC-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||||
path: PollyMC.tar.gz
|
path: PollyMC.tar.gz
|
||||||
|
|
||||||
- name: Upload binary zip (Windows)
|
- name: Upload binary zip (Windows)
|
||||||
|
2
.github/workflows/trigger_release.yml
vendored
2
.github/workflows/trigger_release.yml
vendored
@ -40,6 +40,7 @@ jobs:
|
|||||||
mv PollyMC-Linux-Portable*/PollyMC-portable.tar.gz PollyMC-Linux-Portable-${{ env.VERSION }}.tar.gz
|
mv PollyMC-Linux-Portable*/PollyMC-portable.tar.gz PollyMC-Linux-Portable-${{ env.VERSION }}.tar.gz
|
||||||
mv PollyMC-Linux*/PollyMC.tar.gz PollyMC-Linux-${{ env.VERSION }}.tar.gz
|
mv PollyMC-Linux*/PollyMC.tar.gz PollyMC-Linux-${{ env.VERSION }}.tar.gz
|
||||||
mv PollyMC-*.AppImage/PollyMC-*.AppImage PollyMC-Linux-${{ env.VERSION }}-x86_64.AppImage
|
mv PollyMC-*.AppImage/PollyMC-*.AppImage PollyMC-Linux-${{ env.VERSION }}-x86_64.AppImage
|
||||||
|
mv PollyMC-macOS-Legacy*/PollyMC.tar.gz PollyMC-macOS-Legacy-${{ env.VERSION }}.tar.gz
|
||||||
mv PollyMC-macOS*/PollyMC.tar.gz PollyMC-macOS-${{ env.VERSION }}.tar.gz
|
mv PollyMC-macOS*/PollyMC.tar.gz PollyMC-macOS-${{ env.VERSION }}.tar.gz
|
||||||
|
|
||||||
tar -czf PollyMC-${{ env.VERSION }}.tar.gz PollyMC-${{ env.VERSION }}
|
tar -czf PollyMC-${{ env.VERSION }}.tar.gz PollyMC-${{ env.VERSION }}
|
||||||
@ -80,4 +81,5 @@ jobs:
|
|||||||
PollyMC-Windows-Portable-${{ env.VERSION }}.zip
|
PollyMC-Windows-Portable-${{ env.VERSION }}.zip
|
||||||
PollyMC-Windows-Setup-${{ env.VERSION }}.exe
|
PollyMC-Windows-Setup-${{ env.VERSION }}.exe
|
||||||
PollyMC-macOS-${{ env.VERSION }}.tar.gz
|
PollyMC-macOS-${{ env.VERSION }}.tar.gz
|
||||||
|
PollyMC-macOS-Legacy-${{ env.VERSION }}.tar.gz
|
||||||
PollyMC-${{ env.VERSION }}.tar.gz
|
PollyMC-${{ env.VERSION }}.tar.gz
|
||||||
|
7
.github/workflows/winget.yml
vendored
7
.github/workflows/winget.yml
vendored
@ -7,8 +7,9 @@ jobs:
|
|||||||
publish:
|
publish:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: vedantmgoyal2009/winget-releaser@latest
|
- uses: vedantmgoyal2009/winget-releaser@v1
|
||||||
with:
|
with:
|
||||||
identifier: PolyMC.PolyMC
|
identifier: PrismLauncher.PrismLauncher
|
||||||
installers-regex: 'PolyMC-Windows-Setup-.+\.exe$'
|
version: ${{ github.event.release.tag_name }}
|
||||||
|
installers-regex: 'PrismLauncher-Windows-Setup-.+\.exe$'
|
||||||
token: ${{ secrets.WINGET_TOKEN }}
|
token: ${{ secrets.WINGET_TOKEN }}
|
||||||
|
14
.gitmodules
vendored
14
.gitmodules
vendored
@ -1,8 +1,12 @@
|
|||||||
[submodule "depends/libnbtplusplus"]
|
|
||||||
path = libraries/libnbtplusplus
|
|
||||||
url = https://github.com/PolyMC/libnbtplusplus.git
|
|
||||||
pushurl = git@github.com:PolyMC/libnbtplusplus.git
|
|
||||||
|
|
||||||
[submodule "libraries/quazip"]
|
[submodule "libraries/quazip"]
|
||||||
path = libraries/quazip
|
path = libraries/quazip
|
||||||
url = https://github.com/stachenov/quazip.git
|
url = https://github.com/stachenov/quazip.git
|
||||||
|
[submodule "libraries/tomlplusplus"]
|
||||||
|
path = libraries/tomlplusplus
|
||||||
|
url = https://github.com/marzer/tomlplusplus.git
|
||||||
|
[submodule "libraries/filesystem"]
|
||||||
|
path = libraries/filesystem
|
||||||
|
url = https://github.com/gulrak/filesystem
|
||||||
|
[submodule "libraries/libnbtplusplus"]
|
||||||
|
path = libraries/libnbtplusplus
|
||||||
|
url = https://github.com/PrismLauncher/libnbtplusplus.git
|
||||||
|
52
BUILD.md
52
BUILD.md
@ -1,5 +1,53 @@
|
|||||||
# Build Instructions
|
# Build Instructions
|
||||||
|
|
||||||
Build instructions are available on [the website](https://polymc.org/wiki/development/build-instructions/).
|
Full build instructions will be available on [the website](https://prismlauncher.org/wiki/development/build-instructions/).
|
||||||
|
|
||||||
|
If you would like to contribute or fix an issue with the Build instructions you will be able to do so [here](https://github.com/PrismLauncher/website/blob/master/src/wiki/development/build-instructions.md).
|
||||||
|
|
||||||
|
## Getting the source
|
||||||
|
|
||||||
|
Clone the source code using git, and grab all the submodules. This is generic for all platforms you want to build on.
|
||||||
|
```
|
||||||
|
git clone --recursive https://github.com/PrismLauncher/PrismLauncher
|
||||||
|
cd PrismLauncher
|
||||||
|
```
|
||||||
|
|
||||||
|
## Linux
|
||||||
|
|
||||||
|
This guide will mostly mention dependant packages by their Debian naming and commands are done by a user in the sudoers file.
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
- A C++ compiler capable of building C++17 code (can be found in the package `build-essential`).
|
||||||
|
- Qt Development tools 5.12 or newer (on Debian 11 or Debian-based distributions, `qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5`).
|
||||||
|
- `cmake` 3.15 or newer.
|
||||||
|
- `extra-cmake-modules`.
|
||||||
|
- zlib (`zlib1g-dev` on Debian 11 or Debian-based distributions).
|
||||||
|
- Java Development Kit (Java JDK) (`openjdk-17-jdk` on Debian 11 or Debian-based distributions).
|
||||||
|
- Mesa GL headers (`libgl1-mesa-dev` on Debian 11 or Debian-based distributions).
|
||||||
|
- (Optional) `scdoc` to generate man pages.
|
||||||
|
|
||||||
|
In conclusion, to check if all you need is installed (including optional):
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo apt install build-essential qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5 cmake extra-cmake-modules zlib1g-dev openjdk-17-jdk libgl1-mesa-dev scdoc
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compiling
|
||||||
|
#### Building and installing on the system
|
||||||
|
This is usually the suggested way to build the client.
|
||||||
|
|
||||||
|
```
|
||||||
|
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="/usr" -DENABLE_LTO=ON
|
||||||
|
cmake --build build -j$(nproc)
|
||||||
|
sudo cmake --install build
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Building a portable binary
|
||||||
|
|
||||||
|
```
|
||||||
|
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=install
|
||||||
|
cmake --build build -j$(nproc)
|
||||||
|
cmake --install build
|
||||||
|
cmake --install build --component portable
|
||||||
|
```
|
||||||
|
|
||||||
If you would like to contribute or fix an issue with the Build instructions you can do so [here](https://github.com/PolyMC/polymc.github.io/blob/master/src/wiki/development/build-instructions.md).
|
|
||||||
|
@ -33,9 +33,6 @@ set(CMAKE_CXX_STANDARD 17)
|
|||||||
set(CMAKE_C_STANDARD 11)
|
set(CMAKE_C_STANDARD 11)
|
||||||
include(GenerateExportHeader)
|
include(GenerateExportHeader)
|
||||||
set(CMAKE_CXX_FLAGS "-Wall -pedantic -fstack-protector-strong --param=ssp-buffer-size=4 ${CMAKE_CXX_FLAGS}")
|
set(CMAKE_CXX_FLAGS "-Wall -pedantic -fstack-protector-strong --param=ssp-buffer-size=4 ${CMAKE_CXX_FLAGS}")
|
||||||
if(UNIX AND APPLE)
|
|
||||||
set(CMAKE_CXX_FLAGS "-stdlib=libc++ ${CMAKE_CXX_FLAGS}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Fix build with Qt 5.13
|
# Fix build with Qt 5.13
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_NO_DEPRECATED_WARNINGS=Y")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_NO_DEPRECATED_WARNINGS=Y")
|
||||||
@ -74,9 +71,9 @@ endif()
|
|||||||
##################################### Set Application options #####################################
|
##################################### Set Application options #####################################
|
||||||
|
|
||||||
######## Set URLs ########
|
######## Set URLs ########
|
||||||
set(Launcher_NEWS_RSS_URL "https://polymc.org/feed/feed.xml" CACHE STRING "URL to fetch PolyMC's news RSS feed from.")
|
set(Launcher_NEWS_RSS_URL "https://prismlauncher.org/feed/feed.xml" CACHE STRING "URL to fetch PrismLauncher's news RSS feed from.")
|
||||||
set(Launcher_NEWS_OPEN_URL "https://polymc.org/news" CACHE STRING "URL that gets opened when the user clicks 'More News'")
|
set(Launcher_NEWS_OPEN_URL "https://prismlauncher.org/news" CACHE STRING "URL that gets opened when the user clicks 'More News'")
|
||||||
set(Launcher_HELP_URL "https://polymc.org/wiki/help-pages/%1" CACHE STRING "URL (with arg %1 to be substituted with page-id) that gets opened when the user requests help")
|
set(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 5)
|
set(Launcher_VERSION_MAJOR 5)
|
||||||
@ -93,7 +90,7 @@ set(Launcher_BUILD_PLATFORM "" CACHE STRING "A short string identifying the plat
|
|||||||
set(Launcher_UPDATER_BASE "" CACHE STRING "Base URL for the updater.")
|
set(Launcher_UPDATER_BASE "" CACHE STRING "Base URL for the updater.")
|
||||||
|
|
||||||
# The metadata server
|
# The metadata server
|
||||||
set(Launcher_META_URL "https://meta.polymc.org/v1/" CACHE STRING "URL to fetch Launcher's meta files from.")
|
set(Launcher_META_URL "https://meta.prismlauncher.org/v1/" CACHE STRING "URL to fetch Launcher's meta files from.")
|
||||||
|
|
||||||
# Imgur API Client ID
|
# Imgur API Client ID
|
||||||
set(Launcher_IMGUR_CLIENT_ID "5b97b0713fba4a3" CACHE STRING "Client ID you can get from Imgur when you register an application")
|
set(Launcher_IMGUR_CLIENT_ID "5b97b0713fba4a3" CACHE STRING "Client ID you can get from Imgur when you register an application")
|
||||||
@ -102,7 +99,7 @@ set(Launcher_IMGUR_CLIENT_ID "5b97b0713fba4a3" CACHE STRING "Client ID you can g
|
|||||||
set(Launcher_BUG_TRACKER_URL "https://github.com/fn2006/PollyMC/issues" CACHE STRING "URL for the bug tracker.")
|
set(Launcher_BUG_TRACKER_URL "https://github.com/fn2006/PollyMC/issues" CACHE STRING "URL for the bug tracker.")
|
||||||
|
|
||||||
# Translations Platform URL
|
# Translations Platform URL
|
||||||
set(Launcher_TRANSLATIONS_URL "https://hosted.weblate.org/projects/polymc/polymc/" CACHE STRING "URL for the translations platform.")
|
set(Launcher_TRANSLATIONS_URL "https://hosted.weblate.org/projects/prismlauncher/launcher/" CACHE STRING "URL for the translations platform.")
|
||||||
|
|
||||||
# Matrix Space
|
# Matrix Space
|
||||||
set(Launcher_MATRIX_URL "" CACHE STRING "URL to the Matrix Space")
|
set(Launcher_MATRIX_URL "" CACHE STRING "URL to the Matrix Space")
|
||||||
@ -192,6 +189,14 @@ if (Qt5_POSITION_INDEPENDENT_CODE)
|
|||||||
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(NOT Launcher_FORCE_BUNDLED_LIBS)
|
||||||
|
# Find toml++
|
||||||
|
find_package(tomlplusplus 3.2.0 QUIET)
|
||||||
|
|
||||||
|
# Find ghc_filesystem
|
||||||
|
find_package(ghc_filesystem QUIET)
|
||||||
|
endif()
|
||||||
|
|
||||||
####################################### Program Info #######################################
|
####################################### Program Info #######################################
|
||||||
|
|
||||||
set(Launcher_APP_BINARY_NAME "pollymc" CACHE STRING "Name of the Launcher binary")
|
set(Launcher_APP_BINARY_NAME "pollymc" CACHE STRING "Name of the Launcher binary")
|
||||||
@ -218,14 +223,14 @@ if(UNIX AND APPLE)
|
|||||||
# Mac bundle settings
|
# Mac bundle settings
|
||||||
set(MACOSX_BUNDLE_BUNDLE_NAME "${Launcher_Name}")
|
set(MACOSX_BUNDLE_BUNDLE_NAME "${Launcher_Name}")
|
||||||
set(MACOSX_BUNDLE_INFO_STRING "${Launcher_Name}: A custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once.")
|
set(MACOSX_BUNDLE_INFO_STRING "${Launcher_Name}: A custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once.")
|
||||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER "org.polymc.${Launcher_Name}")
|
set(MACOSX_BUNDLE_GUI_IDENTIFIER "org.prismlauncher.${Launcher_Name}")
|
||||||
set(MACOSX_BUNDLE_BUNDLE_VERSION "${Launcher_VERSION_NAME}")
|
set(MACOSX_BUNDLE_BUNDLE_VERSION "${Launcher_VERSION_NAME}")
|
||||||
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${Launcher_VERSION_NAME}")
|
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${Launcher_VERSION_NAME}")
|
||||||
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${Launcher_VERSION_NAME}")
|
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${Launcher_VERSION_NAME}")
|
||||||
set(MACOSX_BUNDLE_ICON_FILE ${Launcher_Name}.icns)
|
set(MACOSX_BUNDLE_ICON_FILE ${Launcher_Name}.icns)
|
||||||
set(MACOSX_BUNDLE_COPYRIGHT "Copyright 2021-2022 ${Launcher_Copyright}")
|
set(MACOSX_BUNDLE_COPYRIGHT "Copyright 2021-2022 ${Launcher_Copyright}")
|
||||||
set(MACOSX_SPARKLE_UPDATE_PUBLIC_KEY "idALcUIazingvKSSsEa9U7coDVxZVx/ORpOEE/QtJfg=")
|
set(MACOSX_SPARKLE_UPDATE_PUBLIC_KEY "v55ZWWD6QlPoXGV6VLzOTZxZUggWeE51X8cRQyQh6vA=")
|
||||||
set(MACOSX_SPARKLE_UPDATE_FEED_URL "https://polymc.org/feed/appcast.xml")
|
set(MACOSX_SPARKLE_UPDATE_FEED_URL "https://prismlauncher.org/feed/appcast.xml")
|
||||||
|
|
||||||
set(MACOSX_SPARKLE_DOWNLOAD_URL "https://github.com/sparkle-project/Sparkle/releases/download/2.1.0/Sparkle-2.1.0.tar.xz" CACHE STRING "URL to Sparkle release archive")
|
set(MACOSX_SPARKLE_DOWNLOAD_URL "https://github.com/sparkle-project/Sparkle/releases/download/2.1.0/Sparkle-2.1.0.tar.xz" CACHE STRING "URL to Sparkle release archive")
|
||||||
set(MACOSX_SPARKLE_SHA256 "bf6ac1caa9f8d321d5784859c88da874f28412f37fb327bc21b7b14c5d61ef94" CACHE STRING "SHA256 checksum for Sparkle release archive")
|
set(MACOSX_SPARKLE_SHA256 "bf6ac1caa9f8d321d5784859c88da874f28412f37fb327bc21b7b14c5d61ef94" CACHE STRING "SHA256 checksum for Sparkle release archive")
|
||||||
@ -300,7 +305,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
|
||||||
add_subdirectory(libraries/xz-embedded) # xz compression
|
|
||||||
if (FORCE_BUNDLED_QUAZIP)
|
if (FORCE_BUNDLED_QUAZIP)
|
||||||
message(STATUS "Using bundled QuaZip")
|
message(STATUS "Using bundled QuaZip")
|
||||||
set(BUILD_SHARED_LIBS 0) # link statically to avoid conflicts.
|
set(BUILD_SHARED_LIBS 0) # link statically to avoid conflicts.
|
||||||
@ -311,11 +315,23 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
add_subdirectory(libraries/rainbow) # Qt extension for colors
|
add_subdirectory(libraries/rainbow) # Qt extension for colors
|
||||||
add_subdirectory(libraries/LocalPeer) # fork of a library from Qt solutions
|
add_subdirectory(libraries/LocalPeer) # fork of a library from Qt solutions
|
||||||
add_subdirectory(libraries/classparser) # class parser library
|
if(NOT tomlplusplus_FOUND)
|
||||||
add_subdirectory(libraries/tomlc99) # toml parser
|
message(STATUS "Using bundled tomlplusplus")
|
||||||
|
add_subdirectory(libraries/tomlplusplus) # toml parser
|
||||||
|
else()
|
||||||
|
message(STATUS "Using system tomlplusplus")
|
||||||
|
endif()
|
||||||
add_subdirectory(libraries/katabasis) # An OAuth2 library that tried to do too much
|
add_subdirectory(libraries/katabasis) # An OAuth2 library that tried to do too much
|
||||||
add_subdirectory(libraries/gamemode)
|
add_subdirectory(libraries/gamemode)
|
||||||
add_subdirectory(libraries/murmur2) # Hash for usage with the CurseForge API
|
add_subdirectory(libraries/murmur2) # Hash for usage with the CurseForge API
|
||||||
|
if (NOT ghc_filesystem_FOUND)
|
||||||
|
message(STATUS "Using bundled ghc_filesystem")
|
||||||
|
set(GHC_FILESYSTEM_WITH_INSTALL OFF) # Workaround ghc::filesystem bug
|
||||||
|
add_subdirectory(libraries/filesystem) # Implementation of std::filesystem for old C++, for usage in old macOS
|
||||||
|
add_library(ghcFilesystem::ghc_filesystem ALIAS ghc_filesystem)
|
||||||
|
else()
|
||||||
|
message(STATUS "Using system ghc_filesystem")
|
||||||
|
endif()
|
||||||
|
|
||||||
############################### Built Artifacts ###############################
|
############################### Built Artifacts ###############################
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ representative at an online or offline event.
|
|||||||
|
|
||||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
reported to the community leaders responsible for enforcement via email at
|
reported to the community leaders responsible for enforcement via email at
|
||||||
[polymc-enforcement@scrumplex.net](mailto:polymc-enforcement@scrumplex.net) (Email
|
[coc@scrumplex.net](mailto:coc@scrumplex.net) (Email
|
||||||
address subject to change).
|
address subject to change).
|
||||||
All complaints will be reviewed and investigated promptly and fairly.
|
All complaints will be reviewed and investigated promptly and fairly.
|
||||||
|
|
||||||
|
132
COPYING.md
132
COPYING.md
@ -1,3 +1,37 @@
|
|||||||
|
## Prism Launcher
|
||||||
|
|
||||||
|
Prism Launcher - Minecraft Launcher
|
||||||
|
Copyright (C) 2022 Prism Launcher Contributors
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
## PolyMC
|
## PolyMC
|
||||||
|
|
||||||
PolyMC - Minecraft Launcher
|
PolyMC - Minecraft Launcher
|
||||||
@ -191,52 +225,6 @@
|
|||||||
|
|
||||||
See COPYING file for the full LGPL text.
|
See COPYING file for the full LGPL text.
|
||||||
|
|
||||||
## xz-minidec
|
|
||||||
|
|
||||||
XZ decompressor
|
|
||||||
|
|
||||||
Authors: Lasse Collin <lasse.collin@tukaani.org>
|
|
||||||
Igor Pavlov <http://7-zip.org/>
|
|
||||||
|
|
||||||
This file has been put into the public domain.
|
|
||||||
You can do whatever you want with this file.
|
|
||||||
|
|
||||||
## ColumnResizer
|
|
||||||
|
|
||||||
Copyright (c) 2011-2016 Aurélien Gâteau and contributors.
|
|
||||||
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted (subject to the limitations in the
|
|
||||||
disclaimer below) provided that the following conditions are met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in the
|
|
||||||
documentation and/or other materials provided with the
|
|
||||||
distribution.
|
|
||||||
|
|
||||||
* The name of the contributors may not be used to endorse or
|
|
||||||
promote products derived from this software without specific prior
|
|
||||||
written permission.
|
|
||||||
|
|
||||||
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
|
|
||||||
GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
|
|
||||||
HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
|
|
||||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
||||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
|
||||||
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
||||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
|
||||||
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
|
||||||
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
## launcher (`libraries/launcher`)
|
## launcher (`libraries/launcher`)
|
||||||
|
|
||||||
PolyMC - Minecraft Launcher
|
PolyMC - Minecraft Launcher
|
||||||
@ -315,30 +303,24 @@
|
|||||||
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.
|
||||||
|
|
||||||
## tomlc99
|
## tomlplusplus
|
||||||
|
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2017 CK Tan
|
Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
|
||||||
https://github.com/cktan/tomlc99
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
||||||
in the Software without restriction, including without limitation the rights
|
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
|
||||||
copies or substantial portions of the Software.
|
Software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
|
|
||||||
## O2 (Katabasis fork)
|
## O2 (Katabasis fork)
|
||||||
|
|
||||||
@ -394,3 +376,25 @@
|
|||||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
POSSIBILITY OF SUCH DAMAGE.
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
## gulrak/filesystem
|
||||||
|
|
||||||
|
Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
11
README.md
11
README.md
@ -1,17 +1,14 @@
|
|||||||
# One of PolyMC's developers has gone rouge and kicked out all of the other developers
|
|
||||||
### For the time being use I would use `https://meta.prismlauncher.org/v1/` as your metaserver
|
|
||||||
### If you trust him then you can continue using the default metaserver but I take no responsibility for anything that happens while using it
|
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="./program_info/pollymc-header-black.svg#gh-light-mode-only" alt="PollyMC logo" width="60%"/>
|
<img src="./program_info/pollymc-header-black.svg#gh-light-mode-only" alt="PollyMC logo" width="60%"/>
|
||||||
<img src="./program_info/pollymc-header.svg#gh-dark-mode-only" alt="PollyMC logo" width="60%"/>
|
<img src="./program_info/pollymc-header.svg#gh-dark-mode-only" alt="PollyMC logo" width="60%"/>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
PollyMC is a **fork** of PolyMC and is not endorsed by or affiliated with the PolyMC project.
|
PollyMC is a **fork** of Prism Launcher that adds support for Ely.by accounts and allows you to play offline mode without an account
|
||||||
If you have any problems open an issue here, do not bug the PolyMC maintainers.
|
PollyMC is not endorsed by or affiliated with the Prism Launcher project.
|
||||||
|
If you have any problems open an issue here, do not bug the Prism Launcher maintainers.
|
||||||
|
|
||||||
Binaries can be found in releases.
|
Binaries can be found in releases.
|
||||||
|
|
||||||
Workaround for downloading from CurseForge and FTB not working [here](https://github.com/fn2006/PollyMC/wiki/CurseForge-Workaround).
|
Workaround for downloading from CurseForge and FTB not working [here](https://github.com/fn2006/PollyMC/wiki/CurseForge-Workaround).
|
||||||
|
|
||||||
To build this yourself, follow the instructions on the PolyMC website but clone this repo instead.
|
To build this yourself, follow the instructions on the Prism Launcher website but clone this repo instead.
|
||||||
|
@ -140,8 +140,8 @@ class Config {
|
|||||||
QString LIBRARY_BASE = "https://libraries.minecraft.net/";
|
QString LIBRARY_BASE = "https://libraries.minecraft.net/";
|
||||||
QString AUTH_BASE = "https://authserver.mojang.com/";
|
QString AUTH_BASE = "https://authserver.mojang.com/";
|
||||||
QString IMGUR_BASE_URL = "https://api.imgur.com/3/";
|
QString IMGUR_BASE_URL = "https://api.imgur.com/3/";
|
||||||
QString FMLLIBS_BASE_URL = "https://files.polymc.org/fmllibs/";
|
QString FMLLIBS_BASE_URL = "https://files.prismlauncher.org/fmllibs/"; // FIXME: move into CMakeLists
|
||||||
QString TRANSLATIONS_BASE_URL = "https://i18n.polymc.org/";
|
QString TRANSLATIONS_BASE_URL = "https://i18n.prismlauncher.org/"; // FIXME: move into CMakeLists
|
||||||
|
|
||||||
QString MODPACKSCH_API_BASE_URL = "https://api.modpacks.ch/";
|
QString MODPACKSCH_API_BASE_URL = "https://api.modpacks.ch/";
|
||||||
|
|
||||||
|
29
flake.lock
generated
29
flake.lock
generated
@ -21,24 +21,24 @@
|
|||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1650031308,
|
"lastModified": 1650031308,
|
||||||
"narHash": "sha256-TvVOjkUobYJD9itQYueELJX3wmecvEdCbJ0FinW2mL4=",
|
"narHash": "sha256-TvVOjkUobYJD9itQYueELJX3wmecvEdCbJ0FinW2mL4=",
|
||||||
"owner": "PolyMC",
|
"owner": "PrismLauncher",
|
||||||
"repo": "libnbtplusplus",
|
"repo": "libnbtplusplus",
|
||||||
"rev": "2203af7eeb48c45398139b583615134efd8d407f",
|
"rev": "2203af7eeb48c45398139b583615134efd8d407f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "PolyMC",
|
"owner": "PrismLauncher",
|
||||||
"repo": "libnbtplusplus",
|
"repo": "libnbtplusplus",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1658119717,
|
"lastModified": 1666057921,
|
||||||
"narHash": "sha256-4upOZIQQ7Bc4CprqnHsKnqYfw+arJeAuU+QcpjYBXW0=",
|
"narHash": "sha256-VpQqtXdj6G7cH//SvoprjR7XT3KS7p+tCVebGK1N6tE=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "9eb60f25aff0d2218c848dd4574a0ab5e296cabe",
|
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
11
flake.nix
11
flake.nix
@ -4,10 +4,11 @@
|
|||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
|
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
|
||||||
flake-compat = { url = "github:edolstra/flake-compat"; flake = false; };
|
flake-compat = { url = "github:edolstra/flake-compat"; flake = false; };
|
||||||
libnbtplusplus = { url = "github:PolyMC/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,14 +23,14 @@
|
|||||||
pkgs = forAllSystems (system: nixpkgs.legacyPackages.${system});
|
pkgs = forAllSystems (system: nixpkgs.legacyPackages.${system});
|
||||||
|
|
||||||
packagesFn = pkgs: rec {
|
packagesFn = pkgs: rec {
|
||||||
polymc = pkgs.libsForQt5.callPackage ./nix { inherit version self libnbtplusplus; };
|
prismlauncher = pkgs.libsForQt5.callPackage ./nix { inherit version self libnbtplusplus tomlplusplus; };
|
||||||
polymc-qt6 = pkgs.qt6Packages.callPackage ./nix { inherit version self libnbtplusplus; };
|
prismlauncher-qt6 = pkgs.qt6Packages.callPackage ./nix { inherit version self libnbtplusplus tomlplusplus; };
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
packages = forAllSystems (system:
|
packages = forAllSystems (system:
|
||||||
let packages = packagesFn pkgs.${system}; in
|
let packages = packagesFn pkgs.${system}; in
|
||||||
packages // { default = packages.polymc; }
|
packages // { default = packages.prismlauncher; }
|
||||||
);
|
);
|
||||||
|
|
||||||
overlay = final: packagesFn;
|
overlay = final: packagesFn;
|
||||||
|
@ -78,6 +78,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include <QAccessible>
|
#include <QAccessible>
|
||||||
|
#include <QCommandLineParser>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
@ -110,7 +111,6 @@
|
|||||||
#include "translations/TranslationsModel.h"
|
#include "translations/TranslationsModel.h"
|
||||||
#include "meta/Index.h"
|
#include "meta/Index.h"
|
||||||
|
|
||||||
#include <Commandline.h>
|
|
||||||
#include <FileSystem.h>
|
#include <FileSystem.h>
|
||||||
#include <DesktopServices.h>
|
#include <DesktopServices.h>
|
||||||
#include <LocalPeer.h>
|
#include <LocalPeer.h>
|
||||||
@ -136,12 +136,6 @@
|
|||||||
|
|
||||||
static const QLatin1String liveCheckFile("live.check");
|
static const QLatin1String liveCheckFile("live.check");
|
||||||
|
|
||||||
using namespace Commandline;
|
|
||||||
|
|
||||||
#define MACOS_HINT "If you are on macOS Sierra, you might have to move the app to your /Applications or ~/Applications folder. "\
|
|
||||||
"This usually fixes the problem and you can move the application elsewhere afterwards.\n"\
|
|
||||||
"\n"
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void appDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
|
void appDebugOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
|
||||||
{
|
{
|
||||||
@ -242,80 +236,27 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
this->setQuitOnLastWindowClosed(false);
|
this->setQuitOnLastWindowClosed(false);
|
||||||
|
|
||||||
// Commandline parsing
|
// Commandline parsing
|
||||||
QHash<QString, QVariant> args;
|
QCommandLineParser parser;
|
||||||
{
|
parser.setApplicationDescription(BuildConfig.LAUNCHER_DISPLAYNAME);
|
||||||
Parser parser(FlagStyle::GNU, ArgumentStyle::SpaceAndEquals);
|
|
||||||
|
|
||||||
// --help
|
parser.addOptions({
|
||||||
parser.addSwitch("help");
|
{{"d", "dir"}, "Use a custom path as application root (use '.' for current directory)", "directory"},
|
||||||
parser.addShortOpt("help", 'h');
|
{{"l", "launch"}, "Launch the specified instance (by instance ID)", "instance"},
|
||||||
parser.addDocumentation("help", "Display this help and exit.");
|
{{"s", "server"}, "Join the specified server on launch (only valid in combination with --launch)", "address"},
|
||||||
// --version
|
{{"a", "profile"}, "Use the account specified by its profile name (only valid in combination with --launch)", "profile"},
|
||||||
parser.addSwitch("version");
|
{"alive", "Write a small '" + liveCheckFile + "' file after the launcher starts"},
|
||||||
parser.addShortOpt("version", 'V');
|
{{"I", "import"}, "Import instance from specified zip (local path or URL)", "file"}
|
||||||
parser.addDocumentation("version", "Display program version and exit.");
|
});
|
||||||
// --dir
|
parser.addHelpOption();
|
||||||
parser.addOption("dir");
|
parser.addVersionOption();
|
||||||
parser.addShortOpt("dir", 'd');
|
|
||||||
parser.addDocumentation("dir", "Use the supplied folder as application root instead of the binary location (use '.' for current)");
|
|
||||||
// --launch
|
|
||||||
parser.addOption("launch");
|
|
||||||
parser.addShortOpt("launch", 'l');
|
|
||||||
parser.addDocumentation("launch", "Launch the specified instance (by instance ID)");
|
|
||||||
// --server
|
|
||||||
parser.addOption("server");
|
|
||||||
parser.addShortOpt("server", 's');
|
|
||||||
parser.addDocumentation("server", "Join the specified server on launch (only valid in combination with --launch)");
|
|
||||||
// --profile
|
|
||||||
parser.addOption("profile");
|
|
||||||
parser.addShortOpt("profile", 'a');
|
|
||||||
parser.addDocumentation("profile", "Use the account specified by its profile name (only valid in combination with --launch)");
|
|
||||||
// --alive
|
|
||||||
parser.addSwitch("alive");
|
|
||||||
parser.addDocumentation("alive", "Write a small '" + liveCheckFile + "' file after the launcher starts");
|
|
||||||
// --import
|
|
||||||
parser.addOption("import");
|
|
||||||
parser.addShortOpt("import", 'I');
|
|
||||||
parser.addDocumentation("import", "Import instance from specified zip (local path or URL)");
|
|
||||||
|
|
||||||
// parse the arguments
|
parser.process(arguments());
|
||||||
try
|
|
||||||
{
|
|
||||||
args = parser.parse(arguments());
|
|
||||||
}
|
|
||||||
catch (const ParsingError &e)
|
|
||||||
{
|
|
||||||
std::cerr << "CommandLineError: " << e.what() << std::endl;
|
|
||||||
if(argc > 0)
|
|
||||||
std::cerr << "Try '" << argv[0] << " -h' to get help on command line parameters."
|
|
||||||
<< std::endl;
|
|
||||||
m_status = Application::Failed;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// display help and exit
|
m_instanceIdToLaunch = parser.value("launch");
|
||||||
if (args["help"].toBool())
|
m_serverToJoin = parser.value("server");
|
||||||
{
|
m_profileToUse = parser.value("profile");
|
||||||
std::cout << qPrintable(parser.compileHelp(arguments()[0]));
|
m_liveCheck = parser.isSet("alive");
|
||||||
m_status = Application::Succeeded;
|
m_zipToImport = parser.value("import");
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// display version and exit
|
|
||||||
if (args["version"].toBool())
|
|
||||||
{
|
|
||||||
std::cout << "Version " << BuildConfig.printableVersionString().toStdString() << std::endl;
|
|
||||||
std::cout << "Git " << BuildConfig.GIT_COMMIT.toStdString() << std::endl;
|
|
||||||
m_status = Application::Succeeded;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_instanceIdToLaunch = args["launch"].toString();
|
|
||||||
m_serverToJoin = args["server"].toString();
|
|
||||||
m_profileToUse = args["profile"].toString();
|
|
||||||
m_liveCheck = args["alive"].toBool();
|
|
||||||
m_zipToImport = args["import"].toUrl();
|
|
||||||
|
|
||||||
// error if --launch is missing with --server or --profile
|
// error if --launch is missing with --server or --profile
|
||||||
if((!m_serverToJoin.isEmpty() || !m_profileToUse.isEmpty()) && m_instanceIdToLaunch.isEmpty())
|
if((!m_serverToJoin.isEmpty() || !m_profileToUse.isEmpty()) && m_instanceIdToLaunch.isEmpty())
|
||||||
@ -346,7 +287,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
QString adjustedBy;
|
QString adjustedBy;
|
||||||
QString dataPath;
|
QString dataPath;
|
||||||
// change folder
|
// change folder
|
||||||
QString dirParam = args["dir"].toString();
|
QString dirParam = parser.value("dir");
|
||||||
if (!dirParam.isEmpty())
|
if (!dirParam.isEmpty())
|
||||||
{
|
{
|
||||||
// the dir param. it makes multimc data path point to whatever the user specified
|
// the dir param. it makes multimc data path point to whatever the user specified
|
||||||
@ -360,6 +301,12 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
dataPath = foo.absolutePath();
|
dataPath = foo.absolutePath();
|
||||||
adjustedBy = "Persistent data path";
|
adjustedBy = "Persistent data path";
|
||||||
|
|
||||||
|
QDir polymcData(FS::PathCombine(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation), "PolyMC"));
|
||||||
|
if (polymcData.exists()) {
|
||||||
|
dataPath = polymcData.absolutePath();
|
||||||
|
adjustedBy = "PolyMC data path";
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
// TODO: this should be removed in a future version
|
// TODO: this should be removed in a future version
|
||||||
// TODO: provide a migration path similar to macOS migration
|
// TODO: provide a migration path similar to macOS migration
|
||||||
@ -385,9 +332,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
QString(
|
QString(
|
||||||
"The launcher data folder could not be created.\n"
|
"The launcher data folder could not be created.\n"
|
||||||
"\n"
|
"\n"
|
||||||
#if defined(Q_OS_MAC)
|
|
||||||
MACOS_HINT
|
|
||||||
#endif
|
|
||||||
"Make sure you have the right permissions to the launcher data folder and any folder needed to access it.\n"
|
"Make sure you have the right permissions to the launcher data folder and any folder needed to access it.\n"
|
||||||
"(%1)\n"
|
"(%1)\n"
|
||||||
"\n"
|
"\n"
|
||||||
@ -403,9 +347,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
QString(
|
QString(
|
||||||
"The launcher data folder could not be opened.\n"
|
"The launcher data folder could not be opened.\n"
|
||||||
"\n"
|
"\n"
|
||||||
#if defined(Q_OS_MAC)
|
|
||||||
MACOS_HINT
|
|
||||||
#endif
|
|
||||||
"Make sure you have the right permissions to the launcher data folder.\n"
|
"Make sure you have the right permissions to the launcher data folder.\n"
|
||||||
"(%1)\n"
|
"(%1)\n"
|
||||||
"\n"
|
"\n"
|
||||||
@ -486,9 +427,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
QString(
|
QString(
|
||||||
"The launcher couldn't create a log file - the data folder is not writable.\n"
|
"The launcher couldn't create a log file - the data folder is not writable.\n"
|
||||||
"\n"
|
"\n"
|
||||||
#if defined(Q_OS_MAC)
|
|
||||||
MACOS_HINT
|
|
||||||
#endif
|
|
||||||
"Make sure you have write permissions to the data folder.\n"
|
"Make sure you have write permissions to the data folder.\n"
|
||||||
"(%1)\n"
|
"(%1)\n"
|
||||||
"\n"
|
"\n"
|
||||||
@ -550,7 +488,8 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
|
|
||||||
// Initialize application settings
|
// Initialize application settings
|
||||||
{
|
{
|
||||||
m_settings.reset(new INISettingsObject(BuildConfig.LAUNCHER_CONFIGFILE, this));
|
// Provide a fallback for migration from PolyMC
|
||||||
|
m_settings.reset(new INISettingsObject({ BuildConfig.LAUNCHER_CONFIGFILE, "polymc.cfg", "multimc.cfg" }, this));
|
||||||
// Updates
|
// Updates
|
||||||
// Multiple channels are separated by spaces
|
// Multiple channels are separated by spaces
|
||||||
m_settings->registerSetting("UpdateChannel", BuildConfig.VERSION_CHANNEL);
|
m_settings->registerSetting("UpdateChannel", BuildConfig.VERSION_CHANNEL);
|
||||||
@ -877,6 +816,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
m_metacache->addBase("FlamePacks", QDir("cache/FlamePacks").absolutePath());
|
m_metacache->addBase("FlamePacks", QDir("cache/FlamePacks").absolutePath());
|
||||||
m_metacache->addBase("FlameMods", QDir("cache/FlameMods").absolutePath());
|
m_metacache->addBase("FlameMods", QDir("cache/FlameMods").absolutePath());
|
||||||
m_metacache->addBase("ModrinthPacks", QDir("cache/ModrinthPacks").absolutePath());
|
m_metacache->addBase("ModrinthPacks", QDir("cache/ModrinthPacks").absolutePath());
|
||||||
|
m_metacache->addBase("ModrinthModpacks", QDir("cache/ModrinthModpacks").absolutePath());
|
||||||
m_metacache->addBase("root", QDir::currentPath());
|
m_metacache->addBase("root", QDir::currentPath());
|
||||||
m_metacache->addBase("translations", QDir("translations").absolutePath());
|
m_metacache->addBase("translations", QDir("translations").absolutePath());
|
||||||
m_metacache->addBase("icons", QDir("cache/icons").absolutePath());
|
m_metacache->addBase("icons", QDir("cache/icons").absolutePath());
|
||||||
@ -928,12 +868,13 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
qDebug() << "<> Application theme set.";
|
qDebug() << "<> Application theme set.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateCapabilities();
|
||||||
|
|
||||||
if(createSetupWizard())
|
if(createSetupWizard())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateCapabilities();
|
|
||||||
performMainStartupAction();
|
performMainStartupAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,7 +355,7 @@ QString BaseInstance::name() const
|
|||||||
|
|
||||||
QString BaseInstance::windowTitle() const
|
QString BaseInstance::windowTitle() const
|
||||||
{
|
{
|
||||||
return BuildConfig.LAUNCHER_NAME + ": " + name().replace(QRegularExpression("\\s+"), " ");
|
return BuildConfig.LAUNCHER_DISPLAYNAME + ": " + name().replace(QRegularExpression("\\s+"), " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: why is this here? move it to MinecraftInstance!!!
|
// FIXME: why is this here? move it to MinecraftInstance!!!
|
||||||
@ -368,3 +368,8 @@ shared_qobject_ptr<LaunchTask> BaseInstance::getLaunchTask()
|
|||||||
{
|
{
|
||||||
return m_launchProcess;
|
return m_launchProcess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BaseInstance::updateRuntimeContext()
|
||||||
|
{
|
||||||
|
// NOOP
|
||||||
|
}
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
#include "net/Mode.h"
|
#include "net/Mode.h"
|
||||||
|
|
||||||
#include "minecraft/launch/MinecraftServerTarget.h"
|
#include "minecraft/launch/MinecraftServerTarget.h"
|
||||||
|
#include "RuntimeContext.h"
|
||||||
|
|
||||||
class QDir;
|
class QDir;
|
||||||
class Task;
|
class Task;
|
||||||
@ -220,6 +221,12 @@ public:
|
|||||||
|
|
||||||
virtual QString typeName() const = 0;
|
virtual QString typeName() const = 0;
|
||||||
|
|
||||||
|
void updateRuntimeContext();
|
||||||
|
RuntimeContext runtimeContext() const
|
||||||
|
{
|
||||||
|
return m_runtimeContext;
|
||||||
|
}
|
||||||
|
|
||||||
bool hasVersionBroken() const
|
bool hasVersionBroken() const
|
||||||
{
|
{
|
||||||
return m_hasBrokenVersion;
|
return m_hasBrokenVersion;
|
||||||
@ -305,6 +312,7 @@ protected: /* data */
|
|||||||
bool m_isRunning = false;
|
bool m_isRunning = false;
|
||||||
shared_qobject_ptr<LaunchTask> m_launchProcess;
|
shared_qobject_ptr<LaunchTask> m_launchProcess;
|
||||||
QDateTime m_timeStarted;
|
QDateTime m_timeStarted;
|
||||||
|
RuntimeContext m_runtimeContext;
|
||||||
|
|
||||||
private: /* data */
|
private: /* data */
|
||||||
Status m_status = Status::Present;
|
Status m_status = Status::Present;
|
||||||
|
@ -26,6 +26,7 @@ set(CORE_SOURCES
|
|||||||
MMCZip.cpp
|
MMCZip.cpp
|
||||||
MMCStrings.h
|
MMCStrings.h
|
||||||
MMCStrings.cpp
|
MMCStrings.cpp
|
||||||
|
RuntimeContext.h
|
||||||
|
|
||||||
# Basic instance manipulation tasks (derived from InstanceTask)
|
# Basic instance manipulation tasks (derived from InstanceTask)
|
||||||
InstanceCreationTask.h
|
InstanceCreationTask.h
|
||||||
@ -296,8 +297,6 @@ set(MINECRAFT_SOURCES
|
|||||||
minecraft/Rule.h
|
minecraft/Rule.h
|
||||||
minecraft/OneSixVersionFormat.cpp
|
minecraft/OneSixVersionFormat.cpp
|
||||||
minecraft/OneSixVersionFormat.h
|
minecraft/OneSixVersionFormat.h
|
||||||
minecraft/OpSys.cpp
|
|
||||||
minecraft/OpSys.h
|
|
||||||
minecraft/ParseUtils.cpp
|
minecraft/ParseUtils.cpp
|
||||||
minecraft/ParseUtils.h
|
minecraft/ParseUtils.h
|
||||||
minecraft/ProfileUtils.cpp
|
minecraft/ProfileUtils.cpp
|
||||||
@ -865,6 +864,10 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/widgets/PageContainer.cpp
|
ui/widgets/PageContainer.cpp
|
||||||
ui/widgets/PageContainer.h
|
ui/widgets/PageContainer.h
|
||||||
ui/widgets/PageContainer_p.h
|
ui/widgets/PageContainer_p.h
|
||||||
|
ui/widgets/ProjectDescriptionPage.h
|
||||||
|
ui/widgets/ProjectDescriptionPage.cpp
|
||||||
|
ui/widgets/VariableSizedImageObject.h
|
||||||
|
ui/widgets/VariableSizedImageObject.cpp
|
||||||
ui/widgets/ProjectItem.h
|
ui/widgets/ProjectItem.h
|
||||||
ui/widgets/ProjectItem.cpp
|
ui/widgets/ProjectItem.cpp
|
||||||
ui/widgets/VersionListView.cpp
|
ui/widgets/VersionListView.cpp
|
||||||
@ -980,14 +983,14 @@ add_library(Launcher_logic STATIC ${LOGIC_SOURCES} ${LAUNCHER_SOURCES} ${LAUNCHE
|
|||||||
target_include_directories(Launcher_logic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(Launcher_logic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
target_link_libraries(Launcher_logic
|
target_link_libraries(Launcher_logic
|
||||||
systeminfo
|
systeminfo
|
||||||
Launcher_classparser
|
|
||||||
Launcher_murmur2
|
Launcher_murmur2
|
||||||
nbt++
|
nbt++
|
||||||
${ZLIB_LIBRARIES}
|
${ZLIB_LIBRARIES}
|
||||||
tomlc99
|
tomlplusplus::tomlplusplus
|
||||||
BuildConfig
|
BuildConfig
|
||||||
Katabasis
|
Katabasis
|
||||||
Qt${QT_VERSION_MAJOR}::Widgets
|
Qt${QT_VERSION_MAJOR}::Widgets
|
||||||
|
ghcFilesystem::ghc_filesystem
|
||||||
)
|
)
|
||||||
|
|
||||||
if (UNIX AND NOT CYGWIN AND NOT APPLE)
|
if (UNIX AND NOT CYGWIN AND NOT APPLE)
|
||||||
|
@ -92,412 +92,4 @@ QStringList splitArgs(QString args)
|
|||||||
argv << current;
|
argv << current;
|
||||||
return argv;
|
return argv;
|
||||||
}
|
}
|
||||||
|
|
||||||
Parser::Parser(FlagStyle::Enum flagStyle, ArgumentStyle::Enum argStyle)
|
|
||||||
{
|
|
||||||
m_flagStyle = flagStyle;
|
|
||||||
m_argStyle = argStyle;
|
|
||||||
}
|
|
||||||
|
|
||||||
// styles setter/getter
|
|
||||||
void Parser::setArgumentStyle(ArgumentStyle::Enum style)
|
|
||||||
{
|
|
||||||
m_argStyle = style;
|
|
||||||
}
|
|
||||||
ArgumentStyle::Enum Parser::argumentStyle()
|
|
||||||
{
|
|
||||||
return m_argStyle;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Parser::setFlagStyle(FlagStyle::Enum style)
|
|
||||||
{
|
|
||||||
m_flagStyle = style;
|
|
||||||
}
|
|
||||||
FlagStyle::Enum Parser::flagStyle()
|
|
||||||
{
|
|
||||||
return m_flagStyle;
|
|
||||||
}
|
|
||||||
|
|
||||||
// setup methods
|
|
||||||
void Parser::addSwitch(QString name, bool def)
|
|
||||||
{
|
|
||||||
if (m_params.contains(name))
|
|
||||||
throw "Name not unique";
|
|
||||||
|
|
||||||
OptionDef *param = new OptionDef;
|
|
||||||
param->type = otSwitch;
|
|
||||||
param->name = name;
|
|
||||||
param->metavar = QString("<%1>").arg(name);
|
|
||||||
param->def = def;
|
|
||||||
|
|
||||||
m_options[name] = param;
|
|
||||||
m_params[name] = (CommonDef *)param;
|
|
||||||
m_optionList.append(param);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Parser::addOption(QString name, QVariant def)
|
|
||||||
{
|
|
||||||
if (m_params.contains(name))
|
|
||||||
throw "Name not unique";
|
|
||||||
|
|
||||||
OptionDef *param = new OptionDef;
|
|
||||||
param->type = otOption;
|
|
||||||
param->name = name;
|
|
||||||
param->metavar = QString("<%1>").arg(name);
|
|
||||||
param->def = def;
|
|
||||||
|
|
||||||
m_options[name] = param;
|
|
||||||
m_params[name] = (CommonDef *)param;
|
|
||||||
m_optionList.append(param);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Parser::addArgument(QString name, bool required, QVariant def)
|
|
||||||
{
|
|
||||||
if (m_params.contains(name))
|
|
||||||
throw "Name not unique";
|
|
||||||
|
|
||||||
PositionalDef *param = new PositionalDef;
|
|
||||||
param->name = name;
|
|
||||||
param->def = def;
|
|
||||||
param->required = required;
|
|
||||||
param->metavar = name;
|
|
||||||
|
|
||||||
m_positionals.append(param);
|
|
||||||
m_params[name] = (CommonDef *)param;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Parser::addDocumentation(QString name, QString doc, QString metavar)
|
|
||||||
{
|
|
||||||
if (!m_params.contains(name))
|
|
||||||
throw "Name does not exist";
|
|
||||||
|
|
||||||
CommonDef *param = m_params[name];
|
|
||||||
param->doc = doc;
|
|
||||||
if (!metavar.isNull())
|
|
||||||
param->metavar = metavar;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Parser::addShortOpt(QString name, QChar flag)
|
|
||||||
{
|
|
||||||
if (!m_params.contains(name))
|
|
||||||
throw "Name does not exist";
|
|
||||||
if (!m_options.contains(name))
|
|
||||||
throw "Name is not an Option or Swtich";
|
|
||||||
|
|
||||||
OptionDef *param = m_options[name];
|
|
||||||
m_flags[flag] = param;
|
|
||||||
param->flag = flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
// help methods
|
|
||||||
QString Parser::compileHelp(QString progName, int helpIndent, bool useFlags)
|
|
||||||
{
|
|
||||||
QStringList help;
|
|
||||||
help << compileUsage(progName, useFlags) << "\r\n";
|
|
||||||
|
|
||||||
// positionals
|
|
||||||
if (!m_positionals.isEmpty())
|
|
||||||
{
|
|
||||||
help << "\r\n";
|
|
||||||
help << "Positional arguments:\r\n";
|
|
||||||
QListIterator<PositionalDef *> it2(m_positionals);
|
|
||||||
while (it2.hasNext())
|
|
||||||
{
|
|
||||||
PositionalDef *param = it2.next();
|
|
||||||
help << " " << param->metavar;
|
|
||||||
help << " " << QString(helpIndent - param->metavar.length() - 1, ' ');
|
|
||||||
help << param->doc << "\r\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Options
|
|
||||||
if (!m_optionList.isEmpty())
|
|
||||||
{
|
|
||||||
help << "\r\n";
|
|
||||||
QString optPrefix, flagPrefix;
|
|
||||||
getPrefix(optPrefix, flagPrefix);
|
|
||||||
|
|
||||||
help << "Options & Switches:\r\n";
|
|
||||||
QListIterator<OptionDef *> it(m_optionList);
|
|
||||||
while (it.hasNext())
|
|
||||||
{
|
|
||||||
OptionDef *option = it.next();
|
|
||||||
help << " ";
|
|
||||||
int nameLength = optPrefix.length() + option->name.length();
|
|
||||||
if (!option->flag.isNull())
|
|
||||||
{
|
|
||||||
nameLength += 3 + flagPrefix.length();
|
|
||||||
help << flagPrefix << option->flag << ", ";
|
|
||||||
}
|
|
||||||
help << optPrefix << option->name;
|
|
||||||
if (option->type == otOption)
|
|
||||||
{
|
|
||||||
QString arg = QString("%1%2").arg(
|
|
||||||
((m_argStyle == ArgumentStyle::Equals) ? "=" : " "), option->metavar);
|
|
||||||
nameLength += arg.length();
|
|
||||||
help << arg;
|
|
||||||
}
|
|
||||||
help << " " << QString(helpIndent - nameLength - 1, ' ');
|
|
||||||
help << option->doc << "\r\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return help.join("");
|
|
||||||
}
|
|
||||||
|
|
||||||
QString Parser::compileUsage(QString progName, bool useFlags)
|
|
||||||
{
|
|
||||||
QStringList usage;
|
|
||||||
usage << "Usage: " << progName;
|
|
||||||
|
|
||||||
QString optPrefix, flagPrefix;
|
|
||||||
getPrefix(optPrefix, flagPrefix);
|
|
||||||
|
|
||||||
// options
|
|
||||||
QListIterator<OptionDef *> it(m_optionList);
|
|
||||||
while (it.hasNext())
|
|
||||||
{
|
|
||||||
OptionDef *option = it.next();
|
|
||||||
usage << " [";
|
|
||||||
if (!option->flag.isNull() && useFlags)
|
|
||||||
usage << flagPrefix << option->flag;
|
|
||||||
else
|
|
||||||
usage << optPrefix << option->name;
|
|
||||||
if (option->type == otOption)
|
|
||||||
usage << ((m_argStyle == ArgumentStyle::Equals) ? "=" : " ") << option->metavar;
|
|
||||||
usage << "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
// arguments
|
|
||||||
QListIterator<PositionalDef *> it2(m_positionals);
|
|
||||||
while (it2.hasNext())
|
|
||||||
{
|
|
||||||
PositionalDef *param = it2.next();
|
|
||||||
usage << " " << (param->required ? "<" : "[");
|
|
||||||
usage << param->metavar;
|
|
||||||
usage << (param->required ? ">" : "]");
|
|
||||||
}
|
|
||||||
|
|
||||||
return usage.join("");
|
|
||||||
}
|
|
||||||
|
|
||||||
// parsing
|
|
||||||
QHash<QString, QVariant> Parser::parse(QStringList argv)
|
|
||||||
{
|
|
||||||
QHash<QString, QVariant> map;
|
|
||||||
|
|
||||||
QStringListIterator it(argv);
|
|
||||||
QString programName = it.next();
|
|
||||||
|
|
||||||
QString optionPrefix;
|
|
||||||
QString flagPrefix;
|
|
||||||
QListIterator<PositionalDef *> positionals(m_positionals);
|
|
||||||
QStringList expecting;
|
|
||||||
|
|
||||||
getPrefix(optionPrefix, flagPrefix);
|
|
||||||
|
|
||||||
while (it.hasNext())
|
|
||||||
{
|
|
||||||
QString arg = it.next();
|
|
||||||
|
|
||||||
if (!expecting.isEmpty())
|
|
||||||
// we were expecting an argument
|
|
||||||
{
|
|
||||||
QString name = expecting.first();
|
|
||||||
/*
|
|
||||||
if (map.contains(name))
|
|
||||||
throw ParsingError(
|
|
||||||
QString("Option %2%1 was given multiple times").arg(name, optionPrefix));
|
|
||||||
*/
|
|
||||||
map[name] = QVariant(arg);
|
|
||||||
|
|
||||||
expecting.removeFirst();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arg.startsWith(optionPrefix))
|
|
||||||
// we have an option
|
|
||||||
{
|
|
||||||
// qDebug("Found option %s", qPrintable(arg));
|
|
||||||
|
|
||||||
QString name = arg.mid(optionPrefix.length());
|
|
||||||
QString equals;
|
|
||||||
|
|
||||||
if ((m_argStyle == ArgumentStyle::Equals ||
|
|
||||||
m_argStyle == ArgumentStyle::SpaceAndEquals) &&
|
|
||||||
name.contains("="))
|
|
||||||
{
|
|
||||||
int i = name.indexOf("=");
|
|
||||||
equals = name.mid(i + 1);
|
|
||||||
name = name.left(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_options.contains(name))
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
if (map.contains(name))
|
|
||||||
throw ParsingError(QString("Option %2%1 was given multiple times")
|
|
||||||
.arg(name, optionPrefix));
|
|
||||||
*/
|
|
||||||
OptionDef *option = m_options[name];
|
|
||||||
if (option->type == otSwitch)
|
|
||||||
map[name] = true;
|
|
||||||
else // if (option->type == otOption)
|
|
||||||
{
|
|
||||||
if (m_argStyle == ArgumentStyle::Space)
|
|
||||||
expecting.append(name);
|
|
||||||
else if (!equals.isNull())
|
|
||||||
map[name] = equals;
|
|
||||||
else if (m_argStyle == ArgumentStyle::SpaceAndEquals)
|
|
||||||
expecting.append(name);
|
|
||||||
else
|
|
||||||
throw ParsingError(QString("Option %2%1 reqires an argument.")
|
|
||||||
.arg(name, optionPrefix));
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw ParsingError(QString("Unknown Option %2%1").arg(name, optionPrefix));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arg.startsWith(flagPrefix))
|
|
||||||
// we have (a) flag(s)
|
|
||||||
{
|
|
||||||
// qDebug("Found flags %s", qPrintable(arg));
|
|
||||||
|
|
||||||
QString flags = arg.mid(flagPrefix.length());
|
|
||||||
QString equals;
|
|
||||||
|
|
||||||
if ((m_argStyle == ArgumentStyle::Equals ||
|
|
||||||
m_argStyle == ArgumentStyle::SpaceAndEquals) &&
|
|
||||||
flags.contains("="))
|
|
||||||
{
|
|
||||||
int i = flags.indexOf("=");
|
|
||||||
equals = flags.mid(i + 1);
|
|
||||||
flags = flags.left(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < flags.length(); i++)
|
|
||||||
{
|
|
||||||
QChar flag = flags.at(i);
|
|
||||||
|
|
||||||
if (!m_flags.contains(flag))
|
|
||||||
throw ParsingError(QString("Unknown flag %2%1").arg(flag, flagPrefix));
|
|
||||||
|
|
||||||
OptionDef *option = m_flags[flag];
|
|
||||||
/*
|
|
||||||
if (map.contains(option->name))
|
|
||||||
throw ParsingError(QString("Option %2%1 was given multiple times")
|
|
||||||
.arg(option->name, optionPrefix));
|
|
||||||
*/
|
|
||||||
if (option->type == otSwitch)
|
|
||||||
map[option->name] = true;
|
|
||||||
else // if (option->type == otOption)
|
|
||||||
{
|
|
||||||
if (m_argStyle == ArgumentStyle::Space)
|
|
||||||
expecting.append(option->name);
|
|
||||||
else if (!equals.isNull())
|
|
||||||
if (i == flags.length() - 1)
|
|
||||||
map[option->name] = equals;
|
|
||||||
else
|
|
||||||
throw ParsingError(QString("Flag %4%2 of Argument-requiring Option "
|
|
||||||
"%1 not last flag in %4%3")
|
|
||||||
.arg(option->name, flag, flags, flagPrefix));
|
|
||||||
else if (m_argStyle == ArgumentStyle::SpaceAndEquals)
|
|
||||||
expecting.append(option->name);
|
|
||||||
else
|
|
||||||
throw ParsingError(QString("Option %1 reqires an argument. (flag %3%2)")
|
|
||||||
.arg(option->name, flag, flagPrefix));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// must be a positional argument
|
|
||||||
if (!positionals.hasNext())
|
|
||||||
throw ParsingError(QString("Don't know what to do with '%1'").arg(arg));
|
|
||||||
|
|
||||||
PositionalDef *param = positionals.next();
|
|
||||||
|
|
||||||
map[param->name] = arg;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if we're missing something
|
|
||||||
if (!expecting.isEmpty())
|
|
||||||
throw ParsingError(QString("Was still expecting arguments for %2%1").arg(
|
|
||||||
expecting.join(QString(", ") + optionPrefix), optionPrefix));
|
|
||||||
|
|
||||||
while (positionals.hasNext())
|
|
||||||
{
|
|
||||||
PositionalDef *param = positionals.next();
|
|
||||||
if (param->required)
|
|
||||||
throw ParsingError(
|
|
||||||
QString("Missing required positional argument '%1'").arg(param->name));
|
|
||||||
else
|
|
||||||
map[param->name] = param->def;
|
|
||||||
}
|
|
||||||
|
|
||||||
// fill out gaps
|
|
||||||
QListIterator<OptionDef *> iter(m_optionList);
|
|
||||||
while (iter.hasNext())
|
|
||||||
{
|
|
||||||
OptionDef *option = iter.next();
|
|
||||||
if (!map.contains(option->name))
|
|
||||||
map[option->name] = option->def;
|
|
||||||
}
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
// clear defs
|
|
||||||
void Parser::clear()
|
|
||||||
{
|
|
||||||
m_flags.clear();
|
|
||||||
m_params.clear();
|
|
||||||
m_options.clear();
|
|
||||||
|
|
||||||
QMutableListIterator<OptionDef *> it(m_optionList);
|
|
||||||
while (it.hasNext())
|
|
||||||
{
|
|
||||||
OptionDef *option = it.next();
|
|
||||||
it.remove();
|
|
||||||
delete option;
|
|
||||||
}
|
|
||||||
|
|
||||||
QMutableListIterator<PositionalDef *> it2(m_positionals);
|
|
||||||
while (it2.hasNext())
|
|
||||||
{
|
|
||||||
PositionalDef *arg = it2.next();
|
|
||||||
it2.remove();
|
|
||||||
delete arg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destructor
|
|
||||||
Parser::~Parser()
|
|
||||||
{
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// getPrefix
|
|
||||||
void Parser::getPrefix(QString &opt, QString &flag)
|
|
||||||
{
|
|
||||||
if (m_flagStyle == FlagStyle::Windows)
|
|
||||||
opt = flag = "/";
|
|
||||||
else if (m_flagStyle == FlagStyle::Unix)
|
|
||||||
opt = flag = "-";
|
|
||||||
// else if (m_flagStyle == FlagStyle::GNU)
|
|
||||||
else
|
|
||||||
{
|
|
||||||
opt = "--";
|
|
||||||
flag = "-";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParsingError
|
|
||||||
ParsingError::ParsingError(const QString &what) : std::runtime_error(what.toStdString())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -17,12 +17,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <exception>
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QVariant>
|
|
||||||
#include <QHash>
|
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -39,212 +34,4 @@ namespace Commandline
|
|||||||
* @return a QStringList containing all arguments
|
* @return a QStringList containing all arguments
|
||||||
*/
|
*/
|
||||||
QStringList splitArgs(QString args);
|
QStringList splitArgs(QString args);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The FlagStyle enum
|
|
||||||
* Specifies how flags are decorated
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace FlagStyle
|
|
||||||
{
|
|
||||||
enum Enum
|
|
||||||
{
|
|
||||||
GNU, /**< --option and -o (GNU Style) */
|
|
||||||
Unix, /**< -option and -o (Unix Style) */
|
|
||||||
Windows, /**< /option and /o (Windows Style) */
|
|
||||||
#ifdef Q_OS_WIN32
|
|
||||||
Default = Windows
|
|
||||||
#else
|
|
||||||
Default = GNU
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The ArgumentStyle enum
|
|
||||||
*/
|
|
||||||
namespace ArgumentStyle
|
|
||||||
{
|
|
||||||
enum Enum
|
|
||||||
{
|
|
||||||
Space, /**< --option value */
|
|
||||||
Equals, /**< --option=value */
|
|
||||||
SpaceAndEquals, /**< --option[= ]value */
|
|
||||||
#ifdef Q_OS_WIN32
|
|
||||||
Default = Equals
|
|
||||||
#else
|
|
||||||
Default = SpaceAndEquals
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The ParsingError class
|
|
||||||
*/
|
|
||||||
class ParsingError : public std::runtime_error
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ParsingError(const QString &what);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The Parser class
|
|
||||||
*/
|
|
||||||
class Parser
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* @brief Parser constructor
|
|
||||||
* @param flagStyle the FlagStyle to use in this Parser
|
|
||||||
* @param argStyle the ArgumentStyle to use in this Parser
|
|
||||||
*/
|
|
||||||
Parser(FlagStyle::Enum flagStyle = FlagStyle::Default,
|
|
||||||
ArgumentStyle::Enum argStyle = ArgumentStyle::Default);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief set the flag style
|
|
||||||
* @param style
|
|
||||||
*/
|
|
||||||
void setFlagStyle(FlagStyle::Enum style);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief get the flag style
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
FlagStyle::Enum flagStyle();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief set the argument style
|
|
||||||
* @param style
|
|
||||||
*/
|
|
||||||
void setArgumentStyle(ArgumentStyle::Enum style);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief get the argument style
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
ArgumentStyle::Enum argumentStyle();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief define a boolean switch
|
|
||||||
* @param name the parameter name
|
|
||||||
* @param def the default value
|
|
||||||
*/
|
|
||||||
void addSwitch(QString name, bool def = false);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief define an option that takes an additional argument
|
|
||||||
* @param name the parameter name
|
|
||||||
* @param def the default value
|
|
||||||
*/
|
|
||||||
void addOption(QString name, QVariant def = QVariant());
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief define a positional argument
|
|
||||||
* @param name the parameter name
|
|
||||||
* @param required wether this argument is required
|
|
||||||
* @param def the default value
|
|
||||||
*/
|
|
||||||
void addArgument(QString name, bool required = true, QVariant def = QVariant());
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief adds a flag to an existing parameter
|
|
||||||
* @param name the (existing) parameter name
|
|
||||||
* @param flag the flag character
|
|
||||||
* @see addSwitch addArgument addOption
|
|
||||||
* Note: any one parameter can only have one flag
|
|
||||||
*/
|
|
||||||
void addShortOpt(QString name, QChar flag);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief adds documentation to a Parameter
|
|
||||||
* @param name the parameter name
|
|
||||||
* @param metavar a string to be displayed as placeholder for the value
|
|
||||||
* @param doc a QString containing the documentation
|
|
||||||
* Note: on positional arguments, metavar replaces the name as displayed.
|
|
||||||
* on options , metavar replaces the value placeholder
|
|
||||||
*/
|
|
||||||
void addDocumentation(QString name, QString doc, QString metavar = QString());
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief generate a help message
|
|
||||||
* @param progName the program name to use in the help message
|
|
||||||
* @param helpIndent how much the parameter documentation should be indented
|
|
||||||
* @param flagsInUsage whether we should use flags instead of options in the usage
|
|
||||||
* @return a help message
|
|
||||||
*/
|
|
||||||
QString compileHelp(QString progName, int helpIndent = 22, bool flagsInUsage = true);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief generate a short usage message
|
|
||||||
* @param progName the program name to use in the usage message
|
|
||||||
* @param useFlags whether we should use flags instead of options
|
|
||||||
* @return a usage message
|
|
||||||
*/
|
|
||||||
QString compileUsage(QString progName, bool useFlags = true);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief parse
|
|
||||||
* @param argv a QStringList containing the program ARGV
|
|
||||||
* @return a QHash mapping argument names to their values
|
|
||||||
*/
|
|
||||||
QHash<QString, QVariant> parse(QStringList argv);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief clear all definitions
|
|
||||||
*/
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
~Parser();
|
|
||||||
|
|
||||||
private:
|
|
||||||
FlagStyle::Enum m_flagStyle;
|
|
||||||
ArgumentStyle::Enum m_argStyle;
|
|
||||||
|
|
||||||
enum OptionType
|
|
||||||
{
|
|
||||||
otSwitch,
|
|
||||||
otOption
|
|
||||||
};
|
|
||||||
|
|
||||||
// Important: the common part MUST BE COMMON ON ALL THREE structs
|
|
||||||
struct CommonDef
|
|
||||||
{
|
|
||||||
QString name;
|
|
||||||
QString doc;
|
|
||||||
QString metavar;
|
|
||||||
QVariant def;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct OptionDef
|
|
||||||
{
|
|
||||||
// common
|
|
||||||
QString name;
|
|
||||||
QString doc;
|
|
||||||
QString metavar;
|
|
||||||
QVariant def;
|
|
||||||
// option
|
|
||||||
OptionType type;
|
|
||||||
QChar flag;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PositionalDef
|
|
||||||
{
|
|
||||||
// common
|
|
||||||
QString name;
|
|
||||||
QString doc;
|
|
||||||
QString metavar;
|
|
||||||
QVariant def;
|
|
||||||
// positional
|
|
||||||
bool required;
|
|
||||||
};
|
|
||||||
|
|
||||||
QHash<QString, OptionDef *> m_options;
|
|
||||||
QHash<QChar, OptionDef *> m_flags;
|
|
||||||
QHash<QString, CommonDef *> m_params;
|
|
||||||
QList<PositionalDef *> m_positionals;
|
|
||||||
QList<OptionDef *> m_optionList;
|
|
||||||
|
|
||||||
void getPrefix(QString &opt, QString &flag);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,24 @@
|
|||||||
#include <utime.h>
|
#include <utime.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Snippet from https://github.com/gulrak/filesystem#using-it-as-single-file-header
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <Availability.h> // for deployment target to support pre-catalina targets without std::fs
|
||||||
|
#endif // __APPLE__
|
||||||
|
|
||||||
|
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
|
||||||
|
#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
|
||||||
|
#define GHC_USE_STD_FS
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
#endif // MacOS min version check
|
||||||
|
#endif // Other OSes version check
|
||||||
|
|
||||||
|
#ifndef GHC_USE_STD_FS
|
||||||
|
#include <ghc/filesystem.hpp>
|
||||||
|
namespace fs = ghc::filesystem;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined Q_OS_WIN32
|
#if defined Q_OS_WIN32
|
||||||
|
|
||||||
@ -147,7 +164,7 @@ bool ensureFolderPathExists(QString foldernamepath)
|
|||||||
|
|
||||||
bool copy::operator()(const QString& offset)
|
bool copy::operator()(const QString& offset)
|
||||||
{
|
{
|
||||||
using copy_opts = std::filesystem::copy_options;
|
using copy_opts = fs::copy_options;
|
||||||
|
|
||||||
// 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
|
||||||
@ -159,7 +176,7 @@ bool copy::operator()(const QString& offset)
|
|||||||
|
|
||||||
std::error_code err;
|
std::error_code err;
|
||||||
|
|
||||||
std::filesystem::copy_options opt = copy_opts::none;
|
fs::copy_options opt = copy_opts::none;
|
||||||
|
|
||||||
// The default behavior is to follow symlinks
|
// The default behavior is to follow symlinks
|
||||||
if (!m_followSymlinks)
|
if (!m_followSymlinks)
|
||||||
@ -170,7 +187,7 @@ bool copy::operator()(const QString& offset)
|
|||||||
// blacklisted paths, so we iterate over the source directory, and if there's no blacklist
|
// blacklisted paths, so we iterate over the source directory, and if there's no blacklist
|
||||||
// match, we copy the file.
|
// match, we copy the file.
|
||||||
QDir src_dir(src);
|
QDir src_dir(src);
|
||||||
QDirIterator source_it(src, QDir::Filter::Files, QDirIterator::Subdirectories);
|
QDirIterator source_it(src, QDir::Filter::Files | QDir::Filter::Hidden, QDirIterator::Subdirectories);
|
||||||
|
|
||||||
while (source_it.hasNext()) {
|
while (source_it.hasNext()) {
|
||||||
auto src_path = source_it.next();
|
auto src_path = source_it.next();
|
||||||
@ -182,7 +199,7 @@ bool copy::operator()(const QString& offset)
|
|||||||
auto dst_path = PathCombine(dst, relative_path);
|
auto dst_path = PathCombine(dst, relative_path);
|
||||||
ensureFilePathExists(dst_path);
|
ensureFilePathExists(dst_path);
|
||||||
|
|
||||||
std::filesystem::copy(toStdString(src_path), toStdString(dst_path), opt, err);
|
fs::copy(toStdString(src_path), 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;
|
||||||
@ -197,7 +214,7 @@ bool deletePath(QString path)
|
|||||||
{
|
{
|
||||||
std::error_code err;
|
std::error_code err;
|
||||||
|
|
||||||
std::filesystem::remove_all(toStdString(path), err);
|
fs::remove_all(toStdString(path), err);
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
qWarning() << "Failed to remove files:" << QString::fromStdString(err.message());
|
qWarning() << "Failed to remove files:" << QString::fromStdString(err.message());
|
||||||
@ -376,15 +393,15 @@ bool createShortCut(QString location, QString dest, QStringList args, QString na
|
|||||||
|
|
||||||
bool overrideFolder(QString overwritten_path, QString override_path)
|
bool overrideFolder(QString overwritten_path, QString override_path)
|
||||||
{
|
{
|
||||||
using copy_opts = std::filesystem::copy_options;
|
using copy_opts = fs::copy_options;
|
||||||
|
|
||||||
if (!FS::ensureFolderPathExists(overwritten_path))
|
if (!FS::ensureFolderPathExists(overwritten_path))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
std::error_code err;
|
std::error_code err;
|
||||||
std::filesystem::copy_options opt = copy_opts::recursive | copy_opts::overwrite_existing;
|
fs::copy_options opt = copy_opts::recursive | copy_opts::overwrite_existing;
|
||||||
|
|
||||||
std::filesystem::copy(toStdString(override_path), toStdString(overwritten_path), opt, err);
|
fs::copy(toStdString(override_path), toStdString(overwritten_path), opt, err);
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
qCritical() << QString("Failed to apply override from %1 to %2").arg(override_path, overwritten_path);
|
qCritical() << QString("Failed to apply override from %1 to %2").arg(override_path, overwritten_path);
|
||||||
|
@ -93,8 +93,8 @@ void LaunchController::decideAccount()
|
|||||||
auto reply = CustomMessageBox::selectable(
|
auto reply = CustomMessageBox::selectable(
|
||||||
m_parentWidget,
|
m_parentWidget,
|
||||||
tr("No Accounts"),
|
tr("No Accounts"),
|
||||||
tr("In order to play Minecraft, you must have at least one Mojang or Microsoft "
|
tr("In order to play Minecraft, you must have at least one Microsoft or Mojang "
|
||||||
"account logged in. "
|
"account logged in. Mojang accounts can only be used offline. "
|
||||||
"Would you like to open the account manager to add an account now?"),
|
"Would you like to open the account manager to add an account now?"),
|
||||||
QMessageBox::Information,
|
QMessageBox::Information,
|
||||||
QMessageBox::Yes | QMessageBox::No
|
QMessageBox::Yes | QMessageBox::No
|
||||||
@ -382,7 +382,7 @@ void LaunchController::launchInstance()
|
|||||||
m_launcher->prependStep(new TextPrint(m_launcher.get(), "Launched instance in " + online_mode + " mode\n", MessageLevel::Launcher));
|
m_launcher->prependStep(new TextPrint(m_launcher.get(), "Launched instance in " + online_mode + " mode\n", MessageLevel::Launcher));
|
||||||
|
|
||||||
// Prepend Version
|
// Prepend Version
|
||||||
m_launcher->prependStep(new TextPrint(m_launcher.get(), BuildConfig.LAUNCHER_NAME + " version: " + BuildConfig.printableVersionString() + "\n\n", MessageLevel::Launcher));
|
m_launcher->prependStep(new TextPrint(m_launcher.get(), BuildConfig.LAUNCHER_DISPLAYNAME + " version: " + BuildConfig.printableVersionString() + "\n\n", MessageLevel::Launcher));
|
||||||
m_launcher->start();
|
m_launcher->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,38 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* PolyMC - Minecraft Launcher
|
||||||
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This file incorporates work covered by the following copyright and
|
||||||
|
* permission notice:
|
||||||
|
*
|
||||||
|
* Copyright 2013-2021 MultiMC Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "BaseInstance.h"
|
#include "BaseInstance.h"
|
||||||
#include "launch/LaunchTask.h"
|
#include "launch/LaunchTask.h"
|
||||||
@ -84,4 +119,8 @@ public:
|
|||||||
QString modsRoot() const override {
|
QString modsRoot() const override {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
void updateRuntimeContext()
|
||||||
|
{
|
||||||
|
// NOOP
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
88
launcher/RuntimeContext.h
Normal file
88
launcher/RuntimeContext.h
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* PolyMC - Minecraft Launcher
|
||||||
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QSet>
|
||||||
|
#include <QString>
|
||||||
|
#include "settings/SettingsObject.h"
|
||||||
|
|
||||||
|
struct RuntimeContext {
|
||||||
|
QString javaArchitecture;
|
||||||
|
QString javaRealArchitecture;
|
||||||
|
QString javaPath;
|
||||||
|
QString system;
|
||||||
|
|
||||||
|
QString mappedJavaRealArchitecture() const
|
||||||
|
{
|
||||||
|
if (javaRealArchitecture == "amd64")
|
||||||
|
return "x86_64";
|
||||||
|
if (javaRealArchitecture == "i386" || javaRealArchitecture == "i686")
|
||||||
|
return "x86";
|
||||||
|
if (javaRealArchitecture == "aarch64")
|
||||||
|
return "arm64";
|
||||||
|
if (javaRealArchitecture == "arm" || javaRealArchitecture == "armhf")
|
||||||
|
return "arm32";
|
||||||
|
return javaRealArchitecture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateFromInstanceSettings(SettingsObjectPtr instanceSettings)
|
||||||
|
{
|
||||||
|
javaArchitecture = instanceSettings->get("JavaArchitecture").toString();
|
||||||
|
javaRealArchitecture = instanceSettings->get("JavaRealArchitecture").toString();
|
||||||
|
javaPath = instanceSettings->get("JavaPath").toString();
|
||||||
|
system = currentSystem();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString getClassifier() const { return system + "-" + mappedJavaRealArchitecture(); }
|
||||||
|
|
||||||
|
// "Legacy" refers to the fact that Mojang assumed that these are the only two architectures
|
||||||
|
bool isLegacyArch() const
|
||||||
|
{
|
||||||
|
const QString mapped = mappedJavaRealArchitecture();
|
||||||
|
return mapped == "x86_64" || mapped == "x86";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool classifierMatches(QString target) const
|
||||||
|
{
|
||||||
|
// try to match precise classifier "[os]-[arch]"
|
||||||
|
bool x = target == getClassifier();
|
||||||
|
// try to match imprecise classifier on legacy architectures "[os]"
|
||||||
|
if (!x && isLegacyArch())
|
||||||
|
x = target == system;
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString currentSystem()
|
||||||
|
{
|
||||||
|
#if defined(Q_OS_LINUX)
|
||||||
|
return "linux";
|
||||||
|
#elif defined(Q_OS_MACOS)
|
||||||
|
return "osx";
|
||||||
|
#elif defined(Q_OS_WINDOWS)
|
||||||
|
return "windows";
|
||||||
|
#elif defined(Q_OS_FREEBSD)
|
||||||
|
return "freebsd";
|
||||||
|
#elif defined(Q_OS_OPENBSD)
|
||||||
|
return "openbsd";
|
||||||
|
#else
|
||||||
|
return "unknown";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
@ -358,7 +358,7 @@ void UpdateController::fail()
|
|||||||
msg = QObject::tr(
|
msg = QObject::tr(
|
||||||
"Couldn't replace file %1. Changes will be reverted.\n"
|
"Couldn't replace file %1. Changes will be reverted.\n"
|
||||||
"See the %2 log file for details."
|
"See the %2 log file for details."
|
||||||
).arg(m_failedFile, BuildConfig.LAUNCHER_NAME);
|
).arg(m_failedFile, BuildConfig.LAUNCHER_DISPLAYNAME);
|
||||||
doRollback = true;
|
doRollback = true;
|
||||||
QMessageBox::critical(m_parent, failTitle, msg);
|
QMessageBox::critical(m_parent, failTitle, msg);
|
||||||
break;
|
break;
|
||||||
@ -368,7 +368,7 @@ void UpdateController::fail()
|
|||||||
msg = QObject::tr(
|
msg = QObject::tr(
|
||||||
"Couldn't remove file %1. Changes will be reverted.\n"
|
"Couldn't remove file %1. Changes will be reverted.\n"
|
||||||
"See the %2 log file for details."
|
"See the %2 log file for details."
|
||||||
).arg(m_failedFile, BuildConfig.LAUNCHER_NAME);
|
).arg(m_failedFile, BuildConfig.LAUNCHER_DISPLAYNAME);
|
||||||
doRollback = true;
|
doRollback = true;
|
||||||
QMessageBox::critical(m_parent, failTitle, msg);
|
QMessageBox::critical(m_parent, failTitle, msg);
|
||||||
break;
|
break;
|
||||||
@ -399,7 +399,7 @@ void UpdateController::fail()
|
|||||||
{
|
{
|
||||||
msg = QObject::tr("The rollback failed too.\n"
|
msg = QObject::tr("The rollback failed too.\n"
|
||||||
"You will have to repair %1 manually.\n"
|
"You will have to repair %1 manually.\n"
|
||||||
"Please let us know why and how this happened.").arg(BuildConfig.LAUNCHER_NAME);
|
"Please let us know why and how this happened.").arg(BuildConfig.LAUNCHER_DISPLAYNAME);
|
||||||
QMessageBox::critical(m_parent, rollFailTitle, msg);
|
QMessageBox::critical(m_parent, rollFailTitle, msg);
|
||||||
qApp->quit();
|
qApp->quit();
|
||||||
}
|
}
|
||||||
|
@ -174,7 +174,7 @@ JavaInstallPtr JavaUtils::GetDefaultJava()
|
|||||||
|
|
||||||
QStringList addJavasFromEnv(QList<QString> javas)
|
QStringList addJavasFromEnv(QList<QString> javas)
|
||||||
{
|
{
|
||||||
auto env = qEnvironmentVariable("POLYMC_JAVA_PATHS");
|
auto env = qEnvironmentVariable("PRISMLAUNCHER_JAVA_PATHS"); // FIXME: use launcher name from buildconfig
|
||||||
#if defined(Q_OS_WIN32)
|
#if defined(Q_OS_WIN32)
|
||||||
QList<QString> javaPaths = env.replace("\\", "/").split(QLatin1String(";"));
|
QList<QString> javaPaths = env.replace("\\", "/").split(QLatin1String(";"));
|
||||||
|
|
||||||
@ -441,7 +441,7 @@ QList<QString> JavaUtils::FindJavaPaths()
|
|||||||
scanJavaDir("/usr/lib/jvm");
|
scanJavaDir("/usr/lib/jvm");
|
||||||
scanJavaDir("/usr/lib64/jvm");
|
scanJavaDir("/usr/lib64/jvm");
|
||||||
scanJavaDir("/usr/lib32/jvm");
|
scanJavaDir("/usr/lib32/jvm");
|
||||||
// javas stored in PolyMC's folder
|
// javas stored in Prism Launcher's folder
|
||||||
scanJavaDir("java");
|
scanJavaDir("java");
|
||||||
// manually installed JDKs in /opt
|
// manually installed JDKs in /opt
|
||||||
scanJavaDir("/opt/jdk");
|
scanJavaDir("/opt/jdk");
|
||||||
|
@ -121,7 +121,6 @@ void CheckJava::checkJavaFinished(JavaCheckResult result)
|
|||||||
emit logLine(QString("Could not start java:"), MessageLevel::Error);
|
emit logLine(QString("Could not start java:"), MessageLevel::Error);
|
||||||
emit logLines(result.errorLog.split('\n'), MessageLevel::Error);
|
emit logLines(result.errorLog.split('\n'), MessageLevel::Error);
|
||||||
emit logLine(QString("\nCheck your Java settings."), MessageLevel::Launcher);
|
emit logLine(QString("\nCheck your Java settings."), MessageLevel::Launcher);
|
||||||
printSystemInfo(false, false);
|
|
||||||
emitFailed(QString("Could not start java!"));
|
emitFailed(QString("Could not start java!"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -130,7 +129,6 @@ void CheckJava::checkJavaFinished(JavaCheckResult result)
|
|||||||
emit logLine(QString("Java checker returned some invalid data we don't understand:"), MessageLevel::Error);
|
emit logLine(QString("Java checker returned some invalid data we don't understand:"), MessageLevel::Error);
|
||||||
emit logLines(result.outLog.split('\n'), MessageLevel::Warning);
|
emit logLines(result.outLog.split('\n'), MessageLevel::Warning);
|
||||||
emit logLine("\nMinecraft might not start properly.", MessageLevel::Launcher);
|
emit logLine("\nMinecraft might not start properly.", MessageLevel::Launcher);
|
||||||
printSystemInfo(false, false);
|
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -138,7 +136,6 @@ void CheckJava::checkJavaFinished(JavaCheckResult result)
|
|||||||
{
|
{
|
||||||
auto instance = m_parent->instance();
|
auto instance = m_parent->instance();
|
||||||
printJavaInfo(result.javaVersion.toString(), result.mojangPlatform, result.realPlatform, result.javaVendor);
|
printJavaInfo(result.javaVersion.toString(), result.mojangPlatform, result.realPlatform, result.javaVendor);
|
||||||
printSystemInfo(true, result.is_64bit);
|
|
||||||
instance->settings()->set("JavaVersion", result.javaVersion.toString());
|
instance->settings()->set("JavaVersion", result.javaVersion.toString());
|
||||||
instance->settings()->set("JavaArchitecture", result.mojangPlatform);
|
instance->settings()->set("JavaArchitecture", result.mojangPlatform);
|
||||||
instance->settings()->set("JavaRealArchitecture", result.realPlatform);
|
instance->settings()->set("JavaRealArchitecture", result.realPlatform);
|
||||||
@ -155,20 +152,3 @@ void CheckJava::printJavaInfo(const QString& version, const QString& architectur
|
|||||||
emit logLine(QString("Java is version %1, using %2 (%3) architecture, from %4.\n\n")
|
emit logLine(QString("Java is version %1, using %2 (%3) architecture, from %4.\n\n")
|
||||||
.arg(version, architecture, realArchitecture, vendor), MessageLevel::Launcher);
|
.arg(version, architecture, realArchitecture, vendor), MessageLevel::Launcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckJava::printSystemInfo(bool javaIsKnown, bool javaIs64bit)
|
|
||||||
{
|
|
||||||
auto cpu64 = Sys::isCPU64bit();
|
|
||||||
auto system64 = Sys::isSystem64bit();
|
|
||||||
if(cpu64 != system64)
|
|
||||||
{
|
|
||||||
emit logLine(QString("Your CPU architecture is not matching your system architecture. You might want to install a 64bit Operating System.\n\n"), MessageLevel::Error);
|
|
||||||
}
|
|
||||||
if(javaIsKnown)
|
|
||||||
{
|
|
||||||
if(javaIs64bit != system64)
|
|
||||||
{
|
|
||||||
emit logLine(QString("Your Java architecture is not matching your system architecture. You might want to install a 64bit Java version.\n\n"), MessageLevel::Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -75,7 +75,7 @@ int main(int argc, char *argv[])
|
|||||||
Q_INIT_RESOURCE(multimc);
|
Q_INIT_RESOURCE(multimc);
|
||||||
Q_INIT_RESOURCE(backgrounds);
|
Q_INIT_RESOURCE(backgrounds);
|
||||||
Q_INIT_RESOURCE(documents);
|
Q_INIT_RESOURCE(documents);
|
||||||
Q_INIT_RESOURCE(polymc);
|
Q_INIT_RESOURCE(prismlauncher);
|
||||||
|
|
||||||
Q_INIT_RESOURCE(pe_dark);
|
Q_INIT_RESOURCE(pe_dark);
|
||||||
Q_INIT_RESOURCE(pe_light);
|
Q_INIT_RESOURCE(pe_light);
|
||||||
|
@ -1,3 +1,38 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* PolyMC - Minecraft Launcher
|
||||||
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This file incorporates work covered by the following copyright and
|
||||||
|
* permission notice:
|
||||||
|
*
|
||||||
|
* Copyright 2013-2021 MultiMC Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
#include <meta/VersionList.h>
|
#include <meta/VersionList.h>
|
||||||
#include <meta/Index.h>
|
#include <meta/Index.h>
|
||||||
#include "Component.h"
|
#include "Component.h"
|
||||||
@ -60,7 +95,7 @@ void Component::applyTo(LaunchProfile* profile)
|
|||||||
auto vfile = getVersionFile();
|
auto vfile = getVersionFile();
|
||||||
if(vfile)
|
if(vfile)
|
||||||
{
|
{
|
||||||
vfile->applyTo(profile);
|
vfile->applyTo(profile, m_parent->runtimeContext());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -173,9 +173,9 @@ void LaunchProfile::applyCompatibleJavaMajors(QList<int>& javaMajor)
|
|||||||
m_compatibleJavaMajors.append(javaMajor);
|
m_compatibleJavaMajors.append(javaMajor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaunchProfile::applyLibrary(LibraryPtr library)
|
void LaunchProfile::applyLibrary(LibraryPtr library, const RuntimeContext & runtimeContext)
|
||||||
{
|
{
|
||||||
if(!library->isActive())
|
if(!library->isActive(runtimeContext))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -205,9 +205,9 @@ void LaunchProfile::applyLibrary(LibraryPtr library)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaunchProfile::applyMavenFile(LibraryPtr mavenFile)
|
void LaunchProfile::applyMavenFile(LibraryPtr mavenFile, const RuntimeContext & runtimeContext)
|
||||||
{
|
{
|
||||||
if(!mavenFile->isActive())
|
if(!mavenFile->isActive(runtimeContext))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -221,10 +221,10 @@ void LaunchProfile::applyMavenFile(LibraryPtr mavenFile)
|
|||||||
m_mavenFiles.append(Library::limitedCopy(mavenFile));
|
m_mavenFiles.append(Library::limitedCopy(mavenFile));
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaunchProfile::applyAgent(AgentPtr agent)
|
void LaunchProfile::applyAgent(AgentPtr agent, const RuntimeContext & runtimeContext)
|
||||||
{
|
{
|
||||||
auto lib = agent->library();
|
auto lib = agent->library();
|
||||||
if(!lib->isActive())
|
if(!lib->isActive(runtimeContext))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -354,7 +354,7 @@ const QList<int> & LaunchProfile::getCompatibleJavaMajors() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
void LaunchProfile::getLibraryFiles(
|
void LaunchProfile::getLibraryFiles(
|
||||||
const QString& architecture,
|
const RuntimeContext & runtimeContext,
|
||||||
QStringList& jars,
|
QStringList& jars,
|
||||||
QStringList& nativeJars,
|
QStringList& nativeJars,
|
||||||
const QString& overridePath,
|
const QString& overridePath,
|
||||||
@ -366,7 +366,7 @@ void LaunchProfile::getLibraryFiles(
|
|||||||
nativeJars.clear();
|
nativeJars.clear();
|
||||||
for (auto lib : getLibraries())
|
for (auto lib : getLibraries())
|
||||||
{
|
{
|
||||||
lib->getApplicableFiles(currentSystem, jars, nativeJars, native32, native64, overridePath);
|
lib->getApplicableFiles(runtimeContext, jars, nativeJars, native32, native64, overridePath);
|
||||||
}
|
}
|
||||||
// NOTE: order is important here, add main jar last to the lists
|
// NOTE: order is important here, add main jar last to the lists
|
||||||
if(m_mainJar)
|
if(m_mainJar)
|
||||||
@ -379,18 +379,18 @@ void LaunchProfile::getLibraryFiles(
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_mainJar->getApplicableFiles(currentSystem, jars, nativeJars, native32, native64, overridePath);
|
m_mainJar->getApplicableFiles(runtimeContext, jars, nativeJars, native32, native64, overridePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (auto lib : getNativeLibraries())
|
for (auto lib : getNativeLibraries())
|
||||||
{
|
{
|
||||||
lib->getApplicableFiles(currentSystem, jars, nativeJars, native32, native64, overridePath);
|
lib->getApplicableFiles(runtimeContext, jars, nativeJars, native32, native64, overridePath);
|
||||||
}
|
}
|
||||||
if(architecture == "32")
|
if(runtimeContext.javaArchitecture == "32")
|
||||||
{
|
{
|
||||||
nativeJars.append(native32);
|
nativeJars.append(native32);
|
||||||
}
|
}
|
||||||
else if(architecture == "64")
|
else if(runtimeContext.javaArchitecture == "64")
|
||||||
{
|
{
|
||||||
nativeJars.append(native64);
|
nativeJars.append(native64);
|
||||||
}
|
}
|
||||||
|
@ -56,9 +56,9 @@ public: /* application of profile variables from patches */
|
|||||||
void applyTweakers(const QStringList &tweakers);
|
void applyTweakers(const QStringList &tweakers);
|
||||||
void applyJarMods(const QList<LibraryPtr> &jarMods);
|
void applyJarMods(const QList<LibraryPtr> &jarMods);
|
||||||
void applyMods(const QList<LibraryPtr> &jarMods);
|
void applyMods(const QList<LibraryPtr> &jarMods);
|
||||||
void applyLibrary(LibraryPtr library);
|
void applyLibrary(LibraryPtr library, const RuntimeContext & runtimeContext);
|
||||||
void applyMavenFile(LibraryPtr library);
|
void applyMavenFile(LibraryPtr library, const RuntimeContext & runtimeContext);
|
||||||
void applyAgent(AgentPtr agent);
|
void applyAgent(AgentPtr agent, const RuntimeContext & runtimeContext);
|
||||||
void applyCompatibleJavaMajors(QList<int>& javaMajor);
|
void applyCompatibleJavaMajors(QList<int>& javaMajor);
|
||||||
void applyMainJar(LibraryPtr jar);
|
void applyMainJar(LibraryPtr jar);
|
||||||
void applyProblemSeverity(ProblemSeverity severity);
|
void applyProblemSeverity(ProblemSeverity severity);
|
||||||
@ -83,7 +83,7 @@ public: /* getters for profile variables */
|
|||||||
const QList<int> & getCompatibleJavaMajors() const;
|
const QList<int> & getCompatibleJavaMajors() const;
|
||||||
const LibraryPtr getMainJar() const;
|
const LibraryPtr getMainJar() const;
|
||||||
void getLibraryFiles(
|
void getLibraryFiles(
|
||||||
const QString & architecture,
|
const RuntimeContext & runtimeContext,
|
||||||
QStringList & jars,
|
QStringList & jars,
|
||||||
QStringList & nativeJars,
|
QStringList & nativeJars,
|
||||||
const QString & overridePath,
|
const QString & overridePath,
|
||||||
|
@ -1,3 +1,38 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* PolyMC - Minecraft Launcher
|
||||||
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This file incorporates work covered by the following copyright and
|
||||||
|
* permission notice:
|
||||||
|
*
|
||||||
|
* Copyright 2013-2021 MultiMC Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "Library.h"
|
#include "Library.h"
|
||||||
#include "MinecraftInstance.h"
|
#include "MinecraftInstance.h"
|
||||||
|
|
||||||
@ -7,7 +42,7 @@
|
|||||||
#include <BuildConfig.h>
|
#include <BuildConfig.h>
|
||||||
|
|
||||||
|
|
||||||
void Library::getApplicableFiles(OpSys system, QStringList& jar, QStringList& native, QStringList& native32,
|
void Library::getApplicableFiles(const RuntimeContext & runtimeContext, QStringList& jar, QStringList& native, QStringList& native32,
|
||||||
QStringList& native64, const QString &overridePath) const
|
QStringList& native64, const QString &overridePath) const
|
||||||
{
|
{
|
||||||
bool local = isLocal();
|
bool local = isLocal();
|
||||||
@ -21,7 +56,7 @@ void Library::getApplicableFiles(OpSys system, QStringList& jar, QStringList& na
|
|||||||
}
|
}
|
||||||
return out.absoluteFilePath();
|
return out.absoluteFilePath();
|
||||||
};
|
};
|
||||||
QString raw_storage = storageSuffix(system);
|
QString raw_storage = storageSuffix(runtimeContext);
|
||||||
if(isNative())
|
if(isNative())
|
||||||
{
|
{
|
||||||
if (raw_storage.contains("${arch}"))
|
if (raw_storage.contains("${arch}"))
|
||||||
@ -45,7 +80,7 @@ void Library::getApplicableFiles(OpSys system, QStringList& jar, QStringList& na
|
|||||||
}
|
}
|
||||||
|
|
||||||
QList<NetAction::Ptr> Library::getDownloads(
|
QList<NetAction::Ptr> Library::getDownloads(
|
||||||
OpSys system,
|
const RuntimeContext & runtimeContext,
|
||||||
class HttpMetaCache* cache,
|
class HttpMetaCache* cache,
|
||||||
QStringList& failedLocalFiles,
|
QStringList& failedLocalFiles,
|
||||||
const QString & overridePath
|
const QString & overridePath
|
||||||
@ -107,14 +142,14 @@ QList<NetAction::Ptr> Library::getDownloads(
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
QString raw_storage = storageSuffix(system);
|
QString raw_storage = storageSuffix(runtimeContext);
|
||||||
if(m_mojangDownloads)
|
if(m_mojangDownloads)
|
||||||
{
|
{
|
||||||
if(isNative())
|
if(isNative())
|
||||||
{
|
{
|
||||||
if(m_nativeClassifiers.contains(system))
|
auto nativeClassifier = getCompatibleNative(runtimeContext);
|
||||||
|
if(!nativeClassifier.isNull())
|
||||||
{
|
{
|
||||||
auto nativeClassifier = m_nativeClassifiers[system];
|
|
||||||
if(nativeClassifier.contains("${arch}"))
|
if(nativeClassifier.contains("${arch}"))
|
||||||
{
|
{
|
||||||
auto nat32Classifier = nativeClassifier;
|
auto nat32Classifier = nativeClassifier;
|
||||||
@ -203,7 +238,7 @@ QList<NetAction::Ptr> Library::getDownloads(
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Library::isActive() const
|
bool Library::isActive(const RuntimeContext & runtimeContext) const
|
||||||
{
|
{
|
||||||
bool result = true;
|
bool result = true;
|
||||||
if (m_rules.empty())
|
if (m_rules.empty())
|
||||||
@ -215,7 +250,7 @@ bool Library::isActive() const
|
|||||||
RuleAction ruleResult = Disallow;
|
RuleAction ruleResult = Disallow;
|
||||||
for (auto rule : m_rules)
|
for (auto rule : m_rules)
|
||||||
{
|
{
|
||||||
RuleAction temp = rule->apply(this);
|
RuleAction temp = rule->apply(this, runtimeContext);
|
||||||
if (temp != Defer)
|
if (temp != Defer)
|
||||||
ruleResult = temp;
|
ruleResult = temp;
|
||||||
}
|
}
|
||||||
@ -223,7 +258,7 @@ bool Library::isActive() const
|
|||||||
}
|
}
|
||||||
if (isNative())
|
if (isNative())
|
||||||
{
|
{
|
||||||
result = result && m_nativeClassifiers.contains(currentSystem);
|
result = result && !getCompatibleNative(runtimeContext).isNull();
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -238,6 +273,19 @@ bool Library::isAlwaysStale() const
|
|||||||
return m_hint == "always-stale";
|
return m_hint == "always-stale";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString Library::getCompatibleNative(const RuntimeContext & runtimeContext) const {
|
||||||
|
// try to match precise classifier "[os]-[arch]"
|
||||||
|
auto entry = m_nativeClassifiers.constFind(runtimeContext.getClassifier());
|
||||||
|
// try to match imprecise classifier on legacy architectures "[os]"
|
||||||
|
if (entry == m_nativeClassifiers.constEnd() && runtimeContext.isLegacyArch())
|
||||||
|
entry = m_nativeClassifiers.constFind(runtimeContext.system);
|
||||||
|
|
||||||
|
if (entry == m_nativeClassifiers.constEnd())
|
||||||
|
return QString();
|
||||||
|
|
||||||
|
return entry.value();
|
||||||
|
}
|
||||||
|
|
||||||
void Library::setStoragePrefix(QString prefix)
|
void Library::setStoragePrefix(QString prefix)
|
||||||
{
|
{
|
||||||
m_storagePrefix = prefix;
|
m_storagePrefix = prefix;
|
||||||
@ -257,7 +305,7 @@ QString Library::storagePrefix() const
|
|||||||
return m_storagePrefix;
|
return m_storagePrefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Library::filename(OpSys system) const
|
QString Library::filename(const RuntimeContext & runtimeContext) const
|
||||||
{
|
{
|
||||||
if(!m_filename.isEmpty())
|
if(!m_filename.isEmpty())
|
||||||
{
|
{
|
||||||
@ -271,9 +319,10 @@ QString Library::filename(OpSys system) const
|
|||||||
|
|
||||||
// otherwise native, override classifiers. Mojang HACK!
|
// otherwise native, override classifiers. Mojang HACK!
|
||||||
GradleSpecifier nativeSpec = m_name;
|
GradleSpecifier nativeSpec = m_name;
|
||||||
if (m_nativeClassifiers.contains(system))
|
QString nativeClassifier = getCompatibleNative(runtimeContext);
|
||||||
|
if (!nativeClassifier.isNull())
|
||||||
{
|
{
|
||||||
nativeSpec.setClassifier(m_nativeClassifiers[system]);
|
nativeSpec.setClassifier(nativeClassifier);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -282,14 +331,14 @@ QString Library::filename(OpSys system) const
|
|||||||
return nativeSpec.getFileName();
|
return nativeSpec.getFileName();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Library::displayName(OpSys system) const
|
QString Library::displayName(const RuntimeContext & runtimeContext) const
|
||||||
{
|
{
|
||||||
if(!m_displayname.isEmpty())
|
if(!m_displayname.isEmpty())
|
||||||
return m_displayname;
|
return m_displayname;
|
||||||
return filename(system);
|
return filename(runtimeContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Library::storageSuffix(OpSys system) const
|
QString Library::storageSuffix(const RuntimeContext & runtimeContext) const
|
||||||
{
|
{
|
||||||
// non-native? use only the gradle specifier
|
// non-native? use only the gradle specifier
|
||||||
if (!isNative())
|
if (!isNative())
|
||||||
@ -299,9 +348,10 @@ QString Library::storageSuffix(OpSys system) const
|
|||||||
|
|
||||||
// otherwise native, override classifiers. Mojang HACK!
|
// otherwise native, override classifiers. Mojang HACK!
|
||||||
GradleSpecifier nativeSpec = m_name;
|
GradleSpecifier nativeSpec = m_name;
|
||||||
if (m_nativeClassifiers.contains(system))
|
QString nativeClassifier = getCompatibleNative(runtimeContext);
|
||||||
|
if (!nativeClassifier.isNull())
|
||||||
{
|
{
|
||||||
nativeSpec.setClassifier(m_nativeClassifiers[system]);
|
nativeSpec.setClassifier(nativeClassifier);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1,8 +1,44 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* PolyMC - Minecraft Launcher
|
||||||
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This file incorporates work covered by the following copyright and
|
||||||
|
* permission notice:
|
||||||
|
*
|
||||||
|
* Copyright 2013-2021 MultiMC Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <net/NetAction.h>
|
#include <net/NetAction.h>
|
||||||
#include <QPair>
|
#include <QPair>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
@ -10,9 +46,9 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "Rule.h"
|
#include "Rule.h"
|
||||||
#include "minecraft/OpSys.h"
|
|
||||||
#include "GradleSpecifier.h"
|
#include "GradleSpecifier.h"
|
||||||
#include "MojangDownloadInfo.h"
|
#include "MojangDownloadInfo.h"
|
||||||
|
#include "RuntimeContext.h"
|
||||||
|
|
||||||
class Library;
|
class Library;
|
||||||
class MinecraftInstance;
|
class MinecraftInstance;
|
||||||
@ -98,7 +134,7 @@ public: /* methods */
|
|||||||
m_repositoryURL = base_url;
|
m_repositoryURL = base_url;
|
||||||
}
|
}
|
||||||
|
|
||||||
void getApplicableFiles(OpSys system, QStringList & jar, QStringList & native,
|
void getApplicableFiles(const RuntimeContext & runtimeContext, QStringList & jar, QStringList & native,
|
||||||
QStringList & native32, QStringList & native64, const QString & overridePath) const;
|
QStringList & native32, QStringList & native64, const QString & overridePath) const;
|
||||||
|
|
||||||
void setAbsoluteUrl(const QString &absolute_url)
|
void setAbsoluteUrl(const QString &absolute_url)
|
||||||
@ -112,7 +148,7 @@ public: /* methods */
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the file name of the library
|
/// Get the file name of the library
|
||||||
QString filename(OpSys system) const;
|
QString filename(const RuntimeContext & runtimeContext) const;
|
||||||
|
|
||||||
// DEPRECATED: set a display name, used by jar mods only
|
// DEPRECATED: set a display name, used by jar mods only
|
||||||
void setDisplayName(const QString & displayName)
|
void setDisplayName(const QString & displayName)
|
||||||
@ -121,7 +157,7 @@ public: /* methods */
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the file name of the library
|
/// Get the file name of the library
|
||||||
QString displayName(OpSys system) const;
|
QString displayName(const RuntimeContext & runtimeContext) const;
|
||||||
|
|
||||||
void setMojangDownloadInfo(MojangLibraryDownloadInfo::Ptr info)
|
void setMojangDownloadInfo(MojangLibraryDownloadInfo::Ptr info)
|
||||||
{
|
{
|
||||||
@ -140,7 +176,7 @@ public: /* methods */
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the library should be loaded (or extracted, in case of natives)
|
/// Returns true if the library should be loaded (or extracted, in case of natives)
|
||||||
bool isActive() const;
|
bool isActive(const RuntimeContext & runtimeContext) const;
|
||||||
|
|
||||||
/// Returns true if the library is contained in an instance and false if it is shared
|
/// Returns true if the library is contained in an instance and false if it is shared
|
||||||
bool isLocal() const;
|
bool isLocal() const;
|
||||||
@ -152,18 +188,20 @@ public: /* methods */
|
|||||||
bool isForge() const;
|
bool isForge() const;
|
||||||
|
|
||||||
// Get a list of downloads for this library
|
// Get a list of downloads for this library
|
||||||
QList<NetAction::Ptr> getDownloads(OpSys system, class HttpMetaCache * cache,
|
QList<NetAction::Ptr> getDownloads(const RuntimeContext & runtimeContext, class HttpMetaCache * cache,
|
||||||
QStringList & failedLocalFiles, const QString & overridePath) const;
|
QStringList & failedLocalFiles, const QString & overridePath) const;
|
||||||
|
|
||||||
|
QString getCompatibleNative(const RuntimeContext & runtimeContext) const;
|
||||||
|
|
||||||
private: /* methods */
|
private: /* methods */
|
||||||
/// the default storage prefix used by PolyMC
|
/// the default storage prefix used by Prism Launcher
|
||||||
static QString defaultStoragePrefix();
|
static QString defaultStoragePrefix();
|
||||||
|
|
||||||
/// Get the prefix - root of the storage to be used
|
/// Get the prefix - root of the storage to be used
|
||||||
QString storagePrefix() const;
|
QString storagePrefix() const;
|
||||||
|
|
||||||
/// Get the relative file path where the library should be saved
|
/// Get the relative file path where the library should be saved
|
||||||
QString storageSuffix(OpSys system) const;
|
QString storageSuffix(const RuntimeContext & runtimeContext) const;
|
||||||
|
|
||||||
QString hint() const
|
QString hint() const
|
||||||
{
|
{
|
||||||
@ -177,23 +215,23 @@ protected: /* data */
|
|||||||
/// DEPRECATED URL prefix of the maven repo where the file can be downloaded
|
/// DEPRECATED URL prefix of the maven repo where the file can be downloaded
|
||||||
QString m_repositoryURL;
|
QString m_repositoryURL;
|
||||||
|
|
||||||
/// DEPRECATED: PolyMC-specific absolute URL. takes precedence over the implicit maven repo URL, if defined
|
/// DEPRECATED: Prism Launcher-specific absolute URL. takes precedence over the implicit maven repo URL, if defined
|
||||||
QString m_absoluteURL;
|
QString m_absoluteURL;
|
||||||
|
|
||||||
/// PolyMC extension - filename override
|
/// Prism Launcher extension - filename override
|
||||||
QString m_filename;
|
QString m_filename;
|
||||||
|
|
||||||
/// DEPRECATED PolyMC extension - display name
|
/// DEPRECATED Prism Launcher extension - display name
|
||||||
QString m_displayname;
|
QString m_displayname;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PolyMC-specific type hint - modifies how the library is treated
|
* Prism Launcher-specific type hint - modifies how the library is treated
|
||||||
*/
|
*/
|
||||||
QString m_hint;
|
QString m_hint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* storage - by default the local libraries folder in polymc, but could be elsewhere
|
* storage - by default the local libraries folder in Prism Launcher, but could be elsewhere
|
||||||
* PolyMC specific, because of FTB.
|
* Prism Launcher specific, because of FTB.
|
||||||
*/
|
*/
|
||||||
QString m_storagePrefix;
|
QString m_storagePrefix;
|
||||||
|
|
||||||
@ -204,7 +242,7 @@ protected: /* data */
|
|||||||
QStringList m_extractExcludes;
|
QStringList m_extractExcludes;
|
||||||
|
|
||||||
/// native suffixes per OS
|
/// native suffixes per OS
|
||||||
QMap<OpSys, QString> m_nativeClassifiers;
|
QMap<QString, QString> m_nativeClassifiers;
|
||||||
|
|
||||||
/// true if the library had a rules section (even empty)
|
/// true if the library had a rules section (even empty)
|
||||||
bool applyRules = false;
|
bool applyRules = false;
|
||||||
|
@ -147,6 +147,7 @@ void MinecraftInstance::loadSpecificSettings()
|
|||||||
m_settings->registerPassthrough(global_settings->getSetting("JavaTimestamp"), javaOrLocation);
|
m_settings->registerPassthrough(global_settings->getSetting("JavaTimestamp"), javaOrLocation);
|
||||||
m_settings->registerPassthrough(global_settings->getSetting("JavaVersion"), javaOrLocation);
|
m_settings->registerPassthrough(global_settings->getSetting("JavaVersion"), javaOrLocation);
|
||||||
m_settings->registerPassthrough(global_settings->getSetting("JavaArchitecture"), javaOrLocation);
|
m_settings->registerPassthrough(global_settings->getSetting("JavaArchitecture"), javaOrLocation);
|
||||||
|
m_settings->registerPassthrough(global_settings->getSetting("JavaRealArchitecture"), javaOrLocation);
|
||||||
|
|
||||||
// Window Size
|
// Window Size
|
||||||
auto windowSetting = m_settings->registerSetting("OverrideWindow", false);
|
auto windowSetting = m_settings->registerSetting("OverrideWindow", false);
|
||||||
@ -190,6 +191,13 @@ void MinecraftInstance::loadSpecificSettings()
|
|||||||
qDebug() << "Instance-type specific settings were loaded!";
|
qDebug() << "Instance-type specific settings were loaded!";
|
||||||
|
|
||||||
setSpecificSettingsLoaded(true);
|
setSpecificSettingsLoaded(true);
|
||||||
|
|
||||||
|
updateRuntimeContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MinecraftInstance::updateRuntimeContext()
|
||||||
|
{
|
||||||
|
m_runtimeContext.updateFromInstanceSettings(m_settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MinecraftInstance::typeName() const
|
QString MinecraftInstance::typeName() const
|
||||||
@ -327,9 +335,8 @@ QDir MinecraftInstance::versionsPath() const
|
|||||||
QStringList MinecraftInstance::getClassPath()
|
QStringList MinecraftInstance::getClassPath()
|
||||||
{
|
{
|
||||||
QStringList jars, nativeJars;
|
QStringList jars, nativeJars;
|
||||||
auto javaArchitecture = settings()->get("JavaArchitecture").toString();
|
|
||||||
auto profile = m_components->getProfile();
|
auto profile = m_components->getProfile();
|
||||||
profile->getLibraryFiles(javaArchitecture, jars, nativeJars, getLocalLibraryPath(), binRoot());
|
profile->getLibraryFiles(runtimeContext(), jars, nativeJars, getLocalLibraryPath(), binRoot());
|
||||||
return jars;
|
return jars;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,9 +349,8 @@ QString MinecraftInstance::getMainClass() const
|
|||||||
QStringList MinecraftInstance::getNativeJars()
|
QStringList MinecraftInstance::getNativeJars()
|
||||||
{
|
{
|
||||||
QStringList jars, nativeJars;
|
QStringList jars, nativeJars;
|
||||||
auto javaArchitecture = settings()->get("JavaArchitecture").toString();
|
|
||||||
auto profile = m_components->getProfile();
|
auto profile = m_components->getProfile();
|
||||||
profile->getLibraryFiles(javaArchitecture, jars, nativeJars, getLocalLibraryPath(), binRoot());
|
profile->getLibraryFiles(runtimeContext(), jars, nativeJars, getLocalLibraryPath(), binRoot());
|
||||||
return nativeJars;
|
return nativeJars;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,7 +375,7 @@ QStringList MinecraftInstance::extraArguments()
|
|||||||
for (auto agent : agents)
|
for (auto agent : agents)
|
||||||
{
|
{
|
||||||
QStringList jar, temp1, temp2, temp3;
|
QStringList jar, temp1, temp2, temp3;
|
||||||
agent->library()->getApplicableFiles(currentSystem, jar, temp1, temp2, temp3, getLocalLibraryPath());
|
agent->library()->getApplicableFiles(runtimeContext(), jar, temp1, temp2, temp3, getLocalLibraryPath());
|
||||||
list.append("-javaagent:"+jar[0]+(agent->argument().isEmpty() ? "" : "="+agent->argument()));
|
list.append("-javaagent:"+jar[0]+(agent->argument().isEmpty() ? "" : "="+agent->argument()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -633,8 +639,7 @@ QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftS
|
|||||||
// libraries and class path.
|
// libraries and class path.
|
||||||
{
|
{
|
||||||
QStringList jars, nativeJars;
|
QStringList jars, nativeJars;
|
||||||
auto javaArchitecture = settings()->get("JavaArchitecture").toString();
|
profile->getLibraryFiles(runtimeContext(), jars, nativeJars, getLocalLibraryPath(), binRoot());
|
||||||
profile->getLibraryFiles(javaArchitecture, jars, nativeJars, getLocalLibraryPath(), binRoot());
|
|
||||||
for(auto file: jars)
|
for(auto file: jars)
|
||||||
{
|
{
|
||||||
launchScript += "cp " + file + "\n";
|
launchScript += "cp " + file + "\n";
|
||||||
@ -690,8 +695,7 @@ QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, Minecr
|
|||||||
{
|
{
|
||||||
out << "Libraries:";
|
out << "Libraries:";
|
||||||
QStringList jars, nativeJars;
|
QStringList jars, nativeJars;
|
||||||
auto javaArchitecture = settings->get("JavaArchitecture").toString();
|
profile->getLibraryFiles(runtimeContext(), jars, nativeJars, getLocalLibraryPath(), binRoot());
|
||||||
profile->getLibraryFiles(javaArchitecture, jars, nativeJars, getLocalLibraryPath(), binRoot());
|
|
||||||
auto printLibFile = [&](const QString & path)
|
auto printLibFile = [&](const QString & path)
|
||||||
{
|
{
|
||||||
QFileInfo info(path);
|
QFileInfo info(path);
|
||||||
@ -756,8 +760,8 @@ QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, Minecr
|
|||||||
out << "Jar Mods:";
|
out << "Jar Mods:";
|
||||||
for(auto & jarmod: jarMods)
|
for(auto & jarmod: jarMods)
|
||||||
{
|
{
|
||||||
auto displayname = jarmod->displayName(currentSystem);
|
auto displayname = jarmod->displayName(runtimeContext());
|
||||||
auto realname = jarmod->filename(currentSystem);
|
auto realname = jarmod->filename(runtimeContext());
|
||||||
if(displayname != realname)
|
if(displayname != realname)
|
||||||
{
|
{
|
||||||
out << " " + displayname + " (" + realname + ")";
|
out << " " + displayname + " (" + realname + ")";
|
||||||
@ -919,6 +923,7 @@ QString MinecraftInstance::getStatusbarDescription()
|
|||||||
|
|
||||||
Task::Ptr MinecraftInstance::createUpdateTask(Net::Mode mode)
|
Task::Ptr MinecraftInstance::createUpdateTask(Net::Mode mode)
|
||||||
{
|
{
|
||||||
|
updateRuntimeContext();
|
||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
case Net::Mode::Offline:
|
case Net::Mode::Offline:
|
||||||
@ -935,6 +940,7 @@ Task::Ptr MinecraftInstance::createUpdateTask(Net::Mode mode)
|
|||||||
|
|
||||||
shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin)
|
shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin)
|
||||||
{
|
{
|
||||||
|
updateRuntimeContext();
|
||||||
// FIXME: get rid of shared_from_this ...
|
// FIXME: get rid of shared_from_this ...
|
||||||
auto process = LaunchTask::create(std::dynamic_pointer_cast<MinecraftInstance>(shared_from_this()));
|
auto process = LaunchTask::create(std::dynamic_pointer_cast<MinecraftInstance>(shared_from_this()));
|
||||||
auto pptr = process.get();
|
auto pptr = process.get();
|
||||||
@ -1172,7 +1178,7 @@ QList<Mod*> MinecraftInstance::getJarMods() const
|
|||||||
for (auto jarmod : profile->getJarMods())
|
for (auto jarmod : profile->getJarMods())
|
||||||
{
|
{
|
||||||
QStringList jar, temp1, temp2, temp3;
|
QStringList jar, temp1, temp2, temp3;
|
||||||
jarmod->getApplicableFiles(currentSystem, jar, temp1, temp2, temp3, jarmodsPath().absolutePath());
|
jarmod->getApplicableFiles(runtimeContext(), jar, temp1, temp2, temp3, jarmodsPath().absolutePath());
|
||||||
// QString filePath = jarmodsPath().absoluteFilePath(jarmod->filename(currentSystem));
|
// QString filePath = jarmodsPath().absoluteFilePath(jarmod->filename(currentSystem));
|
||||||
mods.push_back(new Mod(QFileInfo(jar[0])));
|
mods.push_back(new Mod(QFileInfo(jar[0])));
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,38 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* PolyMC - Minecraft Launcher
|
||||||
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This file incorporates work covered by the following copyright and
|
||||||
|
* permission notice:
|
||||||
|
*
|
||||||
|
* Copyright 2013-2021 MultiMC Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "BaseInstance.h"
|
#include "BaseInstance.h"
|
||||||
#include <java/JavaVersion.h>
|
#include <java/JavaVersion.h>
|
||||||
@ -73,6 +108,8 @@ public:
|
|||||||
/** Returns whether the instance, with its version, has support for demo mode. */
|
/** Returns whether the instance, with its version, has support for demo mode. */
|
||||||
[[nodiscard]] bool supportsDemo() const;
|
[[nodiscard]] bool supportsDemo() const;
|
||||||
|
|
||||||
|
void updateRuntimeContext();
|
||||||
|
|
||||||
////// Profile management //////
|
////// Profile management //////
|
||||||
std::shared_ptr<PackProfile> getPackProfile() const;
|
std::shared_ptr<PackProfile> getPackProfile() const;
|
||||||
|
|
||||||
|
@ -214,7 +214,7 @@ void MojangVersionFormat::readVersionProperties(const QJsonObject &in, VersionFi
|
|||||||
QObject::tr("The 'minimumLauncherVersion' value of this version (%1) is higher than supported by %3 (%2). It might not work properly!")
|
QObject::tr("The 'minimumLauncherVersion' value of this version (%1) is higher than supported by %3 (%2). It might not work properly!")
|
||||||
.arg(out->minimumLauncherVersion)
|
.arg(out->minimumLauncherVersion)
|
||||||
.arg(CURRENT_MINIMUM_LAUNCHER_VERSION)
|
.arg(CURRENT_MINIMUM_LAUNCHER_VERSION)
|
||||||
.arg(BuildConfig.LAUNCHER_NAME)
|
.arg(BuildConfig.LAUNCHER_DISPLAYNAME)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -362,11 +362,8 @@ LibraryPtr MojangVersionFormat::libraryFromJson(ProblemContainer & problems, con
|
|||||||
{
|
{
|
||||||
qWarning() << filename << "contains an invalid native (skipping)";
|
qWarning() << filename << "contains an invalid native (skipping)";
|
||||||
}
|
}
|
||||||
OpSys opSys = OpSys_fromString(it.key());
|
// FIXME: Skip unknown platforms
|
||||||
if (opSys != Os_Other)
|
out->m_nativeClassifiers[it.key()] = it.value().toString();
|
||||||
{
|
|
||||||
out->m_nativeClassifiers[opSys] = it.value().toString();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (libObj.contains("rules"))
|
if (libObj.contains("rules"))
|
||||||
@ -395,7 +392,7 @@ QJsonObject MojangVersionFormat::libraryToJson(Library *library)
|
|||||||
auto iter = library->m_nativeClassifiers.begin();
|
auto iter = library->m_nativeClassifiers.begin();
|
||||||
while (iter != library->m_nativeClassifiers.end())
|
while (iter != library->m_nativeClassifiers.end())
|
||||||
{
|
{
|
||||||
nativeList.insert(OpSys_toString(iter.key()), iter.value());
|
nativeList.insert(iter.key(), iter.value());
|
||||||
iter++;
|
iter++;
|
||||||
}
|
}
|
||||||
libRoot.insert("natives", nativeList);
|
libRoot.insert("natives", nativeList);
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
/* Copyright 2013-2021 MultiMC Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "OpSys.h"
|
|
||||||
|
|
||||||
OpSys OpSys_fromString(QString name)
|
|
||||||
{
|
|
||||||
if (name == "freebsd")
|
|
||||||
return Os_FreeBSD;
|
|
||||||
if (name == "linux")
|
|
||||||
return Os_Linux;
|
|
||||||
if (name == "windows")
|
|
||||||
return Os_Windows;
|
|
||||||
if (name == "osx")
|
|
||||||
return Os_OSX;
|
|
||||||
return Os_Other;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString OpSys_toString(OpSys name)
|
|
||||||
{
|
|
||||||
switch (name)
|
|
||||||
{
|
|
||||||
case Os_FreeBSD:
|
|
||||||
return "freebsd";
|
|
||||||
case Os_Linux:
|
|
||||||
return "linux";
|
|
||||||
case Os_OSX:
|
|
||||||
return "osx";
|
|
||||||
case Os_Windows:
|
|
||||||
return "windows";
|
|
||||||
default:
|
|
||||||
return "other";
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
/* Copyright 2013-2021 MultiMC Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include <QString>
|
|
||||||
enum OpSys
|
|
||||||
{
|
|
||||||
Os_Windows,
|
|
||||||
Os_FreeBSD,
|
|
||||||
Os_Linux,
|
|
||||||
Os_OSX,
|
|
||||||
Os_Other
|
|
||||||
};
|
|
||||||
|
|
||||||
OpSys OpSys_fromString(QString);
|
|
||||||
QString OpSys_toString(OpSys);
|
|
||||||
|
|
||||||
#ifdef Q_OS_WIN32
|
|
||||||
#define currentSystem Os_Windows
|
|
||||||
#elif defined Q_OS_MAC
|
|
||||||
#define currentSystem Os_OSX
|
|
||||||
#elif defined Q_OS_FREEBSD
|
|
||||||
#define currentSystem Os_FreeBSD
|
|
||||||
#else
|
|
||||||
#define currentSystem Os_Linux
|
|
||||||
#endif
|
|
@ -273,6 +273,11 @@ void PackProfile::scheduleSave()
|
|||||||
d->m_saveTimer.start();
|
d->m_saveTimer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RuntimeContext PackProfile::runtimeContext()
|
||||||
|
{
|
||||||
|
return d->m_instance->runtimeContext();
|
||||||
|
}
|
||||||
|
|
||||||
QString PackProfile::componentsFilePath() const
|
QString PackProfile::componentsFilePath() const
|
||||||
{
|
{
|
||||||
return FS::PathCombine(d->m_instance->instanceRoot(), "mmc-pack.json");
|
return FS::PathCombine(d->m_instance->instanceRoot(), "mmc-pack.json");
|
||||||
@ -784,7 +789,7 @@ bool PackProfile::removeComponent_internal(ComponentPtr patch)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
QStringList jar, temp1, temp2, temp3;
|
QStringList jar, temp1, temp2, temp3;
|
||||||
jarMod->getApplicableFiles(currentSystem, jar, temp1, temp2, temp3, d->m_instance->jarmodsPath().absolutePath());
|
jarMod->getApplicableFiles(d->m_instance->runtimeContext(), jar, temp1, temp2, temp3, d->m_instance->jarmodsPath().absolutePath());
|
||||||
QFileInfo finfo (jar[0]);
|
QFileInfo finfo (jar[0]);
|
||||||
if(finfo.exists())
|
if(finfo.exists())
|
||||||
{
|
{
|
||||||
|
@ -1,16 +1,36 @@
|
|||||||
/* Copyright 2013-2021 MultiMC Contributors
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* PolyMC - Minecraft Launcher
|
||||||
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* you may not use this file except in compliance with the License.
|
* it under the terms of the GNU General Public License as published by
|
||||||
* You may obtain a copy of the License at
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* You should have received a copy of the GNU General Public License
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
*
|
||||||
* See the License for the specific language governing permissions and
|
* This file incorporates work covered by the following copyright and
|
||||||
* limitations under the License.
|
* permission notice:
|
||||||
|
*
|
||||||
|
* Copyright 2013-2021 MultiMC Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@ -104,6 +124,9 @@ public:
|
|||||||
/// if there is a save scheduled, do it now.
|
/// if there is a save scheduled, do it now.
|
||||||
void saveNow();
|
void saveNow();
|
||||||
|
|
||||||
|
/// helper method, returns RuntimeContext of instance
|
||||||
|
RuntimeContext runtimeContext();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void minecraftChanged();
|
void minecraftChanged();
|
||||||
|
|
||||||
|
@ -1,16 +1,36 @@
|
|||||||
/* Copyright 2013-2021 MultiMC Contributors
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* PolyMC - Minecraft Launcher
|
||||||
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* you may not use this file except in compliance with the License.
|
* it under the terms of the GNU General Public License as published by
|
||||||
* You may obtain a copy of the License at
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* You should have received a copy of the GNU General Public License
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
*
|
||||||
* See the License for the specific language governing permissions and
|
* This file incorporates work covered by the following copyright and
|
||||||
* limitations under the License.
|
* permission notice:
|
||||||
|
*
|
||||||
|
* Copyright 2013-2021 MultiMC Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
@ -60,10 +80,10 @@ QList<std::shared_ptr<Rule>> rulesFromJsonV4(const QJsonObject &objectWithRules)
|
|||||||
auto osNameVal = osObj.value("name");
|
auto osNameVal = osObj.value("name");
|
||||||
if (!osNameVal.isString())
|
if (!osNameVal.isString())
|
||||||
continue;
|
continue;
|
||||||
OpSys requiredOs = OpSys_fromString(osNameVal.toString());
|
QString osName = osNameVal.toString();
|
||||||
QString versionRegex = osObj.value("version").toString();
|
QString versionRegex = osObj.value("version").toString();
|
||||||
// add a new OS rule
|
// add a new OS rule
|
||||||
rules.append(OsRule::create(action, requiredOs, versionRegex));
|
rules.append(OsRule::create(action, osName, versionRegex));
|
||||||
}
|
}
|
||||||
return rules;
|
return rules;
|
||||||
}
|
}
|
||||||
@ -81,7 +101,7 @@ QJsonObject OsRule::toJson()
|
|||||||
ruleObj.insert("action", m_result == Allow ? QString("allow") : QString("disallow"));
|
ruleObj.insert("action", m_result == Allow ? QString("allow") : QString("disallow"));
|
||||||
QJsonObject osObj;
|
QJsonObject osObj;
|
||||||
{
|
{
|
||||||
osObj.insert("name", OpSys_toString(m_system));
|
osObj.insert("name", m_system);
|
||||||
if(!m_version_regexp.isEmpty())
|
if(!m_version_regexp.isEmpty())
|
||||||
{
|
{
|
||||||
osObj.insert("version", m_version_regexp);
|
osObj.insert("version", m_version_regexp);
|
||||||
|
@ -1,16 +1,36 @@
|
|||||||
/* Copyright 2013-2021 MultiMC Contributors
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* PolyMC - Minecraft Launcher
|
||||||
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* you may not use this file except in compliance with the License.
|
* it under the terms of the GNU General Public License as published by
|
||||||
* You may obtain a copy of the License at
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* You should have received a copy of the GNU General Public License
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
*
|
||||||
* See the License for the specific language governing permissions and
|
* This file incorporates work covered by the following copyright and
|
||||||
* limitations under the License.
|
* permission notice:
|
||||||
|
*
|
||||||
|
* Copyright 2013-2021 MultiMC Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@ -19,7 +39,7 @@
|
|||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "OpSys.h"
|
#include "RuntimeContext.h"
|
||||||
|
|
||||||
class Library;
|
class Library;
|
||||||
class Rule;
|
class Rule;
|
||||||
@ -37,7 +57,7 @@ class Rule
|
|||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
RuleAction m_result;
|
RuleAction m_result;
|
||||||
virtual bool applies(const Library *parent) = 0;
|
virtual bool applies(const Library *parent, const RuntimeContext & runtimeContext) = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Rule(RuleAction result) : m_result(result)
|
Rule(RuleAction result) : m_result(result)
|
||||||
@ -45,9 +65,9 @@ public:
|
|||||||
}
|
}
|
||||||
virtual ~Rule() {};
|
virtual ~Rule() {};
|
||||||
virtual QJsonObject toJson() = 0;
|
virtual QJsonObject toJson() = 0;
|
||||||
RuleAction apply(const Library *parent)
|
RuleAction apply(const Library *parent, const RuntimeContext & runtimeContext)
|
||||||
{
|
{
|
||||||
if (applies(parent))
|
if (applies(parent, runtimeContext))
|
||||||
return m_result;
|
return m_result;
|
||||||
else
|
else
|
||||||
return Defer;
|
return Defer;
|
||||||
@ -58,23 +78,23 @@ class OsRule : public Rule
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
// the OS
|
// the OS
|
||||||
OpSys m_system;
|
QString m_system;
|
||||||
// the OS version regexp
|
// the OS version regexp
|
||||||
QString m_version_regexp;
|
QString m_version_regexp;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool applies(const Library *)
|
virtual bool applies(const Library *, const RuntimeContext & runtimeContext)
|
||||||
{
|
{
|
||||||
return (m_system == currentSystem);
|
return runtimeContext.classifierMatches(m_system);
|
||||||
}
|
}
|
||||||
OsRule(RuleAction result, OpSys system, QString version_regexp)
|
OsRule(RuleAction result, QString system, QString version_regexp)
|
||||||
: Rule(result), m_system(system), m_version_regexp(version_regexp)
|
: Rule(result), m_system(system), m_version_regexp(version_regexp)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual QJsonObject toJson();
|
virtual QJsonObject toJson();
|
||||||
static std::shared_ptr<OsRule> create(RuleAction result, OpSys system,
|
static std::shared_ptr<OsRule> create(RuleAction result, QString system,
|
||||||
QString version_regexp)
|
QString version_regexp)
|
||||||
{
|
{
|
||||||
return std::shared_ptr<OsRule>(new OsRule(result, system, version_regexp));
|
return std::shared_ptr<OsRule>(new OsRule(result, system, version_regexp));
|
||||||
@ -84,7 +104,7 @@ public:
|
|||||||
class ImplicitRule : public Rule
|
class ImplicitRule : public Rule
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
virtual bool applies(const Library *)
|
virtual bool applies(const Library *, const RuntimeContext & runtimeContext)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ static bool isMinecraftVersion(const QString &uid)
|
|||||||
return uid == "net.minecraft";
|
return uid == "net.minecraft";
|
||||||
}
|
}
|
||||||
|
|
||||||
void VersionFile::applyTo(LaunchProfile *profile)
|
void VersionFile::applyTo(LaunchProfile *profile, const RuntimeContext & runtimeContext)
|
||||||
{
|
{
|
||||||
// Only real Minecraft can set those. Don't let anything override them.
|
// Only real Minecraft can set those. Don't let anything override them.
|
||||||
if (isMinecraftVersion(uid))
|
if (isMinecraftVersion(uid))
|
||||||
@ -77,15 +77,15 @@ void VersionFile::applyTo(LaunchProfile *profile)
|
|||||||
|
|
||||||
for (auto library : libraries)
|
for (auto library : libraries)
|
||||||
{
|
{
|
||||||
profile->applyLibrary(library);
|
profile->applyLibrary(library, runtimeContext);
|
||||||
}
|
}
|
||||||
for (auto mavenFile : mavenFiles)
|
for (auto mavenFile : mavenFiles)
|
||||||
{
|
{
|
||||||
profile->applyMavenFile(mavenFile);
|
profile->applyMavenFile(mavenFile, runtimeContext);
|
||||||
}
|
}
|
||||||
for (auto agent : agents)
|
for (auto agent : agents)
|
||||||
{
|
{
|
||||||
profile->applyAgent(agent);
|
profile->applyAgent(agent, runtimeContext);
|
||||||
}
|
}
|
||||||
profile->applyProblemSeverity(getProblemSeverity());
|
profile->applyProblemSeverity(getProblemSeverity());
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,6 @@
|
|||||||
#include <QSet>
|
#include <QSet>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "minecraft/OpSys.h"
|
|
||||||
#include "minecraft/Rule.h"
|
#include "minecraft/Rule.h"
|
||||||
#include "ProblemProvider.h"
|
#include "ProblemProvider.h"
|
||||||
#include "Library.h"
|
#include "Library.h"
|
||||||
@ -60,22 +59,22 @@ class VersionFile : public ProblemContainer
|
|||||||
friend class MojangVersionFormat;
|
friend class MojangVersionFormat;
|
||||||
friend class OneSixVersionFormat;
|
friend class OneSixVersionFormat;
|
||||||
public: /* methods */
|
public: /* methods */
|
||||||
void applyTo(LaunchProfile* profile);
|
void applyTo(LaunchProfile* profile, const RuntimeContext & runtimeContext);
|
||||||
|
|
||||||
public: /* data */
|
public: /* data */
|
||||||
/// PolyMC: order hint for this version file if no explicit order is set
|
/// Prism Launcher: order hint for this version file if no explicit order is set
|
||||||
int order = 0;
|
int order = 0;
|
||||||
|
|
||||||
/// PolyMC: human readable name of this package
|
/// Prism Launcher: human readable name of this package
|
||||||
QString name;
|
QString name;
|
||||||
|
|
||||||
/// PolyMC: package ID of this package
|
/// Prism Launcher: package ID of this package
|
||||||
QString uid;
|
QString uid;
|
||||||
|
|
||||||
/// PolyMC: version of this package
|
/// Prism Launcher: version of this package
|
||||||
QString version;
|
QString version;
|
||||||
|
|
||||||
/// PolyMC: DEPRECATED dependency on a Minecraft version
|
/// Prism Launcher: DEPRECATED dependency on a Minecraft version
|
||||||
QString dependsOnMinecraftVersion;
|
QString dependsOnMinecraftVersion;
|
||||||
|
|
||||||
/// Mojang: DEPRECATED used to version the Mojang version format
|
/// Mojang: DEPRECATED used to version the Mojang version format
|
||||||
@ -87,13 +86,13 @@ public: /* data */
|
|||||||
/// Mojang: class to launch Minecraft with
|
/// Mojang: class to launch Minecraft with
|
||||||
QString mainClass;
|
QString mainClass;
|
||||||
|
|
||||||
/// PolyMC: class to launch legacy Minecraft with (embed in a custom window)
|
/// Prism Launcher: class to launch legacy Minecraft with (embed in a custom window)
|
||||||
QString appletClass;
|
QString appletClass;
|
||||||
|
|
||||||
/// Mojang: Minecraft launch arguments (may contain placeholders for variable substitution)
|
/// Mojang: Minecraft launch arguments (may contain placeholders for variable substitution)
|
||||||
QString minecraftArguments;
|
QString minecraftArguments;
|
||||||
|
|
||||||
/// PolyMC: Additional JVM launch arguments
|
/// Prism Launcher: Additional JVM launch arguments
|
||||||
QStringList addnJvmArguments;
|
QStringList addnJvmArguments;
|
||||||
|
|
||||||
/// Mojang: list of compatible java majors
|
/// Mojang: list of compatible java majors
|
||||||
@ -111,38 +110,38 @@ public: /* data */
|
|||||||
/// Mojang: DEPRECATED asset group to be used with Minecraft
|
/// Mojang: DEPRECATED asset group to be used with Minecraft
|
||||||
QString assets;
|
QString assets;
|
||||||
|
|
||||||
/// PolyMC: list of tweaker mod arguments for launchwrapper
|
/// Prism Launcher: list of tweaker mod arguments for launchwrapper
|
||||||
QStringList addTweakers;
|
QStringList addTweakers;
|
||||||
|
|
||||||
/// Mojang: list of libraries to add to the version
|
/// Mojang: list of libraries to add to the version
|
||||||
QList<LibraryPtr> libraries;
|
QList<LibraryPtr> libraries;
|
||||||
|
|
||||||
/// PolyMC: list of maven files to put in the libraries folder, but not in classpath
|
/// Prism Launcher: list of maven files to put in the libraries folder, but not in classpath
|
||||||
QList<LibraryPtr> mavenFiles;
|
QList<LibraryPtr> mavenFiles;
|
||||||
|
|
||||||
/// PolyMC: list of agents to add to JVM arguments
|
/// Prism Launcher: list of agents to add to JVM arguments
|
||||||
QList<AgentPtr> agents;
|
QList<AgentPtr> agents;
|
||||||
|
|
||||||
/// The main jar (Minecraft version library, normally)
|
/// The main jar (Minecraft version library, normally)
|
||||||
LibraryPtr mainJar;
|
LibraryPtr mainJar;
|
||||||
|
|
||||||
/// PolyMC: list of attached traits of this version file - used to enable features
|
/// Prism Launcher: list of attached traits of this version file - used to enable features
|
||||||
QSet<QString> traits;
|
QSet<QString> traits;
|
||||||
|
|
||||||
/// PolyMC: list of jar mods added to this version
|
/// Prism Launcher: list of jar mods added to this version
|
||||||
QList<LibraryPtr> jarMods;
|
QList<LibraryPtr> jarMods;
|
||||||
|
|
||||||
/// PolyMC: list of mods added to this version
|
/// Prism Launcher: list of mods added to this version
|
||||||
QList<LibraryPtr> mods;
|
QList<LibraryPtr> mods;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PolyMC: set of packages this depends on
|
* Prism Launcher: set of packages this depends on
|
||||||
* NOTE: this is shared with the meta format!!!
|
* NOTE: this is shared with the meta format!!!
|
||||||
*/
|
*/
|
||||||
Meta::RequireSet requires;
|
Meta::RequireSet requires;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PolyMC: set of packages this conflicts with
|
* Prism Launcher: set of packages this conflicts with
|
||||||
* NOTE: this is shared with the meta format!!!
|
* NOTE: this is shared with the meta format!!!
|
||||||
*/
|
*/
|
||||||
Meta::RequireSet conflicts;
|
Meta::RequireSet conflicts;
|
||||||
|
@ -44,7 +44,7 @@
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
* List of available Mojang accounts.
|
* List of available Mojang accounts.
|
||||||
* This should be loaded in the background by PolyMC on startup.
|
* This should be loaded in the background by Prism Launcher on startup.
|
||||||
*/
|
*/
|
||||||
class AccountList : public QAbstractListModel
|
class AccountList : public QAbstractListModel
|
||||||
{
|
{
|
||||||
|
@ -61,7 +61,7 @@ Q_DECLARE_METATYPE(MinecraftAccountPtr)
|
|||||||
* A profile within someone's Mojang account.
|
* A profile within someone's Mojang account.
|
||||||
*
|
*
|
||||||
* Currently, the profile system has not been implemented by Mojang yet,
|
* Currently, the profile system has not been implemented by Mojang yet,
|
||||||
* but we might as well add some things for it in PolyMC right now so
|
* but we might as well add some things for it in Prism Launcher right now so
|
||||||
* we don't have to rip the code to pieces to add it later.
|
* we don't have to rip the code to pieces to add it later.
|
||||||
*/
|
*/
|
||||||
struct AccountProfile
|
struct AccountProfile
|
||||||
|
@ -154,7 +154,7 @@ void LauncherPartLaunch::executeTask()
|
|||||||
#else
|
#else
|
||||||
args << classPath.join(':');
|
args << classPath.join(':');
|
||||||
#endif
|
#endif
|
||||||
args << "org.polymc.EntryPoint";
|
args << "org.prismlauncher.EntryPoint";
|
||||||
|
|
||||||
qDebug() << args.join(' ');
|
qDebug() << args.join(' ');
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ MinecraftServerTarget MinecraftServerTarget::parse(const QString &fullAddress) {
|
|||||||
|
|
||||||
// The logic below replicates the exact logic minecraft uses for parsing server addresses.
|
// The logic below replicates the exact logic minecraft uses for parsing server addresses.
|
||||||
// While the conversion is not lossless and eats errors, it ensures the same behavior
|
// While the conversion is not lossless and eats errors, it ensures the same behavior
|
||||||
// within Minecraft and PolyMC when entering server addresses.
|
// within Minecraft and Prism Launcher when entering server addresses.
|
||||||
if (fullAddress.startsWith("["))
|
if (fullAddress.startsWith("["))
|
||||||
{
|
{
|
||||||
int bracket = fullAddress.indexOf("]");
|
int bracket = fullAddress.indexOf("]");
|
||||||
|
@ -1,22 +1,41 @@
|
|||||||
/* Copyright 2013-2021 MultiMC Contributors
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* PolyMC - Minecraft Launcher
|
||||||
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* you may not use this file except in compliance with the License.
|
* it under the terms of the GNU General Public License as published by
|
||||||
* You may obtain a copy of the License at
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* You should have received a copy of the GNU General Public License
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
*
|
||||||
* See the License for the specific language governing permissions and
|
* This file incorporates work covered by the following copyright and
|
||||||
* limitations under the License.
|
* permission notice:
|
||||||
|
*
|
||||||
|
* Copyright 2013-2021 MultiMC Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ModMinecraftJar.h"
|
#include "ModMinecraftJar.h"
|
||||||
#include "launch/LaunchTask.h"
|
#include "launch/LaunchTask.h"
|
||||||
#include "MMCZip.h"
|
#include "MMCZip.h"
|
||||||
#include "minecraft/OpSys.h"
|
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include "minecraft/MinecraftInstance.h"
|
#include "minecraft/MinecraftInstance.h"
|
||||||
#include "minecraft/PackProfile.h"
|
#include "minecraft/PackProfile.h"
|
||||||
@ -50,7 +69,7 @@ void ModMinecraftJar::executeTask()
|
|||||||
{
|
{
|
||||||
auto mainJar = profile->getMainJar();
|
auto mainJar = profile->getMainJar();
|
||||||
QStringList jars, temp1, temp2, temp3, temp4;
|
QStringList jars, temp1, temp2, temp3, temp4;
|
||||||
mainJar->getApplicableFiles(currentSystem, jars, temp1, temp2, temp3, m_inst->getLocalLibraryPath());
|
mainJar->getApplicableFiles(m_inst->runtimeContext(), jars, temp1, temp2, temp3, m_inst->getLocalLibraryPath());
|
||||||
auto sourceJarPath = jars[0];
|
auto sourceJarPath = jars[0];
|
||||||
if(!MMCZip::createModdedJar(sourceJarPath, finalJarPath, jarMods))
|
if(!MMCZip::createModdedJar(sourceJarPath, finalJarPath, jarMods))
|
||||||
{
|
{
|
||||||
|
@ -1,22 +1,41 @@
|
|||||||
/* Copyright 2013-2021 MultiMC Contributors
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* PolyMC - Minecraft Launcher
|
||||||
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* you may not use this file except in compliance with the License.
|
* it under the terms of the GNU General Public License as published by
|
||||||
* You may obtain a copy of the License at
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* You should have received a copy of the GNU General Public License
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
*
|
||||||
* See the License for the specific language governing permissions and
|
* This file incorporates work covered by the following copyright and
|
||||||
* limitations under the License.
|
* permission notice:
|
||||||
|
*
|
||||||
|
* Copyright 2013-2021 MultiMC Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ScanModFolders.h"
|
#include "ScanModFolders.h"
|
||||||
#include "launch/LaunchTask.h"
|
#include "launch/LaunchTask.h"
|
||||||
#include "MMCZip.h"
|
#include "MMCZip.h"
|
||||||
#include "minecraft/OpSys.h"
|
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include "minecraft/MinecraftInstance.h"
|
#include "minecraft/MinecraftInstance.h"
|
||||||
#include "minecraft/mod/ModFolderModel.h"
|
#include "minecraft/mod/ModFolderModel.h"
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
#include "LocalModParseTask.h"
|
#include "LocalModParseTask.h"
|
||||||
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QJsonValue>
|
|
||||||
#include <QString>
|
|
||||||
#include <quazip/quazip.h>
|
#include <quazip/quazip.h>
|
||||||
#include <quazip/quazipfile.h>
|
#include <quazip/quazipfile.h>
|
||||||
#include <toml.h>
|
#include <toml++/toml.h>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonValue>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include "FileSystem.h"
|
||||||
#include "Json.h"
|
#include "Json.h"
|
||||||
#include "settings/INIFile.h"
|
#include "settings/INIFile.h"
|
||||||
#include "FileSystem.h"
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@ -22,8 +22,7 @@ namespace {
|
|||||||
// https://github.com/MinecraftForge/FML/wiki/FML-mod-information-file/5bf6a2d05145ec79387acc0d45c958642fb049fc
|
// https://github.com/MinecraftForge/FML/wiki/FML-mod-information-file/5bf6a2d05145ec79387acc0d45c958642fb049fc
|
||||||
ModDetails ReadMCModInfo(QByteArray contents)
|
ModDetails ReadMCModInfo(QByteArray contents)
|
||||||
{
|
{
|
||||||
auto getInfoFromArray = [&](QJsonArray arr) -> ModDetails
|
auto getInfoFromArray = [&](QJsonArray arr) -> ModDetails {
|
||||||
{
|
|
||||||
if (!arr.at(0).isObject()) {
|
if (!arr.at(0).isObject()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -32,16 +31,14 @@ ModDetails ReadMCModInfo(QByteArray contents)
|
|||||||
details.mod_id = firstObj.value("modid").toString();
|
details.mod_id = firstObj.value("modid").toString();
|
||||||
auto name = firstObj.value("name").toString();
|
auto name = firstObj.value("name").toString();
|
||||||
// NOTE: ignore stupid example mods copies where the author didn't even bother to change the name
|
// NOTE: ignore stupid example mods copies where the author didn't even bother to change the name
|
||||||
if(name != "Example Mod") {
|
if (name != "Example Mod") {
|
||||||
details.name = name;
|
details.name = name;
|
||||||
}
|
}
|
||||||
details.version = firstObj.value("version").toString();
|
details.version = firstObj.value("version").toString();
|
||||||
auto homeurl = firstObj.value("url").toString().trimmed();
|
auto homeurl = firstObj.value("url").toString().trimmed();
|
||||||
if(!homeurl.isEmpty())
|
if (!homeurl.isEmpty()) {
|
||||||
{
|
|
||||||
// fix up url.
|
// fix up url.
|
||||||
if (!homeurl.startsWith("http://") && !homeurl.startsWith("https://") && !homeurl.startsWith("ftp://"))
|
if (!homeurl.startsWith("http://") && !homeurl.startsWith("https://") && !homeurl.startsWith("ftp://")) {
|
||||||
{
|
|
||||||
homeurl.prepend("http://");
|
homeurl.prepend("http://");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -53,8 +50,7 @@ ModDetails ReadMCModInfo(QByteArray contents)
|
|||||||
authors = firstObj.value("authors").toArray();
|
authors = firstObj.value("authors").toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto author: authors)
|
for (auto author : authors) {
|
||||||
{
|
|
||||||
details.authors.append(author.toString());
|
details.authors.append(author.toString());
|
||||||
}
|
}
|
||||||
return details;
|
return details;
|
||||||
@ -62,14 +58,11 @@ ModDetails ReadMCModInfo(QByteArray contents)
|
|||||||
QJsonParseError jsonError;
|
QJsonParseError jsonError;
|
||||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(contents, &jsonError);
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(contents, &jsonError);
|
||||||
// this is the very old format that had just the array
|
// this is the very old format that had just the array
|
||||||
if (jsonDoc.isArray())
|
if (jsonDoc.isArray()) {
|
||||||
{
|
|
||||||
return getInfoFromArray(jsonDoc.array());
|
return getInfoFromArray(jsonDoc.array());
|
||||||
}
|
} else if (jsonDoc.isObject()) {
|
||||||
else if (jsonDoc.isObject())
|
|
||||||
{
|
|
||||||
auto val = jsonDoc.object().value("modinfoversion");
|
auto val = jsonDoc.object().value("modinfoversion");
|
||||||
if(val.isUndefined()) {
|
if (val.isUndefined()) {
|
||||||
val = jsonDoc.object().value("modListVersion");
|
val = jsonDoc.object().value("modListVersion");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,18 +72,16 @@ ModDetails ReadMCModInfo(QByteArray contents)
|
|||||||
if (version < 0)
|
if (version < 0)
|
||||||
version = Json::ensureString(val, "").toInt();
|
version = Json::ensureString(val, "").toInt();
|
||||||
|
|
||||||
if (version != 2)
|
if (version != 2) {
|
||||||
{
|
|
||||||
qCritical() << "BAD stuff happened to mod json:";
|
qCritical() << "BAD stuff happened to mod json:";
|
||||||
qCritical() << contents;
|
qCritical() << contents;
|
||||||
return {};
|
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");
|
||||||
}
|
}
|
||||||
if (arrVal.isArray())
|
if (arrVal.isArray()) {
|
||||||
{
|
|
||||||
return getInfoFromArray(arrVal.toArray());
|
return getInfoFromArray(arrVal.toArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -102,109 +93,76 @@ ModDetails ReadMCModTOML(QByteArray contents)
|
|||||||
{
|
{
|
||||||
ModDetails details;
|
ModDetails details;
|
||||||
|
|
||||||
char errbuf[200];
|
toml::table tomlData;
|
||||||
// top-level table
|
#if TOML_EXCEPTIONS
|
||||||
toml_table_t* tomlData = toml_parse(contents.data(), errbuf, sizeof(errbuf));
|
try {
|
||||||
|
tomlData = toml::parse(contents.toStdString());
|
||||||
if(!tomlData)
|
} catch (const toml::parse_error& err) {
|
||||||
{
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
tomlData = toml::parse(contents.toStdString());
|
||||||
|
if (!tomlData) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// array defined by [[mods]]
|
// array defined by [[mods]]
|
||||||
toml_array_t* tomlModsArr = toml_array_in(tomlData, "mods");
|
auto tomlModsArr = tomlData["mods"].as_array();
|
||||||
if(!tomlModsArr)
|
if (!tomlModsArr) {
|
||||||
{
|
|
||||||
qWarning() << "Corrupted mods.toml? Couldn't find [[mods]] array!";
|
qWarning() << "Corrupted mods.toml? Couldn't find [[mods]] array!";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// we only really care about the first element, since multiple mods in one file is not supported by us at the moment
|
// we only really care about the first element, since multiple mods in one file is not supported by us at the moment
|
||||||
toml_table_t* tomlModsTable0 = toml_table_at(tomlModsArr, 0);
|
auto tomlModsTable0 = tomlModsArr->get(0);
|
||||||
if(!tomlModsTable0)
|
if (!tomlModsTable0) {
|
||||||
{
|
|
||||||
qWarning() << "Corrupted mods.toml? [[mods]] didn't have an element at index 0!";
|
qWarning() << "Corrupted mods.toml? [[mods]] didn't have an element at index 0!";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
auto modsTable = tomlModsTable0->as_table();
|
||||||
|
if (!tomlModsTable0) {
|
||||||
|
qWarning() << "Corrupted mods.toml? [[mods]] was not a table!";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
// mandatory properties - always in [[mods]]
|
// mandatory properties - always in [[mods]]
|
||||||
toml_datum_t modIdDatum = toml_string_in(tomlModsTable0, "modId");
|
if (auto modIdDatum = (*modsTable)["modId"].as_string()) {
|
||||||
if(modIdDatum.ok)
|
details.mod_id = QString::fromStdString(modIdDatum->get());
|
||||||
{
|
|
||||||
details.mod_id = modIdDatum.u.s;
|
|
||||||
// library says this is required for strings
|
|
||||||
free(modIdDatum.u.s);
|
|
||||||
}
|
}
|
||||||
toml_datum_t versionDatum = toml_string_in(tomlModsTable0, "version");
|
if (auto versionDatum = (*modsTable)["version"].as_string()) {
|
||||||
if(versionDatum.ok)
|
details.version = QString::fromStdString(versionDatum->get());
|
||||||
{
|
|
||||||
details.version = versionDatum.u.s;
|
|
||||||
free(versionDatum.u.s);
|
|
||||||
}
|
}
|
||||||
toml_datum_t displayNameDatum = toml_string_in(tomlModsTable0, "displayName");
|
if (auto displayNameDatum = (*modsTable)["displayName"].as_string()) {
|
||||||
if(displayNameDatum.ok)
|
details.name = QString::fromStdString(displayNameDatum->get());
|
||||||
{
|
|
||||||
details.name = displayNameDatum.u.s;
|
|
||||||
free(displayNameDatum.u.s);
|
|
||||||
}
|
}
|
||||||
toml_datum_t descriptionDatum = toml_string_in(tomlModsTable0, "description");
|
if (auto descriptionDatum = (*modsTable)["description"].as_string()) {
|
||||||
if(descriptionDatum.ok)
|
details.description = QString::fromStdString(descriptionDatum->get());
|
||||||
{
|
|
||||||
details.description = descriptionDatum.u.s;
|
|
||||||
free(descriptionDatum.u.s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// optional properties - can be in the root table or [[mods]]
|
// optional properties - can be in the root table or [[mods]]
|
||||||
toml_datum_t authorsDatum = toml_string_in(tomlData, "authors");
|
|
||||||
QString authors = "";
|
QString authors = "";
|
||||||
if(authorsDatum.ok)
|
if (auto authorsDatum = tomlData["authors"].as_string()) {
|
||||||
{
|
authors = QString::fromStdString(authorsDatum->get());
|
||||||
authors = authorsDatum.u.s;
|
} else if (auto authorsDatum = (*modsTable)["authors"].as_string()) {
|
||||||
free(authorsDatum.u.s);
|
authors = QString::fromStdString(authorsDatum->get());
|
||||||
}
|
}
|
||||||
else
|
if (!authors.isEmpty()) {
|
||||||
{
|
|
||||||
authorsDatum = toml_string_in(tomlModsTable0, "authors");
|
|
||||||
if(authorsDatum.ok)
|
|
||||||
{
|
|
||||||
authors = authorsDatum.u.s;
|
|
||||||
free(authorsDatum.u.s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!authors.isEmpty())
|
|
||||||
{
|
|
||||||
details.authors.append(authors);
|
details.authors.append(authors);
|
||||||
}
|
}
|
||||||
|
|
||||||
toml_datum_t homeurlDatum = toml_string_in(tomlData, "displayURL");
|
|
||||||
QString homeurl = "";
|
QString homeurl = "";
|
||||||
if(homeurlDatum.ok)
|
if (auto homeurlDatum = tomlData["displayURL"].as_string()) {
|
||||||
{
|
homeurl = QString::fromStdString(homeurlDatum->get());
|
||||||
homeurl = homeurlDatum.u.s;
|
} else if (auto homeurlDatum = (*modsTable)["displayURL"].as_string()) {
|
||||||
free(homeurlDatum.u.s);
|
homeurl = QString::fromStdString(homeurlDatum->get());
|
||||||
}
|
}
|
||||||
else
|
// fix up url.
|
||||||
{
|
if (!homeurl.isEmpty() && !homeurl.startsWith("http://") && !homeurl.startsWith("https://") && !homeurl.startsWith("ftp://")) {
|
||||||
homeurlDatum = toml_string_in(tomlModsTable0, "displayURL");
|
homeurl.prepend("http://");
|
||||||
if(homeurlDatum.ok)
|
|
||||||
{
|
|
||||||
homeurl = homeurlDatum.u.s;
|
|
||||||
free(homeurlDatum.u.s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!homeurl.isEmpty())
|
|
||||||
{
|
|
||||||
// fix up url.
|
|
||||||
if (!homeurl.startsWith("http://") && !homeurl.startsWith("https://") && !homeurl.startsWith("ftp://"))
|
|
||||||
{
|
|
||||||
homeurl.prepend("http://");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
details.homeurl = homeurl;
|
details.homeurl = homeurl;
|
||||||
|
|
||||||
// this seems to be recursive, so it should free everything
|
|
||||||
toml_free(tomlData);
|
|
||||||
|
|
||||||
return details;
|
return details;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,25 +182,20 @@ ModDetails ReadFabricModInfo(QByteArray contents)
|
|||||||
details.name = object.contains("name") ? object.value("name").toString() : details.mod_id;
|
details.name = object.contains("name") ? object.value("name").toString() : details.mod_id;
|
||||||
details.description = object.value("description").toString();
|
details.description = object.value("description").toString();
|
||||||
|
|
||||||
if (schemaVersion >= 1)
|
if (schemaVersion >= 1) {
|
||||||
{
|
|
||||||
QJsonArray authors = object.value("authors").toArray();
|
QJsonArray authors = object.value("authors").toArray();
|
||||||
for (auto author: authors)
|
for (auto author : authors) {
|
||||||
{
|
if (author.isObject()) {
|
||||||
if(author.isObject()) {
|
|
||||||
details.authors.append(author.toObject().value("name").toString());
|
details.authors.append(author.toObject().value("name").toString());
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
details.authors.append(author.toString());
|
details.authors.append(author.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (object.contains("contact"))
|
if (object.contains("contact")) {
|
||||||
{
|
|
||||||
QJsonObject contact = object.value("contact").toObject();
|
QJsonObject contact = object.value("contact").toObject();
|
||||||
|
|
||||||
if (contact.contains("homepage"))
|
if (contact.contains("homepage")) {
|
||||||
{
|
|
||||||
details.homeurl = contact.value("homepage").toString();
|
details.homeurl = contact.value("homepage").toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -261,8 +214,7 @@ ModDetails ReadQuiltModInfo(QByteArray contents)
|
|||||||
ModDetails details;
|
ModDetails details;
|
||||||
|
|
||||||
// https://github.com/QuiltMC/rfcs/blob/be6ba280d785395fefa90a43db48e5bfc1d15eb4/specification/0002-quilt.mod.json.md
|
// https://github.com/QuiltMC/rfcs/blob/be6ba280d785395fefa90a43db48e5bfc1d15eb4/specification/0002-quilt.mod.json.md
|
||||||
if (schemaVersion == 1)
|
if (schemaVersion == 1) {
|
||||||
{
|
|
||||||
auto modInfo = Json::requireObject(object.value("quilt_loader"), "Quilt mod info");
|
auto modInfo = Json::requireObject(object.value("quilt_loader"), "Quilt mod info");
|
||||||
|
|
||||||
details.mod_id = Json::requireString(modInfo.value("id"), "Mod ID");
|
details.mod_id = Json::requireString(modInfo.value("id"), "Mod ID");
|
||||||
@ -280,8 +232,7 @@ ModDetails ReadQuiltModInfo(QByteArray contents)
|
|||||||
|
|
||||||
auto modContact = Json::ensureObject(modMetadata.value("contact"));
|
auto modContact = Json::ensureObject(modMetadata.value("contact"));
|
||||||
|
|
||||||
if (modContact.contains("homepage"))
|
if (modContact.contains("homepage")) {
|
||||||
{
|
|
||||||
details.homeurl = Json::requireString(modContact.value("homepage"));
|
details.homeurl = Json::requireString(modContact.value("homepage"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -314,21 +265,17 @@ ModDetails ReadLiteModInfo(QByteArray contents)
|
|||||||
QJsonParseError jsonError;
|
QJsonParseError jsonError;
|
||||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(contents, &jsonError);
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(contents, &jsonError);
|
||||||
auto object = jsonDoc.object();
|
auto object = jsonDoc.object();
|
||||||
if (object.contains("name"))
|
if (object.contains("name")) {
|
||||||
{
|
|
||||||
details.mod_id = details.name = object.value("name").toString();
|
details.mod_id = details.name = object.value("name").toString();
|
||||||
}
|
}
|
||||||
if (object.contains("version"))
|
if (object.contains("version")) {
|
||||||
{
|
|
||||||
details.version = object.value("version").toString("");
|
details.version = object.value("version").toString("");
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
details.version = object.value("revision").toString("");
|
details.version = object.value("revision").toString("");
|
||||||
}
|
}
|
||||||
details.mcversion = object.value("mcversion").toString();
|
details.mcversion = object.value("mcversion").toString();
|
||||||
auto author = object.value("author").toString();
|
auto author = object.value("author").toString();
|
||||||
if(!author.isEmpty()) {
|
if (!author.isEmpty()) {
|
||||||
details.authors.append(author);
|
details.authors.append(author);
|
||||||
}
|
}
|
||||||
details.description = object.value("description").toString();
|
details.description = object.value("description").toString();
|
||||||
@ -336,14 +283,10 @@ ModDetails ReadLiteModInfo(QByteArray contents)
|
|||||||
return details;
|
return details;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace
|
||||||
|
|
||||||
LocalModParseTask::LocalModParseTask(int token, ResourceType type, const QFileInfo& modFile):
|
LocalModParseTask::LocalModParseTask(int token, ResourceType type, const QFileInfo& modFile)
|
||||||
Task(nullptr, false),
|
: Task(nullptr, false), m_token(token), m_type(type), m_modFile(modFile), m_result(new Result())
|
||||||
m_token(token),
|
|
||||||
m_type(type),
|
|
||||||
m_modFile(modFile),
|
|
||||||
m_result(new Result())
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void LocalModParseTask::processAsZip()
|
void LocalModParseTask::processAsZip()
|
||||||
@ -354,10 +297,8 @@ void LocalModParseTask::processAsZip()
|
|||||||
|
|
||||||
QuaZipFile file(&zip);
|
QuaZipFile file(&zip);
|
||||||
|
|
||||||
if (zip.setCurrentFile("META-INF/mods.toml"))
|
if (zip.setCurrentFile("META-INF/mods.toml")) {
|
||||||
{
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
if (!file.open(QIODevice::ReadOnly))
|
|
||||||
{
|
|
||||||
zip.close();
|
zip.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -366,12 +307,9 @@ void LocalModParseTask::processAsZip()
|
|||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
// to replace ${file.jarVersion} with the actual version, as needed
|
// to replace ${file.jarVersion} with the actual version, as needed
|
||||||
if (m_result->details.version == "${file.jarVersion}")
|
if (m_result->details.version == "${file.jarVersion}") {
|
||||||
{
|
if (zip.setCurrentFile("META-INF/MANIFEST.MF")) {
|
||||||
if (zip.setCurrentFile("META-INF/MANIFEST.MF"))
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
{
|
|
||||||
if (!file.open(QIODevice::ReadOnly))
|
|
||||||
{
|
|
||||||
zip.close();
|
zip.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -379,10 +317,8 @@ void LocalModParseTask::processAsZip()
|
|||||||
// quick and dirty line-by-line parser
|
// quick and dirty line-by-line parser
|
||||||
auto manifestLines = file.readAll().split('\n');
|
auto manifestLines = file.readAll().split('\n');
|
||||||
QString manifestVersion = "";
|
QString manifestVersion = "";
|
||||||
for (auto &line : manifestLines)
|
for (auto& line : manifestLines) {
|
||||||
{
|
if (QString(line).startsWith("Implementation-Version: ")) {
|
||||||
if (QString(line).startsWith("Implementation-Version: "))
|
|
||||||
{
|
|
||||||
manifestVersion = QString(line).remove("Implementation-Version: ");
|
manifestVersion = QString(line).remove("Implementation-Version: ");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -390,8 +326,7 @@ void LocalModParseTask::processAsZip()
|
|||||||
|
|
||||||
// some mods use ${projectversion} in their build.gradle, causing this mess to show up in MANIFEST.MF
|
// some mods use ${projectversion} in their build.gradle, causing this mess to show up in MANIFEST.MF
|
||||||
// also keep with forge's behavior of setting the version to "NONE" if none is found
|
// also keep with forge's behavior of setting the version to "NONE" if none is found
|
||||||
if (manifestVersion.contains("task ':jar' property 'archiveVersion'") || manifestVersion == "")
|
if (manifestVersion.contains("task ':jar' property 'archiveVersion'") || manifestVersion == "") {
|
||||||
{
|
|
||||||
manifestVersion = "NONE";
|
manifestVersion = "NONE";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,11 +338,8 @@ void LocalModParseTask::processAsZip()
|
|||||||
|
|
||||||
zip.close();
|
zip.close();
|
||||||
return;
|
return;
|
||||||
}
|
} else if (zip.setCurrentFile("mcmod.info")) {
|
||||||
else if (zip.setCurrentFile("mcmod.info"))
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
{
|
|
||||||
if (!file.open(QIODevice::ReadOnly))
|
|
||||||
{
|
|
||||||
zip.close();
|
zip.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -416,11 +348,8 @@ void LocalModParseTask::processAsZip()
|
|||||||
file.close();
|
file.close();
|
||||||
zip.close();
|
zip.close();
|
||||||
return;
|
return;
|
||||||
}
|
} else if (zip.setCurrentFile("quilt.mod.json")) {
|
||||||
else if (zip.setCurrentFile("quilt.mod.json"))
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
{
|
|
||||||
if (!file.open(QIODevice::ReadOnly))
|
|
||||||
{
|
|
||||||
zip.close();
|
zip.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -429,11 +358,8 @@ void LocalModParseTask::processAsZip()
|
|||||||
file.close();
|
file.close();
|
||||||
zip.close();
|
zip.close();
|
||||||
return;
|
return;
|
||||||
}
|
} else if (zip.setCurrentFile("fabric.mod.json")) {
|
||||||
else if (zip.setCurrentFile("fabric.mod.json"))
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
{
|
|
||||||
if (!file.open(QIODevice::ReadOnly))
|
|
||||||
{
|
|
||||||
zip.close();
|
zip.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -442,11 +368,8 @@ void LocalModParseTask::processAsZip()
|
|||||||
file.close();
|
file.close();
|
||||||
zip.close();
|
zip.close();
|
||||||
return;
|
return;
|
||||||
}
|
} else if (zip.setCurrentFile("forgeversion.properties")) {
|
||||||
else if (zip.setCurrentFile("forgeversion.properties"))
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
{
|
|
||||||
if (!file.open(QIODevice::ReadOnly))
|
|
||||||
{
|
|
||||||
zip.close();
|
zip.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -463,8 +386,7 @@ void LocalModParseTask::processAsZip()
|
|||||||
void LocalModParseTask::processAsFolder()
|
void LocalModParseTask::processAsFolder()
|
||||||
{
|
{
|
||||||
QFileInfo mcmod_info(FS::PathCombine(m_modFile.filePath(), "mcmod.info"));
|
QFileInfo mcmod_info(FS::PathCombine(m_modFile.filePath(), "mcmod.info"));
|
||||||
if (mcmod_info.isFile())
|
if (mcmod_info.isFile()) {
|
||||||
{
|
|
||||||
QFile mcmod(mcmod_info.filePath());
|
QFile mcmod(mcmod_info.filePath());
|
||||||
if (!mcmod.open(QIODevice::ReadOnly))
|
if (!mcmod.open(QIODevice::ReadOnly))
|
||||||
return;
|
return;
|
||||||
@ -483,10 +405,8 @@ void LocalModParseTask::processAsLitemod()
|
|||||||
|
|
||||||
QuaZipFile file(&zip);
|
QuaZipFile file(&zip);
|
||||||
|
|
||||||
if (zip.setCurrentFile("litemod.json"))
|
if (zip.setCurrentFile("litemod.json")) {
|
||||||
{
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
if (!file.open(QIODevice::ReadOnly))
|
|
||||||
{
|
|
||||||
zip.close();
|
zip.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -505,8 +425,7 @@ bool LocalModParseTask::abort()
|
|||||||
|
|
||||||
void LocalModParseTask::executeTask()
|
void LocalModParseTask::executeTask()
|
||||||
{
|
{
|
||||||
switch(m_type)
|
switch (m_type) {
|
||||||
{
|
|
||||||
case ResourceType::ZIPFILE:
|
case ResourceType::ZIPFILE:
|
||||||
processAsZip();
|
processAsZip();
|
||||||
break;
|
break;
|
||||||
|
@ -1,3 +1,38 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* PolyMC - Minecraft Launcher
|
||||||
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This file incorporates work covered by the following copyright and
|
||||||
|
* permission notice:
|
||||||
|
*
|
||||||
|
* Copyright 2013-2021 MultiMC Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
#include "FoldersTask.h"
|
#include "FoldersTask.h"
|
||||||
#include "minecraft/MinecraftInstance.h"
|
#include "minecraft/MinecraftInstance.h"
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
@ -34,7 +34,7 @@ void LibrariesTask::executeTask()
|
|||||||
emitFailed(tr("Null jar is specified in the metadata, aborting."));
|
emitFailed(tr("Null jar is specified in the metadata, aborting."));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto dls = lib->getDownloads(currentSystem, metacache.get(), errors, localPath);
|
auto dls = lib->getDownloads(inst->runtimeContext(), metacache.get(), errors, localPath);
|
||||||
for(auto dl : dls)
|
for(auto dl : dls)
|
||||||
{
|
{
|
||||||
downloadJob->addNetAction(dl);
|
downloadJob->addNetAction(dl);
|
||||||
|
@ -9,9 +9,10 @@ Flame::FileResolvingTask::FileResolvingTask(const shared_qobject_ptr<QNetworkAcc
|
|||||||
|
|
||||||
bool Flame::FileResolvingTask::abort()
|
bool Flame::FileResolvingTask::abort()
|
||||||
{
|
{
|
||||||
|
bool aborted = true;
|
||||||
if (m_dljob)
|
if (m_dljob)
|
||||||
return m_dljob->abort();
|
aborted &= m_dljob->abort();
|
||||||
return true;
|
return aborted ? Task::abort() : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Flame::FileResolvingTask::executeTask()
|
void Flame::FileResolvingTask::executeTask()
|
||||||
|
@ -65,48 +65,42 @@ void PackInstallTask::executeTask()
|
|||||||
void PackInstallTask::downloadPack()
|
void PackInstallTask::downloadPack()
|
||||||
{
|
{
|
||||||
setStatus(tr("Downloading zip for %1").arg(m_pack.name));
|
setStatus(tr("Downloading zip for %1").arg(m_pack.name));
|
||||||
|
setAbortable(false);
|
||||||
|
|
||||||
|
archivePath = QString("%1/%2/%3").arg(m_pack.dir, m_version.replace(".", "_"), m_pack.file);
|
||||||
|
|
||||||
auto packoffset = QString("%1/%2/%3").arg(m_pack.dir, m_version.replace(".", "_"), m_pack.file);
|
|
||||||
auto entry = APPLICATION->metacache()->resolveEntry("FTBPacks", packoffset);
|
|
||||||
netJobContainer = new NetJob("Download FTB Pack", m_network);
|
netJobContainer = new NetJob("Download FTB Pack", m_network);
|
||||||
|
|
||||||
entry->setStale(true);
|
|
||||||
QString url;
|
QString url;
|
||||||
if(m_pack.type == PackType::Private)
|
if (m_pack.type == PackType::Private) {
|
||||||
{
|
url = QString(BuildConfig.LEGACY_FTB_CDN_BASE_URL + "privatepacks/%1").arg(archivePath);
|
||||||
url = QString(BuildConfig.LEGACY_FTB_CDN_BASE_URL + "privatepacks/%1").arg(packoffset);
|
} else {
|
||||||
|
url = QString(BuildConfig.LEGACY_FTB_CDN_BASE_URL + "modpacks/%1").arg(archivePath);
|
||||||
}
|
}
|
||||||
else
|
netJobContainer->addNetAction(Net::Download::makeFile(url, archivePath));
|
||||||
{
|
|
||||||
url = QString(BuildConfig.LEGACY_FTB_CDN_BASE_URL + "modpacks/%1").arg(packoffset);
|
|
||||||
}
|
|
||||||
netJobContainer->addNetAction(Net::Download::makeCached(url, entry));
|
|
||||||
archivePath = entry->getFullPath();
|
|
||||||
|
|
||||||
connect(netJobContainer.get(), &NetJob::succeeded, this, &PackInstallTask::onDownloadSucceeded);
|
connect(netJobContainer.get(), &NetJob::succeeded, this, &PackInstallTask::onDownloadSucceeded);
|
||||||
connect(netJobContainer.get(), &NetJob::failed, this, &PackInstallTask::onDownloadFailed);
|
connect(netJobContainer.get(), &NetJob::failed, this, &PackInstallTask::onDownloadFailed);
|
||||||
connect(netJobContainer.get(), &NetJob::progress, this, &PackInstallTask::onDownloadProgress);
|
connect(netJobContainer.get(), &NetJob::progress, this, &PackInstallTask::onDownloadProgress);
|
||||||
connect(netJobContainer.get(), &NetJob::aborted, this, &PackInstallTask::onDownloadAborted);
|
connect(netJobContainer.get(), &NetJob::aborted, this, &PackInstallTask::onDownloadAborted);
|
||||||
|
|
||||||
netJobContainer->start();
|
netJobContainer->start();
|
||||||
|
|
||||||
|
setAbortable(true);
|
||||||
progress(1, 4);
|
progress(1, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PackInstallTask::onDownloadSucceeded()
|
void PackInstallTask::onDownloadSucceeded()
|
||||||
{
|
{
|
||||||
abortable = false;
|
|
||||||
unzip();
|
unzip();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PackInstallTask::onDownloadFailed(QString reason)
|
void PackInstallTask::onDownloadFailed(QString reason)
|
||||||
{
|
{
|
||||||
abortable = false;
|
|
||||||
emitFailed(reason);
|
emitFailed(reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PackInstallTask::onDownloadProgress(qint64 current, qint64 total)
|
void PackInstallTask::onDownloadProgress(qint64 current, qint64 total)
|
||||||
{
|
{
|
||||||
abortable = true;
|
|
||||||
progress(current, total * 4);
|
progress(current, total * 4);
|
||||||
setStatus(tr("Downloading zip for %1 (%2%)").arg(m_pack.name).arg(current / 10));
|
setStatus(tr("Downloading zip for %1 (%2%)").arg(m_pack.name).arg(current / 10));
|
||||||
}
|
}
|
||||||
@ -118,8 +112,10 @@ void PackInstallTask::onDownloadAborted()
|
|||||||
|
|
||||||
void PackInstallTask::unzip()
|
void PackInstallTask::unzip()
|
||||||
{
|
{
|
||||||
progress(2, 4);
|
|
||||||
setStatus(tr("Extracting modpack"));
|
setStatus(tr("Extracting modpack"));
|
||||||
|
setAbortable(false);
|
||||||
|
progress(2, 4);
|
||||||
|
|
||||||
QDir extractDir(m_stagingPath);
|
QDir extractDir(m_stagingPath);
|
||||||
|
|
||||||
m_packZip.reset(new QuaZip(archivePath));
|
m_packZip.reset(new QuaZip(archivePath));
|
||||||
@ -151,8 +147,8 @@ void PackInstallTask::onUnzipCanceled()
|
|||||||
|
|
||||||
void PackInstallTask::install()
|
void PackInstallTask::install()
|
||||||
{
|
{
|
||||||
progress(3, 4);
|
|
||||||
setStatus(tr("Installing modpack"));
|
setStatus(tr("Installing modpack"));
|
||||||
|
progress(3, 4);
|
||||||
QDir unzipMcDir(m_stagingPath + "/unzip/minecraft");
|
QDir unzipMcDir(m_stagingPath + "/unzip/minecraft");
|
||||||
if(unzipMcDir.exists())
|
if(unzipMcDir.exists())
|
||||||
{
|
{
|
||||||
@ -247,11 +243,12 @@ void PackInstallTask::install()
|
|||||||
|
|
||||||
bool PackInstallTask::abort()
|
bool PackInstallTask::abort()
|
||||||
{
|
{
|
||||||
if(abortable)
|
if (!canAbort()) {
|
||||||
{
|
return false;
|
||||||
return netJobContainer->abort();
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
netJobContainer->abort();
|
||||||
|
return InstanceTask::abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,9 @@ PackInstallTask::PackInstallTask(Modpack pack, QString version, QWidget* parent)
|
|||||||
|
|
||||||
bool PackInstallTask::abort()
|
bool PackInstallTask::abort()
|
||||||
{
|
{
|
||||||
|
if (!canAbort())
|
||||||
|
return false;
|
||||||
|
|
||||||
bool aborted = true;
|
bool aborted = true;
|
||||||
|
|
||||||
if (m_net_job)
|
if (m_net_job)
|
||||||
@ -65,15 +68,13 @@ bool PackInstallTask::abort()
|
|||||||
if (m_mod_id_resolver_task)
|
if (m_mod_id_resolver_task)
|
||||||
aborted &= m_mod_id_resolver_task->abort();
|
aborted &= m_mod_id_resolver_task->abort();
|
||||||
|
|
||||||
if (aborted)
|
return aborted ? InstanceTask::abort() : false;
|
||||||
emitAborted();
|
|
||||||
|
|
||||||
return aborted;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PackInstallTask::executeTask()
|
void PackInstallTask::executeTask()
|
||||||
{
|
{
|
||||||
setStatus(tr("Getting the manifest..."));
|
setStatus(tr("Getting the manifest..."));
|
||||||
|
setAbortable(false);
|
||||||
|
|
||||||
// Find pack version
|
// Find pack version
|
||||||
auto version_it = std::find_if(m_pack.versions.constBegin(), m_pack.versions.constEnd(),
|
auto version_it = std::find_if(m_pack.versions.constBegin(), m_pack.versions.constEnd(),
|
||||||
@ -93,10 +94,12 @@ void PackInstallTask::executeTask()
|
|||||||
|
|
||||||
QObject::connect(netJob, &NetJob::succeeded, this, &PackInstallTask::onManifestDownloadSucceeded);
|
QObject::connect(netJob, &NetJob::succeeded, this, &PackInstallTask::onManifestDownloadSucceeded);
|
||||||
QObject::connect(netJob, &NetJob::failed, this, &PackInstallTask::onManifestDownloadFailed);
|
QObject::connect(netJob, &NetJob::failed, this, &PackInstallTask::onManifestDownloadFailed);
|
||||||
|
QObject::connect(netJob, &NetJob::aborted, this, &PackInstallTask::abort);
|
||||||
QObject::connect(netJob, &NetJob::progress, this, &PackInstallTask::setProgress);
|
QObject::connect(netJob, &NetJob::progress, this, &PackInstallTask::setProgress);
|
||||||
|
|
||||||
m_net_job = netJob;
|
m_net_job = netJob;
|
||||||
|
|
||||||
|
setAbortable(true);
|
||||||
netJob->start();
|
netJob->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,6 +133,7 @@ void PackInstallTask::onManifestDownloadSucceeded()
|
|||||||
void PackInstallTask::resolveMods()
|
void PackInstallTask::resolveMods()
|
||||||
{
|
{
|
||||||
setStatus(tr("Resolving mods..."));
|
setStatus(tr("Resolving mods..."));
|
||||||
|
setAbortable(false);
|
||||||
setProgress(0, 100);
|
setProgress(0, 100);
|
||||||
|
|
||||||
m_file_id_map.clear();
|
m_file_id_map.clear();
|
||||||
@ -162,15 +166,16 @@ void PackInstallTask::resolveMods()
|
|||||||
|
|
||||||
connect(m_mod_id_resolver_task.get(), &Flame::FileResolvingTask::succeeded, this, &PackInstallTask::onResolveModsSucceeded);
|
connect(m_mod_id_resolver_task.get(), &Flame::FileResolvingTask::succeeded, this, &PackInstallTask::onResolveModsSucceeded);
|
||||||
connect(m_mod_id_resolver_task.get(), &Flame::FileResolvingTask::failed, this, &PackInstallTask::onResolveModsFailed);
|
connect(m_mod_id_resolver_task.get(), &Flame::FileResolvingTask::failed, this, &PackInstallTask::onResolveModsFailed);
|
||||||
|
connect(m_mod_id_resolver_task.get(), &Flame::FileResolvingTask::aborted, this, &PackInstallTask::abort);
|
||||||
connect(m_mod_id_resolver_task.get(), &Flame::FileResolvingTask::progress, this, &PackInstallTask::setProgress);
|
connect(m_mod_id_resolver_task.get(), &Flame::FileResolvingTask::progress, this, &PackInstallTask::setProgress);
|
||||||
|
|
||||||
|
setAbortable(true);
|
||||||
|
|
||||||
m_mod_id_resolver_task->start();
|
m_mod_id_resolver_task->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PackInstallTask::onResolveModsSucceeded()
|
void PackInstallTask::onResolveModsSucceeded()
|
||||||
{
|
{
|
||||||
m_abortable = false;
|
|
||||||
|
|
||||||
QString text;
|
QString text;
|
||||||
QList<QUrl> urls;
|
QList<QUrl> urls;
|
||||||
auto anyBlocked = false;
|
auto anyBlocked = false;
|
||||||
@ -209,94 +214,23 @@ void PackInstallTask::onResolveModsSucceeded()
|
|||||||
urls);
|
urls);
|
||||||
|
|
||||||
if (message_dialog->exec() == QDialog::Accepted)
|
if (message_dialog->exec() == QDialog::Accepted)
|
||||||
downloadPack();
|
createInstance();
|
||||||
else
|
else
|
||||||
abort();
|
abort();
|
||||||
} else {
|
} else {
|
||||||
downloadPack();
|
createInstance();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PackInstallTask::downloadPack()
|
void PackInstallTask::createInstance()
|
||||||
{
|
{
|
||||||
setStatus(tr("Downloading mods..."));
|
setAbortable(false);
|
||||||
|
|
||||||
auto* jobPtr = new NetJob(tr("Mod download"), APPLICATION->network());
|
setStatus(tr("Creating the instance..."));
|
||||||
for (auto const& file : m_version.files) {
|
|
||||||
if (file.serverOnly || file.url.isEmpty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
QFileInfo file_info(file.name);
|
|
||||||
auto cacheName = file_info.completeBaseName() + "-" + file.sha1 + "." + file_info.suffix();
|
|
||||||
|
|
||||||
auto entry = APPLICATION->metacache()->resolveEntry("ModpacksCHPacks", cacheName);
|
|
||||||
entry->setStale(true);
|
|
||||||
|
|
||||||
auto relpath = FS::PathCombine("minecraft", file.path, file.name);
|
|
||||||
auto path = FS::PathCombine(m_stagingPath, relpath);
|
|
||||||
|
|
||||||
if (m_files_to_copy.contains(path)) {
|
|
||||||
qWarning() << "Ignoring" << file.url << "as a file of that path is already downloading.";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
qDebug() << "Will download" << file.url << "to" << path;
|
|
||||||
m_files_to_copy[path] = entry->getFullPath();
|
|
||||||
|
|
||||||
auto dl = Net::Download::makeCached(file.url, entry);
|
|
||||||
if (!file.sha1.isEmpty()) {
|
|
||||||
auto rawSha1 = QByteArray::fromHex(file.sha1.toLatin1());
|
|
||||||
dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawSha1));
|
|
||||||
}
|
|
||||||
|
|
||||||
jobPtr->addNetAction(dl);
|
|
||||||
}
|
|
||||||
|
|
||||||
connect(jobPtr, &NetJob::succeeded, this, &PackInstallTask::onModDownloadSucceeded);
|
|
||||||
connect(jobPtr, &NetJob::failed, this, &PackInstallTask::onModDownloadFailed);
|
|
||||||
connect(jobPtr, &NetJob::progress, this, &PackInstallTask::setProgress);
|
|
||||||
|
|
||||||
m_net_job = jobPtr;
|
|
||||||
jobPtr->start();
|
|
||||||
|
|
||||||
m_abortable = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PackInstallTask::onModDownloadSucceeded()
|
|
||||||
{
|
|
||||||
m_net_job.reset();
|
|
||||||
install();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PackInstallTask::install()
|
|
||||||
{
|
|
||||||
setStatus(tr("Copying modpack files..."));
|
|
||||||
setProgress(0, m_files_to_copy.size());
|
|
||||||
QCoreApplication::processEvents();
|
|
||||||
|
|
||||||
m_abortable = false;
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
for (auto iter = m_files_to_copy.constBegin(); iter != m_files_to_copy.constEnd(); iter++) {
|
|
||||||
auto& to = iter.key();
|
|
||||||
auto& from = iter.value();
|
|
||||||
FS::copy fileCopyOperation(from, to);
|
|
||||||
if (!fileCopyOperation()) {
|
|
||||||
qWarning() << "Failed to copy" << from << "to" << to;
|
|
||||||
emitFailed(tr("Failed to copy files"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setProgress(i++, m_files_to_copy.size());
|
|
||||||
QCoreApplication::processEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
setStatus(tr("Installing modpack..."));
|
|
||||||
QCoreApplication::processEvents();
|
QCoreApplication::processEvents();
|
||||||
|
|
||||||
auto instanceConfigPath = FS::PathCombine(m_stagingPath, "instance.cfg");
|
auto instanceConfigPath = FS::PathCombine(m_stagingPath, "instance.cfg");
|
||||||
auto instanceSettings = std::make_shared<INISettingsObject>(instanceConfigPath);
|
auto instanceSettings = std::make_shared<INISettingsObject>(instanceConfigPath);
|
||||||
instanceSettings->suspendSave();
|
|
||||||
|
|
||||||
MinecraftInstance instance(m_globalSettings, instanceSettings, m_stagingPath);
|
MinecraftInstance instance(m_globalSettings, instanceSettings, m_stagingPath);
|
||||||
auto components = instance.getPackProfile();
|
auto components = instance.getPackProfile();
|
||||||
@ -337,8 +271,55 @@ void PackInstallTask::install()
|
|||||||
instance.setName(name());
|
instance.setName(name());
|
||||||
instance.setIconKey(m_instIcon);
|
instance.setIconKey(m_instIcon);
|
||||||
instance.setManagedPack("modpacksch", QString::number(m_pack.id), m_pack.name, QString::number(m_version.id), m_version.name);
|
instance.setManagedPack("modpacksch", QString::number(m_pack.id), m_pack.name, QString::number(m_version.id), m_version.name);
|
||||||
instanceSettings->resumeSave();
|
|
||||||
|
|
||||||
|
instance.saveNow();
|
||||||
|
|
||||||
|
onCreateInstanceSucceeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PackInstallTask::onCreateInstanceSucceeded()
|
||||||
|
{
|
||||||
|
downloadPack();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PackInstallTask::downloadPack()
|
||||||
|
{
|
||||||
|
setStatus(tr("Downloading mods..."));
|
||||||
|
setAbortable(false);
|
||||||
|
|
||||||
|
auto* jobPtr = new NetJob(tr("Mod download"), APPLICATION->network());
|
||||||
|
for (auto const& file : m_version.files) {
|
||||||
|
if (file.serverOnly || file.url.isEmpty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto path = FS::PathCombine(m_stagingPath, ".minecraft", file.path, file.name);
|
||||||
|
qDebug() << "Will try to download" << file.url << "to" << path;
|
||||||
|
|
||||||
|
QFileInfo file_info(file.name);
|
||||||
|
|
||||||
|
auto dl = Net::Download::makeFile(file.url, path);
|
||||||
|
if (!file.sha1.isEmpty()) {
|
||||||
|
auto rawSha1 = QByteArray::fromHex(file.sha1.toLatin1());
|
||||||
|
dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawSha1));
|
||||||
|
}
|
||||||
|
|
||||||
|
jobPtr->addNetAction(dl);
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(jobPtr, &NetJob::succeeded, this, &PackInstallTask::onModDownloadSucceeded);
|
||||||
|
connect(jobPtr, &NetJob::failed, this, &PackInstallTask::onModDownloadFailed);
|
||||||
|
connect(jobPtr, &NetJob::aborted, this, &PackInstallTask::abort);
|
||||||
|
connect(jobPtr, &NetJob::progress, this, &PackInstallTask::setProgress);
|
||||||
|
|
||||||
|
m_net_job = jobPtr;
|
||||||
|
|
||||||
|
setAbortable(true);
|
||||||
|
jobPtr->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PackInstallTask::onModDownloadSucceeded()
|
||||||
|
{
|
||||||
|
m_net_job.reset();
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,6 +333,10 @@ void PackInstallTask::onResolveModsFailed(QString reason)
|
|||||||
m_net_job.reset();
|
m_net_job.reset();
|
||||||
emitFailed(reason);
|
emitFailed(reason);
|
||||||
}
|
}
|
||||||
|
void PackInstallTask::onCreateInstanceFailed(QString reason)
|
||||||
|
{
|
||||||
|
emitFailed(reason);
|
||||||
|
}
|
||||||
void PackInstallTask::onModDownloadFailed(QString reason)
|
void PackInstallTask::onModDownloadFailed(QString reason)
|
||||||
{
|
{
|
||||||
m_net_job.reset();
|
m_net_job.reset();
|
||||||
|
@ -56,7 +56,6 @@ public:
|
|||||||
explicit PackInstallTask(Modpack pack, QString version, QWidget* parent = nullptr);
|
explicit PackInstallTask(Modpack pack, QString version, QWidget* parent = nullptr);
|
||||||
~PackInstallTask() override = default;
|
~PackInstallTask() override = default;
|
||||||
|
|
||||||
bool canAbort() const override { return m_abortable; }
|
|
||||||
bool abort() override;
|
bool abort() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -65,20 +64,20 @@ protected:
|
|||||||
private slots:
|
private slots:
|
||||||
void onManifestDownloadSucceeded();
|
void onManifestDownloadSucceeded();
|
||||||
void onResolveModsSucceeded();
|
void onResolveModsSucceeded();
|
||||||
|
void onCreateInstanceSucceeded();
|
||||||
void onModDownloadSucceeded();
|
void onModDownloadSucceeded();
|
||||||
|
|
||||||
void onManifestDownloadFailed(QString reason);
|
void onManifestDownloadFailed(QString reason);
|
||||||
void onResolveModsFailed(QString reason);
|
void onResolveModsFailed(QString reason);
|
||||||
|
void onCreateInstanceFailed(QString reason);
|
||||||
void onModDownloadFailed(QString reason);
|
void onModDownloadFailed(QString reason);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void resolveMods();
|
void resolveMods();
|
||||||
|
void createInstance();
|
||||||
void downloadPack();
|
void downloadPack();
|
||||||
void install();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_abortable = true;
|
|
||||||
|
|
||||||
NetJob::Ptr m_net_job = nullptr;
|
NetJob::Ptr m_net_job = nullptr;
|
||||||
shared_qobject_ptr<Flame::FileResolvingTask> m_mod_id_resolver_task = nullptr;
|
shared_qobject_ptr<Flame::FileResolvingTask> m_mod_id_resolver_task = nullptr;
|
||||||
|
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
/*
|
/*
|
||||||
* PolyMC - Minecraft Launcher
|
* PolyMC - Minecraft Launcher
|
||||||
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
|
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, version 3.
|
* the Free Software Foundation, version 3.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Packwiz.h"
|
#include "Packwiz.h"
|
||||||
|
|
||||||
@ -22,9 +22,7 @@
|
|||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
#include "toml.h"
|
#include <toml++/toml.h>
|
||||||
#include "FileSystem.h"
|
|
||||||
|
|
||||||
#include "minecraft/mod/Mod.h"
|
#include "minecraft/mod/Mod.h"
|
||||||
#include "modplatform/ModIndex.h"
|
#include "modplatform/ModIndex.h"
|
||||||
|
|
||||||
@ -44,7 +42,7 @@ auto getRealIndexName(QDir& index_dir, QString normalized_fname, bool should_fin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(should_find_match && !QString::compare(normalized_fname, real_fname, Qt::CaseSensitive)){
|
if (should_find_match && !QString::compare(normalized_fname, real_fname, Qt::CaseSensitive)) {
|
||||||
qCritical() << "Could not find a match for a valid metadata file!";
|
qCritical() << "Could not find a match for a valid metadata file!";
|
||||||
qCritical() << "File: " << normalized_fname;
|
qCritical() << "File: " << normalized_fname;
|
||||||
return {};
|
return {};
|
||||||
@ -57,7 +55,7 @@ auto getRealIndexName(QDir& index_dir, QString normalized_fname, bool should_fin
|
|||||||
// Helpers
|
// Helpers
|
||||||
static inline auto indexFileName(QString const& mod_slug) -> QString
|
static inline auto indexFileName(QString const& mod_slug) -> QString
|
||||||
{
|
{
|
||||||
if(mod_slug.endsWith(".pw.toml"))
|
if (mod_slug.endsWith(".pw.toml"))
|
||||||
return mod_slug;
|
return mod_slug;
|
||||||
return QString("%1.pw.toml").arg(mod_slug);
|
return QString("%1.pw.toml").arg(mod_slug);
|
||||||
}
|
}
|
||||||
@ -65,32 +63,28 @@ static inline auto indexFileName(QString const& mod_slug) -> QString
|
|||||||
static ModPlatform::ProviderCapabilities ProviderCaps;
|
static ModPlatform::ProviderCapabilities ProviderCaps;
|
||||||
|
|
||||||
// Helper functions for extracting data from the TOML file
|
// Helper functions for extracting data from the TOML file
|
||||||
auto stringEntry(toml_table_t* parent, const char* entry_name) -> QString
|
auto stringEntry(toml::table table, const std::string entry_name) -> QString
|
||||||
{
|
{
|
||||||
toml_datum_t var = toml_string_in(parent, entry_name);
|
auto node = table[entry_name];
|
||||||
if (!var.ok) {
|
if (!node) {
|
||||||
qCritical() << QString("Failed to read str property '%1' in mod metadata.").arg(entry_name);
|
qCritical() << QString::fromStdString("Failed to read str property '" + entry_name + "' in mod metadata.");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
QString tmp = var.u.s;
|
return QString::fromStdString(node.value_or(""));
|
||||||
free(var.u.s);
|
|
||||||
|
|
||||||
return tmp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto intEntry(toml_table_t* parent, const char* entry_name) -> int
|
auto intEntry(toml::table table, const std::string entry_name) -> int
|
||||||
{
|
{
|
||||||
toml_datum_t var = toml_int_in(parent, entry_name);
|
auto node = table[entry_name];
|
||||||
if (!var.ok) {
|
if (!node) {
|
||||||
qCritical() << QString("Failed to read int property '%1' in mod metadata.").arg(entry_name);
|
qCritical() << QString::fromStdString("Failed to read int property '" + entry_name + "' in mod metadata.");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return var.u.i;
|
return node.value_or(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
auto V1::createModFormat(QDir& index_dir, ModPlatform::IndexedPack& mod_pack, ModPlatform::IndexedVersion& mod_version) -> Mod
|
auto V1::createModFormat(QDir& index_dir, ModPlatform::IndexedPack& mod_pack, ModPlatform::IndexedVersion& mod_version) -> Mod
|
||||||
{
|
{
|
||||||
Mod mod;
|
Mod mod;
|
||||||
@ -99,10 +93,9 @@ auto V1::createModFormat(QDir& index_dir, ModPlatform::IndexedPack& mod_pack, Mo
|
|||||||
mod.name = mod_pack.name;
|
mod.name = mod_pack.name;
|
||||||
mod.filename = mod_version.fileName;
|
mod.filename = mod_version.fileName;
|
||||||
|
|
||||||
if(mod_pack.provider == ModPlatform::Provider::FLAME){
|
if (mod_pack.provider == ModPlatform::Provider::FLAME) {
|
||||||
mod.mode = "metadata:curseforge";
|
mod.mode = "metadata:curseforge";
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
mod.mode = "url";
|
mod.mode = "url";
|
||||||
mod.url = mod_version.downloadUrl;
|
mod.url = mod_version.downloadUrl;
|
||||||
}
|
}
|
||||||
@ -120,8 +113,8 @@ auto V1::createModFormat(QDir& index_dir, ModPlatform::IndexedPack& mod_pack, Mo
|
|||||||
auto V1::createModFormat(QDir& index_dir, ::Mod& internal_mod, QString slug) -> Mod
|
auto V1::createModFormat(QDir& index_dir, ::Mod& internal_mod, QString slug) -> Mod
|
||||||
{
|
{
|
||||||
// Try getting metadata if it exists
|
// Try getting metadata if it exists
|
||||||
Mod mod { getIndexForMod(index_dir, slug) };
|
Mod mod{ getIndexForMod(index_dir, slug) };
|
||||||
if(mod.isValid())
|
if (mod.isValid())
|
||||||
return mod;
|
return mod;
|
||||||
|
|
||||||
qWarning() << QString("Tried to create mod metadata with a Mod without metadata!");
|
qWarning() << QString("Tried to create mod metadata with a Mod without metadata!");
|
||||||
@ -131,7 +124,7 @@ auto V1::createModFormat(QDir& index_dir, ::Mod& internal_mod, QString slug) ->
|
|||||||
|
|
||||||
void V1::updateModIndex(QDir& index_dir, Mod& mod)
|
void V1::updateModIndex(QDir& index_dir, Mod& mod)
|
||||||
{
|
{
|
||||||
if(!mod.isValid()){
|
if (!mod.isValid()) {
|
||||||
qCritical() << QString("Tried to update metadata of an invalid mod!");
|
qCritical() << QString("Tried to update metadata of an invalid mod!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -150,7 +143,9 @@ void V1::updateModIndex(QDir& index_dir, Mod& mod)
|
|||||||
// TODO: We should do more stuff here, as the user is likely trying to
|
// TODO: We should do more stuff here, as the user is likely trying to
|
||||||
// override a file. In this case, check versions and ask the user what
|
// override a file. In this case, check versions and ask the user what
|
||||||
// they want to do!
|
// they want to do!
|
||||||
if (index_file.exists()) { index_file.remove(); }
|
if (index_file.exists()) {
|
||||||
|
index_file.remove();
|
||||||
|
}
|
||||||
|
|
||||||
if (!index_file.open(QIODevice::ReadWrite)) {
|
if (!index_file.open(QIODevice::ReadWrite)) {
|
||||||
qCritical() << QString("Could not open file %1!").arg(indexFileName(mod.name));
|
qCritical() << QString("Could not open file %1!").arg(indexFileName(mod.name));
|
||||||
@ -174,15 +169,15 @@ void V1::updateModIndex(QDir& index_dir, Mod& mod)
|
|||||||
|
|
||||||
in_stream << QString("\n[update]\n");
|
in_stream << QString("\n[update]\n");
|
||||||
in_stream << QString("[update.%1]\n").arg(ProviderCaps.name(mod.provider));
|
in_stream << QString("[update.%1]\n").arg(ProviderCaps.name(mod.provider));
|
||||||
switch(mod.provider){
|
switch (mod.provider) {
|
||||||
case(ModPlatform::Provider::FLAME):
|
case (ModPlatform::Provider::FLAME):
|
||||||
in_stream << QString("file-id = %1\n").arg(mod.file_id.toString());
|
in_stream << QString("file-id = %1\n").arg(mod.file_id.toString());
|
||||||
in_stream << QString("project-id = %1\n").arg(mod.project_id.toString());
|
in_stream << QString("project-id = %1\n").arg(mod.project_id.toString());
|
||||||
break;
|
break;
|
||||||
case(ModPlatform::Provider::MODRINTH):
|
case (ModPlatform::Provider::MODRINTH):
|
||||||
addToStream("mod-id", mod.mod_id().toString());
|
addToStream("mod-id", mod.mod_id().toString());
|
||||||
addToStream("version", mod.version().toString());
|
addToStream("version", mod.version().toString());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,27 +225,25 @@ auto V1::getIndexForMod(QDir& index_dir, QString slug) -> Mod
|
|||||||
if (real_fname.isEmpty())
|
if (real_fname.isEmpty())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
QFile index_file(index_dir.absoluteFilePath(real_fname));
|
toml::table table;
|
||||||
|
#if TOML_EXCEPTIONS
|
||||||
if (!index_file.open(QIODevice::ReadOnly)) {
|
try {
|
||||||
qWarning() << QString("Failed to open mod metadata for %1").arg(slug);
|
table = toml::parse_file(index_dir.absoluteFilePath(real_fname).toStdString());
|
||||||
|
} catch (const toml::parse_error& err) {
|
||||||
|
qWarning() << QString("Could not open file %1!").arg(normalized_fname);
|
||||||
|
qWarning() << "Reason: " << QString(err.what());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
toml_table_t* table = nullptr;
|
table = toml::parse_file(index_dir.absoluteFilePath(real_fname).toStdString());
|
||||||
|
|
||||||
// NOLINTNEXTLINE(modernize-avoid-c-arrays)
|
|
||||||
char errbuf[200];
|
|
||||||
auto file_bytearray = index_file.readAll();
|
|
||||||
table = toml_parse(file_bytearray.data(), errbuf, sizeof(errbuf));
|
|
||||||
|
|
||||||
index_file.close();
|
|
||||||
|
|
||||||
if (!table) {
|
if (!table) {
|
||||||
qWarning() << QString("Could not open file %1!").arg(normalized_fname);
|
qWarning() << QString("Could not open file %1!").arg(normalized_fname);
|
||||||
qWarning() << "Reason: " << QString(errbuf);
|
qWarning() << "Reason: " << QString(table.error().what());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// index_file.close();
|
||||||
|
|
||||||
mod.slug = slug;
|
mod.slug = slug;
|
||||||
|
|
||||||
@ -261,45 +254,42 @@ auto V1::getIndexForMod(QDir& index_dir, QString slug) -> Mod
|
|||||||
}
|
}
|
||||||
|
|
||||||
{ // [download] info
|
{ // [download] info
|
||||||
toml_table_t* download_table = toml_table_in(table, "download");
|
auto download_table = table["download"].as_table();
|
||||||
if (!download_table) {
|
if (!download_table) {
|
||||||
qCritical() << QString("No [download] section found on mod metadata!");
|
qCritical() << QString("No [download] section found on mod metadata!");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
mod.mode = stringEntry(download_table, "mode");
|
mod.mode = stringEntry(*download_table, "mode");
|
||||||
mod.url = stringEntry(download_table, "url");
|
mod.url = stringEntry(*download_table, "url");
|
||||||
mod.hash_format = stringEntry(download_table, "hash-format");
|
mod.hash_format = stringEntry(*download_table, "hash-format");
|
||||||
mod.hash = stringEntry(download_table, "hash");
|
mod.hash = stringEntry(*download_table, "hash");
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // [update] info
|
{ // [update] info
|
||||||
using Provider = ModPlatform::Provider;
|
using Provider = ModPlatform::Provider;
|
||||||
|
|
||||||
toml_table_t* update_table = toml_table_in(table, "update");
|
auto update_table = table["update"];
|
||||||
if (!update_table) {
|
if (!update_table || !update_table.is_table()) {
|
||||||
qCritical() << QString("No [update] section found on mod metadata!");
|
qCritical() << QString("No [update] section found on mod metadata!");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
toml_table_t* mod_provider_table = nullptr;
|
toml::table* mod_provider_table = nullptr;
|
||||||
if ((mod_provider_table = toml_table_in(update_table, ProviderCaps.name(Provider::FLAME)))) {
|
if ((mod_provider_table = update_table[ProviderCaps.name(Provider::FLAME)].as_table())) {
|
||||||
mod.provider = Provider::FLAME;
|
mod.provider = Provider::FLAME;
|
||||||
mod.file_id = intEntry(mod_provider_table, "file-id");
|
mod.file_id = intEntry(*mod_provider_table, "file-id");
|
||||||
mod.project_id = intEntry(mod_provider_table, "project-id");
|
mod.project_id = intEntry(*mod_provider_table, "project-id");
|
||||||
} else if ((mod_provider_table = toml_table_in(update_table, ProviderCaps.name(Provider::MODRINTH)))) {
|
} else if ((mod_provider_table = update_table[ProviderCaps.name(Provider::MODRINTH)].as_table())) {
|
||||||
mod.provider = Provider::MODRINTH;
|
mod.provider = Provider::MODRINTH;
|
||||||
mod.mod_id() = stringEntry(mod_provider_table, "mod-id");
|
mod.mod_id() = stringEntry(*mod_provider_table, "mod-id");
|
||||||
mod.version() = stringEntry(mod_provider_table, "version");
|
mod.version() = stringEntry(*mod_provider_table, "version");
|
||||||
} else {
|
} else {
|
||||||
qCritical() << QString("No mod provider on mod metadata!");
|
qCritical() << QString("No mod provider on mod metadata!");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toml_free(table);
|
|
||||||
|
|
||||||
return mod;
|
return mod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,6 +162,18 @@ auto HttpMetaCache::evictEntry(MetaEntryPtr entry) -> bool
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HttpMetaCache::evictAll()
|
||||||
|
{
|
||||||
|
for (QString& base : m_entries.keys()) {
|
||||||
|
EntryMap& map = m_entries[base];
|
||||||
|
qDebug() << "Evicting base" << base;
|
||||||
|
for (MetaEntryPtr entry : map.entry_list) {
|
||||||
|
if (!evictEntry(entry))
|
||||||
|
qWarning() << "Unexpected missing cache entry" << entry->basePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto HttpMetaCache::staleEntry(QString base, QString resource_path) -> MetaEntryPtr
|
auto HttpMetaCache::staleEntry(QString base, QString resource_path) -> MetaEntryPtr
|
||||||
{
|
{
|
||||||
auto foo = new MetaEntry();
|
auto foo = new MetaEntry();
|
||||||
|
@ -113,6 +113,7 @@ class HttpMetaCache : public QObject {
|
|||||||
|
|
||||||
// evict selected entry from cache
|
// evict selected entry from cache
|
||||||
auto evictEntry(MetaEntryPtr entry) -> bool;
|
auto evictEntry(MetaEntryPtr entry) -> bool;
|
||||||
|
void evictAll();
|
||||||
|
|
||||||
void addBase(QString base, QString base_root);
|
void addBase(QString base, QString base_root);
|
||||||
|
|
||||||
|
@ -311,6 +311,6 @@
|
|||||||
|
|
||||||
<file>scalable/instances/fox.svg</file>
|
<file>scalable/instances/fox.svg</file>
|
||||||
<file>scalable/instances/bee.svg</file>
|
<file>scalable/instances/bee.svg</file>
|
||||||
<file>scalable/instances/polymc.svg</file>
|
<file>scalable/instances/prismlauncher.svg</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
<svg width="64" height="64" version="1.1" viewBox="0 0 16.933 16.933" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
||||||
<defs>
|
|
||||||
<linearGradient id="linearGradient84726" x1="4.4979" x2="12.435" y1="3.8011" y2="9.5681" gradientUnits="userSpaceOnUse">
|
|
||||||
<stop stop-color="#88b858" offset="0"/>
|
|
||||||
<stop stop-color="#72b147" offset=".5"/>
|
|
||||||
<stop stop-color="#5a9a30" offset="1"/>
|
|
||||||
</linearGradient>
|
|
||||||
</defs>
|
|
||||||
<g>
|
|
||||||
<path d="m3.561 16.016s0-3.5642 4.9056-3.5642c4.9069 0 4.9056 3.5642 4.9056 3.5642z" fill="#765338"/>
|
|
||||||
<path d="m8.4667 12.452-4.9056 3.5642-3.0319-9.3311z" fill="#b7835a"/>
|
|
||||||
<path d="m8.4667 12.452 7.9375-5.7669-3.0319 9.3311z" fill="#5b422d"/>
|
|
||||||
<path d="m8.8308 12.716-0.36417 0.26458-0.36417-0.26458c0-0.26458 0.36417-0.26458 0.36417-0.26458s0.36417 0 0.36417 0.26458z" fill="#72b147"/>
|
|
||||||
<path d="m8.4667 12.452s-2e-7 -5.7669 7.9375-5.7669l-0.22507 0.69269-0.91853 1.1965-0.91853 0.13819-0.91853 1.1965-0.91853 0.13819-0.91853 1.1965-0.91853 0.13819-0.91853 1.1965-0.91853 0.13819z" fill="#5a9a30"/>
|
|
||||||
<path d="m8.1025 12.716-0.91853-0.13819-0.91853-1.1965-0.91853-0.13819-0.91853-1.1965-0.91853-0.13819-0.91853-1.1965-0.91853-0.13819-0.91853-1.1965-0.22507-0.69269c7.9375 1e-7 7.9375 5.7669 7.9375 5.7669z" fill="#88b858"/>
|
|
||||||
<path d="m0.52917 6.6846 7.9375 5.7669 7.9375-5.7669-7.9375-5.7669z" fill="url(#linearGradient84726)"/>
|
|
||||||
</g>
|
|
||||||
<path d="m0.75424 7.3773-0.22507-0.69269 7.9375 5.7669 7.9375-5.7669-0.22507 0.69269-7.7124 5.6034z" fill-opacity="0"/>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 1.6 KiB |
@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
<svg width="512" height="512" version="1.1" viewBox="0 0 135.47 135.47" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g transform="matrix(1.3386 0 0 1.3386 16.155 10.174)">
|
||||||
|
<path d="m18.78 50.126c0 1.342 0.356 2.6345 1.0008 3.758l-18.279 10.617c-0.96723-1.6842-1.5023-3.6252-1.5023-5.6404v-31.721c0-2.0152 0.53511-3.9517 1.5001-5.6382l18.281 10.614c-0.6448 1.1235-1.0008 2.416-1.0008 3.7602z" fill="#7a573b"/>
|
||||||
|
<path d="m77.065 27.139v15.861h-18.78v-7.1243c0-1.342-0.3559-2.6367-1.003-3.7602l18.279-10.614c0.9694 1.6843 1.5023 3.6252 1.5023 5.6404z" fill="#f3db6c"/>
|
||||||
|
<path d="m77.065 43v15.861c0 2.0152-0.5351 3.9562-1.5023 5.6404l-17.278-10.031-1.003-0.5832c0.6471-1.1236 1.003-2.4183 1.003-3.7603v-7.1265z" fill="#7ab392"/>
|
||||||
|
<path d="m75.563 64.501c-0.9695 1.6843-2.3711 3.1208-4.1062 4.1296l-13.658 7.9303-9.3924-16.356 6.1392-3.5644c1.1553-0.6733 2.089-1.628 2.736-2.7516l18.279 10.614z" fill="#4b7cbc"/>
|
||||||
|
<path d="m57.799 76.559-13.658 7.9303c-1.7352 1.0065-3.6719 1.5109-5.6086 1.5109v-21.226c1.2896 0 2.5792-0.3355 3.739-1.0088l6.1348-3.5644 9.3924 16.356z" fill="#6f488c"/>
|
||||||
|
<path d="m57.799 9.4412-9.3924 16.356-6.1348-3.5644c-1.1598-0.6732-2.4494-1.0065-3.739-1.0065v-21.226c1.9367 0 3.8734 0.50437 5.6086 1.5109z" fill="#df6277"/>
|
||||||
|
<path d="m38.532 0v21.226c-1.2896 0-2.5793 0.3333-3.7391 1.0065l-12.274 7.1288c-1.1576 0.671-2.0912 1.6279-2.7383 2.7538l-18.281-10.614c0.96947-1.6865 2.3733-3.1208 4.1085-4.1295l27.315-15.861c1.7352-1.0065 3.6719-1.5109 5.6086-1.5109z" fill="#99cd61"/>
|
||||||
|
<path d="m75.563 21.501-18.279 10.614c-0.647-1.1236-1.5807-2.0806-2.736-2.7516l-6.1392-3.5644 9.3924-16.356 13.658 7.9303c1.7352 1.0065 3.1368 2.4431 4.1062 4.1296z" fill="#fb9168"/>
|
||||||
|
<path d="m38.532 64.776v21.226c-1.9367 0-3.8733-0.5044-5.6085-1.5109l-27.315-15.863c-1.7352-1.0087-3.1368-2.443-4.1062-4.1295l18.279-10.614c0.647 1.1236 1.5807 2.0783 2.736 2.7516l12.274 7.1287c1.1598 0.6733 2.4495 1.0088 3.7391 1.0088z" fill="#4d3f33"/>
|
||||||
|
<path d="m58.285 35.876v14.251c0 2.6885-1.424 5.1698-3.7391 6.5118l-12.274 7.1288c-1.1597 0.6732-2.4494 1.0087-3.739 1.0087-1.2897 0-2.5793-0.3355-3.7391-1.0087l-12.274-7.1288c-2.3151-1.342-3.7391-3.8233-3.7391-6.5118v-14.251c0-2.6884 1.424-5.1698 3.7391-6.5118l12.274-7.1287c1.1598-0.6733 2.4494-1.0065 3.7391-1.0065 1.2896 0 2.5793 0.3355 3.739 1.0065l6.1348 3.5643 6.1392 3.5644c1.1553 0.6733 2.089 1.628 2.736 2.7516 0.6471 1.1235 1.0031 2.4182 1.0031 3.7602z" fill="#fff"/>
|
||||||
|
<path d="m58.285 35.876v14.251c0 1.342-0.356 2.6367-1.0031 3.7603s-1.5807 2.0783-2.736 2.7515l-6.1392 3.5644-6.1348 3.5644c-1.1598 0.6732-2.4494 1.0087-3.739 1.0087v-21.774l14.728-8.5495 4.0234-2.335c0.6471 1.1236 1.0031 2.4183 1.0031 3.7603z" fill="#dfdfdf"/>
|
||||||
|
<path d="m38.532 43v21.774c-1.2897 0-2.5793-0.3355-3.7391-1.0088l-12.274-7.1287c-1.1553-0.6733-2.089-1.628-2.7361-2.7516-0.647-1.1235-1.003-2.4182-1.003-3.7602v-14.251c0-1.342 0.356-2.6367 1.003-3.7603l18.751 10.884z" fill="#d6d2d2"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.0 KiB |
@ -16,7 +16,30 @@
|
|||||||
#include "INISettingsObject.h"
|
#include "INISettingsObject.h"
|
||||||
#include "Setting.h"
|
#include "Setting.h"
|
||||||
|
|
||||||
INISettingsObject::INISettingsObject(const QString &path, QObject *parent)
|
#include <QDebug>
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
|
INISettingsObject::INISettingsObject(QStringList paths, QObject *parent)
|
||||||
|
: SettingsObject(parent)
|
||||||
|
{
|
||||||
|
auto first_path = paths.constFirst();
|
||||||
|
for (auto path : paths) {
|
||||||
|
if (!QFile::exists(path))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (path != first_path && QFile::exists(path)) {
|
||||||
|
// Copy the fallback to the preferred path.
|
||||||
|
QFile::copy(path, first_path);
|
||||||
|
qDebug() << "Copied settings from" << path << "to" << first_path;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_filePath = first_path;
|
||||||
|
m_ini.loadFile(first_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
INISettingsObject::INISettingsObject(QString path, QObject* parent)
|
||||||
: SettingsObject(parent)
|
: SettingsObject(parent)
|
||||||
{
|
{
|
||||||
m_filePath = path;
|
m_filePath = path;
|
||||||
|
@ -28,7 +28,10 @@ class INISettingsObject : public SettingsObject
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit INISettingsObject(const QString &path, QObject *parent = 0);
|
/** 'paths' is a list of INI files to try, in order, for fallback support. */
|
||||||
|
explicit INISettingsObject(QStringList paths, QObject* parent = nullptr);
|
||||||
|
|
||||||
|
explicit INISettingsObject(QString path, QObject* parent = nullptr);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Gets the path to the INI file.
|
* \brief Gets the path to the INI file.
|
||||||
|
@ -33,7 +33,7 @@ public:
|
|||||||
* Construct a Setting
|
* Construct a Setting
|
||||||
*
|
*
|
||||||
* Synonyms are all the possible names used in the settings object, in order of preference.
|
* Synonyms are all the possible names used in the settings object, in order of preference.
|
||||||
* First synonym is the ID, which identifies the setting in PolyMC.
|
* First synonym is the ID, which identifies the setting in Prism Launcher.
|
||||||
*
|
*
|
||||||
* defVal is the default value that will be returned when the settings object
|
* defVal is the default value that will be returned when the settings object
|
||||||
* doesn't have any value for this setting.
|
* doesn't have any value for this setting.
|
||||||
|
@ -161,7 +161,7 @@ public:
|
|||||||
QString result;
|
QString result;
|
||||||
result = QApplication::translate("MainWindow", m_text);
|
result = QApplication::translate("MainWindow", m_text);
|
||||||
if(result.contains("%1")) {
|
if(result.contains("%1")) {
|
||||||
result = result.arg(BuildConfig.LAUNCHER_NAME);
|
result = result.arg(BuildConfig.LAUNCHER_DISPLAYNAME);
|
||||||
}
|
}
|
||||||
m_contained->setText(result);
|
m_contained->setText(result);
|
||||||
}
|
}
|
||||||
@ -170,7 +170,7 @@ public:
|
|||||||
QString result;
|
QString result;
|
||||||
result = QApplication::translate("MainWindow", m_tooltip);
|
result = QApplication::translate("MainWindow", m_tooltip);
|
||||||
if(result.contains("%1")) {
|
if(result.contains("%1")) {
|
||||||
result = result.arg(BuildConfig.LAUNCHER_NAME);
|
result = result.arg(BuildConfig.LAUNCHER_DISPLAYNAME);
|
||||||
}
|
}
|
||||||
m_contained->setToolTip(result);
|
m_contained->setToolTip(result);
|
||||||
}
|
}
|
||||||
@ -229,19 +229,13 @@ public:
|
|||||||
TranslatedAction actionRenameInstance;
|
TranslatedAction actionRenameInstance;
|
||||||
TranslatedAction actionChangeInstGroup;
|
TranslatedAction actionChangeInstGroup;
|
||||||
TranslatedAction actionChangeInstIcon;
|
TranslatedAction actionChangeInstIcon;
|
||||||
TranslatedAction actionEditInstNotes;
|
|
||||||
TranslatedAction actionEditInstance;
|
TranslatedAction actionEditInstance;
|
||||||
TranslatedAction actionWorlds;
|
|
||||||
TranslatedAction actionMods;
|
|
||||||
TranslatedAction actionViewSelectedInstFolder;
|
TranslatedAction actionViewSelectedInstFolder;
|
||||||
TranslatedAction actionViewSelectedMCFolder;
|
|
||||||
TranslatedAction actionDeleteInstance;
|
TranslatedAction actionDeleteInstance;
|
||||||
TranslatedAction actionConfig_Folder;
|
|
||||||
TranslatedAction actionCAT;
|
TranslatedAction actionCAT;
|
||||||
TranslatedAction actionCopyInstance;
|
TranslatedAction actionCopyInstance;
|
||||||
TranslatedAction actionLaunchInstanceOffline;
|
TranslatedAction actionLaunchInstanceOffline;
|
||||||
TranslatedAction actionLaunchInstanceDemo;
|
TranslatedAction actionLaunchInstanceDemo;
|
||||||
TranslatedAction actionScreenshots;
|
|
||||||
TranslatedAction actionExportInstance;
|
TranslatedAction actionExportInstance;
|
||||||
QVector<TranslatedAction *> all_actions;
|
QVector<TranslatedAction *> all_actions;
|
||||||
|
|
||||||
@ -258,6 +252,7 @@ public:
|
|||||||
|
|
||||||
QMenu * helpMenu = nullptr;
|
QMenu * helpMenu = nullptr;
|
||||||
TranslatedToolButton helpMenuButton;
|
TranslatedToolButton helpMenuButton;
|
||||||
|
TranslatedAction actionClearMetadata;
|
||||||
TranslatedAction actionReportBug;
|
TranslatedAction actionReportBug;
|
||||||
TranslatedAction actionDISCORD;
|
TranslatedAction actionDISCORD;
|
||||||
TranslatedAction actionMATRIX;
|
TranslatedAction actionMATRIX;
|
||||||
@ -347,6 +342,13 @@ public:
|
|||||||
actionUndoTrashInstance->setShortcut(QKeySequence("Ctrl+Z"));
|
actionUndoTrashInstance->setShortcut(QKeySequence("Ctrl+Z"));
|
||||||
all_actions.append(&actionUndoTrashInstance);
|
all_actions.append(&actionUndoTrashInstance);
|
||||||
|
|
||||||
|
actionClearMetadata = TranslatedAction(MainWindow);
|
||||||
|
actionClearMetadata->setObjectName(QStringLiteral("actionClearMetadata"));
|
||||||
|
actionClearMetadata->setIcon(APPLICATION->getThemedIcon("refresh"));
|
||||||
|
actionClearMetadata.setTextId(QT_TRANSLATE_NOOP("MainWindow", "&Clear Metadata Cache"));
|
||||||
|
actionClearMetadata.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Clear cached metadata"));
|
||||||
|
all_actions.append(&actionClearMetadata);
|
||||||
|
|
||||||
if (!BuildConfig.BUG_TRACKER_URL.isEmpty()) {
|
if (!BuildConfig.BUG_TRACKER_URL.isEmpty()) {
|
||||||
actionReportBug = TranslatedAction(MainWindow);
|
actionReportBug = TranslatedAction(MainWindow);
|
||||||
actionReportBug->setObjectName(QStringLiteral("actionReportBug"));
|
actionReportBug->setObjectName(QStringLiteral("actionReportBug"));
|
||||||
@ -445,6 +447,8 @@ public:
|
|||||||
helpMenu = new QMenu(MainWindow);
|
helpMenu = new QMenu(MainWindow);
|
||||||
helpMenu->setToolTipsVisible(true);
|
helpMenu->setToolTipsVisible(true);
|
||||||
|
|
||||||
|
helpMenu->addAction(actionClearMetadata);
|
||||||
|
|
||||||
if (!BuildConfig.BUG_TRACKER_URL.isEmpty()) {
|
if (!BuildConfig.BUG_TRACKER_URL.isEmpty()) {
|
||||||
helpMenu->addAction(actionReportBug);
|
helpMenu->addAction(actionReportBug);
|
||||||
}
|
}
|
||||||
@ -505,16 +509,8 @@ public:
|
|||||||
fileMenu->addAction(actionCloseWindow);
|
fileMenu->addAction(actionCloseWindow);
|
||||||
fileMenu->addSeparator();
|
fileMenu->addSeparator();
|
||||||
fileMenu->addAction(actionEditInstance);
|
fileMenu->addAction(actionEditInstance);
|
||||||
fileMenu->addAction(actionEditInstNotes);
|
|
||||||
fileMenu->addAction(actionMods);
|
|
||||||
fileMenu->addAction(actionWorlds);
|
|
||||||
fileMenu->addAction(actionScreenshots);
|
|
||||||
fileMenu->addAction(actionChangeInstGroup);
|
fileMenu->addAction(actionChangeInstGroup);
|
||||||
fileMenu->addSeparator();
|
|
||||||
fileMenu->addAction(actionViewSelectedMCFolder);
|
|
||||||
fileMenu->addAction(actionConfig_Folder);
|
|
||||||
fileMenu->addAction(actionViewSelectedInstFolder);
|
fileMenu->addAction(actionViewSelectedInstFolder);
|
||||||
fileMenu->addSeparator();
|
|
||||||
fileMenu->addAction(actionExportInstance);
|
fileMenu->addAction(actionExportInstance);
|
||||||
fileMenu->addAction(actionDeleteInstance);
|
fileMenu->addAction(actionDeleteInstance);
|
||||||
fileMenu->addAction(actionCopyInstance);
|
fileMenu->addAction(actionCopyInstance);
|
||||||
@ -537,6 +533,8 @@ public:
|
|||||||
|
|
||||||
helpMenu = menuBar->addMenu(tr("&Help"));
|
helpMenu = menuBar->addMenu(tr("&Help"));
|
||||||
helpMenu->setSeparatorsCollapsible(false);
|
helpMenu->setSeparatorsCollapsible(false);
|
||||||
|
helpMenu->addAction(actionClearMetadata);
|
||||||
|
helpMenu->addSeparator();
|
||||||
helpMenu->addAction(actionAbout);
|
helpMenu->addAction(actionAbout);
|
||||||
helpMenu->addAction(actionOpenWiki);
|
helpMenu->addAction(actionOpenWiki);
|
||||||
helpMenu->addAction(actionNewsMenuBar);
|
helpMenu->addAction(actionNewsMenuBar);
|
||||||
@ -586,13 +584,7 @@ public:
|
|||||||
void setInstanceActionsEnabled(bool enabled)
|
void setInstanceActionsEnabled(bool enabled)
|
||||||
{
|
{
|
||||||
actionEditInstance->setEnabled(enabled);
|
actionEditInstance->setEnabled(enabled);
|
||||||
actionEditInstNotes->setEnabled(enabled);
|
|
||||||
actionMods->setEnabled(enabled);
|
|
||||||
actionWorlds->setEnabled(enabled);
|
|
||||||
actionScreenshots->setEnabled(enabled);
|
|
||||||
actionChangeInstGroup->setEnabled(enabled);
|
actionChangeInstGroup->setEnabled(enabled);
|
||||||
actionViewSelectedMCFolder->setEnabled(enabled);
|
|
||||||
actionConfig_Folder->setEnabled(enabled);
|
|
||||||
actionViewSelectedInstFolder->setEnabled(enabled);
|
actionViewSelectedInstFolder->setEnabled(enabled);
|
||||||
actionExportInstance->setEnabled(enabled);
|
actionExportInstance->setEnabled(enabled);
|
||||||
actionDeleteInstance->setEnabled(enabled);
|
actionDeleteInstance->setEnabled(enabled);
|
||||||
@ -687,35 +679,11 @@ public:
|
|||||||
|
|
||||||
actionEditInstance = TranslatedAction(MainWindow);
|
actionEditInstance = TranslatedAction(MainWindow);
|
||||||
actionEditInstance->setObjectName(QStringLiteral("actionEditInstance"));
|
actionEditInstance->setObjectName(QStringLiteral("actionEditInstance"));
|
||||||
actionEditInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Edit Inst&ance..."));
|
actionEditInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "&Edit..."));
|
||||||
actionEditInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Change the instance settings, mods and versions."));
|
actionEditInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Change the instance settings, mods and versions."));
|
||||||
actionEditInstance->setShortcut(QKeySequence(tr("Ctrl+I")));
|
actionEditInstance->setShortcut(QKeySequence(tr("Ctrl+I")));
|
||||||
all_actions.append(&actionEditInstance);
|
all_actions.append(&actionEditInstance);
|
||||||
|
|
||||||
actionEditInstNotes = TranslatedAction(MainWindow);
|
|
||||||
actionEditInstNotes->setObjectName(QStringLiteral("actionEditInstNotes"));
|
|
||||||
actionEditInstNotes.setTextId(QT_TRANSLATE_NOOP("MainWindow", "E&dit Notes..."));
|
|
||||||
actionEditInstNotes.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Edit the notes for the selected instance."));
|
|
||||||
all_actions.append(&actionEditInstNotes);
|
|
||||||
|
|
||||||
actionMods = TranslatedAction(MainWindow);
|
|
||||||
actionMods->setObjectName(QStringLiteral("actionMods"));
|
|
||||||
actionMods.setTextId(QT_TRANSLATE_NOOP("MainWindow", "View &Mods"));
|
|
||||||
actionMods.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "View the mods of this instance."));
|
|
||||||
all_actions.append(&actionMods);
|
|
||||||
|
|
||||||
actionWorlds = TranslatedAction(MainWindow);
|
|
||||||
actionWorlds->setObjectName(QStringLiteral("actionWorlds"));
|
|
||||||
actionWorlds.setTextId(QT_TRANSLATE_NOOP("MainWindow", "&View Worlds"));
|
|
||||||
actionWorlds.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "View the worlds of this instance."));
|
|
||||||
all_actions.append(&actionWorlds);
|
|
||||||
|
|
||||||
actionScreenshots = TranslatedAction(MainWindow);
|
|
||||||
actionScreenshots->setObjectName(QStringLiteral("actionScreenshots"));
|
|
||||||
actionScreenshots.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Manage &Screenshots"));
|
|
||||||
actionScreenshots.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "View and upload screenshots for this instance."));
|
|
||||||
all_actions.append(&actionScreenshots);
|
|
||||||
|
|
||||||
actionChangeInstGroup = TranslatedAction(MainWindow);
|
actionChangeInstGroup = TranslatedAction(MainWindow);
|
||||||
actionChangeInstGroup->setObjectName(QStringLiteral("actionChangeInstGroup"));
|
actionChangeInstGroup->setObjectName(QStringLiteral("actionChangeInstGroup"));
|
||||||
actionChangeInstGroup.setTextId(QT_TRANSLATE_NOOP("MainWindow", "&Change Group..."));
|
actionChangeInstGroup.setTextId(QT_TRANSLATE_NOOP("MainWindow", "&Change Group..."));
|
||||||
@ -723,38 +691,22 @@ public:
|
|||||||
actionChangeInstGroup->setShortcut(QKeySequence(tr("Ctrl+G")));
|
actionChangeInstGroup->setShortcut(QKeySequence(tr("Ctrl+G")));
|
||||||
all_actions.append(&actionChangeInstGroup);
|
all_actions.append(&actionChangeInstGroup);
|
||||||
|
|
||||||
actionViewSelectedMCFolder = TranslatedAction(MainWindow);
|
|
||||||
actionViewSelectedMCFolder->setObjectName(QStringLiteral("actionViewSelectedMCFolder"));
|
|
||||||
actionViewSelectedMCFolder.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Minec&raft Folder"));
|
|
||||||
actionViewSelectedMCFolder.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the selected instance's Minecraft folder in a file browser."));
|
|
||||||
actionViewSelectedMCFolder->setShortcut(QKeySequence(tr("Ctrl+M")));
|
|
||||||
all_actions.append(&actionViewSelectedMCFolder);
|
|
||||||
|
|
||||||
actionConfig_Folder = TranslatedAction(MainWindow);
|
|
||||||
actionConfig_Folder->setObjectName(QStringLiteral("actionConfig_Folder"));
|
|
||||||
actionConfig_Folder.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Confi&g Folder"));
|
|
||||||
actionConfig_Folder.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the instance's config folder."));
|
|
||||||
// Qt on macOS is "smart" and will eat up this action when added to the menu bar because it starts with the word "config"...
|
|
||||||
// Docs: https://doc.qt.io/qt-5/qmenubar.html#qmenubar-as-a-global-menu-bar
|
|
||||||
actionConfig_Folder->setMenuRole(QAction::NoRole);
|
|
||||||
all_actions.append(&actionConfig_Folder);
|
|
||||||
|
|
||||||
actionViewSelectedInstFolder = TranslatedAction(MainWindow);
|
actionViewSelectedInstFolder = TranslatedAction(MainWindow);
|
||||||
actionViewSelectedInstFolder->setObjectName(QStringLiteral("actionViewSelectedInstFolder"));
|
actionViewSelectedInstFolder->setObjectName(QStringLiteral("actionViewSelectedInstFolder"));
|
||||||
actionViewSelectedInstFolder.setTextId(QT_TRANSLATE_NOOP("MainWindow", "&Instance Folder"));
|
actionViewSelectedInstFolder.setTextId(QT_TRANSLATE_NOOP("MainWindow", "&Folder"));
|
||||||
actionViewSelectedInstFolder.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the selected instance's root folder in a file browser."));
|
actionViewSelectedInstFolder.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the selected instance's root folder in a file browser."));
|
||||||
all_actions.append(&actionViewSelectedInstFolder);
|
all_actions.append(&actionViewSelectedInstFolder);
|
||||||
|
|
||||||
actionExportInstance = TranslatedAction(MainWindow);
|
actionExportInstance = TranslatedAction(MainWindow);
|
||||||
actionExportInstance->setObjectName(QStringLiteral("actionExportInstance"));
|
actionExportInstance->setObjectName(QStringLiteral("actionExportInstance"));
|
||||||
actionExportInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "E&xport Instance..."));
|
actionExportInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "E&xport..."));
|
||||||
actionExportInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Export the selected instance as a zip file."));
|
actionExportInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Export the selected instance as a zip file."));
|
||||||
actionExportInstance->setShortcut(QKeySequence(tr("Ctrl+E")));
|
actionExportInstance->setShortcut(QKeySequence(tr("Ctrl+E")));
|
||||||
all_actions.append(&actionExportInstance);
|
all_actions.append(&actionExportInstance);
|
||||||
|
|
||||||
actionDeleteInstance = TranslatedAction(MainWindow);
|
actionDeleteInstance = TranslatedAction(MainWindow);
|
||||||
actionDeleteInstance->setObjectName(QStringLiteral("actionDeleteInstance"));
|
actionDeleteInstance->setObjectName(QStringLiteral("actionDeleteInstance"));
|
||||||
actionDeleteInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Dele&te Instance"));
|
actionDeleteInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Dele&te"));
|
||||||
actionDeleteInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Delete the selected instance."));
|
actionDeleteInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Delete the selected instance."));
|
||||||
actionDeleteInstance->setShortcuts({QKeySequence(tr("Backspace")), QKeySequence::Delete});
|
actionDeleteInstance->setShortcuts({QKeySequence(tr("Backspace")), QKeySequence::Delete});
|
||||||
actionDeleteInstance->setAutoRepeat(false);
|
actionDeleteInstance->setAutoRepeat(false);
|
||||||
@ -763,7 +715,7 @@ public:
|
|||||||
actionCopyInstance = TranslatedAction(MainWindow);
|
actionCopyInstance = TranslatedAction(MainWindow);
|
||||||
actionCopyInstance->setObjectName(QStringLiteral("actionCopyInstance"));
|
actionCopyInstance->setObjectName(QStringLiteral("actionCopyInstance"));
|
||||||
actionCopyInstance->setIcon(APPLICATION->getThemedIcon("copy"));
|
actionCopyInstance->setIcon(APPLICATION->getThemedIcon("copy"));
|
||||||
actionCopyInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Cop&y Instance..."));
|
actionCopyInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Cop&y..."));
|
||||||
actionCopyInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Copy the selected instance."));
|
actionCopyInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Copy the selected instance."));
|
||||||
actionCopyInstance->setShortcut(QKeySequence(tr("Ctrl+D")));
|
actionCopyInstance->setShortcut(QKeySequence(tr("Ctrl+D")));
|
||||||
all_actions.append(&actionCopyInstance);
|
all_actions.append(&actionCopyInstance);
|
||||||
@ -792,26 +744,15 @@ public:
|
|||||||
instanceToolBar->addSeparator();
|
instanceToolBar->addSeparator();
|
||||||
|
|
||||||
instanceToolBar->addAction(actionLaunchInstance);
|
instanceToolBar->addAction(actionLaunchInstance);
|
||||||
instanceToolBar->addAction(actionLaunchInstanceOffline);
|
|
||||||
instanceToolBar->addAction(actionKillInstance);
|
instanceToolBar->addAction(actionKillInstance);
|
||||||
|
|
||||||
instanceToolBar->addSeparator();
|
instanceToolBar->addSeparator();
|
||||||
|
|
||||||
instanceToolBar->addAction(actionEditInstance);
|
instanceToolBar->addAction(actionEditInstance);
|
||||||
instanceToolBar->addAction(actionEditInstNotes);
|
|
||||||
instanceToolBar->addAction(actionMods);
|
|
||||||
instanceToolBar->addAction(actionWorlds);
|
|
||||||
instanceToolBar->addAction(actionScreenshots);
|
|
||||||
instanceToolBar->addAction(actionChangeInstGroup);
|
instanceToolBar->addAction(actionChangeInstGroup);
|
||||||
|
|
||||||
instanceToolBar->addSeparator();
|
|
||||||
|
|
||||||
instanceToolBar->addAction(actionViewSelectedMCFolder);
|
|
||||||
instanceToolBar->addAction(actionConfig_Folder);
|
|
||||||
instanceToolBar->addAction(actionViewSelectedInstFolder);
|
instanceToolBar->addAction(actionViewSelectedInstFolder);
|
||||||
|
|
||||||
instanceToolBar->addSeparator();
|
|
||||||
|
|
||||||
instanceToolBar->addAction(actionExportInstance);
|
instanceToolBar->addAction(actionExportInstance);
|
||||||
instanceToolBar->addAction(actionDeleteInstance);
|
instanceToolBar->addAction(actionDeleteInstance);
|
||||||
instanceToolBar->addAction(actionCopyInstance);
|
instanceToolBar->addAction(actionCopyInstance);
|
||||||
@ -830,7 +771,7 @@ public:
|
|||||||
MainWindow->setWindowIcon(APPLICATION->getThemedIcon("logo"));
|
MainWindow->setWindowIcon(APPLICATION->getThemedIcon("logo"));
|
||||||
MainWindow->setWindowTitle(APPLICATION->applicationDisplayName());
|
MainWindow->setWindowTitle(APPLICATION->applicationDisplayName());
|
||||||
#ifndef QT_NO_ACCESSIBILITY
|
#ifndef QT_NO_ACCESSIBILITY
|
||||||
MainWindow->setAccessibleName(BuildConfig.LAUNCHER_NAME);
|
MainWindow->setAccessibleName(BuildConfig.LAUNCHER_DISPLAYNAME);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
createMainToolbarActions(MainWindow);
|
createMainToolbarActions(MainWindow);
|
||||||
@ -1147,7 +1088,7 @@ void MainWindow::showInstanceContextMenu(const QPoint &pos)
|
|||||||
{
|
{
|
||||||
auto group = view->groupNameAt(pos);
|
auto group = view->groupNameAt(pos);
|
||||||
|
|
||||||
QAction *actionVoid = new QAction(BuildConfig.LAUNCHER_NAME, this);
|
QAction *actionVoid = new QAction(BuildConfig.LAUNCHER_DISPLAYNAME, this);
|
||||||
actionVoid->setEnabled(false);
|
actionVoid->setEnabled(false);
|
||||||
|
|
||||||
QAction *actionCreateInstance = new QAction(tr("Create instance"), this);
|
QAction *actionCreateInstance = new QAction(tr("Create instance"), this);
|
||||||
@ -1197,7 +1138,6 @@ void MainWindow::updateMainToolBar()
|
|||||||
void MainWindow::updateToolsMenu()
|
void MainWindow::updateToolsMenu()
|
||||||
{
|
{
|
||||||
QToolButton *launchButton = dynamic_cast<QToolButton*>(ui->instanceToolBar->widgetForAction(ui->actionLaunchInstance));
|
QToolButton *launchButton = dynamic_cast<QToolButton*>(ui->instanceToolBar->widgetForAction(ui->actionLaunchInstance));
|
||||||
QToolButton *launchOfflineButton = dynamic_cast<QToolButton*>(ui->instanceToolBar->widgetForAction(ui->actionLaunchInstanceOffline));
|
|
||||||
|
|
||||||
bool currentInstanceRunning = m_selectedInstance && m_selectedInstance->isRunning();
|
bool currentInstanceRunning = m_selectedInstance && m_selectedInstance->isRunning();
|
||||||
|
|
||||||
@ -1206,9 +1146,7 @@ void MainWindow::updateToolsMenu()
|
|||||||
ui->actionLaunchInstanceDemo->setDisabled(!m_selectedInstance || currentInstanceRunning);
|
ui->actionLaunchInstanceDemo->setDisabled(!m_selectedInstance || currentInstanceRunning);
|
||||||
|
|
||||||
QMenu *launchMenu = ui->actionLaunchInstance->menu();
|
QMenu *launchMenu = ui->actionLaunchInstance->menu();
|
||||||
QMenu *launchOfflineMenu = ui->actionLaunchInstanceOffline->menu();
|
|
||||||
launchButton->setPopupMode(QToolButton::MenuButtonPopup);
|
launchButton->setPopupMode(QToolButton::MenuButtonPopup);
|
||||||
launchOfflineButton->setPopupMode(QToolButton::MenuButtonPopup);
|
|
||||||
if (launchMenu)
|
if (launchMenu)
|
||||||
{
|
{
|
||||||
launchMenu->clear();
|
launchMenu->clear();
|
||||||
@ -1217,19 +1155,12 @@ void MainWindow::updateToolsMenu()
|
|||||||
{
|
{
|
||||||
launchMenu = new QMenu(this);
|
launchMenu = new QMenu(this);
|
||||||
}
|
}
|
||||||
if (launchOfflineMenu) {
|
|
||||||
launchOfflineMenu->clear();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
launchOfflineMenu = new QMenu(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
QAction *normalLaunch = launchMenu->addAction(tr("Launch"));
|
QAction *normalLaunch = launchMenu->addAction(tr("Launch"));
|
||||||
normalLaunch->setShortcut(QKeySequence::Open);
|
normalLaunch->setShortcut(QKeySequence::Open);
|
||||||
QAction *normalLaunchOffline = launchOfflineMenu->addAction(tr("Launch Offline"));
|
QAction *normalLaunchOffline = launchMenu->addAction(tr("Launch Offline"));
|
||||||
normalLaunchOffline->setShortcut(QKeySequence(tr("Ctrl+Shift+O")));
|
normalLaunchOffline->setShortcut(QKeySequence(tr("Ctrl+Shift+O")));
|
||||||
QAction *normalLaunchDemo = launchOfflineMenu->addAction(tr("Launch Demo"));
|
QAction *normalLaunchDemo = launchMenu->addAction(tr("Launch Demo"));
|
||||||
normalLaunchDemo->setShortcut(QKeySequence(tr("Ctrl+Alt+O")));
|
normalLaunchDemo->setShortcut(QKeySequence(tr("Ctrl+Alt+O")));
|
||||||
if (m_selectedInstance)
|
if (m_selectedInstance)
|
||||||
{
|
{
|
||||||
@ -1262,11 +1193,10 @@ void MainWindow::updateToolsMenu()
|
|||||||
|
|
||||||
QString profilersTitle = tr("Profilers");
|
QString profilersTitle = tr("Profilers");
|
||||||
launchMenu->addSeparator()->setText(profilersTitle);
|
launchMenu->addSeparator()->setText(profilersTitle);
|
||||||
launchOfflineMenu->addSeparator()->setText(profilersTitle);
|
|
||||||
for (auto profiler : APPLICATION->profilers().values())
|
for (auto profiler : APPLICATION->profilers().values())
|
||||||
{
|
{
|
||||||
QAction *profilerAction = launchMenu->addAction(profiler->name());
|
QAction *profilerAction = launchMenu->addAction(profiler->name());
|
||||||
QAction *profilerOfflineAction = launchOfflineMenu->addAction(profiler->name());
|
QAction *profilerOfflineAction = launchMenu->addAction(tr("%1 Offline").arg(profiler->name()));
|
||||||
QString error;
|
QString error;
|
||||||
if (!profiler->check(&error))
|
if (!profiler->check(&error))
|
||||||
{
|
{
|
||||||
@ -1297,7 +1227,6 @@ void MainWindow::updateToolsMenu()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ui->actionLaunchInstance->setMenu(launchMenu);
|
ui->actionLaunchInstance->setMenu(launchMenu);
|
||||||
ui->actionLaunchInstanceOffline->setMenu(launchOfflineMenu);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::repopulateAccountsMenu()
|
void MainWindow::repopulateAccountsMenu()
|
||||||
@ -1903,15 +1832,6 @@ void MainWindow::on_actionViewCentralModsFolder_triggered()
|
|||||||
DesktopServices::openDirectory(APPLICATION->settings()->get("CentralModsDir").toString(), true);
|
DesktopServices::openDirectory(APPLICATION->settings()->get("CentralModsDir").toString(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_actionConfig_Folder_triggered()
|
|
||||||
{
|
|
||||||
if (m_selectedInstance)
|
|
||||||
{
|
|
||||||
QString str = m_selectedInstance->instanceConfigFolder();
|
|
||||||
DesktopServices::openDirectory(QDir(str).absolutePath());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::checkForUpdates()
|
void MainWindow::checkForUpdates()
|
||||||
{
|
{
|
||||||
if(BuildConfig.UPDATER_ENABLED)
|
if(BuildConfig.UPDATER_ENABLED)
|
||||||
@ -1940,36 +1860,16 @@ void MainWindow::globalSettingsClosed()
|
|||||||
updateToolsMenu();
|
updateToolsMenu();
|
||||||
updateStatusCenter();
|
updateStatusCenter();
|
||||||
// This needs to be done to prevent UI elements disappearing in the event the config is changed
|
// This needs to be done to prevent UI elements disappearing in the event the config is changed
|
||||||
// but PolyMC exits abnormally, causing the window state to never be saved:
|
// but Prism Launcher exits abnormally, causing the window state to never be saved:
|
||||||
APPLICATION->settings()->set("MainWindowState", saveState().toBase64());
|
APPLICATION->settings()->set("MainWindowState", saveState().toBase64());
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_actionEditInstNotes_triggered()
|
|
||||||
{
|
|
||||||
APPLICATION->showInstanceWindow(m_selectedInstance, "notes");
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::on_actionWorlds_triggered()
|
|
||||||
{
|
|
||||||
APPLICATION->showInstanceWindow(m_selectedInstance, "worlds");
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::on_actionMods_triggered()
|
|
||||||
{
|
|
||||||
APPLICATION->showInstanceWindow(m_selectedInstance, "mods");
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::on_actionEditInstance_triggered()
|
void MainWindow::on_actionEditInstance_triggered()
|
||||||
{
|
{
|
||||||
APPLICATION->showInstanceWindow(m_selectedInstance);
|
APPLICATION->showInstanceWindow(m_selectedInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_actionScreenshots_triggered()
|
|
||||||
{
|
|
||||||
APPLICATION->showInstanceWindow(m_selectedInstance, "screenshots");
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::on_actionManageAccounts_triggered()
|
void MainWindow::on_actionManageAccounts_triggered()
|
||||||
{
|
{
|
||||||
APPLICATION->ShowGlobalSettings(this, "accounts");
|
APPLICATION->ShowGlobalSettings(this, "accounts");
|
||||||
@ -1980,6 +1880,11 @@ void MainWindow::on_actionReportBug_triggered()
|
|||||||
DesktopServices::openUrl(QUrl(BuildConfig.BUG_TRACKER_URL));
|
DesktopServices::openUrl(QUrl(BuildConfig.BUG_TRACKER_URL));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionClearMetadata_triggered()
|
||||||
|
{
|
||||||
|
APPLICATION->metacache()->evictAll();
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::on_actionOpenWiki_triggered()
|
void MainWindow::on_actionOpenWiki_triggered()
|
||||||
{
|
{
|
||||||
DesktopServices::openUrl(QUrl(BuildConfig.HELP_URL.arg("")));
|
DesktopServices::openUrl(QUrl(BuildConfig.HELP_URL.arg("")));
|
||||||
@ -2058,20 +1963,6 @@ void MainWindow::on_actionViewSelectedInstFolder_triggered()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_actionViewSelectedMCFolder_triggered()
|
|
||||||
{
|
|
||||||
if (m_selectedInstance)
|
|
||||||
{
|
|
||||||
QString str = m_selectedInstance->gameRoot();
|
|
||||||
if (!FS::ensureFilePathExists(str))
|
|
||||||
{
|
|
||||||
// TODO: report error
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
DesktopServices::openDirectory(QDir(str).absolutePath());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::closeEvent(QCloseEvent *event)
|
void MainWindow::closeEvent(QCloseEvent *event)
|
||||||
{
|
{
|
||||||
// Save the window state and geometry.
|
// Save the window state and geometry.
|
||||||
@ -2252,7 +2143,7 @@ void MainWindow::checkInstancePathForProblems()
|
|||||||
"You have now two options: <br/>"
|
"You have now two options: <br/>"
|
||||||
" - change the instance folder in the settings <br/>"
|
" - change the instance folder in the settings <br/>"
|
||||||
" - move this installation of %1 to a different folder"
|
" - move this installation of %1 to a different folder"
|
||||||
).arg(BuildConfig.LAUNCHER_NAME)
|
).arg(BuildConfig.LAUNCHER_DISPLAYNAME)
|
||||||
);
|
);
|
||||||
warning.setDefaultButton(QMessageBox::Ok);
|
warning.setDefaultButton(QMessageBox::Ok);
|
||||||
warning.exec();
|
warning.exec();
|
||||||
|
@ -112,12 +112,8 @@ private slots:
|
|||||||
|
|
||||||
void on_actionViewInstanceFolder_triggered();
|
void on_actionViewInstanceFolder_triggered();
|
||||||
|
|
||||||
void on_actionConfig_Folder_triggered();
|
|
||||||
|
|
||||||
void on_actionViewSelectedInstFolder_triggered();
|
void on_actionViewSelectedInstFolder_triggered();
|
||||||
|
|
||||||
void on_actionViewSelectedMCFolder_triggered();
|
|
||||||
|
|
||||||
void refreshInstances();
|
void refreshInstances();
|
||||||
|
|
||||||
void on_actionViewCentralModsFolder_triggered();
|
void on_actionViewCentralModsFolder_triggered();
|
||||||
@ -130,6 +126,8 @@ private slots:
|
|||||||
|
|
||||||
void on_actionReportBug_triggered();
|
void on_actionReportBug_triggered();
|
||||||
|
|
||||||
|
void on_actionClearMetadata_triggered();
|
||||||
|
|
||||||
void on_actionOpenWiki_triggered();
|
void on_actionOpenWiki_triggered();
|
||||||
|
|
||||||
void on_actionMoreNews_triggered();
|
void on_actionMoreNews_triggered();
|
||||||
@ -159,14 +157,6 @@ private slots:
|
|||||||
|
|
||||||
void on_actionEditInstance_triggered();
|
void on_actionEditInstance_triggered();
|
||||||
|
|
||||||
void on_actionEditInstNotes_triggered();
|
|
||||||
|
|
||||||
void on_actionMods_triggered();
|
|
||||||
|
|
||||||
void on_actionWorlds_triggered();
|
|
||||||
|
|
||||||
void on_actionScreenshots_triggered();
|
|
||||||
|
|
||||||
void taskEnd();
|
void taskEnd();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -69,20 +69,19 @@ QString getCreditsHtml()
|
|||||||
#endif
|
#endif
|
||||||
stream << "<center>\n";
|
stream << "<center>\n";
|
||||||
|
|
||||||
//: %1 is the name of the launcher, determined at build time, e.g. "PolyMC Developers"
|
//: %1 is the name of the launcher, determined at build time, e.g. "Prism Launcher Developers"
|
||||||
stream << "<h3>" << QObject::tr("%1 Developers", "About Credits").arg(BuildConfig.LAUNCHER_NAME) << "</h3>\n";
|
stream << "<h3>" << QObject::tr("%1 Developers", "About Credits").arg(BuildConfig.LAUNCHER_DISPLAYNAME) << "</h3>\n";
|
||||||
stream << QString("<p>fn2006 %1</p>\n") .arg(getGitHub("fn2006"));
|
stream << QString("<p>fn2006 %1</p>\n") .arg(getGitHub("fn2006"));
|
||||||
stream << "<br />\n";
|
stream << "<br />\n";
|
||||||
|
|
||||||
//: %1 is the name of the launcher, determined at build time, e.g. "PolyMC Contributors"
|
//: %1 is the name of the launcher, determined at build time, e.g. "Prism Launcher Contributors"
|
||||||
stream << "<h3>" << QObject::tr("%1 Contributors", "About Credits").arg(BuildConfig.LAUNCHER_NAME) << "</h3>\n";
|
stream << "<h3>" << QObject::tr("%1 Contributors", "About Credits").arg(BuildConfig.LAUNCHER_DISPLAYNAME) << "</h3>\n";
|
||||||
stream << QString("<p>anoraktrend %1</p>\n") .arg(getGitHub("anoraktrend"));
|
stream << QString("<p>anoraktrend %1</p>\n") .arg(getGitHub("anoraktrend"));
|
||||||
stream << QString("<p>Emma Tebibyte %1</p>\n") .arg(getWebsite("https://tebibyte.media/"));
|
stream << QString("<p>Emma Tebibyte %1</p>\n") .arg(getWebsite("https://tebibyte.media/"));
|
||||||
stream << "<br />\n";
|
stream << "<br />\n";
|
||||||
|
|
||||||
//: %1 is the name of the launcher, determined at build time, e.g. "PolyMC Developers"
|
//: %1 is the name of the launcher, determined at build time, e.g. "Prism Launcher Developers"
|
||||||
stream << "<h3>" << QObject::tr("%1 Developers", "About Credits").arg("PolyMC") << "</h3>\n";
|
stream << "<h3>" << QObject::tr("%1 Developers", "About Credits").arg("Prism Launcher") << "</h3>\n";
|
||||||
stream << QString("<p>LennyMcLennington %1</p>\n") .arg(getGitHub("LennyMcLennington"));
|
|
||||||
stream << QString("<p>Sefa Eyeoglu (Scrumplex) %1</p>\n") .arg(getWebsite("https://scrumplex.net"));
|
stream << QString("<p>Sefa Eyeoglu (Scrumplex) %1</p>\n") .arg(getWebsite("https://scrumplex.net"));
|
||||||
stream << QString("<p>dada513 %1</p>\n") .arg(getGitHub("dada513"));
|
stream << QString("<p>dada513 %1</p>\n") .arg(getGitHub("dada513"));
|
||||||
stream << QString("<p>txtsd %1</p>\n") .arg(getGitHub("txtsd"));
|
stream << QString("<p>txtsd %1</p>\n") .arg(getGitHub("txtsd"));
|
||||||
@ -91,15 +90,15 @@ QString getCreditsHtml()
|
|||||||
stream << QString("<p>cozyGalvinism %1</p>\n") .arg(getGitHub("cozyGalvinism"));
|
stream << QString("<p>cozyGalvinism %1</p>\n") .arg(getGitHub("cozyGalvinism"));
|
||||||
stream << "<br />\n";
|
stream << "<br />\n";
|
||||||
|
|
||||||
//: %1 is the name of the launcher, determined at build time, e.g. "PolyMC Contributors"
|
//: %1 is the name of the launcher, determined at build time, e.g. "Prism Launcher Contributors"
|
||||||
stream << "<h3>" << QObject::tr("%1 Contributors", "About Credits").arg("PolyMC") << "</h3>\n";
|
stream << "<h3>" << QObject::tr("%1 Contributors", "About Credits").arg("Prism Launcher") << "</h3>\n";
|
||||||
stream << QString("<p>DioEgizio %1</p>\n") .arg(getGitHub("DioEgizio"));
|
stream << QString("<p>DioEgizio %1</p>\n") .arg(getGitHub("DioEgizio"));
|
||||||
stream << QString("<p>flowln %1</p>\n") .arg(getGitHub("flowln"));
|
stream << QString("<p>flowln %1</p>\n") .arg(getGitHub("flowln"));
|
||||||
stream << QString("<p>swirl %1</p>\n") .arg(getWebsite("https://swurl.xyz/"));
|
stream << QString("<p>swirl %1</p>\n") .arg(getWebsite("https://swurl.xyz/"));
|
||||||
stream << "<br />\n";
|
stream << "<br />\n";
|
||||||
|
|
||||||
// TODO: possibly retrieve from git history at build time?
|
// TODO: possibly retrieve from git history at build time?
|
||||||
//: %1 is the name of the launcher, determined at build time, e.g. "PolyMC Developers"
|
//: %1 is the name of the launcher, determined at build time, e.g. "Prism Launcher Developers"
|
||||||
stream << "<h3>" << QObject::tr("%1 Developers", "About Credits").arg("MultiMC") << "</h3>\n";
|
stream << "<h3>" << QObject::tr("%1 Developers", "About Credits").arg("MultiMC") << "</h3>\n";
|
||||||
stream << "<p>Andrew Okin <<a href='mailto:forkk@forkk.net'>forkk@forkk.net</a>></p>\n";
|
stream << "<p>Andrew Okin <<a href='mailto:forkk@forkk.net'>forkk@forkk.net</a>></p>\n";
|
||||||
stream << QString("<p>Petr Mrázek <<a href='mailto:peterix@gmail.com'>peterix@gmail.com</a>></p>\n");
|
stream << QString("<p>Petr Mrázek <<a href='mailto:peterix@gmail.com'>peterix@gmail.com</a>></p>\n");
|
||||||
@ -109,12 +108,20 @@ QString getCreditsHtml()
|
|||||||
stream << "<br />\n";
|
stream << "<br />\n";
|
||||||
|
|
||||||
stream << "<h3>" << QObject::tr("With thanks to", "About Credits") << "</h3>\n";
|
stream << "<h3>" << QObject::tr("With thanks to", "About Credits") << "</h3>\n";
|
||||||
|
stream << QString("<p>Boba %1</p>\n") .arg(getWebsite("https://cmdplusv.neocities.org/"));
|
||||||
|
stream << QString("<p>Davi Rafael %1</p>\n") .arg(getWebsite("https://auti.one/"));
|
||||||
|
stream << QString("<p>Fulmine %1</p>\n") .arg(getWebsite("https://www.fulmine.xyz/"));
|
||||||
|
stream << QString("<p>ely %1</p>\n") .arg(getGitHub("elyrodso"));
|
||||||
|
stream << QString("<p>gon sawa %1</p>\n") .arg(getGitHub("gonsawa"));
|
||||||
|
stream << QString("<p>Pankakes</p>\n");
|
||||||
|
stream << QString("<p>tobimori %1</p>\n") .arg(getGitHub("tobimori"));
|
||||||
stream << "<p>Orochimarufan <<a href='mailto:orochimarufan.x3@gmail.com'>orochimarufan.x3@gmail.com</a>></p>\n";
|
stream << "<p>Orochimarufan <<a href='mailto:orochimarufan.x3@gmail.com'>orochimarufan.x3@gmail.com</a>></p>\n";
|
||||||
stream << "<p>TakSuyu <<a href='mailto:taksuyu@gmail.com'>taksuyu@gmail.com</a>></p>\n";
|
stream << "<p>TakSuyu <<a href='mailto:taksuyu@gmail.com'>taksuyu@gmail.com</a>></p>\n";
|
||||||
stream << "<p>Kilobyte <<a href='mailto:stiepen22@gmx.de'>stiepen22@gmx.de</a>></p>\n";
|
stream << "<p>Kilobyte <<a href='mailto:stiepen22@gmx.de'>stiepen22@gmx.de</a>></p>\n";
|
||||||
stream << "<p>Rootbear75 <<a href='https://twitter.com/rootbear75'>@rootbear75</a>></p>\n";
|
stream << "<p>Rootbear75 <<a href='https://twitter.com/rootbear75'>@rootbear75</a>></p>\n";
|
||||||
stream << "<p>Zeker Zhayard <<a href='https://twitter.com/zeker_zhayard'>@Zeker_Zhayard</a>></p>\n";
|
stream << "<p>Zeker Zhayard <<a href='https://twitter.com/zeker_zhayard'>@Zeker_Zhayard</a>></p>\n";
|
||||||
stream << "<p>Everyone else who <a href='https://github.com/PolyMC/PolyMC/graphs/contributors'>contributed</a>!</p>\n";
|
stream << "<p>Everyone who helped establish our branding!</p>\n";
|
||||||
|
stream << "<p>And everyone else who <a href='https://github.com/PrismLauncher/PrismLauncher/graphs/contributors'>contributed</a>!</p>\n";
|
||||||
stream << "<br />\n";
|
stream << "<br />\n";
|
||||||
|
|
||||||
stream << "</center>\n";
|
stream << "</center>\n";
|
||||||
@ -136,7 +143,7 @@ AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent), ui(new Ui::AboutDia
|
|||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
QString launcherName = BuildConfig.LAUNCHER_NAME;
|
QString launcherName = BuildConfig.LAUNCHER_DISPLAYNAME;
|
||||||
|
|
||||||
setWindowTitle(tr("About %1").arg(launcherName));
|
setWindowTitle(tr("About %1").arg(launcherName));
|
||||||
|
|
||||||
|
@ -139,6 +139,10 @@ NewInstanceDialog::NewInstanceDialog(const QString & initialGroup, const QString
|
|||||||
void NewInstanceDialog::reject()
|
void NewInstanceDialog::reject()
|
||||||
{
|
{
|
||||||
APPLICATION->settings()->set("NewInstanceGeometry", saveGeometry().toBase64());
|
APPLICATION->settings()->set("NewInstanceGeometry", saveGeometry().toBase64());
|
||||||
|
|
||||||
|
// This is just so that the pages get the close() call and can react to it, if needed.
|
||||||
|
m_container->prepareToClose();
|
||||||
|
|
||||||
QDialog::reject();
|
QDialog::reject();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,6 +150,10 @@ void NewInstanceDialog::accept()
|
|||||||
{
|
{
|
||||||
APPLICATION->settings()->set("NewInstanceGeometry", saveGeometry().toBase64());
|
APPLICATION->settings()->set("NewInstanceGeometry", saveGeometry().toBase64());
|
||||||
importIconNow();
|
importIconNow();
|
||||||
|
|
||||||
|
// This is just so that the pages get the close() call and can react to it, if needed.
|
||||||
|
m_container->prepareToClose();
|
||||||
|
|
||||||
QDialog::accept();
|
QDialog::accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,9 @@ NewsDialog::NewsDialog(QList<NewsEntryPtr> entries, QWidget* parent) : QDialog(p
|
|||||||
|
|
||||||
auto article_entry = m_entries.constFind(first_item->text()).value();
|
auto article_entry = m_entries.constFind(first_item->text()).value();
|
||||||
ui->articleTitleLabel->setText(QString("<a href='%1'>%2</a>").arg(article_entry->link, first_item->text()));
|
ui->articleTitleLabel->setText(QString("<a href='%1'>%2</a>").arg(article_entry->link, first_item->text()));
|
||||||
|
|
||||||
ui->currentArticleContentBrowser->setText(article_entry->content);
|
ui->currentArticleContentBrowser->setText(article_entry->content);
|
||||||
|
ui->currentArticleContentBrowser->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
NewsDialog::~NewsDialog()
|
NewsDialog::~NewsDialog()
|
||||||
@ -33,7 +35,9 @@ void NewsDialog::selectedArticleChanged(const QString& new_title)
|
|||||||
auto const& article_entry = m_entries.constFind(new_title).value();
|
auto const& article_entry = m_entries.constFind(new_title).value();
|
||||||
|
|
||||||
ui->articleTitleLabel->setText(QString("<a href='%1'>%2</a>").arg(article_entry->link, new_title));
|
ui->articleTitleLabel->setText(QString("<a href='%1'>%2</a>").arg(article_entry->link, new_title));
|
||||||
|
|
||||||
ui->currentArticleContentBrowser->setText(article_entry->content);
|
ui->currentArticleContentBrowser->setText(article_entry->content);
|
||||||
|
ui->currentArticleContentBrowser->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NewsDialog::toggleArticleList()
|
void NewsDialog::toggleArticleList()
|
||||||
|
@ -49,7 +49,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QTextBrowser" name="currentArticleContentBrowser">
|
<widget class="ProjectDescriptionPage" name="currentArticleContentBrowser">
|
||||||
<property name="textInteractionFlags">
|
<property name="textInteractionFlags">
|
||||||
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||||
</property>
|
</property>
|
||||||
@ -91,6 +91,13 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>ProjectDescriptionPage</class>
|
||||||
|
<extends>QTextBrowser</extends>
|
||||||
|
<header>ui/widgets/ProjectDescriptionPage.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections>
|
<connections>
|
||||||
<connection>
|
<connection>
|
||||||
|
@ -25,6 +25,7 @@ ProgressDialog::ProgressDialog(QWidget* parent) : QDialog(parent), ui(new Ui::Pr
|
|||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
this->setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
this->setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||||
|
setAttribute(Qt::WidgetAttribute::WA_QuitOnClose, true);
|
||||||
setSkipButton(false);
|
setSkipButton(false);
|
||||||
changeProgress(0, 100);
|
changeProgress(0, 100);
|
||||||
}
|
}
|
||||||
@ -67,7 +68,7 @@ int ProgressDialog::execWithTask(Task* task)
|
|||||||
return QDialog::DialogCode::Accepted;
|
return QDialog::DialogCode::Accepted;
|
||||||
}
|
}
|
||||||
|
|
||||||
QDialog::DialogCode result;
|
QDialog::DialogCode result {};
|
||||||
if (handleImmediateResult(result)) {
|
if (handleImmediateResult(result)) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -80,7 +81,7 @@ int ProgressDialog::execWithTask(Task* task)
|
|||||||
connect(task, &Task::stepStatus, this, &ProgressDialog::changeStatus);
|
connect(task, &Task::stepStatus, this, &ProgressDialog::changeStatus);
|
||||||
connect(task, &Task::progress, this, &ProgressDialog::changeProgress);
|
connect(task, &Task::progress, this, &ProgressDialog::changeProgress);
|
||||||
|
|
||||||
connect(task, &Task::aborted, [this] { QDialog::reject(); });
|
connect(task, &Task::aborted, this, &ProgressDialog::hide);
|
||||||
connect(task, &Task::abortStatusChanged, ui->skipButton, &QPushButton::setEnabled);
|
connect(task, &Task::abortStatusChanged, ui->skipButton, &QPushButton::setEnabled);
|
||||||
|
|
||||||
m_is_multi_step = task->isMultiStep();
|
m_is_multi_step = task->isMultiStep();
|
||||||
|
@ -73,12 +73,12 @@ void UpdateDialog::loadChangelog()
|
|||||||
QString url;
|
QString url;
|
||||||
if(channel == "stable")
|
if(channel == "stable")
|
||||||
{
|
{
|
||||||
url = QString("https://raw.githubusercontent.com/PolyMC/PolyMC/%1/changelog.md").arg(channel);
|
url = QString("https://raw.githubusercontent.com/PrismLauncher/PrismLauncher/%1/changelog.md").arg(channel);
|
||||||
m_changelogType = CHANGELOG_MARKDOWN;
|
m_changelogType = CHANGELOG_MARKDOWN;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
url = QString("https://api.github.com/repos/PolyMC/PolyMC/compare/%1...%2").arg(BuildConfig.GIT_COMMIT, channel);
|
url = QString("https://api.github.com/repos/PrismLauncher/PrismLauncher/compare/%1...%2").arg(BuildConfig.GIT_COMMIT, channel);
|
||||||
m_changelogType = CHANGELOG_COMMITS;
|
m_changelogType = CHANGELOG_COMMITS;
|
||||||
}
|
}
|
||||||
dljob->addNetAction(Net::Download::makeByteArray(QUrl(url), &changelogData));
|
dljob->addNetAction(Net::Download::makeByteArray(QUrl(url), &changelogData));
|
||||||
@ -93,7 +93,7 @@ QString reprocessMarkdown(QByteArray markdown)
|
|||||||
QString output = hoedown.process(markdown);
|
QString output = hoedown.process(markdown);
|
||||||
|
|
||||||
// HACK: easier than customizing hoedown
|
// HACK: easier than customizing hoedown
|
||||||
output.replace(QRegularExpression("GH-([0-9]+)"), "<a href=\"https://github.com/PolyMC/PolyMC/issues/\\1\">GH-\\1</a>");
|
output.replace(QRegularExpression("GH-([0-9]+)"), "<a href=\"https://github.com/PrismLauncher/PrismLauncher/issues/\\1\">GH-\\1</a>");
|
||||||
qDebug() << output;
|
qDebug() << output;
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
@ -135,7 +135,7 @@ QString reprocessCommits(QByteArray json)
|
|||||||
result += "<tr><td>";
|
result += "<tr><td>";
|
||||||
if(issuenr.length())
|
if(issuenr.length())
|
||||||
{
|
{
|
||||||
result += QString("<a href=\"https://github.com/PolyMC/PolyMC/issues/%1\">GH-%2</a>").arg(issuenr, issuenr);
|
result += QString("<a href=\"https://github.com/PrismLauncher/PrismLauncher/issues/%1\">GH-%2</a>").arg(issuenr, issuenr);
|
||||||
}
|
}
|
||||||
else if(prefix.length())
|
else if(prefix.length())
|
||||||
{
|
{
|
||||||
|
@ -168,7 +168,7 @@ void AccountListPage::on_actionAddMicrosoft_triggered()
|
|||||||
tr(
|
tr(
|
||||||
"Microsoft accounts are only usable on macOS 10.13 or newer, with fully updated %1.\n\n"
|
"Microsoft accounts are only usable on macOS 10.13 or newer, with fully updated %1.\n\n"
|
||||||
"Please update both your operating system and %1."
|
"Please update both your operating system and %1."
|
||||||
).arg(BuildConfig.LAUNCHER_NAME),
|
).arg(BuildConfig.LAUNCHER_DISPLAYNAME),
|
||||||
QMessageBox::Warning
|
QMessageBox::Warning
|
||||||
)->exec();
|
)->exec();
|
||||||
return;
|
return;
|
||||||
|
@ -151,7 +151,7 @@ void LauncherPage::on_instDirBrowseBtn_clicked()
|
|||||||
"This is known to cause problems. "
|
"This is known to cause problems. "
|
||||||
"After a restart the launcher might break, "
|
"After a restart the launcher might break, "
|
||||||
"because it will no longer have access to that directory.\n\n"
|
"because it will no longer have access to that directory.\n\n"
|
||||||
"Granting PolyMC access to it via Flatseal is recommended."));
|
"Granting %1 access to it via Flatseal is recommended.").arg(BuildConfig.LAUNCHER_DISPLAYNAME));
|
||||||
warning.setInformativeText(
|
warning.setInformativeText(
|
||||||
tr("Do you want to proceed anyway?"));
|
tr("Do you want to proceed anyway?"));
|
||||||
warning.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
|
warning.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
|
||||||
|
@ -176,7 +176,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="metadataWarningLabel">
|
<widget class="QLabel" name="metadataWarningLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string><html><head/><body><p><span style=" font-weight:600; color:#f5c211;">Warning</span><span style=" color:#f5c211;">: Disabling mod metadata may also disable some upcoming QoL features, such as mod updating!</span></p></body></html></string>
|
<string><html><head/><body><p><span style=" font-weight:600; color:#f5c211;">Warning</span><span style=" color:#f5c211;">: Disabling mod metadata may also disable some QoL features, such as mod updating!</span></p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="wordWrap">
|
<property name="wordWrap">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
|
@ -103,10 +103,6 @@ void ExternalResourcesPage::runningStateChanged(bool running)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
m_controlsEnabled = !running;
|
m_controlsEnabled = !running;
|
||||||
ui->actionAddItem->setEnabled(m_controlsEnabled);
|
|
||||||
ui->actionDisableItem->setEnabled(m_controlsEnabled);
|
|
||||||
ui->actionEnableItem->setEnabled(m_controlsEnabled);
|
|
||||||
ui->actionRemoveItem->setEnabled(m_controlsEnabled);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExternalResourcesPage::shouldDisplay() const
|
bool ExternalResourcesPage::shouldDisplay() const
|
||||||
|
@ -274,6 +274,9 @@ void InstanceSettingsPage::applySettings()
|
|||||||
{
|
{
|
||||||
m_settings->reset("JoinServerOnLaunchAddress");
|
m_settings->reset("JoinServerOnLaunchAddress");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: This should probably be called by a signal instead
|
||||||
|
m_instance->updateRuntimeContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceSettingsPage::loadSettings()
|
void InstanceSettingsPage::loadSettings()
|
||||||
|
@ -279,7 +279,7 @@ void LogPage::on_btnPaste_clicked()
|
|||||||
MessageLevel::Launcher,
|
MessageLevel::Launcher,
|
||||||
QString("%2: Log upload triggered at: %1").arg(
|
QString("%2: Log upload triggered at: %1").arg(
|
||||||
QDateTime::currentDateTime().toString(Qt::RFC2822Date),
|
QDateTime::currentDateTime().toString(Qt::RFC2822Date),
|
||||||
BuildConfig.LAUNCHER_NAME
|
BuildConfig.LAUNCHER_DISPLAYNAME
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
auto url = GuiUtil::uploadPaste(m_model->toPlainText(), this);
|
auto url = GuiUtil::uploadPaste(m_model->toPlainText(), this);
|
||||||
@ -289,7 +289,7 @@ void LogPage::on_btnPaste_clicked()
|
|||||||
MessageLevel::Launcher,
|
MessageLevel::Launcher,
|
||||||
QString("%2: Log uploaded to: %1").arg(
|
QString("%2: Log uploaded to: %1").arg(
|
||||||
url,
|
url,
|
||||||
BuildConfig.LAUNCHER_NAME
|
BuildConfig.LAUNCHER_DISPLAYNAME
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -297,7 +297,7 @@ void LogPage::on_btnPaste_clicked()
|
|||||||
{
|
{
|
||||||
m_model->append(
|
m_model->append(
|
||||||
MessageLevel::Error,
|
MessageLevel::Error,
|
||||||
QString("%1: Log upload failed!").arg(BuildConfig.LAUNCHER_NAME)
|
QString("%1: Log upload failed!").arg(BuildConfig.LAUNCHER_DISPLAYNAME)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,6 +117,10 @@ void ModFolderPage::runningStateChanged(bool running)
|
|||||||
ExternalResourcesPage::runningStateChanged(running);
|
ExternalResourcesPage::runningStateChanged(running);
|
||||||
ui->actionDownloadItem->setEnabled(!running);
|
ui->actionDownloadItem->setEnabled(!running);
|
||||||
ui->actionUpdateItem->setEnabled(!running);
|
ui->actionUpdateItem->setEnabled(!running);
|
||||||
|
ui->actionAddItem->setEnabled(!running);
|
||||||
|
ui->actionEnableItem->setEnabled(!running);
|
||||||
|
ui->actionDisableItem->setEnabled(!running);
|
||||||
|
ui->actionRemoveItem->setEnabled(!running);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModFolderPage::shouldDisplay() const
|
bool ModFolderPage::shouldDisplay() const
|
||||||
|
@ -60,7 +60,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label_2">
|
<widget class="QLabel" name="label_2">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>- PolyMC / MultiMC exported instances (ZIP)</string>
|
<string>- Prism Launcher, PolyMC or MultiMC exported instances (ZIP)</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="alignment">
|
<property name="alignment">
|
||||||
<set>Qt::AlignCenter</set>
|
<set>Qt::AlignCenter</set>
|
||||||
|
@ -62,11 +62,7 @@ auto ListModel::data(const QModelIndex& index, int role) const -> QVariant
|
|||||||
}
|
}
|
||||||
case Qt::DecorationRole: {
|
case Qt::DecorationRole: {
|
||||||
if (m_logoMap.contains(pack.logoName)) {
|
if (m_logoMap.contains(pack.logoName)) {
|
||||||
auto icon = m_logoMap.value(pack.logoName);
|
return m_logoMap.value(pack.logoName);
|
||||||
// FIXME: This doesn't really belong here, but Qt doesn't offer a good way right now ;(
|
|
||||||
auto icon_scaled = QIcon(icon.pixmap(48, 48).scaledToWidth(48));
|
|
||||||
|
|
||||||
return icon_scaled;
|
|
||||||
}
|
}
|
||||||
QIcon icon = APPLICATION->getThemedIcon("screenshot-placeholder");
|
QIcon icon = APPLICATION->getThemedIcon("screenshot-placeholder");
|
||||||
// un-const-ify this
|
// un-const-ify this
|
||||||
@ -175,7 +171,7 @@ void ListModel::getLogo(const QString& logo, const QString& logoUrl, LogoCallbac
|
|||||||
|
|
||||||
void ListModel::requestLogo(QString logo, QString url)
|
void ListModel::requestLogo(QString logo, QString url)
|
||||||
{
|
{
|
||||||
if (m_loadingLogos.contains(logo) || m_failedLogos.contains(logo)) {
|
if (m_loadingLogos.contains(logo) || m_failedLogos.contains(logo) || url.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,7 +265,7 @@ void ListModel::searchRequestFailed(QString reason)
|
|||||||
//: %1 refers to the launcher itself
|
//: %1 refers to the launcher itself
|
||||||
QString("%1 %2")
|
QString("%1 %2")
|
||||||
.arg(m_parent->displayName())
|
.arg(m_parent->displayName())
|
||||||
.arg(tr("API version too old!\nPlease update %1!").arg(BuildConfig.LAUNCHER_NAME)));
|
.arg(tr("API version too old!\nPlease update %1!").arg(BuildConfig.LAUNCHER_DISPLAYNAME)));
|
||||||
}
|
}
|
||||||
jobPtr.reset();
|
jobPtr.reset();
|
||||||
|
|
||||||
|
@ -265,7 +265,9 @@ void ModPage::updateModVersions(int prev_count)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(valid || m_filter->versions.size() == 0)
|
|
||||||
|
// Only add the version if it's valid or using the 'Any' filter, but never if the version is opted out
|
||||||
|
if ((valid || m_filter->versions.empty()) && !optedOut(version))
|
||||||
ui->versionSelectionBox->addItem(version.version, QVariant(i));
|
ui->versionSelectionBox->addItem(version.version, QVariant(i));
|
||||||
}
|
}
|
||||||
if (ui->versionSelectionBox->count() == 0 && prev_count != 0) {
|
if (ui->versionSelectionBox->count() == 0 && prev_count != 0) {
|
||||||
@ -350,4 +352,5 @@ void ModPage::updateUi()
|
|||||||
|
|
||||||
HoeDown h;
|
HoeDown h;
|
||||||
ui->packDescription->setHtml(text + (current.extraData.body.isEmpty() ? current.description : h.process(current.extraData.body.toUtf8())));
|
ui->packDescription->setHtml(text + (current.extraData.body.isEmpty() ? current.description : h.process(current.extraData.body.toUtf8())));
|
||||||
|
ui->packDescription->flush();
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,7 @@ class ModPage : public QWidget, public BasePage {
|
|||||||
|
|
||||||
auto shouldDisplay() const -> bool override = 0;
|
auto shouldDisplay() const -> bool override = 0;
|
||||||
virtual auto validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, ModAPI::ModLoaderTypes loaders = ModAPI::Unspecified) const -> bool = 0;
|
virtual auto validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, ModAPI::ModLoaderTypes loaders = ModAPI::Unspecified) const -> bool = 0;
|
||||||
|
virtual bool optedOut(ModPlatform::IndexedVersion& ver) const { return false; };
|
||||||
|
|
||||||
auto apiProvider() -> ModAPI* { return api.get(); };
|
auto apiProvider() -> ModAPI* { return api.get(); };
|
||||||
auto getFilter() const -> const std::shared_ptr<ModFilterWidget::Filter> { return m_filter; }
|
auto getFilter() const -> const std::shared_ptr<ModFilterWidget::Filter> { return m_filter; }
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
<item row="1" column="0" colspan="4">
|
<item row="1" column="0" colspan="4">
|
||||||
<layout class="QGridLayout" name="gridLayout_3">
|
<layout class="QGridLayout" name="gridLayout_3">
|
||||||
<item row="1" column="2">
|
<item row="1" column="2">
|
||||||
<widget class="QTextBrowser" name="packDescription">
|
<widget class="ProjectDescriptionPage" name="packDescription">
|
||||||
<property name="openExternalLinks">
|
<property name="openExternalLinks">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
@ -98,6 +98,13 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>ProjectDescriptionPage</class>
|
||||||
|
<extends>QTextBrowser</extends>
|
||||||
|
<header>ui/widgets/ProjectDescriptionPage.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>searchEdit</tabstop>
|
<tabstop>searchEdit</tabstop>
|
||||||
<tabstop>searchButton</tabstop>
|
<tabstop>searchButton</tabstop>
|
||||||
|
@ -59,6 +59,8 @@ FlameModPage::FlameModPage(ModDownloadDialog* dialog, BaseInstance* instance)
|
|||||||
connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &FlameModPage::onSelectionChanged);
|
connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &FlameModPage::onSelectionChanged);
|
||||||
connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &FlameModPage::onVersionSelectionChanged);
|
connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &FlameModPage::onVersionSelectionChanged);
|
||||||
connect(ui->modSelectionButton, &QPushButton::clicked, this, &FlameModPage::onModSelected);
|
connect(ui->modSelectionButton, &QPushButton::clicked, this, &FlameModPage::onModSelected);
|
||||||
|
|
||||||
|
ui->packDescription->setMetaEntry(metaEntryBase());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto FlameModPage::validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, ModAPI::ModLoaderTypes loaders) const -> bool
|
auto FlameModPage::validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, ModAPI::ModLoaderTypes loaders) const -> bool
|
||||||
@ -67,6 +69,11 @@ auto FlameModPage::validateVersion(ModPlatform::IndexedVersion& ver, QString min
|
|||||||
return ver.mcVersion.contains(mineVer) && !ver.downloadUrl.isEmpty();
|
return ver.mcVersion.contains(mineVer) && !ver.downloadUrl.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FlameModPage::optedOut(ModPlatform::IndexedVersion& ver) const
|
||||||
|
{
|
||||||
|
return ver.downloadUrl.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
// I don't know why, but doing this on the parent class makes it so that
|
// I don't know why, but doing this on the parent class makes it so that
|
||||||
// other mod providers start loading before being selected, at least with
|
// other mod providers start loading before being selected, at least with
|
||||||
// my Qt, so we need to implement this in every derived class...
|
// my Qt, so we need to implement this in every derived class...
|
||||||
|
@ -61,6 +61,7 @@ class FlameModPage : public ModPage {
|
|||||||
inline auto metaEntryBase() const -> QString override { return "FlameMods"; };
|
inline auto metaEntryBase() const -> QString override { return "FlameMods"; };
|
||||||
|
|
||||||
auto validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, ModAPI::ModLoaderTypes loaders = ModAPI::Unspecified) const -> bool override;
|
auto validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, ModAPI::ModLoaderTypes loaders = ModAPI::Unspecified) const -> bool override;
|
||||||
|
bool optedOut(ModPlatform::IndexedVersion& ver) const override;
|
||||||
|
|
||||||
auto shouldDisplay() const -> bool override;
|
auto shouldDisplay() const -> bool override;
|
||||||
};
|
};
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
</font>
|
</font>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Note: CurseForge allows creators to block access to third-party tools like PolyMC. As such, you may need to manually download some mods to be able to install a modpack.</string>
|
<string>Note: CurseForge allows creators to block access to third-party tools like Prism Launcher. As such, you may need to manually download some mods to be able to install a modpack.</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="alignment">
|
<property name="alignment">
|
||||||
<set>Qt::AlignCenter</set>
|
<set>Qt::AlignCenter</set>
|
||||||
|
@ -103,6 +103,8 @@ void ListModel::getLogo(const QString &logo, const QString &logoUrl, LogoCallbac
|
|||||||
|
|
||||||
void ListModel::request()
|
void ListModel::request()
|
||||||
{
|
{
|
||||||
|
m_aborted = false;
|
||||||
|
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
modpacks.clear();
|
modpacks.clear();
|
||||||
endResetModel();
|
endResetModel();
|
||||||
@ -117,6 +119,12 @@ void ListModel::request()
|
|||||||
QObject::connect(netJob, &NetJob::failed, this, &ListModel::requestFailed);
|
QObject::connect(netJob, &NetJob::failed, this, &ListModel::requestFailed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ListModel::abortRequest()
|
||||||
|
{
|
||||||
|
m_aborted = jobPtr->abort();
|
||||||
|
jobPtr.reset();
|
||||||
|
}
|
||||||
|
|
||||||
void ListModel::requestFinished()
|
void ListModel::requestFinished()
|
||||||
{
|
{
|
||||||
jobPtr.reset();
|
jobPtr.reset();
|
||||||
@ -162,6 +170,9 @@ void ListModel::requestPack()
|
|||||||
|
|
||||||
void ListModel::packRequestFinished()
|
void ListModel::packRequestFinished()
|
||||||
{
|
{
|
||||||
|
if (!jobPtr || m_aborted)
|
||||||
|
return;
|
||||||
|
|
||||||
jobPtr.reset();
|
jobPtr.reset();
|
||||||
remainingPacks.removeOne(currentPack);
|
remainingPacks.removeOne(currentPack);
|
||||||
|
|
||||||
|
@ -47,9 +47,13 @@ public:
|
|||||||
QVariant data(const QModelIndex &index, int role) const override;
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
|
|
||||||
void request();
|
void request();
|
||||||
|
void abortRequest();
|
||||||
|
|
||||||
void getLogo(const QString &logo, const QString &logoUrl, LogoCallback callback);
|
void getLogo(const QString &logo, const QString &logoUrl, LogoCallback callback);
|
||||||
|
|
||||||
|
[[nodiscard]] bool isMakingRequest() const { return jobPtr.get(); }
|
||||||
|
[[nodiscard]] bool wasAborted() const { return m_aborted; }
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void requestFinished();
|
void requestFinished();
|
||||||
void requestFailed(QString reason);
|
void requestFailed(QString reason);
|
||||||
@ -65,6 +69,8 @@ private:
|
|||||||
void requestLogo(QString file, QString url);
|
void requestLogo(QString file, QString url);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool m_aborted = false;
|
||||||
|
|
||||||
QList<ModpacksCH::Modpack> modpacks;
|
QList<ModpacksCH::Modpack> modpacks;
|
||||||
LogoMap m_logoMap;
|
LogoMap m_logoMap;
|
||||||
|
|
||||||
|
@ -73,6 +73,8 @@ FtbPage::FtbPage(NewInstanceDialog* dialog, QWidget *parent)
|
|||||||
connect(ui->sortByBox, &QComboBox::currentTextChanged, this, &FtbPage::onSortingSelectionChanged);
|
connect(ui->sortByBox, &QComboBox::currentTextChanged, this, &FtbPage::onSortingSelectionChanged);
|
||||||
connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &FtbPage::onSelectionChanged);
|
connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &FtbPage::onSelectionChanged);
|
||||||
connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &FtbPage::onVersionSelectionChanged);
|
connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &FtbPage::onVersionSelectionChanged);
|
||||||
|
|
||||||
|
ui->packDescription->setMetaEntry("FTBPacks");
|
||||||
}
|
}
|
||||||
|
|
||||||
FtbPage::~FtbPage()
|
FtbPage::~FtbPage()
|
||||||
@ -105,7 +107,7 @@ void FtbPage::retranslate()
|
|||||||
|
|
||||||
void FtbPage::openedImpl()
|
void FtbPage::openedImpl()
|
||||||
{
|
{
|
||||||
if(!initialised)
|
if(!initialised || listModel->wasAborted())
|
||||||
{
|
{
|
||||||
listModel->request();
|
listModel->request();
|
||||||
initialised = true;
|
initialised = true;
|
||||||
@ -114,6 +116,12 @@ void FtbPage::openedImpl()
|
|||||||
suggestCurrent();
|
suggestCurrent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FtbPage::closedImpl()
|
||||||
|
{
|
||||||
|
if (listModel->isMakingRequest())
|
||||||
|
listModel->abortRequest();
|
||||||
|
}
|
||||||
|
|
||||||
void FtbPage::suggestCurrent()
|
void FtbPage::suggestCurrent()
|
||||||
{
|
{
|
||||||
if(!isOpened)
|
if(!isOpened)
|
||||||
|
@ -78,6 +78,7 @@ public:
|
|||||||
void retranslate() override;
|
void retranslate() override;
|
||||||
|
|
||||||
void openedImpl() override;
|
void openedImpl() override;
|
||||||
|
void closedImpl() override;
|
||||||
|
|
||||||
bool eventFilter(QObject * watched, QEvent * event) override;
|
bool eventFilter(QObject * watched, QEvent * event) override;
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="QTextBrowser" name="packDescription">
|
<widget class="ProjectDescriptionPage" name="packDescription">
|
||||||
<property name="openExternalLinks">
|
<property name="openExternalLinks">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
@ -70,6 +70,13 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>ProjectDescriptionPage</class>
|
||||||
|
<extends>QTextBrowser</extends>
|
||||||
|
<header>ui/widgets/ProjectDescriptionPage.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>searchEdit</tabstop>
|
<tabstop>searchEdit</tabstop>
|
||||||
<tabstop>versionSelectionBox</tabstop>
|
<tabstop>versionSelectionBox</tabstop>
|
||||||
|
@ -59,6 +59,8 @@ ModrinthModPage::ModrinthModPage(ModDownloadDialog* dialog, BaseInstance* instan
|
|||||||
connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &ModrinthModPage::onSelectionChanged);
|
connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &ModrinthModPage::onSelectionChanged);
|
||||||
connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &ModrinthModPage::onVersionSelectionChanged);
|
connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &ModrinthModPage::onVersionSelectionChanged);
|
||||||
connect(ui->modSelectionButton, &QPushButton::clicked, this, &ModrinthModPage::onModSelected);
|
connect(ui->modSelectionButton, &QPushButton::clicked, this, &ModrinthModPage::onModSelected);
|
||||||
|
|
||||||
|
ui->packDescription->setMetaEntry(metaEntryBase());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ModrinthModPage::validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, ModAPI::ModLoaderTypes loaders) const -> bool
|
auto ModrinthModPage::validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, ModAPI::ModLoaderTypes loaders) const -> bool
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
#include "minecraft/MinecraftInstance.h"
|
#include "minecraft/MinecraftInstance.h"
|
||||||
#include "minecraft/PackProfile.h"
|
#include "minecraft/PackProfile.h"
|
||||||
#include "ui/dialogs/ModDownloadDialog.h"
|
#include "ui/dialogs/ModDownloadDialog.h"
|
||||||
|
#include "ui/widgets/ProjectItem.h"
|
||||||
|
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
@ -74,31 +75,40 @@ auto ModpackListModel::data(const QModelIndex& index, int role) const -> QVarian
|
|||||||
}
|
}
|
||||||
|
|
||||||
Modrinth::Modpack pack = modpacks.at(pos);
|
Modrinth::Modpack pack = modpacks.at(pos);
|
||||||
if (role == Qt::DisplayRole) {
|
switch (role) {
|
||||||
return pack.name;
|
case Qt::ToolTipRole: {
|
||||||
} else if (role == Qt::ToolTipRole) {
|
if (pack.description.length() > 100) {
|
||||||
if (pack.description.length() > 100) {
|
// some magic to prevent to long tooltips and replace html linebreaks
|
||||||
// some magic to prevent to long tooltips and replace html linebreaks
|
QString edit = pack.description.left(97);
|
||||||
QString edit = pack.description.left(97);
|
edit = edit.left(edit.lastIndexOf("<br>")).left(edit.lastIndexOf(" ")).append("...");
|
||||||
edit = edit.left(edit.lastIndexOf("<br>")).left(edit.lastIndexOf(" ")).append("...");
|
return edit;
|
||||||
return edit;
|
}
|
||||||
|
return pack.description;
|
||||||
}
|
}
|
||||||
return pack.description;
|
case Qt::DecorationRole: {
|
||||||
} else if (role == Qt::DecorationRole) {
|
if (m_logoMap.contains(pack.iconName))
|
||||||
if (m_logoMap.contains(pack.iconName)) {
|
return m_logoMap.value(pack.iconName);
|
||||||
auto icon = m_logoMap.value(pack.iconName);
|
|
||||||
// FIXME: This doesn't really belong here, but Qt doesn't offer a good way right now ;(
|
|
||||||
auto icon_scaled = QIcon(icon.pixmap(48, 48).scaledToWidth(48));
|
|
||||||
|
|
||||||
return icon_scaled;
|
QIcon icon = APPLICATION->getThemedIcon("screenshot-placeholder");
|
||||||
|
((ModpackListModel*)this)->requestLogo(pack.iconName, pack.iconUrl.toString());
|
||||||
|
return icon;
|
||||||
}
|
}
|
||||||
QIcon icon = APPLICATION->getThemedIcon("screenshot-placeholder");
|
case Qt::UserRole: {
|
||||||
((ModpackListModel*)this)->requestLogo(pack.iconName, pack.iconUrl.toString());
|
QVariant v;
|
||||||
return icon;
|
v.setValue(pack);
|
||||||
} else if (role == Qt::UserRole) {
|
return v;
|
||||||
QVariant v;
|
}
|
||||||
v.setValue(pack);
|
case Qt::SizeHintRole:
|
||||||
return v;
|
return QSize(0, 58);
|
||||||
|
// Custom data
|
||||||
|
case UserDataTypes::TITLE:
|
||||||
|
return pack.name;
|
||||||
|
case UserDataTypes::DESCRIPTION:
|
||||||
|
return pack.description;
|
||||||
|
case UserDataTypes::SELECTED:
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
@ -208,7 +218,7 @@ void ModpackListModel::getLogo(const QString& logo, const QString& logoUrl, Logo
|
|||||||
{
|
{
|
||||||
if (m_logoMap.contains(logo)) {
|
if (m_logoMap.contains(logo)) {
|
||||||
callback(APPLICATION->metacache()
|
callback(APPLICATION->metacache()
|
||||||
->resolveEntry("ModrinthPacks", QString("logos/%1").arg(logo.section(".", 0, 0)))
|
->resolveEntry(m_parent->metaEntryBase(), QString("logos/%1").arg(logo.section(".", 0, 0)))
|
||||||
->getFullPath());
|
->getFullPath());
|
||||||
} else {
|
} else {
|
||||||
requestLogo(logo, logoUrl);
|
requestLogo(logo, logoUrl);
|
||||||
@ -217,12 +227,12 @@ void ModpackListModel::getLogo(const QString& logo, const QString& logoUrl, Logo
|
|||||||
|
|
||||||
void ModpackListModel::requestLogo(QString logo, QString url)
|
void ModpackListModel::requestLogo(QString logo, QString url)
|
||||||
{
|
{
|
||||||
if (m_loadingLogos.contains(logo) || m_failedLogos.contains(logo)) {
|
if (m_loadingLogos.contains(logo) || m_failedLogos.contains(logo) || url.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaEntryPtr entry =
|
MetaEntryPtr entry =
|
||||||
APPLICATION->metacache()->resolveEntry("ModrinthPacks", QString("logos/%1").arg(logo.section(".", 0, 0)));
|
APPLICATION->metacache()->resolveEntry(m_parent->metaEntryBase(), QString("logos/%1").arg(logo.section(".", 0, 0)));
|
||||||
auto job = new NetJob(QString("%1 Icon Download %2").arg(m_parent->debugName()).arg(logo), APPLICATION->network());
|
auto job = new NetJob(QString("%1 Icon Download %2").arg(m_parent->debugName()).arg(logo), APPLICATION->network());
|
||||||
job->addNetAction(Net::Download::makeCached(QUrl(url), entry));
|
job->addNetAction(Net::Download::makeCached(QUrl(url), entry));
|
||||||
|
|
||||||
@ -311,7 +321,7 @@ void ModpackListModel::searchRequestFailed(QString reason)
|
|||||||
//: %1 refers to the launcher itself
|
//: %1 refers to the launcher itself
|
||||||
QString("%1 %2")
|
QString("%1 %2")
|
||||||
.arg(m_parent->displayName())
|
.arg(m_parent->displayName())
|
||||||
.arg(tr("API version too old!\nPlease update %1!").arg(BuildConfig.LAUNCHER_NAME)));
|
.arg(tr("API version too old!\nPlease update %1!").arg(BuildConfig.LAUNCHER_DISPLAYNAME)));
|
||||||
}
|
}
|
||||||
jobPtr.reset();
|
jobPtr.reset();
|
||||||
|
|
||||||
|
@ -43,6 +43,8 @@
|
|||||||
#include "InstanceImportTask.h"
|
#include "InstanceImportTask.h"
|
||||||
#include "Json.h"
|
#include "Json.h"
|
||||||
|
|
||||||
|
#include "ui/widgets/ProjectItem.h"
|
||||||
|
|
||||||
#include <HoeDown.h>
|
#include <HoeDown.h>
|
||||||
|
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
@ -70,6 +72,9 @@ ModrinthPage::ModrinthPage(NewInstanceDialog* dialog, QWidget* parent) : QWidget
|
|||||||
connect(ui->sortByBox, SIGNAL(currentIndexChanged(int)), this, SLOT(triggerSearch()));
|
connect(ui->sortByBox, SIGNAL(currentIndexChanged(int)), this, SLOT(triggerSearch()));
|
||||||
connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &ModrinthPage::onSelectionChanged);
|
connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &ModrinthPage::onSelectionChanged);
|
||||||
connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &ModrinthPage::onVersionSelectionChanged);
|
connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &ModrinthPage::onVersionSelectionChanged);
|
||||||
|
|
||||||
|
ui->packView->setItemDelegate(new ProjectItemDelegate(this));
|
||||||
|
ui->packDescription->setMetaEntry(metaEntryBase());
|
||||||
}
|
}
|
||||||
|
|
||||||
ModrinthPage::~ModrinthPage()
|
ModrinthPage::~ModrinthPage()
|
||||||
@ -279,6 +284,7 @@ void ModrinthPage::updateUI()
|
|||||||
text += h.process(current.extra.body.toUtf8());
|
text += h.process(current.extra.body.toUtf8());
|
||||||
|
|
||||||
ui->packDescription->setHtml(text + current.description);
|
ui->packDescription->setHtml(text + current.description);
|
||||||
|
ui->packDescription->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModrinthPage::suggestCurrent()
|
void ModrinthPage::suggestCurrent()
|
||||||
|
@ -66,7 +66,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QTextBrowser" name="packDescription">
|
<widget class="ProjectDescriptionPage" name="packDescription">
|
||||||
<property name="openExternalLinks">
|
<property name="openExternalLinks">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
@ -99,6 +99,13 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>ProjectDescriptionPage</class>
|
||||||
|
<extends>QTextBrowser</extends>
|
||||||
|
<header>ui/widgets/ProjectDescriptionPage.h</header>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>searchEdit</tabstop>
|
<tabstop>searchEdit</tabstop>
|
||||||
<tabstop>searchButton</tabstop>
|
<tabstop>searchButton</tabstop>
|
||||||
|
@ -44,6 +44,6 @@ bool LanguageWizardPage::validatePage()
|
|||||||
void LanguageWizardPage::retranslate()
|
void LanguageWizardPage::retranslate()
|
||||||
{
|
{
|
||||||
setTitle(tr("Language"));
|
setTitle(tr("Language"));
|
||||||
setSubTitle(tr("Select the language to use in %1").arg(BuildConfig.LAUNCHER_NAME));
|
setSubTitle(tr("Select the language to use in %1").arg(BuildConfig.LAUNCHER_DISPLAYNAME));
|
||||||
mainWidget->retranslate();
|
mainWidget->retranslate();
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ void SetupWizard::retranslate()
|
|||||||
setButtonText(QWizard::BackButton, tr("< &Back"));
|
setButtonText(QWizard::BackButton, tr("< &Back"));
|
||||||
setButtonText(QWizard::FinishButton, tr("&Finish"));
|
setButtonText(QWizard::FinishButton, tr("&Finish"));
|
||||||
setButtonText(QWizard::CustomButton1, tr("&Refresh"));
|
setButtonText(QWizard::CustomButton1, tr("&Refresh"));
|
||||||
setWindowTitle(tr("%1 Quick Setup").arg(BuildConfig.LAUNCHER_NAME));
|
setWindowTitle(tr("%1 Quick Setup").arg(BuildConfig.LAUNCHER_DISPLAYNAME));
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseWizardPage * SetupWizard::getBasePage(int id)
|
BaseWizardPage * SetupWizard::getBasePage(int id)
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#include "BrightTheme.h"
|
#include "BrightTheme.h"
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
QString BrightTheme::id()
|
QString BrightTheme::id()
|
||||||
{
|
{
|
||||||
return "bright";
|
return "bright";
|
||||||
@ -18,19 +20,19 @@ bool BrightTheme::hasColorScheme()
|
|||||||
QPalette BrightTheme::colorScheme()
|
QPalette BrightTheme::colorScheme()
|
||||||
{
|
{
|
||||||
QPalette brightPalette;
|
QPalette brightPalette;
|
||||||
brightPalette.setColor(QPalette::Window, QColor(239,240,241));
|
brightPalette.setColor(QPalette::Window, QColor(255,255,255));
|
||||||
brightPalette.setColor(QPalette::WindowText, QColor(49,54,59));
|
brightPalette.setColor(QPalette::WindowText, QColor(17,17,17));
|
||||||
brightPalette.setColor(QPalette::Base, QColor(252,252,252));
|
brightPalette.setColor(QPalette::Base, QColor(250,250,250));
|
||||||
brightPalette.setColor(QPalette::AlternateBase, QColor(239,240,241));
|
brightPalette.setColor(QPalette::AlternateBase, QColor(240,240,240));
|
||||||
brightPalette.setColor(QPalette::ToolTipBase, QColor(49,54,59));
|
brightPalette.setColor(QPalette::ToolTipBase, QColor(17,17,17));
|
||||||
brightPalette.setColor(QPalette::ToolTipText, QColor(239,240,241));
|
brightPalette.setColor(QPalette::ToolTipText, QColor(255,255,255));
|
||||||
brightPalette.setColor(QPalette::Text, QColor(49,54,59));
|
brightPalette.setColor(QPalette::Text, Qt::black);
|
||||||
brightPalette.setColor(QPalette::Button, QColor(239,240,241));
|
brightPalette.setColor(QPalette::Button, QColor(249,249,249));
|
||||||
brightPalette.setColor(QPalette::ButtonText, QColor(49,54,59));
|
brightPalette.setColor(QPalette::ButtonText, Qt::black);
|
||||||
brightPalette.setColor(QPalette::BrightText, Qt::red);
|
brightPalette.setColor(QPalette::BrightText, Qt::red);
|
||||||
brightPalette.setColor(QPalette::Link, QColor(41, 128, 185));
|
brightPalette.setColor(QPalette::Link, QColor(37,137,164));
|
||||||
brightPalette.setColor(QPalette::Highlight, QColor(61, 174, 233));
|
brightPalette.setColor(QPalette::Highlight, QColor(137,207,84));
|
||||||
brightPalette.setColor(QPalette::HighlightedText, QColor(239,240,241));
|
brightPalette.setColor(QPalette::HighlightedText, Qt::black);
|
||||||
return fadeInactive(brightPalette, fadeAmount(), fadeColor());
|
return fadeInactive(brightPalette, fadeAmount(), fadeColor());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,7 +43,7 @@ double BrightTheme::fadeAmount()
|
|||||||
|
|
||||||
QColor BrightTheme::fadeColor()
|
QColor BrightTheme::fadeColor()
|
||||||
{
|
{
|
||||||
return QColor(239,240,241);
|
return QColor(255,255,255);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BrightTheme::hasStyleSheet()
|
bool BrightTheme::hasStyleSheet()
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user