mirror of
https://github.com/PrismLauncher/PrismLauncher.git
synced 2025-04-30 06:34:27 +02:00
Merge branch 'develop' of https://github.com/PrismLauncher/PrismLauncher into metadata2
This commit is contained in:
commit
2a86ceb5d6
2
.github/workflows/backport.yml
vendored
2
.github/workflows/backport.yml
vendored
@ -25,7 +25,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
ref: ${{ github.event.pull_request.head.sha }}
|
ref: ${{ github.event.pull_request.head.sha }}
|
||||||
- name: Create backport PRs
|
- name: Create backport PRs
|
||||||
uses: korthout/backport-action@v3.0.2
|
uses: korthout/backport-action@v3.1.0
|
||||||
with:
|
with:
|
||||||
# Config README: https://github.com/korthout/backport-action#backport-action
|
# Config README: https://github.com/korthout/backport-action#backport-action
|
||||||
pull_description: |-
|
pull_description: |-
|
||||||
|
18
.github/workflows/build.yml
vendored
18
.github/workflows/build.yml
vendored
@ -79,7 +79,7 @@ jobs:
|
|||||||
qt_ver: 6
|
qt_ver: 6
|
||||||
qt_host: windows
|
qt_host: windows
|
||||||
qt_arch: ""
|
qt_arch: ""
|
||||||
qt_version: "6.7.1"
|
qt_version: "6.7.2"
|
||||||
qt_modules: "qt5compat qtimageformats qtnetworkauth"
|
qt_modules: "qt5compat qtimageformats qtnetworkauth"
|
||||||
|
|
||||||
- os: windows-2022
|
- os: windows-2022
|
||||||
@ -90,7 +90,7 @@ jobs:
|
|||||||
qt_ver: 6
|
qt_ver: 6
|
||||||
qt_host: windows
|
qt_host: windows
|
||||||
qt_arch: "win64_msvc2019_arm64"
|
qt_arch: "win64_msvc2019_arm64"
|
||||||
qt_version: "6.7.1"
|
qt_version: "6.7.2"
|
||||||
qt_modules: "qt5compat qtimageformats qtnetworkauth"
|
qt_modules: "qt5compat qtimageformats qtnetworkauth"
|
||||||
|
|
||||||
- os: macos-12
|
- os: macos-12
|
||||||
@ -99,7 +99,7 @@ jobs:
|
|||||||
qt_ver: 6
|
qt_ver: 6
|
||||||
qt_host: mac
|
qt_host: mac
|
||||||
qt_arch: ""
|
qt_arch: ""
|
||||||
qt_version: "6.7.1"
|
qt_version: "6.7.2"
|
||||||
qt_modules: "qt5compat qtimageformats qtnetworkauth"
|
qt_modules: "qt5compat qtimageformats qtnetworkauth"
|
||||||
|
|
||||||
- os: macos-12
|
- os: macos-12
|
||||||
@ -160,7 +160,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Setup ccache
|
- name: Setup ccache
|
||||||
if: (runner.os != 'Windows' || matrix.msystem == '') && inputs.build_type == 'Debug'
|
if: (runner.os != 'Windows' || matrix.msystem == '') && inputs.build_type == 'Debug'
|
||||||
uses: hendrikmuhs/ccache-action@v1.2.13
|
uses: hendrikmuhs/ccache-action@v1.2.14
|
||||||
with:
|
with:
|
||||||
key: ${{ matrix.os }}-qt${{ matrix.qt_ver }}-${{ matrix.architecture }}
|
key: ${{ matrix.os }}-qt${{ matrix.qt_ver }}-${{ matrix.architecture }}
|
||||||
|
|
||||||
@ -266,23 +266,23 @@ jobs:
|
|||||||
- name: Configure CMake (macOS)
|
- name: Configure CMake (macOS)
|
||||||
if: runner.os == 'macOS' && matrix.qt_ver == 6
|
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 -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -G Ninja
|
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DENABLE_JAVA_DOWNLOADER=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -G Ninja
|
||||||
|
|
||||||
- name: Configure CMake (macOS-Legacy)
|
- name: Configure CMake (macOS-Legacy)
|
||||||
if: runner.os == 'macOS' && matrix.qt_ver == 5
|
if: runner.os == 'macOS' && matrix.qt_ver == 5
|
||||||
run: |
|
run: |
|
||||||
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DMACOSX_SPARKLE_UPDATE_PUBLIC_KEY="" -DMACOSX_SPARKLE_UPDATE_FEED_URL="" -G Ninja
|
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DENABLE_JAVA_DOWNLOADER=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DMACOSX_SPARKLE_UPDATE_PUBLIC_KEY="" -DMACOSX_SPARKLE_UPDATE_FEED_URL="" -G Ninja
|
||||||
|
|
||||||
- name: Configure CMake (Windows MinGW-w64)
|
- name: Configure CMake (Windows MinGW-w64)
|
||||||
if: runner.os == 'Windows' && matrix.msystem != ''
|
if: runner.os == 'Windows' && matrix.msystem != ''
|
||||||
shell: msys2 {0}
|
shell: msys2 {0}
|
||||||
run: |
|
run: |
|
||||||
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=6 -DCMAKE_OBJDUMP=/mingw64/bin/objdump.exe -DLauncher_BUILD_ARTIFACT=${{ matrix.name }}-Qt${{ 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 -DENABLE_JAVA_DOWNLOADER=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=6 -DCMAKE_OBJDUMP=/mingw64/bin/objdump.exe -DLauncher_BUILD_ARTIFACT=${{ matrix.name }}-Qt${{ matrix.qt_ver }} -G Ninja
|
||||||
|
|
||||||
- name: Configure CMake (Windows MSVC)
|
- name: Configure CMake (Windows MSVC)
|
||||||
if: runner.os == 'Windows' && matrix.msystem == ''
|
if: runner.os == 'Windows' && matrix.msystem == ''
|
||||||
run: |
|
run: |
|
||||||
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=official -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_MSVC_RUNTIME_LIBRARY="MultiThreadedDLL" -A${{ matrix.architecture}} -DLauncher_FORCE_BUNDLED_LIBS=ON -DLauncher_BUILD_ARTIFACT=${{ matrix.name }}-Qt${{ matrix.qt_ver }}
|
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DENABLE_JAVA_DOWNLOADER=ON -DLauncher_BUILD_PLATFORM=official -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_MSVC_RUNTIME_LIBRARY="MultiThreadedDLL" -A${{ matrix.architecture}} -DLauncher_FORCE_BUNDLED_LIBS=ON -DLauncher_BUILD_ARTIFACT=${{ matrix.name }}-Qt${{ matrix.qt_ver }}
|
||||||
# https://github.com/ccache/ccache/wiki/MS-Visual-Studio (I coudn't figure out the compiler prefix)
|
# https://github.com/ccache/ccache/wiki/MS-Visual-Studio (I coudn't figure out the compiler prefix)
|
||||||
if ("${{ env.CCACHE_VAR }}")
|
if ("${{ env.CCACHE_VAR }}")
|
||||||
{
|
{
|
||||||
@ -297,7 +297,7 @@ jobs:
|
|||||||
- name: Configure CMake (Linux)
|
- name: Configure CMake (Linux)
|
||||||
if: runner.os == 'Linux'
|
if: runner.os == 'Linux'
|
||||||
run: |
|
run: |
|
||||||
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DLauncher_BUILD_ARTIFACT=Linux-Qt${{ matrix.qt_ver }} -G Ninja
|
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DENABLE_JAVA_DOWNLOADER=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DLauncher_BUILD_ARTIFACT=Linux-Qt${{ matrix.qt_ver }} -G Ninja
|
||||||
|
|
||||||
##
|
##
|
||||||
# BUILD
|
# BUILD
|
||||||
|
2
.github/workflows/update-flake.yml
vendored
2
.github/workflows/update-flake.yml
vendored
@ -19,7 +19,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27
|
- uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27
|
||||||
|
|
||||||
- uses: DeterminateSystems/update-flake-lock@v22
|
- uses: DeterminateSystems/update-flake-lock@v23
|
||||||
with:
|
with:
|
||||||
commit-msg: "chore(nix): update lockfile"
|
commit-msg: "chore(nix): update lockfile"
|
||||||
pr-title: "chore(nix): update lockfile"
|
pr-title: "chore(nix): update lockfile"
|
||||||
|
@ -219,6 +219,19 @@ set(Launcher_SUBREDDIT_URL "https://prismlauncher.org/reddit" CACHE STRING "URL
|
|||||||
set(Launcher_FORCE_BUNDLED_LIBS OFF CACHE BOOL "Prevent using system libraries, if they are available as submodules")
|
set(Launcher_FORCE_BUNDLED_LIBS OFF CACHE BOOL "Prevent using system libraries, if they are available as submodules")
|
||||||
set(Launcher_QT_VERSION_MAJOR "6" CACHE STRING "Major Qt version to build against")
|
set(Launcher_QT_VERSION_MAJOR "6" CACHE STRING "Major Qt version to build against")
|
||||||
|
|
||||||
|
# Java downloader
|
||||||
|
set(ENABLE_JAVA_DOWNLOADER_DEFAULT ON)
|
||||||
|
|
||||||
|
# Although we recommend enabling this, we cannot guarantee binary compatibility on
|
||||||
|
# differing Linux/BSD/etc distributions. Downstream packagers should be explicitly opt-ing into this
|
||||||
|
# feature if they know it will work with their distribution.
|
||||||
|
if(UNIX AND NOT APPLE)
|
||||||
|
set(ENABLE_JAVA_DOWNLOADER_DEFAULT OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Java downloader
|
||||||
|
option(ENABLE_JAVA_DOWNLOADER "Build the java downloader feature" ${ENABLE_JAVA_DOWNLOADER_DEFAULT})
|
||||||
|
|
||||||
# Native libraries
|
# Native libraries
|
||||||
if(UNIX AND APPLE)
|
if(UNIX AND APPLE)
|
||||||
set(Launcher_GLFW_LIBRARY_NAME "libglfw.dylib" CACHE STRING "Name of native glfw library")
|
set(Launcher_GLFW_LIBRARY_NAME "libglfw.dylib" CACHE STRING "Name of native glfw library")
|
||||||
|
@ -81,6 +81,9 @@ Config::Config()
|
|||||||
UPDATER_ENABLED = true;
|
UPDATER_ENABLED = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#cmakedefine01 ENABLE_JAVA_DOWNLOADER
|
||||||
|
JAVA_DOWNLOADER_ENABLED = ENABLE_JAVA_DOWNLOADER;
|
||||||
|
|
||||||
GIT_COMMIT = "@Launcher_GIT_COMMIT@";
|
GIT_COMMIT = "@Launcher_GIT_COMMIT@";
|
||||||
GIT_TAG = "@Launcher_GIT_TAG@";
|
GIT_TAG = "@Launcher_GIT_TAG@";
|
||||||
GIT_REFSPEC = "@Launcher_GIT_REFSPEC@";
|
GIT_REFSPEC = "@Launcher_GIT_REFSPEC@";
|
||||||
|
@ -67,6 +67,7 @@ class Config {
|
|||||||
QString VERSION_CHANNEL;
|
QString VERSION_CHANNEL;
|
||||||
|
|
||||||
bool UPDATER_ENABLED = false;
|
bool UPDATER_ENABLED = false;
|
||||||
|
bool JAVA_DOWNLOADER_ENABLED = false;
|
||||||
|
|
||||||
/// A short string identifying this build's platform or distribution.
|
/// A short string identifying this build's platform or distribution.
|
||||||
QString BUILD_PLATFORM;
|
QString BUILD_PLATFORM;
|
||||||
|
18
flake.lock
generated
18
flake.lock
generated
@ -23,11 +23,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1719994518,
|
"lastModified": 1722555600,
|
||||||
"narHash": "sha256-pQMhCCHyQGRzdfAkdJ4cIWiw+JNuWsTX7f0ZYSyz0VY=",
|
"narHash": "sha256-XOQkdLafnb/p9ij77byFQjDf5m5QYl9b2REiVClC+x4=",
|
||||||
"owner": "hercules-ci",
|
"owner": "hercules-ci",
|
||||||
"repo": "flake-parts",
|
"repo": "flake-parts",
|
||||||
"rev": "9227223f6d922fee3c7b190b2cc238a99527bbb7",
|
"rev": "8471fe90ad337a8074e957b69ca4d0089218391d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -75,11 +75,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1720768451,
|
"lastModified": 1723637854,
|
||||||
"narHash": "sha256-EYekUHJE2gxeo2pM/zM9Wlqw1Uw2XTJXOSAO79ksc4Y=",
|
"narHash": "sha256-med8+5DSWa2UnOqtdICndjDAEjxr5D7zaIiK4pn0Q7c=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "7e7c39ea35c5cdd002cd4588b03a3fb9ece6fad9",
|
"rev": "c3aa7b8938b17aebd2deecf7be0636000d62a2b9",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -103,11 +103,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1720524665,
|
"lastModified": 1723803910,
|
||||||
"narHash": "sha256-ni/87oHPZm6Gv0ECYxr1f6uxB0UKBWJ6HvS7lwLU6oY=",
|
"narHash": "sha256-yezvUuFiEnCFbGuwj/bQcqg7RykIEqudOy/RBrId0pc=",
|
||||||
"owner": "cachix",
|
"owner": "cachix",
|
||||||
"repo": "pre-commit-hooks.nix",
|
"repo": "pre-commit-hooks.nix",
|
||||||
"rev": "8d6a17d0cdf411c55f12602624df6368ad86fac1",
|
"rev": "bfef0ada09e2c8ac55bbcd0831bd0c9d42e651ba",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -44,10 +44,10 @@
|
|||||||
#include "BuildConfig.h"
|
#include "BuildConfig.h"
|
||||||
|
|
||||||
#include "DataMigrationTask.h"
|
#include "DataMigrationTask.h"
|
||||||
|
#include "java/JavaInstallList.h"
|
||||||
#include "net/PasteUpload.h"
|
#include "net/PasteUpload.h"
|
||||||
#include "pathmatcher/MultiMatcher.h"
|
#include "pathmatcher/MultiMatcher.h"
|
||||||
#include "pathmatcher/SimplePrefixMatcher.h"
|
#include "pathmatcher/SimplePrefixMatcher.h"
|
||||||
#include "settings/INIFile.h"
|
|
||||||
#include "tools/GenericProfiler.h"
|
#include "tools/GenericProfiler.h"
|
||||||
#include "ui/InstanceWindow.h"
|
#include "ui/InstanceWindow.h"
|
||||||
#include "ui/MainWindow.h"
|
#include "ui/MainWindow.h"
|
||||||
@ -106,7 +106,7 @@
|
|||||||
#include "icons/IconList.h"
|
#include "icons/IconList.h"
|
||||||
#include "net/HttpMetaCache.h"
|
#include "net/HttpMetaCache.h"
|
||||||
|
|
||||||
#include "java/JavaUtils.h"
|
#include "java/JavaInstallList.h"
|
||||||
|
|
||||||
#include "updater/ExternalUpdater.h"
|
#include "updater/ExternalUpdater.h"
|
||||||
|
|
||||||
@ -126,6 +126,7 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys.h>
|
#include <sys.h>
|
||||||
|
#include "SysInfo.h"
|
||||||
|
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
@ -151,6 +152,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined Q_OS_WIN32
|
#if defined Q_OS_WIN32
|
||||||
|
#include <windows.h>
|
||||||
#include "WindowsConsole.h"
|
#include "WindowsConsole.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -236,6 +238,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
{ { { "d", "dir" }, "Use a custom path as application root (use '.' for current directory)", "directory" },
|
{ { { "d", "dir" }, "Use a custom path as application root (use '.' for current directory)", "directory" },
|
||||||
{ { "l", "launch" }, "Launch the specified instance (by instance ID)", "instance" },
|
{ { "l", "launch" }, "Launch the specified instance (by instance ID)", "instance" },
|
||||||
{ { "s", "server" }, "Join the specified server on launch (only valid in combination with --launch)", "address" },
|
{ { "s", "server" }, "Join the specified server on launch (only valid in combination with --launch)", "address" },
|
||||||
|
{ { "w", "world" }, "Join the specified world on launch (only valid in combination with --launch)", "world" },
|
||||||
{ { "a", "profile" }, "Use the account specified by its profile name (only valid in combination with --launch)", "profile" },
|
{ { "a", "profile" }, "Use the account specified by its profile name (only valid in combination with --launch)", "profile" },
|
||||||
{ "alive", "Write a small '" + liveCheckFile + "' file after the launcher starts" },
|
{ "alive", "Write a small '" + liveCheckFile + "' file after the launcher starts" },
|
||||||
{ { "I", "import" }, "Import instance or resource from specified local path or URL", "url" },
|
{ { "I", "import" }, "Import instance or resource from specified local path or URL", "url" },
|
||||||
@ -250,6 +253,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
|
|
||||||
m_instanceIdToLaunch = parser.value("launch");
|
m_instanceIdToLaunch = parser.value("launch");
|
||||||
m_serverToJoin = parser.value("server");
|
m_serverToJoin = parser.value("server");
|
||||||
|
m_worldToJoin = parser.value("world");
|
||||||
m_profileToUse = parser.value("profile");
|
m_profileToUse = parser.value("profile");
|
||||||
m_liveCheck = parser.isSet("alive");
|
m_liveCheck = parser.isSet("alive");
|
||||||
|
|
||||||
@ -265,7 +269,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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_worldToJoin.isEmpty()) || !m_profileToUse.isEmpty()) && m_instanceIdToLaunch.isEmpty()) {
|
||||||
std::cerr << "--server and --profile can only be used in combination with --launch!" << std::endl;
|
std::cerr << "--server and --profile can only be used in combination with --launch!" << std::endl;
|
||||||
m_status = Application::Failed;
|
m_status = Application::Failed;
|
||||||
return;
|
return;
|
||||||
@ -385,6 +389,8 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
|
|
||||||
if (!m_serverToJoin.isEmpty()) {
|
if (!m_serverToJoin.isEmpty()) {
|
||||||
launch.args["server"] = m_serverToJoin;
|
launch.args["server"] = m_serverToJoin;
|
||||||
|
} else if (!m_worldToJoin.isEmpty()) {
|
||||||
|
launch.args["world"] = m_worldToJoin;
|
||||||
}
|
}
|
||||||
if (!m_profileToUse.isEmpty()) {
|
if (!m_profileToUse.isEmpty()) {
|
||||||
launch.args["profile"] = m_profileToUse;
|
launch.args["profile"] = m_profileToUse;
|
||||||
@ -523,6 +529,8 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
}
|
}
|
||||||
if (!m_serverToJoin.isEmpty()) {
|
if (!m_serverToJoin.isEmpty()) {
|
||||||
qDebug() << "Address of server to join :" << m_serverToJoin;
|
qDebug() << "Address of server to join :" << m_serverToJoin;
|
||||||
|
} else if (!m_worldToJoin.isEmpty()) {
|
||||||
|
qDebug() << "Name of the world to join :" << m_worldToJoin;
|
||||||
}
|
}
|
||||||
qDebug() << "<> Paths set.";
|
qDebug() << "<> Paths set.";
|
||||||
}
|
}
|
||||||
@ -596,6 +604,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
m_settings->registerSetting("DownloadsDir", QStandardPaths::writableLocation(QStandardPaths::DownloadLocation));
|
m_settings->registerSetting("DownloadsDir", QStandardPaths::writableLocation(QStandardPaths::DownloadLocation));
|
||||||
m_settings->registerSetting("DownloadsDirWatchRecursive", false);
|
m_settings->registerSetting("DownloadsDirWatchRecursive", false);
|
||||||
m_settings->registerSetting("SkinsDir", "skins");
|
m_settings->registerSetting("SkinsDir", "skins");
|
||||||
|
m_settings->registerSetting("JavaDir", "java");
|
||||||
|
|
||||||
// Editors
|
// Editors
|
||||||
m_settings->registerSetting("JsonEditor", QString());
|
m_settings->registerSetting("JsonEditor", QString());
|
||||||
@ -624,7 +633,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
|
|
||||||
// Memory
|
// Memory
|
||||||
m_settings->registerSetting({ "MinMemAlloc", "MinMemoryAlloc" }, 512);
|
m_settings->registerSetting({ "MinMemAlloc", "MinMemoryAlloc" }, 512);
|
||||||
m_settings->registerSetting({ "MaxMemAlloc", "MaxMemoryAlloc" }, suitableMaxMem());
|
m_settings->registerSetting({ "MaxMemAlloc", "MaxMemoryAlloc" }, SysInfo::suitableMaxMem());
|
||||||
m_settings->registerSetting("PermGen", 128);
|
m_settings->registerSetting("PermGen", 128);
|
||||||
|
|
||||||
// Java Settings
|
// Java Settings
|
||||||
@ -638,6 +647,9 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
m_settings->registerSetting("JvmArgs", "");
|
m_settings->registerSetting("JvmArgs", "");
|
||||||
m_settings->registerSetting("IgnoreJavaCompatibility", false);
|
m_settings->registerSetting("IgnoreJavaCompatibility", false);
|
||||||
m_settings->registerSetting("IgnoreJavaWizard", false);
|
m_settings->registerSetting("IgnoreJavaWizard", false);
|
||||||
|
auto defaultEnableAutoJava = m_settings->get("JavaPath").toString().isEmpty();
|
||||||
|
m_settings->registerSetting("AutomaticJavaSwitch", defaultEnableAutoJava);
|
||||||
|
m_settings->registerSetting("AutomaticJavaDownload", defaultEnableAutoJava);
|
||||||
|
|
||||||
// Legacy settings
|
// Legacy settings
|
||||||
m_settings->registerSetting("OnlineFixes", false);
|
m_settings->registerSetting("OnlineFixes", false);
|
||||||
@ -867,6 +879,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
m_metacache->addBase("ModrinthModpacks", QDir("cache/ModrinthModpacks").absolutePath());
|
m_metacache->addBase("ModrinthModpacks", QDir("cache/ModrinthModpacks").absolutePath());
|
||||||
m_metacache->addBase("translations", QDir("translations").absolutePath());
|
m_metacache->addBase("translations", QDir("translations").absolutePath());
|
||||||
m_metacache->addBase("meta", QDir("meta").absolutePath());
|
m_metacache->addBase("meta", QDir("meta").absolutePath());
|
||||||
|
m_metacache->addBase("java", QDir("cache/java").absolutePath());
|
||||||
m_metacache->Load();
|
m_metacache->Load();
|
||||||
qDebug() << "<> Cache initialized.";
|
qDebug() << "<> Cache initialized.";
|
||||||
}
|
}
|
||||||
@ -1157,14 +1170,17 @@ void Application::performMainStartupAction()
|
|||||||
if (!m_instanceIdToLaunch.isEmpty()) {
|
if (!m_instanceIdToLaunch.isEmpty()) {
|
||||||
auto inst = instances()->getInstanceById(m_instanceIdToLaunch);
|
auto inst = instances()->getInstanceById(m_instanceIdToLaunch);
|
||||||
if (inst) {
|
if (inst) {
|
||||||
MinecraftServerTargetPtr serverToJoin = nullptr;
|
MinecraftTarget::Ptr targetToJoin = nullptr;
|
||||||
MinecraftAccountPtr accountToUse = nullptr;
|
MinecraftAccountPtr accountToUse = nullptr;
|
||||||
|
|
||||||
qDebug() << "<> Instance" << m_instanceIdToLaunch << "launching";
|
qDebug() << "<> Instance" << m_instanceIdToLaunch << "launching";
|
||||||
if (!m_serverToJoin.isEmpty()) {
|
if (!m_serverToJoin.isEmpty()) {
|
||||||
// FIXME: validate the server string
|
// FIXME: validate the server string
|
||||||
serverToJoin.reset(new MinecraftServerTarget(MinecraftServerTarget::parse(m_serverToJoin)));
|
targetToJoin.reset(new MinecraftTarget(MinecraftTarget::parse(m_serverToJoin, false)));
|
||||||
qDebug() << " Launching with server" << m_serverToJoin;
|
qDebug() << " Launching with server" << m_serverToJoin;
|
||||||
|
} else if (!m_worldToJoin.isEmpty()) {
|
||||||
|
targetToJoin.reset(new MinecraftTarget(MinecraftTarget::parse(m_worldToJoin, true)));
|
||||||
|
qDebug() << " Launching with world" << m_worldToJoin;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_profileToUse.isEmpty()) {
|
if (!m_profileToUse.isEmpty()) {
|
||||||
@ -1175,7 +1191,7 @@ void Application::performMainStartupAction()
|
|||||||
qDebug() << " Launching with account" << m_profileToUse;
|
qDebug() << " Launching with account" << m_profileToUse;
|
||||||
}
|
}
|
||||||
|
|
||||||
launch(inst, true, false, serverToJoin, accountToUse);
|
launch(inst, true, false, targetToJoin, accountToUse);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1265,6 +1281,7 @@ void Application::messageReceived(const QByteArray& message)
|
|||||||
} else if (command == "launch") {
|
} else if (command == "launch") {
|
||||||
QString id = received.args["id"];
|
QString id = received.args["id"];
|
||||||
QString server = received.args["server"];
|
QString server = received.args["server"];
|
||||||
|
QString world = received.args["world"];
|
||||||
QString profile = received.args["profile"];
|
QString profile = received.args["profile"];
|
||||||
|
|
||||||
InstancePtr instance;
|
InstancePtr instance;
|
||||||
@ -1279,11 +1296,12 @@ void Application::messageReceived(const QByteArray& message)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MinecraftServerTargetPtr serverObject = nullptr;
|
MinecraftTarget::Ptr serverObject = nullptr;
|
||||||
if (!server.isEmpty()) {
|
if (!server.isEmpty()) {
|
||||||
serverObject = std::make_shared<MinecraftServerTarget>(MinecraftServerTarget::parse(server));
|
serverObject = std::make_shared<MinecraftTarget>(MinecraftTarget::parse(server, false));
|
||||||
|
} else if (!world.isEmpty()) {
|
||||||
|
serverObject = std::make_shared<MinecraftTarget>(MinecraftTarget::parse(world, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
MinecraftAccountPtr accountObject;
|
MinecraftAccountPtr accountObject;
|
||||||
if (!profile.isEmpty()) {
|
if (!profile.isEmpty()) {
|
||||||
accountObject = accounts()->getAccountByProfileName(profile);
|
accountObject = accounts()->getAccountByProfileName(profile);
|
||||||
@ -1332,11 +1350,7 @@ bool Application::openJsonEditor(const QString& filename)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Application::launch(InstancePtr instance,
|
bool Application::launch(InstancePtr instance, bool online, bool demo, MinecraftTarget::Ptr targetToJoin, MinecraftAccountPtr accountToUse)
|
||||||
bool online,
|
|
||||||
bool demo,
|
|
||||||
MinecraftServerTargetPtr serverToJoin,
|
|
||||||
MinecraftAccountPtr accountToUse)
|
|
||||||
{
|
{
|
||||||
if (m_updateRunning) {
|
if (m_updateRunning) {
|
||||||
qDebug() << "Cannot launch instances while an update is running. Please try again when updates are completed.";
|
qDebug() << "Cannot launch instances while an update is running. Please try again when updates are completed.";
|
||||||
@ -1354,7 +1368,7 @@ bool Application::launch(InstancePtr instance,
|
|||||||
controller->setOnline(online);
|
controller->setOnline(online);
|
||||||
controller->setDemo(demo);
|
controller->setDemo(demo);
|
||||||
controller->setProfiler(profilers().value(instance->settings()->get("Profiler").toString(), nullptr).get());
|
controller->setProfiler(profilers().value(instance->settings()->get("Profiler").toString(), nullptr).get());
|
||||||
controller->setServerToJoin(serverToJoin);
|
controller->setTargetToJoin(targetToJoin);
|
||||||
controller->setAccountToUse(accountToUse);
|
controller->setAccountToUse(accountToUse);
|
||||||
if (window) {
|
if (window) {
|
||||||
controller->setParentWidget(window);
|
controller->setParentWidget(window);
|
||||||
@ -1733,20 +1747,6 @@ QString Application::getUserAgentUncached()
|
|||||||
return BuildConfig.USER_AGENT_UNCACHED;
|
return BuildConfig.USER_AGENT_UNCACHED;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Application::suitableMaxMem()
|
|
||||||
{
|
|
||||||
float totalRAM = (float)Sys::getSystemRam() / (float)Sys::mebibyte;
|
|
||||||
int maxMemoryAlloc;
|
|
||||||
|
|
||||||
// If totalRAM < 6GB, use (totalRAM / 1.5), else 4GB
|
|
||||||
if (totalRAM < (4096 * 1.5))
|
|
||||||
maxMemoryAlloc = (int)(totalRAM / 1.5);
|
|
||||||
else
|
|
||||||
maxMemoryAlloc = 4096;
|
|
||||||
|
|
||||||
return maxMemoryAlloc;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Application::handleDataMigration(const QString& currentData,
|
bool Application::handleDataMigration(const QString& currentData,
|
||||||
const QString& oldData,
|
const QString& oldData,
|
||||||
const QString& name,
|
const QString& name,
|
||||||
@ -1853,3 +1853,7 @@ QUrl Application::normalizeImportUrl(QString const& url)
|
|||||||
return QUrl::fromUserInput(url);
|
return QUrl::fromUserInput(url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const QString Application::javaPath()
|
||||||
|
{
|
||||||
|
return m_settings->get("JavaDir").toString();
|
||||||
|
}
|
||||||
|
@ -47,7 +47,7 @@
|
|||||||
|
|
||||||
#include <BaseInstance.h>
|
#include <BaseInstance.h>
|
||||||
|
|
||||||
#include "minecraft/launch/MinecraftServerTarget.h"
|
#include "minecraft/launch/MinecraftTarget.h"
|
||||||
|
|
||||||
class LaunchController;
|
class LaunchController;
|
||||||
class LocalPeer;
|
class LocalPeer;
|
||||||
@ -161,6 +161,9 @@ class Application : public QApplication {
|
|||||||
/// the data path the application is using
|
/// the data path the application is using
|
||||||
const QString& dataRoot() { return m_dataPath; }
|
const QString& dataRoot() { return m_dataPath; }
|
||||||
|
|
||||||
|
/// the java installed path the application is using
|
||||||
|
const QString javaPath();
|
||||||
|
|
||||||
bool isPortable() { return m_portable; }
|
bool isPortable() { return m_portable; }
|
||||||
|
|
||||||
const Capabilities capabilities() { return m_capabilities; }
|
const Capabilities capabilities() { return m_capabilities; }
|
||||||
@ -179,8 +182,6 @@ class Application : public QApplication {
|
|||||||
|
|
||||||
void ShowGlobalSettings(class QWidget* parent, QString open_page = QString());
|
void ShowGlobalSettings(class QWidget* parent, QString open_page = QString());
|
||||||
|
|
||||||
int suitableMaxMem();
|
|
||||||
|
|
||||||
bool updaterEnabled();
|
bool updaterEnabled();
|
||||||
QString updaterBinaryName();
|
QString updaterBinaryName();
|
||||||
|
|
||||||
@ -202,7 +203,7 @@ class Application : public QApplication {
|
|||||||
bool launch(InstancePtr instance,
|
bool launch(InstancePtr instance,
|
||||||
bool online = true,
|
bool online = true,
|
||||||
bool demo = false,
|
bool demo = false,
|
||||||
MinecraftServerTargetPtr serverToJoin = nullptr,
|
MinecraftTarget::Ptr targetToJoin = nullptr,
|
||||||
MinecraftAccountPtr accountToUse = nullptr);
|
MinecraftAccountPtr accountToUse = nullptr);
|
||||||
bool kill(InstancePtr instance);
|
bool kill(InstancePtr instance);
|
||||||
void closeCurrentWindow();
|
void closeCurrentWindow();
|
||||||
@ -290,6 +291,7 @@ class Application : public QApplication {
|
|||||||
QString m_detectedOpenALPath;
|
QString m_detectedOpenALPath;
|
||||||
QString m_instanceIdToLaunch;
|
QString m_instanceIdToLaunch;
|
||||||
QString m_serverToJoin;
|
QString m_serverToJoin;
|
||||||
|
QString m_worldToJoin;
|
||||||
QString m_profileToUse;
|
QString m_profileToUse;
|
||||||
bool m_liveCheck = false;
|
bool m_liveCheck = false;
|
||||||
QList<QUrl> m_urlsToImport;
|
QList<QUrl> m_urlsToImport;
|
||||||
|
@ -56,7 +56,7 @@
|
|||||||
#include "net/Mode.h"
|
#include "net/Mode.h"
|
||||||
|
|
||||||
#include "RuntimeContext.h"
|
#include "RuntimeContext.h"
|
||||||
#include "minecraft/launch/MinecraftServerTarget.h"
|
#include "minecraft/launch/MinecraftTarget.h"
|
||||||
|
|
||||||
class QDir;
|
class QDir;
|
||||||
class Task;
|
class Task;
|
||||||
@ -184,7 +184,7 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
|
|||||||
virtual Task::Ptr createUpdateTask(Net::Mode mode) = 0;
|
virtual Task::Ptr createUpdateTask(Net::Mode mode) = 0;
|
||||||
|
|
||||||
/// returns a valid launcher (task container)
|
/// returns a valid launcher (task container)
|
||||||
virtual shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) = 0;
|
virtual shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account, MinecraftTarget::Ptr targetToJoin) = 0;
|
||||||
|
|
||||||
/// returns the current launch task (if any)
|
/// returns the current launch task (if any)
|
||||||
shared_qobject_ptr<LaunchTask> getLaunchTask();
|
shared_qobject_ptr<LaunchTask> getLaunchTask();
|
||||||
@ -256,7 +256,7 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
|
|||||||
/**
|
/**
|
||||||
* 'print' a verbose description of the instance into a QStringList
|
* 'print' a verbose description of the instance into a QStringList
|
||||||
*/
|
*/
|
||||||
virtual QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) = 0;
|
virtual QStringList verboseDescription(AuthSessionPtr session, MinecraftTarget::Ptr targetToJoin) = 0;
|
||||||
|
|
||||||
Status currentStatus() const;
|
Status currentStatus() const;
|
||||||
|
|
||||||
|
@ -78,6 +78,14 @@ QVariant BaseVersionList::data(const QModelIndex& index, int role) const
|
|||||||
case TypeRole:
|
case TypeRole:
|
||||||
return version->typeString();
|
return version->typeString();
|
||||||
|
|
||||||
|
case JavaMajorRole: {
|
||||||
|
auto major = version->name();
|
||||||
|
if (major.startsWith("java")) {
|
||||||
|
major = "Java " + major.mid(4);
|
||||||
|
}
|
||||||
|
return major;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
@ -110,6 +118,8 @@ QHash<int, QByteArray> BaseVersionList::roleNames() const
|
|||||||
roles.insert(TypeRole, "type");
|
roles.insert(TypeRole, "type");
|
||||||
roles.insert(BranchRole, "branch");
|
roles.insert(BranchRole, "branch");
|
||||||
roles.insert(PathRole, "path");
|
roles.insert(PathRole, "path");
|
||||||
roles.insert(ArchitectureRole, "architecture");
|
roles.insert(JavaNameRole, "javaName");
|
||||||
|
roles.insert(CPUArchitectureRole, "architecture");
|
||||||
|
roles.insert(JavaMajorRole, "javaMajor");
|
||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,9 @@ class BaseVersionList : public QAbstractListModel {
|
|||||||
TypeRole,
|
TypeRole,
|
||||||
BranchRole,
|
BranchRole,
|
||||||
PathRole,
|
PathRole,
|
||||||
ArchitectureRole,
|
JavaNameRole,
|
||||||
|
JavaMajorRole,
|
||||||
|
CPUArchitectureRole,
|
||||||
SortRole
|
SortRole
|
||||||
};
|
};
|
||||||
using RoleList = QList<int>;
|
using RoleList = QList<int>;
|
||||||
|
@ -24,6 +24,8 @@ set(CORE_SOURCES
|
|||||||
NullInstance.h
|
NullInstance.h
|
||||||
MMCZip.h
|
MMCZip.h
|
||||||
MMCZip.cpp
|
MMCZip.cpp
|
||||||
|
Untar.h
|
||||||
|
Untar.cpp
|
||||||
StringUtils.h
|
StringUtils.h
|
||||||
StringUtils.cpp
|
StringUtils.cpp
|
||||||
QVariantUtils.h
|
QVariantUtils.h
|
||||||
@ -262,8 +264,8 @@ set(MINECRAFT_SOURCES
|
|||||||
minecraft/launch/ExtractNatives.h
|
minecraft/launch/ExtractNatives.h
|
||||||
minecraft/launch/LauncherPartLaunch.cpp
|
minecraft/launch/LauncherPartLaunch.cpp
|
||||||
minecraft/launch/LauncherPartLaunch.h
|
minecraft/launch/LauncherPartLaunch.h
|
||||||
minecraft/launch/MinecraftServerTarget.cpp
|
minecraft/launch/MinecraftTarget.cpp
|
||||||
minecraft/launch/MinecraftServerTarget.h
|
minecraft/launch/MinecraftTarget.h
|
||||||
minecraft/launch/PrintInstanceInfo.cpp
|
minecraft/launch/PrintInstanceInfo.cpp
|
||||||
minecraft/launch/PrintInstanceInfo.h
|
minecraft/launch/PrintInstanceInfo.h
|
||||||
minecraft/launch/ReconstructAssets.cpp
|
minecraft/launch/ReconstructAssets.cpp
|
||||||
@ -272,6 +274,8 @@ set(MINECRAFT_SOURCES
|
|||||||
minecraft/launch/ScanModFolders.h
|
minecraft/launch/ScanModFolders.h
|
||||||
minecraft/launch/VerifyJavaInstall.cpp
|
minecraft/launch/VerifyJavaInstall.cpp
|
||||||
minecraft/launch/VerifyJavaInstall.h
|
minecraft/launch/VerifyJavaInstall.h
|
||||||
|
minecraft/launch/AutoInstallJava.cpp
|
||||||
|
minecraft/launch/AutoInstallJava.h
|
||||||
|
|
||||||
minecraft/GradleSpecifier.h
|
minecraft/GradleSpecifier.h
|
||||||
minecraft/MinecraftInstance.cpp
|
minecraft/MinecraftInstance.cpp
|
||||||
@ -417,8 +421,6 @@ set(SETTINGS_SOURCES
|
|||||||
set(JAVA_SOURCES
|
set(JAVA_SOURCES
|
||||||
java/JavaChecker.h
|
java/JavaChecker.h
|
||||||
java/JavaChecker.cpp
|
java/JavaChecker.cpp
|
||||||
java/JavaCheckerJob.h
|
|
||||||
java/JavaCheckerJob.cpp
|
|
||||||
java/JavaInstall.h
|
java/JavaInstall.h
|
||||||
java/JavaInstall.cpp
|
java/JavaInstall.cpp
|
||||||
java/JavaInstallList.h
|
java/JavaInstallList.h
|
||||||
@ -427,6 +429,18 @@ set(JAVA_SOURCES
|
|||||||
java/JavaUtils.cpp
|
java/JavaUtils.cpp
|
||||||
java/JavaVersion.h
|
java/JavaVersion.h
|
||||||
java/JavaVersion.cpp
|
java/JavaVersion.cpp
|
||||||
|
|
||||||
|
java/JavaMetadata.h
|
||||||
|
java/JavaMetadata.cpp
|
||||||
|
java/download/ArchiveDownloadTask.cpp
|
||||||
|
java/download/ArchiveDownloadTask.h
|
||||||
|
java/download/ManifestDownloadTask.cpp
|
||||||
|
java/download/ManifestDownloadTask.h
|
||||||
|
|
||||||
|
ui/java/InstallJavaDialog.h
|
||||||
|
ui/java/InstallJavaDialog.cpp
|
||||||
|
ui/java/VersionList.h
|
||||||
|
ui/java/VersionList.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(TRANSLATIONS_SOURCES
|
set(TRANSLATIONS_SOURCES
|
||||||
@ -746,6 +760,8 @@ SET(LAUNCHER_SOURCES
|
|||||||
DataMigrationTask.cpp
|
DataMigrationTask.cpp
|
||||||
ApplicationMessage.h
|
ApplicationMessage.h
|
||||||
ApplicationMessage.cpp
|
ApplicationMessage.cpp
|
||||||
|
SysInfo.h
|
||||||
|
SysInfo.cpp
|
||||||
|
|
||||||
# GUI - general utilities
|
# GUI - general utilities
|
||||||
DesktopServices.h
|
DesktopServices.h
|
||||||
@ -784,8 +800,6 @@ SET(LAUNCHER_SOURCES
|
|||||||
# GUI - windows
|
# GUI - windows
|
||||||
ui/GuiUtil.h
|
ui/GuiUtil.h
|
||||||
ui/GuiUtil.cpp
|
ui/GuiUtil.cpp
|
||||||
ui/ColorCache.h
|
|
||||||
ui/ColorCache.cpp
|
|
||||||
ui/MainWindow.h
|
ui/MainWindow.h
|
||||||
ui/MainWindow.cpp
|
ui/MainWindow.cpp
|
||||||
ui/InstanceWindow.h
|
ui/InstanceWindow.h
|
||||||
|
@ -276,6 +276,9 @@ bool ensureFolderPathExists(const QFileInfo folderPath)
|
|||||||
{
|
{
|
||||||
QDir dir;
|
QDir dir;
|
||||||
QString ensuredPath = folderPath.filePath();
|
QString ensuredPath = folderPath.filePath();
|
||||||
|
if (folderPath.exists())
|
||||||
|
return true;
|
||||||
|
|
||||||
bool success = dir.mkpath(ensuredPath);
|
bool success = dir.mkpath(ensuredPath);
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
#include "Filter.h"
|
#include "Filter.h"
|
||||||
|
|
||||||
Filter::~Filter() {}
|
|
||||||
|
|
||||||
ContainsFilter::ContainsFilter(const QString& pattern) : pattern(pattern) {}
|
ContainsFilter::ContainsFilter(const QString& pattern) : pattern(pattern) {}
|
||||||
ContainsFilter::~ContainsFilter() {}
|
|
||||||
bool ContainsFilter::accepts(const QString& value)
|
bool ContainsFilter::accepts(const QString& value)
|
||||||
{
|
{
|
||||||
return value.contains(pattern);
|
return value.contains(pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExactFilter::ExactFilter(const QString& pattern) : pattern(pattern) {}
|
ExactFilter::ExactFilter(const QString& pattern) : pattern(pattern) {}
|
||||||
ExactFilter::~ExactFilter() {}
|
|
||||||
bool ExactFilter::accepts(const QString& value)
|
bool ExactFilter::accepts(const QString& value)
|
||||||
{
|
{
|
||||||
return value == pattern;
|
return value == pattern;
|
||||||
@ -27,10 +23,15 @@ RegexpFilter::RegexpFilter(const QString& regexp, bool invert) : invert(invert)
|
|||||||
pattern.setPattern(regexp);
|
pattern.setPattern(regexp);
|
||||||
pattern.optimize();
|
pattern.optimize();
|
||||||
}
|
}
|
||||||
RegexpFilter::~RegexpFilter() {}
|
|
||||||
bool RegexpFilter::accepts(const QString& value)
|
bool RegexpFilter::accepts(const QString& value)
|
||||||
{
|
{
|
||||||
auto match = pattern.match(value);
|
auto match = pattern.match(value);
|
||||||
bool matched = match.hasMatch();
|
bool matched = match.hasMatch();
|
||||||
return invert ? (!matched) : (matched);
|
return invert ? (!matched) : (matched);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExactListFilter::ExactListFilter(const QStringList& pattern) : m_pattern(pattern) {}
|
||||||
|
bool ExactListFilter::accepts(const QString& value)
|
||||||
|
{
|
||||||
|
return m_pattern.isEmpty() || m_pattern.contains(value);
|
||||||
|
}
|
@ -5,14 +5,14 @@
|
|||||||
|
|
||||||
class Filter {
|
class Filter {
|
||||||
public:
|
public:
|
||||||
virtual ~Filter();
|
virtual ~Filter() = default;
|
||||||
virtual bool accepts(const QString& value) = 0;
|
virtual bool accepts(const QString& value) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ContainsFilter : public Filter {
|
class ContainsFilter : public Filter {
|
||||||
public:
|
public:
|
||||||
ContainsFilter(const QString& pattern);
|
ContainsFilter(const QString& pattern);
|
||||||
virtual ~ContainsFilter();
|
virtual ~ContainsFilter() = default;
|
||||||
bool accepts(const QString& value) override;
|
bool accepts(const QString& value) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -22,7 +22,7 @@ class ContainsFilter : public Filter {
|
|||||||
class ExactFilter : public Filter {
|
class ExactFilter : public Filter {
|
||||||
public:
|
public:
|
||||||
ExactFilter(const QString& pattern);
|
ExactFilter(const QString& pattern);
|
||||||
virtual ~ExactFilter();
|
virtual ~ExactFilter() = default;
|
||||||
bool accepts(const QString& value) override;
|
bool accepts(const QString& value) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -32,7 +32,7 @@ class ExactFilter : public Filter {
|
|||||||
class ExactIfPresentFilter : public Filter {
|
class ExactIfPresentFilter : public Filter {
|
||||||
public:
|
public:
|
||||||
ExactIfPresentFilter(const QString& pattern);
|
ExactIfPresentFilter(const QString& pattern);
|
||||||
~ExactIfPresentFilter() override = default;
|
virtual ~ExactIfPresentFilter() override = default;
|
||||||
bool accepts(const QString& value) override;
|
bool accepts(const QString& value) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -42,10 +42,20 @@ class ExactIfPresentFilter : public Filter {
|
|||||||
class RegexpFilter : public Filter {
|
class RegexpFilter : public Filter {
|
||||||
public:
|
public:
|
||||||
RegexpFilter(const QString& regexp, bool invert);
|
RegexpFilter(const QString& regexp, bool invert);
|
||||||
virtual ~RegexpFilter();
|
virtual ~RegexpFilter() = default;
|
||||||
bool accepts(const QString& value) override;
|
bool accepts(const QString& value) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QRegularExpression pattern;
|
QRegularExpression pattern;
|
||||||
bool invert = false;
|
bool invert = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ExactListFilter : public Filter {
|
||||||
|
public:
|
||||||
|
ExactListFilter(const QStringList& pattern = {});
|
||||||
|
virtual ~ExactListFilter() = default;
|
||||||
|
bool accepts(const QString& value) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const QStringList& m_pattern;
|
||||||
|
};
|
||||||
|
@ -22,7 +22,7 @@ class InstancePageProvider : protected QObject, public BasePageProvider {
|
|||||||
public:
|
public:
|
||||||
explicit InstancePageProvider(InstancePtr parent) { inst = parent; }
|
explicit InstancePageProvider(InstancePtr parent) { inst = parent; }
|
||||||
|
|
||||||
virtual ~InstancePageProvider() {};
|
virtual ~InstancePageProvider() = default;
|
||||||
virtual QList<BasePage*> getPages() override
|
virtual QList<BasePage*> getPages() override
|
||||||
{
|
{
|
||||||
QList<BasePage*> values;
|
QList<BasePage*> values;
|
||||||
@ -39,7 +39,7 @@ class InstancePageProvider : protected QObject, public BasePageProvider {
|
|||||||
values.append(new TexturePackPage(onesix.get(), onesix->texturePackList()));
|
values.append(new TexturePackPage(onesix.get(), onesix->texturePackList()));
|
||||||
values.append(new ShaderPackPage(onesix.get(), onesix->shaderPackList()));
|
values.append(new ShaderPackPage(onesix.get(), onesix->shaderPackList()));
|
||||||
values.append(new NotesPage(onesix.get()));
|
values.append(new NotesPage(onesix.get()));
|
||||||
values.append(new WorldListPage(onesix.get(), onesix->worldList()));
|
values.append(new WorldListPage(onesix, onesix->worldList()));
|
||||||
values.append(new ServersPage(onesix));
|
values.append(new ServersPage(onesix));
|
||||||
// values.append(new GameOptionsPage(onesix.get()));
|
// values.append(new GameOptionsPage(onesix.get()));
|
||||||
values.append(new ScreenshotsPage(FS::PathCombine(onesix->gameRoot(), "screenshots")));
|
values.append(new ScreenshotsPage(FS::PathCombine(onesix->gameRoot(), "screenshots")));
|
||||||
|
@ -63,7 +63,7 @@ bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget* parent)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void JavaCommon::javaWasOk(QWidget* parent, const JavaCheckResult& result)
|
void JavaCommon::javaWasOk(QWidget* parent, const JavaChecker::Result& result)
|
||||||
{
|
{
|
||||||
QString text;
|
QString text;
|
||||||
text += QObject::tr(
|
text += QObject::tr(
|
||||||
@ -79,7 +79,7 @@ void JavaCommon::javaWasOk(QWidget* parent, const JavaCheckResult& result)
|
|||||||
CustomMessageBox::selectable(parent, QObject::tr("Java test success"), text, QMessageBox::Information)->show();
|
CustomMessageBox::selectable(parent, QObject::tr("Java test success"), text, QMessageBox::Information)->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JavaCommon::javaArgsWereBad(QWidget* parent, const JavaCheckResult& result)
|
void JavaCommon::javaArgsWereBad(QWidget* parent, const JavaChecker::Result& result)
|
||||||
{
|
{
|
||||||
auto htmlError = result.errorLog;
|
auto htmlError = result.errorLog;
|
||||||
QString text;
|
QString text;
|
||||||
@ -89,7 +89,7 @@ void JavaCommon::javaArgsWereBad(QWidget* parent, const JavaCheckResult& result)
|
|||||||
CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
|
CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JavaCommon::javaBinaryWasBad(QWidget* parent, const JavaCheckResult& result)
|
void JavaCommon::javaBinaryWasBad(QWidget* parent, const JavaChecker::Result& result)
|
||||||
{
|
{
|
||||||
QString text;
|
QString text;
|
||||||
text += QObject::tr(
|
text += QObject::tr(
|
||||||
@ -116,34 +116,26 @@ void JavaCommon::TestCheck::run()
|
|||||||
emit finished();
|
emit finished();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
checker.reset(new JavaChecker());
|
checker.reset(new JavaChecker(m_path, "", 0, 0, 0, 0, this));
|
||||||
connect(checker.get(), &JavaChecker::checkFinished, this, &JavaCommon::TestCheck::checkFinished);
|
connect(checker.get(), &JavaChecker::checkFinished, this, &JavaCommon::TestCheck::checkFinished);
|
||||||
checker->m_path = m_path;
|
checker->start();
|
||||||
checker->performCheck();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void JavaCommon::TestCheck::checkFinished(JavaCheckResult result)
|
void JavaCommon::TestCheck::checkFinished(const JavaChecker::Result& result)
|
||||||
{
|
{
|
||||||
if (result.validity != JavaCheckResult::Validity::Valid) {
|
if (result.validity != JavaChecker::Result::Validity::Valid) {
|
||||||
javaBinaryWasBad(m_parent, result);
|
javaBinaryWasBad(m_parent, result);
|
||||||
emit finished();
|
emit finished();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
checker.reset(new JavaChecker());
|
checker.reset(new JavaChecker(m_path, m_args, m_maxMem, m_maxMem, result.javaVersion.requiresPermGen() ? m_permGen : 0, 0, this));
|
||||||
connect(checker.get(), &JavaChecker::checkFinished, this, &JavaCommon::TestCheck::checkFinishedWithArgs);
|
connect(checker.get(), &JavaChecker::checkFinished, this, &JavaCommon::TestCheck::checkFinishedWithArgs);
|
||||||
checker->m_path = m_path;
|
checker->start();
|
||||||
checker->m_args = m_args;
|
|
||||||
checker->m_minMem = m_minMem;
|
|
||||||
checker->m_maxMem = m_maxMem;
|
|
||||||
if (result.javaVersion.requiresPermGen()) {
|
|
||||||
checker->m_permGen = m_permGen;
|
|
||||||
}
|
|
||||||
checker->performCheck();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void JavaCommon::TestCheck::checkFinishedWithArgs(JavaCheckResult result)
|
void JavaCommon::TestCheck::checkFinishedWithArgs(const JavaChecker::Result& result)
|
||||||
{
|
{
|
||||||
if (result.validity == JavaCheckResult::Validity::Valid) {
|
if (result.validity == JavaChecker::Result::Validity::Valid) {
|
||||||
javaWasOk(m_parent, result);
|
javaWasOk(m_parent, result);
|
||||||
emit finished();
|
emit finished();
|
||||||
return;
|
return;
|
||||||
|
@ -10,11 +10,11 @@ namespace JavaCommon {
|
|||||||
bool checkJVMArgs(QString args, QWidget* parent);
|
bool checkJVMArgs(QString args, QWidget* parent);
|
||||||
|
|
||||||
// Show a dialog saying that the Java binary was usable
|
// Show a dialog saying that the Java binary was usable
|
||||||
void javaWasOk(QWidget* parent, const JavaCheckResult& result);
|
void javaWasOk(QWidget* parent, const JavaChecker::Result& result);
|
||||||
// Show a dialog saying that the Java binary was not usable because of bad options
|
// Show a dialog saying that the Java binary was not usable because of bad options
|
||||||
void javaArgsWereBad(QWidget* parent, const JavaCheckResult& result);
|
void javaArgsWereBad(QWidget* parent, const JavaChecker::Result& result);
|
||||||
// Show a dialog saying that the Java binary was not usable
|
// Show a dialog saying that the Java binary was not usable
|
||||||
void javaBinaryWasBad(QWidget* parent, const JavaCheckResult& result);
|
void javaBinaryWasBad(QWidget* parent, const JavaChecker::Result& result);
|
||||||
// Show a dialog if we couldn't find Java Checker
|
// Show a dialog if we couldn't find Java Checker
|
||||||
void javaCheckNotFound(QWidget* parent);
|
void javaCheckNotFound(QWidget* parent);
|
||||||
|
|
||||||
@ -32,11 +32,11 @@ class TestCheck : public QObject {
|
|||||||
void finished();
|
void finished();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void checkFinished(JavaCheckResult result);
|
void checkFinished(const JavaChecker::Result& result);
|
||||||
void checkFinishedWithArgs(JavaCheckResult result);
|
void checkFinishedWithArgs(const JavaChecker::Result& result);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<JavaChecker> checker;
|
JavaChecker::Ptr checker;
|
||||||
QWidget* m_parent = nullptr;
|
QWidget* m_parent = nullptr;
|
||||||
QString m_path;
|
QString m_path;
|
||||||
QString m_args;
|
QString m_args;
|
||||||
|
@ -324,7 +324,7 @@ void LaunchController::launchInstance()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_launcher = m_instance->createLaunchTask(m_session, m_serverToJoin);
|
m_launcher = m_instance->createLaunchTask(m_session, m_targetToJoin);
|
||||||
if (!m_launcher) {
|
if (!m_launcher) {
|
||||||
emitFailed(tr("Couldn't instantiate a launcher."));
|
emitFailed(tr("Couldn't instantiate a launcher."));
|
||||||
return;
|
return;
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
#include "minecraft/auth/MinecraftAccount.h"
|
#include "minecraft/auth/MinecraftAccount.h"
|
||||||
#include "minecraft/launch/MinecraftServerTarget.h"
|
#include "minecraft/launch/MinecraftTarget.h"
|
||||||
|
|
||||||
class InstanceWindow;
|
class InstanceWindow;
|
||||||
class LaunchController : public Task {
|
class LaunchController : public Task {
|
||||||
@ -48,7 +48,7 @@ class LaunchController : public Task {
|
|||||||
void executeTask() override;
|
void executeTask() override;
|
||||||
|
|
||||||
LaunchController(QObject* parent = nullptr);
|
LaunchController(QObject* parent = nullptr);
|
||||||
virtual ~LaunchController() {};
|
virtual ~LaunchController() = default;
|
||||||
|
|
||||||
void setInstance(InstancePtr instance) { m_instance = instance; }
|
void setInstance(InstancePtr instance) { m_instance = instance; }
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ class LaunchController : public Task {
|
|||||||
|
|
||||||
void setParentWidget(QWidget* widget) { m_parentWidget = widget; }
|
void setParentWidget(QWidget* widget) { m_parentWidget = widget; }
|
||||||
|
|
||||||
void setServerToJoin(MinecraftServerTargetPtr serverToJoin) { m_serverToJoin = std::move(serverToJoin); }
|
void setTargetToJoin(MinecraftTarget::Ptr targetToJoin) { m_targetToJoin = std::move(targetToJoin); }
|
||||||
|
|
||||||
void setAccountToUse(MinecraftAccountPtr accountToUse) { m_accountToUse = std::move(accountToUse); }
|
void setAccountToUse(MinecraftAccountPtr accountToUse) { m_accountToUse = std::move(accountToUse); }
|
||||||
|
|
||||||
@ -94,5 +94,5 @@ class LaunchController : public Task {
|
|||||||
MinecraftAccountPtr m_accountToUse = nullptr;
|
MinecraftAccountPtr m_accountToUse = nullptr;
|
||||||
AuthSessionPtr m_session;
|
AuthSessionPtr m_session;
|
||||||
shared_qobject_ptr<LaunchTask> m_launcher;
|
shared_qobject_ptr<LaunchTask> m_launcher;
|
||||||
MinecraftServerTargetPtr m_serverToJoin;
|
MinecraftTarget::Ptr m_targetToJoin;
|
||||||
};
|
};
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
/*
|
/*
|
||||||
* Prism Launcher - Minecraft Launcher
|
* Prism Launcher - Minecraft Launcher
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
* Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
|
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -536,6 +536,10 @@ bool ExportToZipTask::abort()
|
|||||||
|
|
||||||
void ExtractZipTask::executeTask()
|
void ExtractZipTask::executeTask()
|
||||||
{
|
{
|
||||||
|
if (!m_input->isOpen() && !m_input->open(QuaZip::mdUnzip)) {
|
||||||
|
emitFailed(tr("Unable to open supplied zip file."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
m_zip_future = QtConcurrent::run(QThreadPool::globalInstance(), [this]() { return extractZip(); });
|
m_zip_future = QtConcurrent::run(QThreadPool::globalInstance(), [this]() { return extractZip(); });
|
||||||
connect(&m_zip_watcher, &QFutureWatcher<ZipResult>::finished, this, &ExtractZipTask::finish);
|
connect(&m_zip_watcher, &QFutureWatcher<ZipResult>::finished, this, &ExtractZipTask::finish);
|
||||||
m_zip_watcher.setFuture(m_zip_future);
|
m_zip_watcher.setFuture(m_zip_future);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
/*
|
/*
|
||||||
* Prism Launcher - Minecraft Launcher
|
* Prism Launcher - Minecraft Launcher
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
* Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
|
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -208,6 +208,9 @@ class ExportToZipTask : public Task {
|
|||||||
|
|
||||||
class ExtractZipTask : public Task {
|
class ExtractZipTask : public Task {
|
||||||
public:
|
public:
|
||||||
|
ExtractZipTask(QString input, QDir outputDir, QString subdirectory = "")
|
||||||
|
: ExtractZipTask(std::make_shared<QuaZip>(input), outputDir, subdirectory)
|
||||||
|
{}
|
||||||
ExtractZipTask(std::shared_ptr<QuaZip> input, QDir outputDir, QString subdirectory = "")
|
ExtractZipTask(std::shared_ptr<QuaZip> input, QDir outputDir, QString subdirectory = "")
|
||||||
: m_input(input), m_output_dir(outputDir), m_subdirectory(subdirectory)
|
: m_input(input), m_output_dir(outputDir), m_subdirectory(subdirectory)
|
||||||
{}
|
{}
|
||||||
|
@ -40,8 +40,8 @@ namespace MangoHud {
|
|||||||
|
|
||||||
QString getLibraryString()
|
QString getLibraryString()
|
||||||
{
|
{
|
||||||
/*
|
/**
|
||||||
* Check for vulkan layers in this order:
|
* Guess MangoHud install location by searching for vulkan layers in this order:
|
||||||
*
|
*
|
||||||
* $VK_LAYER_PATH
|
* $VK_LAYER_PATH
|
||||||
* $XDG_DATA_DIRS (/usr/local/share/:/usr/share/)
|
* $XDG_DATA_DIRS (/usr/local/share/:/usr/share/)
|
||||||
@ -49,8 +49,9 @@ QString getLibraryString()
|
|||||||
* /etc
|
* /etc
|
||||||
* $XDG_CONFIG_DIRS (/etc/xdg)
|
* $XDG_CONFIG_DIRS (/etc/xdg)
|
||||||
* $XDG_CONFIG_HOME (~/.config)
|
* $XDG_CONFIG_HOME (~/.config)
|
||||||
|
*
|
||||||
|
* @returns Absolute path of libMangoHud.so if found and empty QString otherwise.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
QStringList vkLayerList;
|
QStringList vkLayerList;
|
||||||
{
|
{
|
||||||
QString home = QDir::homePath();
|
QString home = QDir::homePath();
|
||||||
@ -85,7 +86,7 @@ QString getLibraryString()
|
|||||||
vkLayerList << FS::PathCombine(xdgConfigHome, "vulkan", "implicit_layer.d");
|
vkLayerList << FS::PathCombine(xdgConfigHome, "vulkan", "implicit_layer.d");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (QString vkLayer : vkLayerList) {
|
for (const QString& vkLayer : vkLayerList) {
|
||||||
// prefer to use architecture specific vulkan layers
|
// prefer to use architecture specific vulkan layers
|
||||||
QString currentArch = QSysInfo::currentCpuArchitecture();
|
QString currentArch = QSysInfo::currentCpuArchitecture();
|
||||||
|
|
||||||
@ -95,8 +96,8 @@ QString getLibraryString()
|
|||||||
|
|
||||||
QStringList manifestNames = { QString("MangoHud.%1.json").arg(currentArch), "MangoHud.json" };
|
QStringList manifestNames = { QString("MangoHud.%1.json").arg(currentArch), "MangoHud.json" };
|
||||||
|
|
||||||
QString filePath = "";
|
QString filePath{};
|
||||||
for (QString manifestName : manifestNames) {
|
for (const QString& manifestName : manifestNames) {
|
||||||
QString tryPath = FS::PathCombine(vkLayer, manifestName);
|
QString tryPath = FS::PathCombine(vkLayer, manifestName);
|
||||||
if (QFile::exists(tryPath)) {
|
if (QFile::exists(tryPath)) {
|
||||||
filePath = tryPath;
|
filePath = tryPath;
|
||||||
@ -111,10 +112,23 @@ QString getLibraryString()
|
|||||||
auto conf = Json::requireDocument(filePath, vkLayer);
|
auto conf = Json::requireDocument(filePath, vkLayer);
|
||||||
auto confObject = Json::requireObject(conf, vkLayer);
|
auto confObject = Json::requireObject(conf, vkLayer);
|
||||||
auto layer = Json::ensureObject(confObject, "layer");
|
auto layer = Json::ensureObject(confObject, "layer");
|
||||||
return Json::ensureString(layer, "library_path");
|
QString libraryName = Json::ensureString(layer, "library_path");
|
||||||
|
|
||||||
|
#ifdef __GLIBC__
|
||||||
|
// Check whether mangohud is usable on a glibc based system
|
||||||
|
if (!libraryName.isEmpty()) {
|
||||||
|
QString libraryPath = findLibrary(libraryName);
|
||||||
|
if (!libraryPath.isEmpty()) {
|
||||||
|
return libraryPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// Without glibc return recorded shared library as-is.
|
||||||
|
return libraryName;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return QString();
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
QString findLibrary(QString libName)
|
QString findLibrary(QString libName)
|
||||||
|
@ -46,13 +46,13 @@ class NullInstance : public BaseInstance {
|
|||||||
{
|
{
|
||||||
setVersionBroken(true);
|
setVersionBroken(true);
|
||||||
}
|
}
|
||||||
virtual ~NullInstance() {};
|
virtual ~NullInstance() = default;
|
||||||
void saveNow() override {}
|
void saveNow() override {}
|
||||||
void loadSpecificSettings() override { setSpecificSettingsLoaded(true); }
|
void loadSpecificSettings() override { setSpecificSettingsLoaded(true); }
|
||||||
QString getStatusbarDescription() override { return tr("Unknown instance type"); };
|
QString getStatusbarDescription() override { return tr("Unknown instance type"); };
|
||||||
QSet<QString> traits() const override { return {}; };
|
QSet<QString> traits() const override { return {}; };
|
||||||
QString instanceConfigFolder() const override { return instanceRoot(); };
|
QString instanceConfigFolder() const override { return instanceRoot(); };
|
||||||
shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr, MinecraftServerTargetPtr) override { return nullptr; }
|
shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr, MinecraftTarget::Ptr) override { return nullptr; }
|
||||||
shared_qobject_ptr<Task> createUpdateTask([[maybe_unused]] Net::Mode mode) override { return nullptr; }
|
shared_qobject_ptr<Task> createUpdateTask([[maybe_unused]] Net::Mode mode) override { return nullptr; }
|
||||||
QProcessEnvironment createEnvironment() override { return QProcessEnvironment(); }
|
QProcessEnvironment createEnvironment() override { return QProcessEnvironment(); }
|
||||||
QProcessEnvironment createLaunchEnvironment() override { return QProcessEnvironment(); }
|
QProcessEnvironment createLaunchEnvironment() override { return QProcessEnvironment(); }
|
||||||
@ -64,7 +64,7 @@ class NullInstance : public BaseInstance {
|
|||||||
bool canEdit() const override { return false; }
|
bool canEdit() const override { return false; }
|
||||||
bool canLaunch() const override { return false; }
|
bool canLaunch() const override { return false; }
|
||||||
void populateLaunchMenu(QMenu* menu) override {}
|
void populateLaunchMenu(QMenu* menu) override {}
|
||||||
QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) override
|
QStringList verboseDescription(AuthSessionPtr session, MinecraftTarget::Ptr targetToJoin) override
|
||||||
{
|
{
|
||||||
QStringList out;
|
QStringList out;
|
||||||
out << "Null instance - placeholder.";
|
out << "Null instance - placeholder.";
|
||||||
|
99
launcher/SysInfo.cpp
Normal file
99
launcher/SysInfo.cpp
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
#include <QDebug>
|
||||||
|
#include <QString>
|
||||||
|
#include "sys.h"
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#endif
|
||||||
|
#include <QFile>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
bool rosettaDetect()
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
size_t size = sizeof(ret);
|
||||||
|
if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return ret == 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace SysInfo {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
QString useQTForArch()
|
||||||
|
{
|
||||||
|
#if defined(Q_OS_MACOS) && !defined(Q_PROCESSOR_ARM)
|
||||||
|
if (rosettaDetect()) {
|
||||||
|
return "arm64";
|
||||||
|
} else {
|
||||||
|
return "x86_64";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return QSysInfo::currentCpuArchitecture();
|
||||||
|
}
|
||||||
|
|
||||||
|
int suitableMaxMem()
|
||||||
|
{
|
||||||
|
float totalRAM = (float)Sys::getSystemRam() / (float)Sys::mebibyte;
|
||||||
|
int maxMemoryAlloc;
|
||||||
|
|
||||||
|
// If totalRAM < 6GB, use (totalRAM / 1.5), else 4GB
|
||||||
|
if (totalRAM < (4096 * 1.5))
|
||||||
|
maxMemoryAlloc = (int)(totalRAM / 1.5);
|
||||||
|
else
|
||||||
|
maxMemoryAlloc = 4096;
|
||||||
|
|
||||||
|
return maxMemoryAlloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString getSupportedJavaArchitecture()
|
||||||
|
{
|
||||||
|
auto sys = currentSystem();
|
||||||
|
auto arch = useQTForArch();
|
||||||
|
if (sys == "windows") {
|
||||||
|
if (arch == "x86_64")
|
||||||
|
return "windows-x64";
|
||||||
|
if (arch == "i386")
|
||||||
|
return "windows-x86";
|
||||||
|
// Unknown, maybe arm, appending arch
|
||||||
|
return "windows-" + arch;
|
||||||
|
}
|
||||||
|
if (sys == "osx") {
|
||||||
|
if (arch == "arm64")
|
||||||
|
return "mac-os-arm64";
|
||||||
|
if (arch.contains("64"))
|
||||||
|
return "mac-os-64";
|
||||||
|
if (arch.contains("86"))
|
||||||
|
return "mac-os-86";
|
||||||
|
// Unknown, maybe something new, appending arch
|
||||||
|
return "mac-os-" + arch;
|
||||||
|
} else if (sys == "linux") {
|
||||||
|
if (arch == "x86_64")
|
||||||
|
return "linux-x64";
|
||||||
|
if (arch == "i386")
|
||||||
|
return "linux-x86";
|
||||||
|
// will work for arm32 arm(64)
|
||||||
|
return "linux-" + arch;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
} // namespace SysInfo
|
8
launcher/SysInfo.h
Normal file
8
launcher/SysInfo.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#include <QString>
|
||||||
|
|
||||||
|
namespace SysInfo {
|
||||||
|
QString currentSystem();
|
||||||
|
QString useQTForArch();
|
||||||
|
QString getSupportedJavaArchitecture();
|
||||||
|
int suitableMaxMem();
|
||||||
|
} // namespace SysInfo
|
260
launcher/Untar.cpp
Normal file
260
launcher/Untar.cpp
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This file incorporates work covered by the following copyright and
|
||||||
|
* permission notice:
|
||||||
|
*
|
||||||
|
* Copyright 2013-2021 MultiMC Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
#include "Untar.h"
|
||||||
|
#include <quagzipfile.h>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QIODevice>
|
||||||
|
#include <QString>
|
||||||
|
#include "FileSystem.h"
|
||||||
|
|
||||||
|
// adaptation of the:
|
||||||
|
// - https://github.com/madler/zlib/blob/develop/contrib/untgz/untgz.c
|
||||||
|
// - https://en.wikipedia.org/wiki/Tar_(computing)
|
||||||
|
// - https://github.com/euroelessar/cutereader/blob/master/karchive/src/ktar.cpp
|
||||||
|
|
||||||
|
#define BLOCKSIZE 512
|
||||||
|
#define SHORTNAMESIZE 100
|
||||||
|
|
||||||
|
enum class TypeFlag : char {
|
||||||
|
Regular = '0', // regular file
|
||||||
|
ARegular = 0, // regular file
|
||||||
|
Link = '1', // link
|
||||||
|
Symlink = '2', // reserved
|
||||||
|
Character = '3', // character special
|
||||||
|
Block = '4', // block special
|
||||||
|
Directory = '5', // directory
|
||||||
|
FIFO = '6', // FIFO special
|
||||||
|
Contiguous = '7', // reserved
|
||||||
|
// Posix stuff
|
||||||
|
GlobalPosixHeader = 'g',
|
||||||
|
ExtendedPosixHeader = 'x',
|
||||||
|
// 'A'– 'Z' Vendor specific extensions(POSIX .1 - 1988)
|
||||||
|
// GNU
|
||||||
|
GNULongLink = 'K', /* long link name */
|
||||||
|
GNULongName = 'L', /* long file name */
|
||||||
|
};
|
||||||
|
|
||||||
|
// struct Header { /* byte offset */
|
||||||
|
// char name[100]; /* 0 */
|
||||||
|
// char mode[8]; /* 100 */
|
||||||
|
// char uid[8]; /* 108 */
|
||||||
|
// char gid[8]; /* 116 */
|
||||||
|
// char size[12]; /* 124 */
|
||||||
|
// char mtime[12]; /* 136 */
|
||||||
|
// char chksum[8]; /* 148 */
|
||||||
|
// TypeFlag typeflag; /* 156 */
|
||||||
|
// char linkname[100]; /* 157 */
|
||||||
|
// char magic[6]; /* 257 */
|
||||||
|
// char version[2]; /* 263 */
|
||||||
|
// char uname[32]; /* 265 */
|
||||||
|
// char gname[32]; /* 297 */
|
||||||
|
// char devmajor[8]; /* 329 */
|
||||||
|
// char devminor[8]; /* 337 */
|
||||||
|
// char prefix[155]; /* 345 */
|
||||||
|
// /* 500 */
|
||||||
|
// };
|
||||||
|
|
||||||
|
bool readLonglink(QIODevice* in, qint64 size, QByteArray& longlink)
|
||||||
|
{
|
||||||
|
qint64 n = 0;
|
||||||
|
size--; // ignore trailing null
|
||||||
|
if (size < 0) {
|
||||||
|
qCritical() << "The filename size is negative";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
longlink.resize(size + (BLOCKSIZE - size % BLOCKSIZE)); // make the size divisible by BLOCKSIZE
|
||||||
|
for (qint64 offset = 0; offset < longlink.size(); offset += BLOCKSIZE) {
|
||||||
|
n = in->read(longlink.data() + offset, BLOCKSIZE);
|
||||||
|
if (n != BLOCKSIZE) {
|
||||||
|
qCritical() << "The expected blocksize was not respected for the name";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
longlink.truncate(qstrlen(longlink.constData()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getOctal(char* buffer, int maxlenght, bool* ok)
|
||||||
|
{
|
||||||
|
return QByteArray(buffer, qstrnlen(buffer, maxlenght)).toInt(ok, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString decodeName(char* name)
|
||||||
|
{
|
||||||
|
return QFile::decodeName(QByteArray(name, qstrnlen(name, 100)));
|
||||||
|
}
|
||||||
|
bool Tar::extract(QIODevice* in, QString dst)
|
||||||
|
{
|
||||||
|
char buffer[BLOCKSIZE];
|
||||||
|
QString name, symlink, firstFolderName;
|
||||||
|
bool doNotReset = false, ok;
|
||||||
|
while (true) {
|
||||||
|
auto n = in->read(buffer, BLOCKSIZE);
|
||||||
|
if (n != BLOCKSIZE) { // allways expect complete blocks
|
||||||
|
qCritical() << "The expected blocksize was not respected";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (buffer[0] == 0) { // end of archive
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
int mode = getOctal(buffer + 100, 8, &ok) | QFile::ReadUser | QFile::WriteUser; // hack to ensure write and read permisions
|
||||||
|
if (!ok) {
|
||||||
|
qCritical() << "The file mode can't be read";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// there are names that are exactly 100 bytes long
|
||||||
|
// and neither longlink nor \0 terminated (bug:101472)
|
||||||
|
|
||||||
|
if (name.isEmpty()) {
|
||||||
|
name = decodeName(buffer);
|
||||||
|
if (!firstFolderName.isEmpty() && name.startsWith(firstFolderName)) {
|
||||||
|
name = name.mid(firstFolderName.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (symlink.isEmpty())
|
||||||
|
symlink = decodeName(buffer);
|
||||||
|
qint64 size = getOctal(buffer + 124, 12, &ok);
|
||||||
|
if (!ok) {
|
||||||
|
qCritical() << "The file size can't be read";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch (TypeFlag(buffer[156])) {
|
||||||
|
case TypeFlag::Regular:
|
||||||
|
/* fallthrough */
|
||||||
|
case TypeFlag::ARegular: {
|
||||||
|
auto fileName = FS::PathCombine(dst, name);
|
||||||
|
if (!FS::ensureFilePathExists(fileName)) {
|
||||||
|
qCritical() << "Can't ensure the file path to exist: " << fileName;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
QFile out(fileName);
|
||||||
|
if (!out.open(QFile::WriteOnly)) {
|
||||||
|
qCritical() << "Can't open file:" << fileName;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
out.setPermissions(QFile::Permissions(mode));
|
||||||
|
while (size > 0) {
|
||||||
|
QByteArray tmp(BLOCKSIZE, 0);
|
||||||
|
n = in->read(tmp.data(), BLOCKSIZE);
|
||||||
|
if (n != BLOCKSIZE) {
|
||||||
|
qCritical() << "The expected blocksize was not respected when reading file";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
tmp.truncate(qMin(qint64(BLOCKSIZE), size));
|
||||||
|
out.write(tmp);
|
||||||
|
size -= BLOCKSIZE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TypeFlag::Directory: {
|
||||||
|
if (firstFolderName.isEmpty()) {
|
||||||
|
firstFolderName = name;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
auto folderPath = FS::PathCombine(dst, name);
|
||||||
|
if (!FS::ensureFolderPathExists(folderPath)) {
|
||||||
|
qCritical() << "Can't ensure that folder exists: " << folderPath;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TypeFlag::GNULongLink: {
|
||||||
|
doNotReset = true;
|
||||||
|
QByteArray longlink;
|
||||||
|
if (readLonglink(in, size, longlink)) {
|
||||||
|
symlink = QFile::decodeName(longlink.constData());
|
||||||
|
} else {
|
||||||
|
qCritical() << "Failed to read long link";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TypeFlag::GNULongName: {
|
||||||
|
doNotReset = true;
|
||||||
|
QByteArray longlink;
|
||||||
|
if (readLonglink(in, size, longlink)) {
|
||||||
|
name = QFile::decodeName(longlink.constData());
|
||||||
|
} else {
|
||||||
|
qCritical() << "Failed to read long name";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TypeFlag::Link:
|
||||||
|
/* fallthrough */
|
||||||
|
case TypeFlag::Symlink: {
|
||||||
|
auto fileName = FS::PathCombine(dst, name);
|
||||||
|
if (!FS::create_link(FS::PathCombine(QFileInfo(fileName).path(), symlink), fileName)()) { // do not use symlinks
|
||||||
|
qCritical() << "Can't create link for:" << fileName << " to:" << FS::PathCombine(QFileInfo(fileName).path(), symlink);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
FS::ensureFilePathExists(fileName);
|
||||||
|
QFile::setPermissions(fileName, QFile::Permissions(mode));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TypeFlag::Character:
|
||||||
|
/* fallthrough */
|
||||||
|
case TypeFlag::Block:
|
||||||
|
/* fallthrough */
|
||||||
|
case TypeFlag::FIFO:
|
||||||
|
/* fallthrough */
|
||||||
|
case TypeFlag::Contiguous:
|
||||||
|
/* fallthrough */
|
||||||
|
case TypeFlag::GlobalPosixHeader:
|
||||||
|
/* fallthrough */
|
||||||
|
case TypeFlag::ExtendedPosixHeader:
|
||||||
|
/* fallthrough */
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!doNotReset) {
|
||||||
|
name.truncate(0);
|
||||||
|
symlink.truncate(0);
|
||||||
|
}
|
||||||
|
doNotReset = false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GZTar::extract(QString src, QString dst)
|
||||||
|
{
|
||||||
|
QuaGzipFile a(src);
|
||||||
|
if (!a.open(QIODevice::ReadOnly)) {
|
||||||
|
qCritical() << "Can't open tar file:" << src;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return Tar::extract(&a, dst);
|
||||||
|
}
|
46
launcher/Untar.h
Normal file
46
launcher/Untar.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This file incorporates work covered by the following copyright and
|
||||||
|
* permission notice:
|
||||||
|
*
|
||||||
|
* Copyright 2013-2021 MultiMC Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <QIODevice>
|
||||||
|
|
||||||
|
// this is a hack used for the java downloader (feel free to remove it in favor of a library)
|
||||||
|
// both extract functions will extract the first folder inside dest(disregarding the prefix)
|
||||||
|
namespace Tar {
|
||||||
|
bool extract(QIODevice* in, QString dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace GZTar {
|
||||||
|
bool extract(QString src, QString dst);
|
||||||
|
}
|
@ -114,10 +114,14 @@ QVariant VersionProxyModel::headerData(int section, Qt::Orientation orientation,
|
|||||||
return tr("Branch");
|
return tr("Branch");
|
||||||
case Type:
|
case Type:
|
||||||
return tr("Type");
|
return tr("Type");
|
||||||
case Architecture:
|
case CPUArchitecture:
|
||||||
return tr("Architecture");
|
return tr("Architecture");
|
||||||
case Path:
|
case Path:
|
||||||
return tr("Path");
|
return tr("Path");
|
||||||
|
case JavaName:
|
||||||
|
return tr("Java Name");
|
||||||
|
case JavaMajor:
|
||||||
|
return tr("Major Version");
|
||||||
case Time:
|
case Time:
|
||||||
return tr("Released");
|
return tr("Released");
|
||||||
}
|
}
|
||||||
@ -131,10 +135,14 @@ QVariant VersionProxyModel::headerData(int section, Qt::Orientation orientation,
|
|||||||
return tr("The version's branch");
|
return tr("The version's branch");
|
||||||
case Type:
|
case Type:
|
||||||
return tr("The version's type");
|
return tr("The version's type");
|
||||||
case Architecture:
|
case CPUArchitecture:
|
||||||
return tr("CPU Architecture");
|
return tr("CPU Architecture");
|
||||||
case Path:
|
case Path:
|
||||||
return tr("Filesystem path to this version");
|
return tr("Filesystem path to this version");
|
||||||
|
case JavaName:
|
||||||
|
return tr("The alternative name of the java version");
|
||||||
|
case JavaMajor:
|
||||||
|
return tr("The java major version");
|
||||||
case Time:
|
case Time:
|
||||||
return tr("Release date of this version");
|
return tr("Release date of this version");
|
||||||
}
|
}
|
||||||
@ -165,10 +173,14 @@ QVariant VersionProxyModel::data(const QModelIndex& index, int role) const
|
|||||||
return sourceModel()->data(parentIndex, BaseVersionList::BranchRole);
|
return sourceModel()->data(parentIndex, BaseVersionList::BranchRole);
|
||||||
case Type:
|
case Type:
|
||||||
return sourceModel()->data(parentIndex, BaseVersionList::TypeRole);
|
return sourceModel()->data(parentIndex, BaseVersionList::TypeRole);
|
||||||
case Architecture:
|
case CPUArchitecture:
|
||||||
return sourceModel()->data(parentIndex, BaseVersionList::ArchitectureRole);
|
return sourceModel()->data(parentIndex, BaseVersionList::CPUArchitectureRole);
|
||||||
case Path:
|
case Path:
|
||||||
return sourceModel()->data(parentIndex, BaseVersionList::PathRole);
|
return sourceModel()->data(parentIndex, BaseVersionList::PathRole);
|
||||||
|
case JavaName:
|
||||||
|
return sourceModel()->data(parentIndex, BaseVersionList::JavaNameRole);
|
||||||
|
case JavaMajor:
|
||||||
|
return sourceModel()->data(parentIndex, BaseVersionList::JavaMajorRole);
|
||||||
case Time:
|
case Time:
|
||||||
return sourceModel()->data(parentIndex, Meta::VersionList::TimeRole).toDate();
|
return sourceModel()->data(parentIndex, Meta::VersionList::TimeRole).toDate();
|
||||||
default:
|
default:
|
||||||
@ -308,12 +320,18 @@ void VersionProxyModel::setSourceModel(QAbstractItemModel* replacingRaw)
|
|||||||
m_columns.push_back(ParentVersion);
|
m_columns.push_back(ParentVersion);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if (roles.contains(BaseVersionList::ArchitectureRole)) {
|
if (roles.contains(BaseVersionList::CPUArchitectureRole)) {
|
||||||
m_columns.push_back(Architecture);
|
m_columns.push_back(CPUArchitecture);
|
||||||
}
|
}
|
||||||
if (roles.contains(BaseVersionList::PathRole)) {
|
if (roles.contains(BaseVersionList::PathRole)) {
|
||||||
m_columns.push_back(Path);
|
m_columns.push_back(Path);
|
||||||
}
|
}
|
||||||
|
if (roles.contains(BaseVersionList::JavaNameRole)) {
|
||||||
|
m_columns.push_back(JavaName);
|
||||||
|
}
|
||||||
|
if (roles.contains(BaseVersionList::JavaMajorRole)) {
|
||||||
|
m_columns.push_back(JavaMajor);
|
||||||
|
}
|
||||||
if (roles.contains(Meta::VersionList::TimeRole)) {
|
if (roles.contains(Meta::VersionList::TimeRole)) {
|
||||||
m_columns.push_back(Time);
|
m_columns.push_back(Time);
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ class VersionFilterModel;
|
|||||||
class VersionProxyModel : public QAbstractProxyModel {
|
class VersionProxyModel : public QAbstractProxyModel {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
enum Column { Name, ParentVersion, Branch, Type, Architecture, Path, Time };
|
enum Column { Name, ParentVersion, Branch, Type, CPUArchitecture, Path, Time, JavaName, JavaMajor };
|
||||||
using FilterMap = QHash<BaseVersionList::ModelRoles, std::shared_ptr<Filter>>;
|
using FilterMap = QHash<BaseVersionList::ModelRoles, std::shared_ptr<Filter>>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -40,14 +40,15 @@
|
|||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
|
|
||||||
#include "Application.h"
|
|
||||||
#include "Commandline.h"
|
#include "Commandline.h"
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include "JavaUtils.h"
|
#include "java/JavaUtils.h"
|
||||||
|
|
||||||
JavaChecker::JavaChecker(QObject* parent) : QObject(parent) {}
|
JavaChecker::JavaChecker(QString path, QString args, int minMem, int maxMem, int permGen, int id, QObject* parent)
|
||||||
|
: Task(parent), m_path(path), m_args(args), m_minMem(minMem), m_maxMem(maxMem), m_permGen(permGen), m_id(id)
|
||||||
|
{}
|
||||||
|
|
||||||
void JavaChecker::performCheck()
|
void JavaChecker::executeTask()
|
||||||
{
|
{
|
||||||
QString checkerJar = JavaUtils::getJavaCheckPath();
|
QString checkerJar = JavaUtils::getJavaCheckPath();
|
||||||
|
|
||||||
@ -72,7 +73,7 @@ void JavaChecker::performCheck()
|
|||||||
if (m_maxMem != 0) {
|
if (m_maxMem != 0) {
|
||||||
args << QString("-Xmx%1m").arg(m_maxMem);
|
args << QString("-Xmx%1m").arg(m_maxMem);
|
||||||
}
|
}
|
||||||
if (m_permGen != 64) {
|
if (m_permGen != 64 && m_permGen != 0) {
|
||||||
args << QString("-XX:PermSize=%1m").arg(m_permGen);
|
args << QString("-XX:PermSize=%1m").arg(m_permGen);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,11 +116,10 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
|
|||||||
QProcessPtr _process = process;
|
QProcessPtr _process = process;
|
||||||
process.reset();
|
process.reset();
|
||||||
|
|
||||||
JavaCheckResult result;
|
Result result = {
|
||||||
{
|
m_path,
|
||||||
result.path = m_path;
|
m_id,
|
||||||
result.id = m_id;
|
};
|
||||||
}
|
|
||||||
result.errorLog = m_stderr;
|
result.errorLog = m_stderr;
|
||||||
result.outLog = m_stdout;
|
result.outLog = m_stdout;
|
||||||
qDebug() << "STDOUT" << m_stdout;
|
qDebug() << "STDOUT" << m_stdout;
|
||||||
@ -127,8 +127,9 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
|
|||||||
qDebug() << "Java checker finished with status" << status << "exit code" << exitcode;
|
qDebug() << "Java checker finished with status" << status << "exit code" << exitcode;
|
||||||
|
|
||||||
if (status == QProcess::CrashExit || exitcode == 1) {
|
if (status == QProcess::CrashExit || exitcode == 1) {
|
||||||
result.validity = JavaCheckResult::Validity::Errored;
|
result.validity = Result::Validity::Errored;
|
||||||
emit checkFinished(result);
|
emit checkFinished(result);
|
||||||
|
emitSucceeded();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,8 +162,9 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!results.contains("os.arch") || !results.contains("java.version") || !results.contains("java.vendor") || !success) {
|
if (!results.contains("os.arch") || !results.contains("java.version") || !results.contains("java.vendor") || !success) {
|
||||||
result.validity = JavaCheckResult::Validity::ReturnedInvalidData;
|
result.validity = Result::Validity::ReturnedInvalidData;
|
||||||
emit checkFinished(result);
|
emit checkFinished(result);
|
||||||
|
emitSucceeded();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,7 +173,7 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
|
|||||||
auto java_vendor = results["java.vendor"];
|
auto java_vendor = results["java.vendor"];
|
||||||
bool is_64 = os_arch == "x86_64" || os_arch == "amd64" || os_arch == "aarch64" || os_arch == "arm64";
|
bool is_64 = os_arch == "x86_64" || os_arch == "amd64" || os_arch == "aarch64" || os_arch == "arm64";
|
||||||
|
|
||||||
result.validity = JavaCheckResult::Validity::Valid;
|
result.validity = Result::Validity::Valid;
|
||||||
result.is_64bit = is_64;
|
result.is_64bit = is_64;
|
||||||
result.mojangPlatform = is_64 ? "64" : "32";
|
result.mojangPlatform = is_64 ? "64" : "32";
|
||||||
result.realPlatform = os_arch;
|
result.realPlatform = os_arch;
|
||||||
@ -179,6 +181,7 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
|
|||||||
result.javaVendor = java_vendor;
|
result.javaVendor = java_vendor;
|
||||||
qDebug() << "Java checker succeeded.";
|
qDebug() << "Java checker succeeded.";
|
||||||
emit checkFinished(result);
|
emit checkFinished(result);
|
||||||
|
emitSucceeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JavaChecker::error(QProcess::ProcessError err)
|
void JavaChecker::error(QProcess::ProcessError err)
|
||||||
@ -190,15 +193,9 @@ void JavaChecker::error(QProcess::ProcessError err)
|
|||||||
qDebug() << "Native environment:";
|
qDebug() << "Native environment:";
|
||||||
qDebug() << QProcessEnvironment::systemEnvironment().toStringList();
|
qDebug() << QProcessEnvironment::systemEnvironment().toStringList();
|
||||||
killTimer.stop();
|
killTimer.stop();
|
||||||
JavaCheckResult result;
|
emit checkFinished({ m_path, m_id });
|
||||||
{
|
|
||||||
result.path = m_path;
|
|
||||||
result.id = m_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit checkFinished(result);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
emitSucceeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
void JavaChecker::timeout()
|
void JavaChecker::timeout()
|
||||||
|
@ -3,14 +3,19 @@
|
|||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "QObjectPtr.h"
|
|
||||||
|
|
||||||
#include "JavaVersion.h"
|
#include "JavaVersion.h"
|
||||||
|
#include "QObjectPtr.h"
|
||||||
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
class JavaChecker;
|
class JavaChecker : public Task {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
using QProcessPtr = shared_qobject_ptr<QProcess>;
|
||||||
|
using Ptr = shared_qobject_ptr<JavaChecker>;
|
||||||
|
|
||||||
struct JavaCheckResult {
|
struct Result {
|
||||||
QString path;
|
QString path;
|
||||||
|
int id;
|
||||||
QString mojangPlatform;
|
QString mojangPlatform;
|
||||||
QString realPlatform;
|
QString realPlatform;
|
||||||
JavaVersion javaVersion;
|
JavaVersion javaVersion;
|
||||||
@ -18,34 +23,31 @@ struct JavaCheckResult {
|
|||||||
QString outLog;
|
QString outLog;
|
||||||
QString errorLog;
|
QString errorLog;
|
||||||
bool is_64bit = false;
|
bool is_64bit = false;
|
||||||
int id;
|
|
||||||
enum class Validity { Errored, ReturnedInvalidData, Valid } validity = Validity::Errored;
|
enum class Validity { Errored, ReturnedInvalidData, Valid } validity = Validity::Errored;
|
||||||
};
|
};
|
||||||
|
|
||||||
using QProcessPtr = shared_qobject_ptr<QProcess>;
|
explicit JavaChecker(QString path, QString args, int minMem = 0, int maxMem = 0, int permGen = 0, int id = 0, QObject* parent = 0);
|
||||||
using JavaCheckerPtr = shared_qobject_ptr<JavaChecker>;
|
|
||||||
class JavaChecker : public QObject {
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit JavaChecker(QObject* parent = 0);
|
|
||||||
void performCheck();
|
|
||||||
|
|
||||||
QString m_path;
|
|
||||||
QString m_args;
|
|
||||||
int m_id = 0;
|
|
||||||
int m_minMem = 0;
|
|
||||||
int m_maxMem = 0;
|
|
||||||
int m_permGen = 64;
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void checkFinished(JavaCheckResult result);
|
void checkFinished(const Result& result);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void executeTask() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QProcessPtr process;
|
QProcessPtr process;
|
||||||
QTimer killTimer;
|
QTimer killTimer;
|
||||||
QString m_stdout;
|
QString m_stdout;
|
||||||
QString m_stderr;
|
QString m_stderr;
|
||||||
public slots:
|
|
||||||
|
QString m_path;
|
||||||
|
QString m_args;
|
||||||
|
int m_minMem = 0;
|
||||||
|
int m_maxMem = 0;
|
||||||
|
int m_permGen = 64;
|
||||||
|
int m_id = 0;
|
||||||
|
|
||||||
|
private slots:
|
||||||
void timeout();
|
void timeout();
|
||||||
void finished(int exitcode, QProcess::ExitStatus);
|
void finished(int exitcode, QProcess::ExitStatus);
|
||||||
void error(QProcess::ProcessError);
|
void error(QProcess::ProcessError);
|
||||||
|
@ -1,41 +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 "JavaCheckerJob.h"
|
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
|
|
||||||
void JavaCheckerJob::partFinished(JavaCheckResult result)
|
|
||||||
{
|
|
||||||
num_finished++;
|
|
||||||
qDebug() << m_job_name.toLocal8Bit() << "progress:" << num_finished << "/" << javacheckers.size();
|
|
||||||
setProgress(num_finished, javacheckers.size());
|
|
||||||
|
|
||||||
javaresults.replace(result.id, result);
|
|
||||||
|
|
||||||
if (num_finished == javacheckers.size()) {
|
|
||||||
emitSucceeded();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void JavaCheckerJob::executeTask()
|
|
||||||
{
|
|
||||||
qDebug() << m_job_name.toLocal8Bit() << " started.";
|
|
||||||
for (auto iter : javacheckers) {
|
|
||||||
javaresults.append(JavaCheckResult());
|
|
||||||
connect(iter.get(), &JavaChecker::checkFinished, this, &JavaCheckerJob::partFinished);
|
|
||||||
iter->performCheck();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,56 +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 <QtNetwork>
|
|
||||||
#include "JavaChecker.h"
|
|
||||||
#include "tasks/Task.h"
|
|
||||||
|
|
||||||
class JavaCheckerJob;
|
|
||||||
using JavaCheckerJobPtr = shared_qobject_ptr<JavaCheckerJob>;
|
|
||||||
|
|
||||||
// FIXME: this just seems horribly redundant
|
|
||||||
class JavaCheckerJob : public Task {
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit JavaCheckerJob(QString job_name) : Task(), m_job_name(job_name) {};
|
|
||||||
virtual ~JavaCheckerJob() {};
|
|
||||||
|
|
||||||
bool addJavaCheckerAction(JavaCheckerPtr base)
|
|
||||||
{
|
|
||||||
javacheckers.append(base);
|
|
||||||
// if this is already running, the action needs to be started right away!
|
|
||||||
if (isRunning()) {
|
|
||||||
setProgress(num_finished, javacheckers.size());
|
|
||||||
connect(base.get(), &JavaChecker::checkFinished, this, &JavaCheckerJob::partFinished);
|
|
||||||
base->performCheck();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
QList<JavaCheckResult> getResults() { return javaresults; }
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void partFinished(JavaCheckResult result);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void executeTask() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString m_job_name;
|
|
||||||
QList<JavaCheckerPtr> javacheckers;
|
|
||||||
QList<JavaCheckResult> javaresults;
|
|
||||||
int num_finished = 0;
|
|
||||||
};
|
|
@ -1,7 +1,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
/*
|
/*
|
||||||
* Prism Launcher - Minecraft Launcher
|
* Prism Launcher - Minecraft Launcher
|
||||||
* Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
|
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
/*
|
/*
|
||||||
* Prism Launcher - Minecraft Launcher
|
* Prism Launcher - Minecraft Launcher
|
||||||
* Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
|
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -40,6 +40,7 @@ struct JavaInstall : public BaseVersion {
|
|||||||
QString arch;
|
QString arch;
|
||||||
QString path;
|
QString path;
|
||||||
bool recommended = false;
|
bool recommended = false;
|
||||||
|
bool is_64bit = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
using JavaInstallPtr = std::shared_ptr<JavaInstall>;
|
using JavaInstallPtr = std::shared_ptr<JavaInstall>;
|
||||||
|
@ -38,13 +38,17 @@
|
|||||||
#include <QtXml>
|
#include <QtXml>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "java/JavaCheckerJob.h"
|
#include "Application.h"
|
||||||
|
#include "java/JavaChecker.h"
|
||||||
#include "java/JavaInstallList.h"
|
#include "java/JavaInstallList.h"
|
||||||
#include "java/JavaUtils.h"
|
#include "java/JavaUtils.h"
|
||||||
#include "minecraft/VersionFilterData.h"
|
#include "tasks/ConcurrentTask.h"
|
||||||
|
|
||||||
JavaInstallList::JavaInstallList(QObject* parent) : BaseVersionList(parent) {}
|
JavaInstallList::JavaInstallList(QObject* parent, bool onlyManagedVersions)
|
||||||
|
: BaseVersionList(parent), m_only_managed_versions(onlyManagedVersions)
|
||||||
|
{}
|
||||||
|
|
||||||
Task::Ptr JavaInstallList::getLoadTask()
|
Task::Ptr JavaInstallList::getLoadTask()
|
||||||
{
|
{
|
||||||
@ -55,7 +59,7 @@ Task::Ptr JavaInstallList::getLoadTask()
|
|||||||
Task::Ptr JavaInstallList::getCurrentTask()
|
Task::Ptr JavaInstallList::getCurrentTask()
|
||||||
{
|
{
|
||||||
if (m_status == Status::InProgress) {
|
if (m_status == Status::InProgress) {
|
||||||
return m_loadTask;
|
return m_load_task;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -64,8 +68,8 @@ void JavaInstallList::load()
|
|||||||
{
|
{
|
||||||
if (m_status != Status::InProgress) {
|
if (m_status != Status::InProgress) {
|
||||||
m_status = Status::InProgress;
|
m_status = Status::InProgress;
|
||||||
m_loadTask.reset(new JavaListLoadTask(this));
|
m_load_task.reset(new JavaListLoadTask(this, m_only_managed_versions));
|
||||||
m_loadTask->start();
|
m_load_task->start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +110,7 @@ QVariant JavaInstallList::data(const QModelIndex& index, int role) const
|
|||||||
return version->recommended;
|
return version->recommended;
|
||||||
case PathRole:
|
case PathRole:
|
||||||
return version->path;
|
return version->path;
|
||||||
case ArchitectureRole:
|
case CPUArchitectureRole:
|
||||||
return version->arch;
|
return version->arch;
|
||||||
default:
|
default:
|
||||||
return QVariant();
|
return QVariant();
|
||||||
@ -115,7 +119,7 @@ QVariant JavaInstallList::data(const QModelIndex& index, int role) const
|
|||||||
|
|
||||||
BaseVersionList::RoleList JavaInstallList::providesRoles() const
|
BaseVersionList::RoleList JavaInstallList::providesRoles() const
|
||||||
{
|
{
|
||||||
return { VersionPointerRole, VersionIdRole, VersionRole, RecommendedRole, PathRole, ArchitectureRole };
|
return { VersionPointerRole, VersionIdRole, VersionRole, RecommendedRole, PathRole, CPUArchitectureRole };
|
||||||
}
|
}
|
||||||
|
|
||||||
void JavaInstallList::updateListData(QList<BaseVersion::Ptr> versions)
|
void JavaInstallList::updateListData(QList<BaseVersion::Ptr> versions)
|
||||||
@ -129,7 +133,7 @@ void JavaInstallList::updateListData(QList<BaseVersion::Ptr> versions)
|
|||||||
}
|
}
|
||||||
endResetModel();
|
endResetModel();
|
||||||
m_status = Status::Done;
|
m_status = Status::Done;
|
||||||
m_loadTask.reset();
|
m_load_task.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sortJavas(BaseVersion::Ptr left, BaseVersion::Ptr right)
|
bool sortJavas(BaseVersion::Ptr left, BaseVersion::Ptr right)
|
||||||
@ -146,35 +150,30 @@ void JavaInstallList::sortVersions()
|
|||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
JavaListLoadTask::JavaListLoadTask(JavaInstallList* vlist) : Task()
|
JavaListLoadTask::JavaListLoadTask(JavaInstallList* vlist, bool onlyManagedVersions) : Task(), m_only_managed_versions(onlyManagedVersions)
|
||||||
{
|
{
|
||||||
m_list = vlist;
|
m_list = vlist;
|
||||||
m_currentRecommended = NULL;
|
m_current_recommended = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
JavaListLoadTask::~JavaListLoadTask() {}
|
|
||||||
|
|
||||||
void JavaListLoadTask::executeTask()
|
void JavaListLoadTask::executeTask()
|
||||||
{
|
{
|
||||||
setStatus(tr("Detecting Java installations..."));
|
setStatus(tr("Detecting Java installations..."));
|
||||||
|
|
||||||
JavaUtils ju;
|
JavaUtils ju;
|
||||||
QList<QString> candidate_paths = ju.FindJavaPaths();
|
QList<QString> candidate_paths = m_only_managed_versions ? getPrismJavaBundle() : ju.FindJavaPaths();
|
||||||
|
|
||||||
m_job.reset(new JavaCheckerJob("Java detection"));
|
ConcurrentTask::Ptr job(new ConcurrentTask(this, "Java detection", APPLICATION->settings()->get("NumberOfConcurrentTasks").toInt()));
|
||||||
|
m_job.reset(job);
|
||||||
connect(m_job.get(), &Task::finished, this, &JavaListLoadTask::javaCheckerFinished);
|
connect(m_job.get(), &Task::finished, this, &JavaListLoadTask::javaCheckerFinished);
|
||||||
connect(m_job.get(), &Task::progress, this, &Task::setProgress);
|
connect(m_job.get(), &Task::progress, this, &Task::setProgress);
|
||||||
|
|
||||||
qDebug() << "Probing the following Java paths: ";
|
qDebug() << "Probing the following Java paths: ";
|
||||||
int id = 0;
|
int id = 0;
|
||||||
for (QString candidate : candidate_paths) {
|
for (QString candidate : candidate_paths) {
|
||||||
qDebug() << " " << candidate;
|
auto checker = new JavaChecker(candidate, "", 0, 0, 0, id, this);
|
||||||
|
connect(checker, &JavaChecker::checkFinished, [this](const JavaChecker::Result& result) { m_results << result; });
|
||||||
auto candidate_checker = new JavaChecker();
|
job->addTask(Task::Ptr(checker));
|
||||||
candidate_checker->m_path = candidate;
|
|
||||||
candidate_checker->m_id = id;
|
|
||||||
m_job->addJavaCheckerAction(JavaCheckerPtr(candidate_checker));
|
|
||||||
|
|
||||||
id++;
|
id++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,16 +183,17 @@ void JavaListLoadTask::executeTask()
|
|||||||
void JavaListLoadTask::javaCheckerFinished()
|
void JavaListLoadTask::javaCheckerFinished()
|
||||||
{
|
{
|
||||||
QList<JavaInstallPtr> candidates;
|
QList<JavaInstallPtr> candidates;
|
||||||
auto results = m_job->getResults();
|
std::sort(m_results.begin(), m_results.end(), [](const JavaChecker::Result& a, const JavaChecker::Result& b) { return a.id < b.id; });
|
||||||
|
|
||||||
qDebug() << "Found the following valid Java installations:";
|
qDebug() << "Found the following valid Java installations:";
|
||||||
for (JavaCheckResult result : results) {
|
for (auto result : m_results) {
|
||||||
if (result.validity == JavaCheckResult::Validity::Valid) {
|
if (result.validity == JavaChecker::Result::Validity::Valid) {
|
||||||
JavaInstallPtr javaVersion(new JavaInstall());
|
JavaInstallPtr javaVersion(new JavaInstall());
|
||||||
|
|
||||||
javaVersion->id = result.javaVersion;
|
javaVersion->id = result.javaVersion;
|
||||||
javaVersion->arch = result.realPlatform;
|
javaVersion->arch = result.realPlatform;
|
||||||
javaVersion->path = result.path;
|
javaVersion->path = result.path;
|
||||||
|
javaVersion->is_64bit = result.is_64bit;
|
||||||
candidates.append(javaVersion);
|
candidates.append(javaVersion);
|
||||||
|
|
||||||
qDebug() << " " << javaVersion->id.toString() << javaVersion->arch << javaVersion->path;
|
qDebug() << " " << javaVersion->id.toString() << javaVersion->arch << javaVersion->path;
|
||||||
|
@ -19,9 +19,9 @@
|
|||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
#include "BaseVersionList.h"
|
#include "BaseVersionList.h"
|
||||||
|
#include "java/JavaChecker.h"
|
||||||
#include "tasks/Task.h"
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
#include "JavaCheckerJob.h"
|
|
||||||
#include "JavaInstall.h"
|
#include "JavaInstall.h"
|
||||||
|
|
||||||
#include "QObjectPtr.h"
|
#include "QObjectPtr.h"
|
||||||
@ -33,9 +33,9 @@ class JavaInstallList : public BaseVersionList {
|
|||||||
enum class Status { NotDone, InProgress, Done };
|
enum class Status { NotDone, InProgress, Done };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit JavaInstallList(QObject* parent = 0);
|
explicit JavaInstallList(QObject* parent = 0, bool onlyManagedVersions = false);
|
||||||
|
|
||||||
Task::Ptr getLoadTask() override;
|
[[nodiscard]] Task::Ptr getLoadTask() override;
|
||||||
bool isLoaded() override;
|
bool isLoaded() override;
|
||||||
const BaseVersion::Ptr at(int i) const override;
|
const BaseVersion::Ptr at(int i) const override;
|
||||||
int count() const override;
|
int count() const override;
|
||||||
@ -53,23 +53,27 @@ class JavaInstallList : public BaseVersionList {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
Status m_status = Status::NotDone;
|
Status m_status = Status::NotDone;
|
||||||
shared_qobject_ptr<JavaListLoadTask> m_loadTask;
|
shared_qobject_ptr<JavaListLoadTask> m_load_task;
|
||||||
QList<BaseVersion::Ptr> m_vlist;
|
QList<BaseVersion::Ptr> m_vlist;
|
||||||
|
bool m_only_managed_versions;
|
||||||
};
|
};
|
||||||
|
|
||||||
class JavaListLoadTask : public Task {
|
class JavaListLoadTask : public Task {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit JavaListLoadTask(JavaInstallList* vlist);
|
explicit JavaListLoadTask(JavaInstallList* vlist, bool onlyManagedVersions = false);
|
||||||
virtual ~JavaListLoadTask();
|
virtual ~JavaListLoadTask() = default;
|
||||||
|
|
||||||
|
protected:
|
||||||
void executeTask() override;
|
void executeTask() override;
|
||||||
public slots:
|
public slots:
|
||||||
void javaCheckerFinished();
|
void javaCheckerFinished();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
shared_qobject_ptr<JavaCheckerJob> m_job;
|
Task::Ptr m_job;
|
||||||
JavaInstallList* m_list;
|
JavaInstallList* m_list;
|
||||||
JavaInstall* m_currentRecommended;
|
JavaInstall* m_current_recommended;
|
||||||
|
QList<JavaChecker::Result> m_results;
|
||||||
|
bool m_only_managed_versions;
|
||||||
};
|
};
|
||||||
|
128
launcher/java/JavaMetadata.cpp
Normal file
128
launcher/java/JavaMetadata.cpp
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "java/JavaMetadata.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "Json.h"
|
||||||
|
#include "StringUtils.h"
|
||||||
|
#include "java/JavaVersion.h"
|
||||||
|
#include "minecraft/ParseUtils.h"
|
||||||
|
|
||||||
|
namespace Java {
|
||||||
|
|
||||||
|
DownloadType parseDownloadType(QString javaDownload)
|
||||||
|
{
|
||||||
|
if (javaDownload == "manifest")
|
||||||
|
return DownloadType::Manifest;
|
||||||
|
else if (javaDownload == "archive")
|
||||||
|
return DownloadType::Archive;
|
||||||
|
else
|
||||||
|
return DownloadType::Unknown;
|
||||||
|
}
|
||||||
|
QString downloadTypeToString(DownloadType javaDownload)
|
||||||
|
{
|
||||||
|
switch (javaDownload) {
|
||||||
|
case DownloadType::Manifest:
|
||||||
|
return "manifest";
|
||||||
|
case DownloadType::Archive:
|
||||||
|
return "archive";
|
||||||
|
case DownloadType::Unknown:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
MetadataPtr parseJavaMeta(const QJsonObject& in)
|
||||||
|
{
|
||||||
|
auto meta = std::make_shared<Metadata>();
|
||||||
|
|
||||||
|
meta->m_name = Json::ensureString(in, "name", "");
|
||||||
|
meta->vendor = Json::ensureString(in, "vendor", "");
|
||||||
|
meta->url = Json::ensureString(in, "url", "");
|
||||||
|
meta->releaseTime = timeFromS3Time(Json::ensureString(in, "releaseTime", ""));
|
||||||
|
meta->downloadType = parseDownloadType(Json::ensureString(in, "downloadType", ""));
|
||||||
|
meta->packageType = Json::ensureString(in, "packageType", "");
|
||||||
|
meta->runtimeOS = Json::ensureString(in, "runtimeOS", "unknown");
|
||||||
|
|
||||||
|
if (in.contains("checksum")) {
|
||||||
|
auto obj = Json::requireObject(in, "checksum");
|
||||||
|
meta->checksumHash = Json::ensureString(obj, "hash", "");
|
||||||
|
meta->checksumType = Json::ensureString(obj, "type", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in.contains("version")) {
|
||||||
|
auto obj = Json::requireObject(in, "version");
|
||||||
|
auto name = Json::ensureString(obj, "name", "");
|
||||||
|
auto major = Json::ensureInteger(obj, "major", 0);
|
||||||
|
auto minor = Json::ensureInteger(obj, "minor", 0);
|
||||||
|
auto security = Json::ensureInteger(obj, "security", 0);
|
||||||
|
auto build = Json::ensureInteger(obj, "build", 0);
|
||||||
|
meta->version = JavaVersion(major, minor, security, build, name);
|
||||||
|
}
|
||||||
|
return meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Metadata::operator<(const Metadata& rhs)
|
||||||
|
{
|
||||||
|
auto id = version;
|
||||||
|
if (id < rhs.version) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (id > rhs.version) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto date = releaseTime;
|
||||||
|
if (date < rhs.releaseTime) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (date > rhs.releaseTime) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return StringUtils::naturalCompare(m_name, rhs.m_name, Qt::CaseInsensitive) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Metadata::operator==(const Metadata& rhs)
|
||||||
|
{
|
||||||
|
return version == rhs.version && m_name == rhs.m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Metadata::operator>(const Metadata& rhs)
|
||||||
|
{
|
||||||
|
return (!operator<(rhs)) && (!operator==(rhs));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Metadata::operator<(BaseVersion& a)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return operator<(dynamic_cast<Metadata&>(a));
|
||||||
|
} catch (const std::bad_cast& e) {
|
||||||
|
return BaseVersion::operator<(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Metadata::operator>(BaseVersion& a)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return operator>(dynamic_cast<Metadata&>(a));
|
||||||
|
} catch (const std::bad_cast& e) {
|
||||||
|
return BaseVersion::operator>(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Java
|
64
launcher/java/JavaMetadata.h
Normal file
64
launcher/java/JavaMetadata.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "BaseVersion.h"
|
||||||
|
#include "java/JavaVersion.h"
|
||||||
|
|
||||||
|
namespace Java {
|
||||||
|
|
||||||
|
enum class DownloadType { Manifest, Archive, Unknown };
|
||||||
|
|
||||||
|
class Metadata : public BaseVersion {
|
||||||
|
public:
|
||||||
|
virtual QString descriptor() override { return version.toString(); }
|
||||||
|
|
||||||
|
virtual QString name() override { return m_name; }
|
||||||
|
|
||||||
|
virtual QString typeString() const override { return vendor; }
|
||||||
|
|
||||||
|
virtual bool operator<(BaseVersion& a) override;
|
||||||
|
virtual bool operator>(BaseVersion& a) override;
|
||||||
|
bool operator<(const Metadata& rhs);
|
||||||
|
bool operator==(const Metadata& rhs);
|
||||||
|
bool operator>(const Metadata& rhs);
|
||||||
|
|
||||||
|
QString m_name;
|
||||||
|
QString vendor;
|
||||||
|
QString url;
|
||||||
|
QDateTime releaseTime;
|
||||||
|
QString checksumType;
|
||||||
|
QString checksumHash;
|
||||||
|
DownloadType downloadType;
|
||||||
|
QString packageType;
|
||||||
|
JavaVersion version;
|
||||||
|
QString runtimeOS;
|
||||||
|
};
|
||||||
|
using MetadataPtr = std::shared_ptr<Metadata>;
|
||||||
|
|
||||||
|
DownloadType parseDownloadType(QString javaDownload);
|
||||||
|
QString downloadTypeToString(DownloadType javaDownload);
|
||||||
|
MetadataPtr parseJavaMeta(const QJsonObject& libObj);
|
||||||
|
|
||||||
|
} // namespace Java
|
@ -182,8 +182,9 @@ QList<JavaInstallPtr> JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString
|
|||||||
else if (keyType == KEY_WOW64_32KEY)
|
else if (keyType == KEY_WOW64_32KEY)
|
||||||
archType = "32";
|
archType = "32";
|
||||||
|
|
||||||
|
for (HKEY baseRegistry : { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE }) {
|
||||||
HKEY jreKey;
|
HKEY jreKey;
|
||||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keyName.toStdWString().c_str(), 0, KEY_READ | keyType | KEY_ENUMERATE_SUB_KEYS, &jreKey) ==
|
if (RegOpenKeyExW(baseRegistry, keyName.toStdWString().c_str(), 0, KEY_READ | keyType | KEY_ENUMERATE_SUB_KEYS, &jreKey) ==
|
||||||
ERROR_SUCCESS) {
|
ERROR_SUCCESS) {
|
||||||
// Read the current type version from the registry.
|
// Read the current type version from the registry.
|
||||||
// This will be used to find any key that contains the JavaHome value.
|
// This will be used to find any key that contains the JavaHome value.
|
||||||
@ -205,7 +206,7 @@ QList<JavaInstallPtr> JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString
|
|||||||
QString newKeyName = keyName + "\\" + newSubkeyName + subkeySuffix;
|
QString newKeyName = keyName + "\\" + newSubkeyName + subkeySuffix;
|
||||||
|
|
||||||
HKEY newKey;
|
HKEY newKey;
|
||||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, newKeyName.toStdWString().c_str(), 0, KEY_READ | keyType, &newKey) ==
|
if (RegOpenKeyExW(baseRegistry, newKeyName.toStdWString().c_str(), 0, KEY_READ | keyType, &newKey) ==
|
||||||
ERROR_SUCCESS) {
|
ERROR_SUCCESS) {
|
||||||
// Read the JavaHome value to find where Java is installed.
|
// Read the JavaHome value to find where Java is installed.
|
||||||
DWORD valueSz = 0;
|
DWORD valueSz = 0;
|
||||||
@ -233,6 +234,7 @@ QList<JavaInstallPtr> JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString
|
|||||||
|
|
||||||
RegCloseKey(jreKey);
|
RegCloseKey(jreKey);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return javas;
|
return javas;
|
||||||
}
|
}
|
||||||
@ -345,6 +347,7 @@ QList<QString> JavaUtils::FindJavaPaths()
|
|||||||
}
|
}
|
||||||
|
|
||||||
candidates.append(getMinecraftJavaBundle());
|
candidates.append(getMinecraftJavaBundle());
|
||||||
|
candidates.append(getPrismJavaBundle());
|
||||||
candidates = addJavasFromEnv(candidates);
|
candidates = addJavasFromEnv(candidates);
|
||||||
candidates.removeDuplicates();
|
candidates.removeDuplicates();
|
||||||
return candidates;
|
return candidates;
|
||||||
@ -389,6 +392,7 @@ QList<QString> JavaUtils::FindJavaPaths()
|
|||||||
}
|
}
|
||||||
|
|
||||||
javas.append(getMinecraftJavaBundle());
|
javas.append(getMinecraftJavaBundle());
|
||||||
|
javas.append(getPrismJavaBundle());
|
||||||
javas = addJavasFromEnv(javas);
|
javas = addJavasFromEnv(javas);
|
||||||
javas.removeDuplicates();
|
javas.removeDuplicates();
|
||||||
return javas;
|
return javas;
|
||||||
@ -452,6 +456,7 @@ QList<QString> JavaUtils::FindJavaPaths()
|
|||||||
scanJavaDirs(FS::PathCombine(home, ".gradle/jdks"));
|
scanJavaDirs(FS::PathCombine(home, ".gradle/jdks"));
|
||||||
|
|
||||||
javas.append(getMinecraftJavaBundle());
|
javas.append(getMinecraftJavaBundle());
|
||||||
|
javas.append(getPrismJavaBundle());
|
||||||
javas = addJavasFromEnv(javas);
|
javas = addJavasFromEnv(javas);
|
||||||
javas.removeDuplicates();
|
javas.removeDuplicates();
|
||||||
return javas;
|
return javas;
|
||||||
@ -465,6 +470,8 @@ QList<QString> JavaUtils::FindJavaPaths()
|
|||||||
javas.append(this->GetDefaultJava()->path);
|
javas.append(this->GetDefaultJava()->path);
|
||||||
|
|
||||||
javas.append(getMinecraftJavaBundle());
|
javas.append(getMinecraftJavaBundle());
|
||||||
|
javas.append(getPrismJavaBundle());
|
||||||
|
javas.removeDuplicates();
|
||||||
return addJavasFromEnv(javas);
|
return addJavasFromEnv(javas);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -476,12 +483,10 @@ QString JavaUtils::getJavaCheckPath()
|
|||||||
|
|
||||||
QStringList getMinecraftJavaBundle()
|
QStringList getMinecraftJavaBundle()
|
||||||
{
|
{
|
||||||
QString executable = "java";
|
|
||||||
QStringList processpaths;
|
QStringList processpaths;
|
||||||
#if defined(Q_OS_OSX)
|
#if defined(Q_OS_OSX)
|
||||||
processpaths << FS::PathCombine(QDir::homePath(), FS::PathCombine("Library", "Application Support", "minecraft", "runtime"));
|
processpaths << FS::PathCombine(QDir::homePath(), FS::PathCombine("Library", "Application Support", "minecraft", "runtime"));
|
||||||
#elif defined(Q_OS_WIN32)
|
#elif defined(Q_OS_WIN32)
|
||||||
executable += "w.exe";
|
|
||||||
|
|
||||||
auto appDataPath = QProcessEnvironment::systemEnvironment().value("APPDATA", "");
|
auto appDataPath = QProcessEnvironment::systemEnvironment().value("APPDATA", "");
|
||||||
processpaths << FS::PathCombine(QFileInfo(appDataPath).absoluteFilePath(), ".minecraft", "runtime");
|
processpaths << FS::PathCombine(QFileInfo(appDataPath).absoluteFilePath(), ".minecraft", "runtime");
|
||||||
@ -506,7 +511,7 @@ QStringList getMinecraftJavaBundle()
|
|||||||
auto binFound = false;
|
auto binFound = false;
|
||||||
for (auto& entry : entries) {
|
for (auto& entry : entries) {
|
||||||
if (entry.baseName() == "bin") {
|
if (entry.baseName() == "bin") {
|
||||||
javas.append(FS::PathCombine(entry.canonicalFilePath(), executable));
|
javas.append(FS::PathCombine(entry.canonicalFilePath(), JavaUtils::javaExecutable));
|
||||||
binFound = true;
|
binFound = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -519,3 +524,33 @@ QStringList getMinecraftJavaBundle()
|
|||||||
}
|
}
|
||||||
return javas;
|
return javas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(Q_OS_WIN32)
|
||||||
|
const QString JavaUtils::javaExecutable = "javaw.exe";
|
||||||
|
#else
|
||||||
|
const QString JavaUtils::javaExecutable = "java";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QStringList getPrismJavaBundle()
|
||||||
|
{
|
||||||
|
QList<QString> javas;
|
||||||
|
|
||||||
|
auto scanDir = [&](QString prefix) {
|
||||||
|
javas.append(FS::PathCombine(prefix, "jre", "bin", JavaUtils::javaExecutable));
|
||||||
|
javas.append(FS::PathCombine(prefix, "bin", JavaUtils::javaExecutable));
|
||||||
|
javas.append(FS::PathCombine(prefix, JavaUtils::javaExecutable));
|
||||||
|
};
|
||||||
|
auto scanJavaDir = [&](const QString& dirPath) {
|
||||||
|
QDir dir(dirPath);
|
||||||
|
if (!dir.exists())
|
||||||
|
return;
|
||||||
|
auto entries = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||||
|
for (auto& entry : entries) {
|
||||||
|
scanDir(entry.canonicalFilePath());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
scanJavaDir(APPLICATION->javaPath());
|
||||||
|
|
||||||
|
return javas;
|
||||||
|
}
|
||||||
|
@ -15,10 +15,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <QProcess>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
#include "java/JavaInstall.h"
|
||||||
#include "JavaChecker.h"
|
|
||||||
#include "JavaInstallList.h"
|
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
@ -27,6 +26,7 @@
|
|||||||
QString stripVariableEntries(QString name, QString target, QString remove);
|
QString stripVariableEntries(QString name, QString target, QString remove);
|
||||||
QProcessEnvironment CleanEnviroment();
|
QProcessEnvironment CleanEnviroment();
|
||||||
QStringList getMinecraftJavaBundle();
|
QStringList getMinecraftJavaBundle();
|
||||||
|
QStringList getPrismJavaBundle();
|
||||||
|
|
||||||
class JavaUtils : public QObject {
|
class JavaUtils : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -42,4 +42,5 @@ class JavaUtils : public QObject {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static QString getJavaCheckPath();
|
static QString getJavaCheckPath();
|
||||||
|
static const QString javaExecutable;
|
||||||
};
|
};
|
||||||
|
@ -43,12 +43,12 @@ QString JavaVersion::toString() const
|
|||||||
return m_string;
|
return m_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JavaVersion::requiresPermGen()
|
bool JavaVersion::requiresPermGen() const
|
||||||
{
|
{
|
||||||
return !m_parseable || m_major < 8;
|
return !m_parseable || m_major < 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JavaVersion::isModular()
|
bool JavaVersion::isModular() const
|
||||||
{
|
{
|
||||||
return m_parseable && m_major >= 9;
|
return m_parseable && m_major >= 9;
|
||||||
}
|
}
|
||||||
@ -59,12 +59,6 @@ bool JavaVersion::operator<(const JavaVersion& rhs)
|
|||||||
auto major = m_major;
|
auto major = m_major;
|
||||||
auto rmajor = rhs.m_major;
|
auto rmajor = rhs.m_major;
|
||||||
|
|
||||||
// HACK: discourage using java 9
|
|
||||||
if (major > 8)
|
|
||||||
major = -major;
|
|
||||||
if (rmajor > 8)
|
|
||||||
rmajor = -rmajor;
|
|
||||||
|
|
||||||
if (major < rmajor)
|
if (major < rmajor)
|
||||||
return true;
|
return true;
|
||||||
if (major > rmajor)
|
if (major > rmajor)
|
||||||
@ -109,3 +103,24 @@ bool JavaVersion::operator>(const JavaVersion& rhs)
|
|||||||
{
|
{
|
||||||
return (!operator<(rhs)) && (!operator==(rhs));
|
return (!operator<(rhs)) && (!operator==(rhs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JavaVersion::JavaVersion(int major, int minor, int security, int build, QString name)
|
||||||
|
: m_major(major), m_minor(minor), m_security(security), m_name(name), m_parseable(true)
|
||||||
|
{
|
||||||
|
QStringList versions;
|
||||||
|
if (build != 0) {
|
||||||
|
m_prerelease = QString::number(build);
|
||||||
|
versions.push_front(m_prerelease);
|
||||||
|
}
|
||||||
|
if (m_security != 0)
|
||||||
|
versions.push_front(QString::number(m_security));
|
||||||
|
else if (!versions.isEmpty())
|
||||||
|
versions.push_front("0");
|
||||||
|
|
||||||
|
if (m_minor != 0)
|
||||||
|
versions.push_front(QString::number(m_minor));
|
||||||
|
else if (!versions.isEmpty())
|
||||||
|
versions.push_front("0");
|
||||||
|
versions.push_front(QString::number(m_major));
|
||||||
|
m_string = versions.join(".");
|
||||||
|
}
|
||||||
|
@ -16,6 +16,7 @@ class JavaVersion {
|
|||||||
public:
|
public:
|
||||||
JavaVersion() {}
|
JavaVersion() {}
|
||||||
JavaVersion(const QString& rhs);
|
JavaVersion(const QString& rhs);
|
||||||
|
JavaVersion(int major, int minor, int security, int build = 0, QString name = "");
|
||||||
|
|
||||||
JavaVersion& operator=(const QString& rhs);
|
JavaVersion& operator=(const QString& rhs);
|
||||||
|
|
||||||
@ -23,21 +24,24 @@ class JavaVersion {
|
|||||||
bool operator==(const JavaVersion& rhs);
|
bool operator==(const JavaVersion& rhs);
|
||||||
bool operator>(const JavaVersion& rhs);
|
bool operator>(const JavaVersion& rhs);
|
||||||
|
|
||||||
bool requiresPermGen();
|
bool requiresPermGen() const;
|
||||||
|
|
||||||
bool isModular();
|
bool isModular() const;
|
||||||
|
|
||||||
QString toString() const;
|
QString toString() const;
|
||||||
|
|
||||||
int major() { return m_major; }
|
int major() const { return m_major; }
|
||||||
int minor() { return m_minor; }
|
int minor() const { return m_minor; }
|
||||||
int security() { return m_security; }
|
int security() const { return m_security; }
|
||||||
|
QString build() const { return m_prerelease; }
|
||||||
|
QString name() const { return m_name; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_string;
|
QString m_string;
|
||||||
int m_major = 0;
|
int m_major = 0;
|
||||||
int m_minor = 0;
|
int m_minor = 0;
|
||||||
int m_security = 0;
|
int m_security = 0;
|
||||||
|
QString m_name = "";
|
||||||
bool m_parseable = false;
|
bool m_parseable = false;
|
||||||
QString m_prerelease;
|
QString m_prerelease;
|
||||||
};
|
};
|
||||||
|
141
launcher/java/download/ArchiveDownloadTask.cpp
Normal file
141
launcher/java/download/ArchiveDownloadTask.cpp
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "java/download/ArchiveDownloadTask.h"
|
||||||
|
#include <quazip.h>
|
||||||
|
#include <memory>
|
||||||
|
#include "MMCZip.h"
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
#include "Untar.h"
|
||||||
|
#include "net/ChecksumValidator.h"
|
||||||
|
#include "net/NetJob.h"
|
||||||
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
|
namespace Java {
|
||||||
|
ArchiveDownloadTask::ArchiveDownloadTask(QUrl url, QString final_path, QString checksumType, QString checksumHash)
|
||||||
|
: m_url(url), m_final_path(final_path), m_checksum_type(checksumType), m_checksum_hash(checksumHash)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void ArchiveDownloadTask::executeTask()
|
||||||
|
{
|
||||||
|
// JRE found ! download the zip
|
||||||
|
setStatus(tr("Downloading Java"));
|
||||||
|
|
||||||
|
MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry("java", m_url.fileName());
|
||||||
|
|
||||||
|
auto download = makeShared<NetJob>(QString("JRE::DownloadJava"), APPLICATION->network());
|
||||||
|
auto action = Net::Download::makeCached(m_url, entry);
|
||||||
|
if (!m_checksum_hash.isEmpty() && !m_checksum_type.isEmpty()) {
|
||||||
|
auto hashType = QCryptographicHash::Algorithm::Sha1;
|
||||||
|
if (m_checksum_type == "sha256") {
|
||||||
|
hashType = QCryptographicHash::Algorithm::Sha256;
|
||||||
|
}
|
||||||
|
action->addValidator(new Net::ChecksumValidator(hashType, QByteArray::fromHex(m_checksum_hash.toUtf8())));
|
||||||
|
}
|
||||||
|
download->addNetAction(action);
|
||||||
|
auto fullPath = entry->getFullPath();
|
||||||
|
|
||||||
|
connect(download.get(), &Task::failed, this, &ArchiveDownloadTask::emitFailed);
|
||||||
|
connect(download.get(), &Task::progress, this, &ArchiveDownloadTask::setProgress);
|
||||||
|
connect(download.get(), &Task::stepProgress, this, &ArchiveDownloadTask::propagateStepProgress);
|
||||||
|
connect(download.get(), &Task::status, this, &ArchiveDownloadTask::setStatus);
|
||||||
|
connect(download.get(), &Task::details, this, &ArchiveDownloadTask::setDetails);
|
||||||
|
connect(download.get(), &Task::succeeded, [this, fullPath] {
|
||||||
|
// This should do all of the extracting and creating folders
|
||||||
|
extractJava(fullPath);
|
||||||
|
});
|
||||||
|
m_task = download;
|
||||||
|
m_task->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ArchiveDownloadTask::extractJava(QString input)
|
||||||
|
{
|
||||||
|
setStatus(tr("Extracting java"));
|
||||||
|
if (input.endsWith("tar")) {
|
||||||
|
setStatus(tr("Extracting Java (Progress is not reported for tar archives)"));
|
||||||
|
QFile in(input);
|
||||||
|
if (!in.open(QFile::ReadOnly)) {
|
||||||
|
emitFailed(tr("Unable to open supplied tar file."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!Tar::extract(&in, QDir(m_final_path).absolutePath())) {
|
||||||
|
emitFailed(tr("Unable to extract supplied tar file."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
emitSucceeded();
|
||||||
|
return;
|
||||||
|
} else if (input.endsWith("tar.gz") || input.endsWith("taz") || input.endsWith("tgz")) {
|
||||||
|
setStatus(tr("Extracting Java (Progress is not reported for tar archives)"));
|
||||||
|
if (!GZTar::extract(input, QDir(m_final_path).absolutePath())) {
|
||||||
|
emitFailed(tr("Unable to extract supplied tar file."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
emitSucceeded();
|
||||||
|
return;
|
||||||
|
} else if (input.endsWith("zip")) {
|
||||||
|
auto zip = std::make_shared<QuaZip>(input);
|
||||||
|
if (!zip->open(QuaZip::mdUnzip)) {
|
||||||
|
emitFailed(tr("Unable to open supplied zip file."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto files = zip->getFileNameList();
|
||||||
|
if (files.isEmpty()) {
|
||||||
|
emitFailed(tr("No files were found in the supplied zip file,"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_task = makeShared<MMCZip::ExtractZipTask>(zip, m_final_path, files[0]);
|
||||||
|
|
||||||
|
auto progressStep = std::make_shared<TaskStepProgress>();
|
||||||
|
connect(m_task.get(), &Task::finished, this, [this, progressStep] {
|
||||||
|
progressStep->state = TaskStepState::Succeeded;
|
||||||
|
stepProgress(*progressStep);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(m_task.get(), &Task::succeeded, this, &ArchiveDownloadTask::emitSucceeded);
|
||||||
|
connect(m_task.get(), &Task::aborted, this, &ArchiveDownloadTask::emitAborted);
|
||||||
|
connect(m_task.get(), &Task::failed, this, [this, progressStep](QString reason) {
|
||||||
|
progressStep->state = TaskStepState::Failed;
|
||||||
|
stepProgress(*progressStep);
|
||||||
|
emitFailed(reason);
|
||||||
|
});
|
||||||
|
connect(m_task.get(), &Task::stepProgress, this, &ArchiveDownloadTask::propagateStepProgress);
|
||||||
|
|
||||||
|
connect(m_task.get(), &Task::progress, this, [this, progressStep](qint64 current, qint64 total) {
|
||||||
|
progressStep->update(current, total);
|
||||||
|
stepProgress(*progressStep);
|
||||||
|
});
|
||||||
|
connect(m_task.get(), &Task::status, this, [this, progressStep](QString status) {
|
||||||
|
progressStep->status = status;
|
||||||
|
stepProgress(*progressStep);
|
||||||
|
});
|
||||||
|
m_task->start();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emitFailed(tr("Could not determine archive type!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ArchiveDownloadTask::abort()
|
||||||
|
{
|
||||||
|
auto aborted = canAbort();
|
||||||
|
if (m_task)
|
||||||
|
aborted = m_task->abort();
|
||||||
|
emitAborted();
|
||||||
|
return aborted;
|
||||||
|
};
|
||||||
|
} // namespace Java
|
45
launcher/java/download/ArchiveDownloadTask.h
Normal file
45
launcher/java/download/ArchiveDownloadTask.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QUrl>
|
||||||
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
|
namespace Java {
|
||||||
|
class ArchiveDownloadTask : public Task {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
ArchiveDownloadTask(QUrl url, QString final_path, QString checksumType = "", QString checksumHash = "");
|
||||||
|
virtual ~ArchiveDownloadTask() = default;
|
||||||
|
|
||||||
|
[[nodiscard]] bool canAbort() const override { return true; }
|
||||||
|
void executeTask() override;
|
||||||
|
virtual bool abort() override;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void extractJava(QString input);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QUrl m_url;
|
||||||
|
QString m_final_path;
|
||||||
|
QString m_checksum_type;
|
||||||
|
QString m_checksum_hash;
|
||||||
|
Task::Ptr m_task;
|
||||||
|
};
|
||||||
|
} // namespace Java
|
138
launcher/java/download/ManifestDownloadTask.cpp
Normal file
138
launcher/java/download/ManifestDownloadTask.cpp
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "java/download/ManifestDownloadTask.h"
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
#include "FileSystem.h"
|
||||||
|
#include "Json.h"
|
||||||
|
#include "net/ChecksumValidator.h"
|
||||||
|
#include "net/NetJob.h"
|
||||||
|
|
||||||
|
struct File {
|
||||||
|
QString path;
|
||||||
|
QString url;
|
||||||
|
QByteArray hash;
|
||||||
|
bool isExec;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace Java {
|
||||||
|
ManifestDownloadTask::ManifestDownloadTask(QUrl url, QString final_path, QString checksumType, QString checksumHash)
|
||||||
|
: m_url(url), m_final_path(final_path), m_checksum_type(checksumType), m_checksum_hash(checksumHash)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void ManifestDownloadTask::executeTask()
|
||||||
|
{
|
||||||
|
setStatus(tr("Downloading Java"));
|
||||||
|
auto download = makeShared<NetJob>(QString("JRE::DownloadJava"), APPLICATION->network());
|
||||||
|
auto files = std::make_shared<QByteArray>();
|
||||||
|
|
||||||
|
auto action = Net::Download::makeByteArray(m_url, files);
|
||||||
|
if (!m_checksum_hash.isEmpty() && !m_checksum_type.isEmpty()) {
|
||||||
|
auto hashType = QCryptographicHash::Algorithm::Sha1;
|
||||||
|
if (m_checksum_type == "sha256") {
|
||||||
|
hashType = QCryptographicHash::Algorithm::Sha256;
|
||||||
|
}
|
||||||
|
action->addValidator(new Net::ChecksumValidator(hashType, QByteArray::fromHex(m_checksum_hash.toUtf8())));
|
||||||
|
}
|
||||||
|
download->addNetAction(action);
|
||||||
|
|
||||||
|
connect(download.get(), &Task::failed, this, &ManifestDownloadTask::emitFailed);
|
||||||
|
connect(download.get(), &Task::progress, this, &ManifestDownloadTask::setProgress);
|
||||||
|
connect(download.get(), &Task::stepProgress, this, &ManifestDownloadTask::propagateStepProgress);
|
||||||
|
connect(download.get(), &Task::status, this, &ManifestDownloadTask::setStatus);
|
||||||
|
connect(download.get(), &Task::details, this, &ManifestDownloadTask::setDetails);
|
||||||
|
|
||||||
|
connect(download.get(), &Task::succeeded, [files, this] {
|
||||||
|
QJsonParseError parse_error{};
|
||||||
|
QJsonDocument doc = QJsonDocument::fromJson(*files, &parse_error);
|
||||||
|
if (parse_error.error != QJsonParseError::NoError) {
|
||||||
|
qWarning() << "Error while parsing JSON response at " << parse_error.offset << ". Reason: " << parse_error.errorString();
|
||||||
|
qWarning() << *files;
|
||||||
|
emitFailed(parse_error.errorString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
downloadJava(doc);
|
||||||
|
});
|
||||||
|
m_task = download;
|
||||||
|
m_task->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ManifestDownloadTask::downloadJava(const QJsonDocument& doc)
|
||||||
|
{
|
||||||
|
// valid json doc, begin making jre spot
|
||||||
|
FS::ensureFolderPathExists(m_final_path);
|
||||||
|
std::vector<File> toDownload;
|
||||||
|
auto list = Json::ensureObject(Json::ensureObject(doc.object()), "files");
|
||||||
|
for (const auto& paths : list.keys()) {
|
||||||
|
auto file = FS::PathCombine(m_final_path, paths);
|
||||||
|
|
||||||
|
const QJsonObject& meta = Json::ensureObject(list, paths);
|
||||||
|
auto type = Json::ensureString(meta, "type");
|
||||||
|
if (type == "directory") {
|
||||||
|
FS::ensureFolderPathExists(file);
|
||||||
|
} else if (type == "link") {
|
||||||
|
// this is linux only !
|
||||||
|
auto path = Json::ensureString(meta, "target");
|
||||||
|
if (!path.isEmpty()) {
|
||||||
|
auto target = FS::PathCombine(file, "../" + path);
|
||||||
|
QFile(target).link(file);
|
||||||
|
}
|
||||||
|
} else if (type == "file") {
|
||||||
|
// TODO download compressed version if it exists ?
|
||||||
|
auto raw = Json::ensureObject(Json::ensureObject(meta, "downloads"), "raw");
|
||||||
|
auto isExec = Json::ensureBoolean(meta, "executable", false);
|
||||||
|
auto url = Json::ensureString(raw, "url");
|
||||||
|
if (!url.isEmpty() && QUrl(url).isValid()) {
|
||||||
|
auto f = File{ file, url, QByteArray::fromHex(Json::ensureString(raw, "sha1").toLatin1()), isExec };
|
||||||
|
toDownload.push_back(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto elementDownload = makeShared<NetJob>("JRE::FileDownload", APPLICATION->network());
|
||||||
|
for (const auto& file : toDownload) {
|
||||||
|
auto dl = Net::Download::makeFile(file.url, file.path);
|
||||||
|
if (!file.hash.isEmpty()) {
|
||||||
|
dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, file.hash));
|
||||||
|
}
|
||||||
|
if (file.isExec) {
|
||||||
|
connect(dl.get(), &Net::Download::succeeded,
|
||||||
|
[file] { QFile(file.path).setPermissions(QFile(file.path).permissions() | QFileDevice::Permissions(0x1111)); });
|
||||||
|
}
|
||||||
|
elementDownload->addNetAction(dl);
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(elementDownload.get(), &Task::failed, this, &ManifestDownloadTask::emitFailed);
|
||||||
|
connect(elementDownload.get(), &Task::progress, this, &ManifestDownloadTask::setProgress);
|
||||||
|
connect(elementDownload.get(), &Task::stepProgress, this, &ManifestDownloadTask::propagateStepProgress);
|
||||||
|
connect(elementDownload.get(), &Task::status, this, &ManifestDownloadTask::setStatus);
|
||||||
|
connect(elementDownload.get(), &Task::details, this, &ManifestDownloadTask::setDetails);
|
||||||
|
|
||||||
|
connect(elementDownload.get(), &Task::succeeded, this, &ManifestDownloadTask::emitSucceeded);
|
||||||
|
m_task = elementDownload;
|
||||||
|
m_task->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ManifestDownloadTask::abort()
|
||||||
|
{
|
||||||
|
auto aborted = canAbort();
|
||||||
|
if (m_task)
|
||||||
|
aborted = m_task->abort();
|
||||||
|
emitAborted();
|
||||||
|
return aborted;
|
||||||
|
};
|
||||||
|
} // namespace Java
|
46
launcher/java/download/ManifestDownloadTask.h
Normal file
46
launcher/java/download/ManifestDownloadTask.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QUrl>
|
||||||
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
|
namespace Java {
|
||||||
|
|
||||||
|
class ManifestDownloadTask : public Task {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
ManifestDownloadTask(QUrl url, QString final_path, QString checksumType = "", QString checksumHash = "");
|
||||||
|
virtual ~ManifestDownloadTask() = default;
|
||||||
|
|
||||||
|
[[nodiscard]] bool canAbort() const override { return true; }
|
||||||
|
void executeTask() override;
|
||||||
|
virtual bool abort() override;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void downloadJava(const QJsonDocument& doc);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QUrl m_url;
|
||||||
|
QString m_final_path;
|
||||||
|
QString m_checksum_type;
|
||||||
|
QString m_checksum_hash;
|
||||||
|
Task::Ptr m_task;
|
||||||
|
};
|
||||||
|
} // namespace Java
|
@ -37,6 +37,7 @@
|
|||||||
#include <FileSystem.h>
|
#include <FileSystem.h>
|
||||||
#include <launch/LaunchTask.h>
|
#include <launch/LaunchTask.h>
|
||||||
#include <sys.h>
|
#include <sys.h>
|
||||||
|
#include <QCryptographicHash>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include "java/JavaUtils.h"
|
#include "java/JavaUtils.h"
|
||||||
@ -45,20 +46,23 @@ void CheckJava::executeTask()
|
|||||||
{
|
{
|
||||||
auto instance = m_parent->instance();
|
auto instance = m_parent->instance();
|
||||||
auto settings = instance->settings();
|
auto settings = instance->settings();
|
||||||
m_javaPath = FS::ResolveExecutable(settings->get("JavaPath").toString());
|
|
||||||
|
QString javaPathSetting = settings->get("JavaPath").toString();
|
||||||
|
m_javaPath = FS::ResolveExecutable(javaPathSetting);
|
||||||
|
|
||||||
bool perInstance = settings->get("OverrideJava").toBool() || settings->get("OverrideJavaLocation").toBool();
|
bool perInstance = settings->get("OverrideJava").toBool() || settings->get("OverrideJavaLocation").toBool();
|
||||||
|
|
||||||
auto realJavaPath = QStandardPaths::findExecutable(m_javaPath);
|
auto realJavaPath = QStandardPaths::findExecutable(m_javaPath);
|
||||||
if (realJavaPath.isEmpty()) {
|
if (realJavaPath.isEmpty()) {
|
||||||
if (perInstance) {
|
if (perInstance) {
|
||||||
emit logLine(QString("The java binary \"%1\" couldn't be found. Please fix the java path "
|
emit logLine(QString("The Java binary \"%1\" couldn't be found. Please fix the Java path "
|
||||||
"override in the instance's settings or disable it.")
|
"override in the instance's settings or disable it.")
|
||||||
.arg(m_javaPath),
|
.arg(javaPathSetting),
|
||||||
MessageLevel::Warning);
|
MessageLevel::Warning);
|
||||||
} else {
|
} else {
|
||||||
emit logLine(QString("The java binary \"%1\" couldn't be found. Please set up java in "
|
emit logLine(QString("The Java binary \"%1\" couldn't be found. Please set up Java in "
|
||||||
"the settings.")
|
"the settings.")
|
||||||
.arg(m_javaPath),
|
.arg(javaPathSetting),
|
||||||
MessageLevel::Warning);
|
MessageLevel::Warning);
|
||||||
}
|
}
|
||||||
emitFailed(QString("Java path is not valid."));
|
emitFailed(QString("Java path is not valid."));
|
||||||
@ -90,11 +94,10 @@ void CheckJava::executeTask()
|
|||||||
// if timestamps are not the same, or something is missing, check!
|
// if timestamps are not the same, or something is missing, check!
|
||||||
if (m_javaSignature != storedSignature || storedVersion.size() == 0 || storedArchitecture.size() == 0 ||
|
if (m_javaSignature != storedSignature || storedVersion.size() == 0 || storedArchitecture.size() == 0 ||
|
||||||
storedRealArchitecture.size() == 0 || storedVendor.size() == 0) {
|
storedRealArchitecture.size() == 0 || storedVendor.size() == 0) {
|
||||||
m_JavaChecker.reset(new JavaChecker);
|
m_JavaChecker.reset(new JavaChecker(realJavaPath, "", 0, 0, 0, 0, this));
|
||||||
emit logLine(QString("Checking Java version..."), MessageLevel::Launcher);
|
emit logLine(QString("Checking Java version..."), MessageLevel::Launcher);
|
||||||
connect(m_JavaChecker.get(), &JavaChecker::checkFinished, this, &CheckJava::checkJavaFinished);
|
connect(m_JavaChecker.get(), &JavaChecker::checkFinished, this, &CheckJava::checkJavaFinished);
|
||||||
m_JavaChecker->m_path = realJavaPath;
|
m_JavaChecker->start();
|
||||||
m_JavaChecker->performCheck();
|
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
auto verString = instance->settings()->get("JavaVersion").toString();
|
auto verString = instance->settings()->get("JavaVersion").toString();
|
||||||
@ -106,10 +109,10 @@ void CheckJava::executeTask()
|
|||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckJava::checkJavaFinished(JavaCheckResult result)
|
void CheckJava::checkJavaFinished(const JavaChecker::Result& result)
|
||||||
{
|
{
|
||||||
switch (result.validity) {
|
switch (result.validity) {
|
||||||
case JavaCheckResult::Validity::Errored: {
|
case JavaChecker::Result::Validity::Errored: {
|
||||||
// Error message displayed if java can't start
|
// Error message displayed if java can't start
|
||||||
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);
|
||||||
@ -117,14 +120,14 @@ void CheckJava::checkJavaFinished(JavaCheckResult result)
|
|||||||
emitFailed(QString("Could not start java!"));
|
emitFailed(QString("Could not start java!"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case JavaCheckResult::Validity::ReturnedInvalidData: {
|
case JavaChecker::Result::Validity::ReturnedInvalidData: {
|
||||||
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);
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case JavaCheckResult::Validity::Valid: {
|
case JavaChecker::Result::Validity::Valid: {
|
||||||
auto instance = m_parent->instance();
|
auto instance = m_parent->instance();
|
||||||
printJavaInfo(result.javaVersion.toString(), result.mojangPlatform, result.realPlatform, result.javaVendor);
|
printJavaInfo(result.javaVersion.toString(), result.mojangPlatform, result.realPlatform, result.javaVendor);
|
||||||
instance->settings()->set("JavaVersion", result.javaVersion.toString());
|
instance->settings()->set("JavaVersion", result.javaVersion.toString());
|
||||||
|
@ -28,7 +28,7 @@ class CheckJava : public LaunchStep {
|
|||||||
virtual void executeTask();
|
virtual void executeTask();
|
||||||
virtual bool canAbort() const { return false; }
|
virtual bool canAbort() const { return false; }
|
||||||
private slots:
|
private slots:
|
||||||
void checkJavaFinished(JavaCheckResult result);
|
void checkJavaFinished(const JavaChecker::Result& result);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void printJavaInfo(const QString& version, const QString& architecture, const QString& realArchitecture, const QString& vendor);
|
void printJavaInfo(const QString& version, const QString& architecture, const QString& realArchitecture, const QString& vendor);
|
||||||
@ -37,5 +37,5 @@ class CheckJava : public LaunchStep {
|
|||||||
private:
|
private:
|
||||||
QString m_javaPath;
|
QString m_javaPath;
|
||||||
QString m_javaSignature;
|
QString m_javaSignature;
|
||||||
JavaCheckerPtr m_JavaChecker;
|
JavaChecker::Ptr m_JavaChecker;
|
||||||
};
|
};
|
||||||
|
@ -30,7 +30,7 @@ void LookupServerAddress::setLookupAddress(const QString& lookupAddress)
|
|||||||
m_dnsLookup->setName(QString("_minecraft._tcp.%1").arg(lookupAddress));
|
m_dnsLookup->setName(QString("_minecraft._tcp.%1").arg(lookupAddress));
|
||||||
}
|
}
|
||||||
|
|
||||||
void LookupServerAddress::setOutputAddressPtr(MinecraftServerTargetPtr output)
|
void LookupServerAddress::setOutputAddressPtr(MinecraftTarget::Ptr output)
|
||||||
{
|
{
|
||||||
m_output = std::move(output);
|
m_output = std::move(output);
|
||||||
}
|
}
|
||||||
|
@ -19,20 +19,20 @@
|
|||||||
#include <launch/LaunchStep.h>
|
#include <launch/LaunchStep.h>
|
||||||
#include <QDnsLookup>
|
#include <QDnsLookup>
|
||||||
|
|
||||||
#include "minecraft/launch/MinecraftServerTarget.h"
|
#include "minecraft/launch/MinecraftTarget.h"
|
||||||
|
|
||||||
class LookupServerAddress : public LaunchStep {
|
class LookupServerAddress : public LaunchStep {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit LookupServerAddress(LaunchTask* parent);
|
explicit LookupServerAddress(LaunchTask* parent);
|
||||||
virtual ~LookupServerAddress() {};
|
virtual ~LookupServerAddress() = default;
|
||||||
|
|
||||||
virtual void executeTask();
|
virtual void executeTask();
|
||||||
virtual bool abort();
|
virtual bool abort();
|
||||||
virtual bool canAbort() const { return true; }
|
virtual bool canAbort() const { return true; }
|
||||||
|
|
||||||
void setLookupAddress(const QString& lookupAddress);
|
void setLookupAddress(const QString& lookupAddress);
|
||||||
void setOutputAddressPtr(MinecraftServerTargetPtr output);
|
void setOutputAddressPtr(MinecraftTarget::Ptr output);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_dnsLookupFinished();
|
void on_dnsLookupFinished();
|
||||||
@ -42,5 +42,5 @@ class LookupServerAddress : public LaunchStep {
|
|||||||
|
|
||||||
QDnsLookup* m_dnsLookup;
|
QDnsLookup* m_dnsLookup;
|
||||||
QString m_lookupAddress;
|
QString m_lookupAddress;
|
||||||
MinecraftServerTargetPtr m_output;
|
MinecraftTarget::Ptr m_output;
|
||||||
};
|
};
|
||||||
|
@ -15,19 +15,26 @@
|
|||||||
|
|
||||||
#include "BaseEntity.h"
|
#include "BaseEntity.h"
|
||||||
|
|
||||||
|
#include "Exception.h"
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include "Json.h"
|
#include "Json.h"
|
||||||
|
#include "modplatform/helpers/HashUtils.h"
|
||||||
#include "net/ApiDownload.h"
|
#include "net/ApiDownload.h"
|
||||||
|
#include "net/ChecksumValidator.h"
|
||||||
#include "net/HttpMetaCache.h"
|
#include "net/HttpMetaCache.h"
|
||||||
|
#include "net/Mode.h"
|
||||||
#include "net/NetJob.h"
|
#include "net/NetJob.h"
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "BuildConfig.h"
|
#include "BuildConfig.h"
|
||||||
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
|
namespace Meta {
|
||||||
|
|
||||||
class ParsingValidator : public Net::Validator {
|
class ParsingValidator : public Net::Validator {
|
||||||
public: /* con/des */
|
public: /* con/des */
|
||||||
ParsingValidator(Meta::BaseEntity* entity) : m_entity(entity) {};
|
ParsingValidator(BaseEntity* entity) : m_entity(entity) {};
|
||||||
virtual ~ParsingValidator() {};
|
virtual ~ParsingValidator() = default;
|
||||||
|
|
||||||
public: /* methods */
|
public: /* methods */
|
||||||
bool init(QNetworkRequest&) override
|
bool init(QNetworkRequest&) override
|
||||||
@ -61,92 +68,131 @@ class ParsingValidator : public Net::Validator {
|
|||||||
|
|
||||||
private: /* data */
|
private: /* data */
|
||||||
QByteArray m_data;
|
QByteArray m_data;
|
||||||
Meta::BaseEntity* m_entity;
|
BaseEntity* m_entity;
|
||||||
};
|
};
|
||||||
|
|
||||||
Meta::BaseEntity::~BaseEntity() {}
|
QUrl BaseEntity::url() const
|
||||||
|
|
||||||
QUrl Meta::BaseEntity::url() const
|
|
||||||
{
|
{
|
||||||
auto s = APPLICATION->settings();
|
auto s = APPLICATION->settings();
|
||||||
QString metaOverride = s->get("MetaURLOverride").toString();
|
QString metaOverride = s->get("MetaURLOverride").toString();
|
||||||
if (metaOverride.isEmpty()) {
|
if (metaOverride.isEmpty()) {
|
||||||
return QUrl(BuildConfig.META_URL).resolved(localFilename());
|
return QUrl(BuildConfig.META_URL).resolved(localFilename());
|
||||||
} else {
|
}
|
||||||
return QUrl(metaOverride).resolved(localFilename());
|
return QUrl(metaOverride).resolved(localFilename());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Task::Ptr BaseEntity::loadTask(Net::Mode mode)
|
||||||
|
{
|
||||||
|
if (m_task && m_task->isRunning()) {
|
||||||
|
return m_task;
|
||||||
|
}
|
||||||
|
m_task.reset(new BaseEntityLoadTask(this, mode));
|
||||||
|
return m_task;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Meta::BaseEntity::loadLocalFile()
|
bool BaseEntity::isLoaded() const
|
||||||
{
|
{
|
||||||
const QString fname = QDir("meta").absoluteFilePath(localFilename());
|
// consider it loaded only if the main hash is either empty and was remote loadded or the hashes match and was loaded
|
||||||
if (!QFile::exists(fname)) {
|
return m_sha256.isEmpty() ? m_load_status == LoadStatus::Remote : m_load_status != LoadStatus::NotLoaded && m_sha256 == m_file_sha256;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
// TODO: check if the file has the expected checksum
|
|
||||||
|
void BaseEntity::setSha256(QString sha256)
|
||||||
|
{
|
||||||
|
m_sha256 = sha256;
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseEntity::LoadStatus BaseEntity::status() const
|
||||||
|
{
|
||||||
|
return m_load_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseEntityLoadTask::BaseEntityLoadTask(BaseEntity* parent, Net::Mode mode) : m_entity(parent), m_mode(mode) {}
|
||||||
|
|
||||||
|
void BaseEntityLoadTask::executeTask()
|
||||||
|
{
|
||||||
|
const QString fname = QDir("meta").absoluteFilePath(m_entity->localFilename());
|
||||||
|
auto hashMatches = false;
|
||||||
|
// the file exists on disk try to load it
|
||||||
|
if (QFile::exists(fname)) {
|
||||||
try {
|
try {
|
||||||
auto doc = Json::requireDocument(fname, fname);
|
QByteArray fileData;
|
||||||
|
// read local file if nothing is loaded yet
|
||||||
|
if (m_entity->m_load_status == BaseEntity::LoadStatus::NotLoaded || m_entity->m_file_sha256.isEmpty()) {
|
||||||
|
setStatus(tr("Loading local file"));
|
||||||
|
fileData = FS::read(fname);
|
||||||
|
m_entity->m_file_sha256 = Hashing::hash(fileData, Hashing::Algorithm::Sha256);
|
||||||
|
}
|
||||||
|
|
||||||
|
// on online the hash needs to match
|
||||||
|
hashMatches = m_entity->m_sha256 == m_entity->m_file_sha256;
|
||||||
|
if (m_mode == Net::Mode::Online && !m_entity->m_sha256.isEmpty() && !hashMatches) {
|
||||||
|
throw Exception("mismatched checksum");
|
||||||
|
}
|
||||||
|
|
||||||
|
// load local file
|
||||||
|
if (m_entity->m_load_status == BaseEntity::LoadStatus::NotLoaded) {
|
||||||
|
auto doc = Json::requireDocument(fileData, fname);
|
||||||
auto obj = Json::requireObject(doc, fname);
|
auto obj = Json::requireObject(doc, fname);
|
||||||
parse(obj);
|
m_entity->parse(obj);
|
||||||
return true;
|
m_entity->m_load_status = BaseEntity::LoadStatus::Local;
|
||||||
|
}
|
||||||
|
|
||||||
} catch (const Exception& e) {
|
} catch (const Exception& e) {
|
||||||
qDebug() << QString("Unable to parse file %1: %2").arg(fname, e.cause());
|
qDebug() << QString("Unable to parse file %1: %2").arg(fname, e.cause());
|
||||||
// just make sure it's gone and we never consider it again.
|
// just make sure it's gone and we never consider it again.
|
||||||
return !FS::deletePath(fname);
|
FS::deletePath(fname);
|
||||||
}
|
m_entity->m_load_status = BaseEntity::LoadStatus::NotLoaded;
|
||||||
}
|
|
||||||
|
|
||||||
void Meta::BaseEntity::load(Net::Mode loadType)
|
|
||||||
{
|
|
||||||
// load local file if nothing is loaded yet
|
|
||||||
if (!isLoaded()) {
|
|
||||||
if (loadLocalFile()) {
|
|
||||||
m_loadStatus = LoadStatus::Local;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if we need remote update, run the update task
|
// if we need remote update, run the update task
|
||||||
if (loadType == Net::Mode::Offline || !shouldStartRemoteUpdate()) {
|
auto wasLoadedOffline = m_entity->m_load_status != BaseEntity::LoadStatus::NotLoaded && m_mode == Net::Mode::Offline;
|
||||||
|
// if has is not present allways fetch from remote(e.g. the main index file), else only fetch if hash doesn't match
|
||||||
|
auto wasLoadedRemote = m_entity->m_sha256.isEmpty() ? m_entity->m_load_status == BaseEntity::LoadStatus::Remote : hashMatches;
|
||||||
|
if (wasLoadedOffline || wasLoadedRemote) {
|
||||||
|
emitSucceeded();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_updateTask.reset(new NetJob(QObject::tr("Download of meta file %1").arg(localFilename()), APPLICATION->network()));
|
m_task.reset(new NetJob(QObject::tr("Download of meta file %1").arg(m_entity->localFilename()), APPLICATION->network()));
|
||||||
auto url = this->url();
|
auto url = m_entity->url();
|
||||||
auto entry = APPLICATION->metacache()->resolveEntry("meta", localFilename());
|
auto entry = APPLICATION->metacache()->resolveEntry("meta", m_entity->localFilename());
|
||||||
entry->setStale(true);
|
entry->setStale(true);
|
||||||
auto dl = Net::ApiDownload::makeCached(url, entry);
|
auto dl = Net::ApiDownload::makeCached(url, entry);
|
||||||
/*
|
/*
|
||||||
* The validator parses the file and loads it into the object.
|
* The validator parses the file and loads it into the object.
|
||||||
* If that fails, the file is not written to storage.
|
* If that fails, the file is not written to storage.
|
||||||
*/
|
*/
|
||||||
dl->addValidator(new ParsingValidator(this));
|
if (!m_entity->m_sha256.isEmpty())
|
||||||
m_updateTask->addNetAction(dl);
|
dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Algorithm::Sha256, m_entity->m_sha256));
|
||||||
m_updateStatus = UpdateStatus::InProgress;
|
dl->addValidator(new ParsingValidator(m_entity));
|
||||||
QObject::connect(m_updateTask.get(), &NetJob::succeeded, [&]() {
|
m_task->addNetAction(dl);
|
||||||
m_loadStatus = LoadStatus::Remote;
|
m_task->setAskRetry(false);
|
||||||
m_updateStatus = UpdateStatus::Succeeded;
|
connect(m_task.get(), &Task::failed, this, &BaseEntityLoadTask::emitFailed);
|
||||||
m_updateTask.reset();
|
connect(m_task.get(), &Task::succeeded, this, &BaseEntityLoadTask::emitSucceeded);
|
||||||
|
connect(m_task.get(), &Task::succeeded, this, [this]() {
|
||||||
|
m_entity->m_load_status = BaseEntity::LoadStatus::Remote;
|
||||||
|
m_entity->m_file_sha256 = m_entity->m_sha256;
|
||||||
});
|
});
|
||||||
QObject::connect(m_updateTask.get(), &NetJob::failed, [&]() {
|
|
||||||
m_updateStatus = UpdateStatus::Failed;
|
connect(m_task.get(), &Task::progress, this, &Task::setProgress);
|
||||||
m_updateTask.reset();
|
connect(m_task.get(), &Task::stepProgress, this, &BaseEntityLoadTask::propagateStepProgress);
|
||||||
});
|
connect(m_task.get(), &Task::status, this, &Task::setStatus);
|
||||||
m_updateTask->start();
|
connect(m_task.get(), &Task::details, this, &Task::setDetails);
|
||||||
|
|
||||||
|
m_task->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Meta::BaseEntity::isLoaded() const
|
bool BaseEntityLoadTask::canAbort() const
|
||||||
{
|
{
|
||||||
return m_loadStatus > LoadStatus::NotLoaded;
|
return m_task ? m_task->canAbort() : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Meta::BaseEntity::shouldStartRemoteUpdate() const
|
bool BaseEntityLoadTask::abort()
|
||||||
{
|
{
|
||||||
// TODO: version-locks and offline mode?
|
if (m_task) {
|
||||||
return m_updateStatus != UpdateStatus::InProgress;
|
Task::abort();
|
||||||
|
return m_task->abort();
|
||||||
|
}
|
||||||
|
return Task::abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
Task::Ptr Meta::BaseEntity::getCurrentTask()
|
} // namespace Meta
|
||||||
{
|
|
||||||
if (m_updateStatus == UpdateStatus::InProgress) {
|
|
||||||
return m_updateTask;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
@ -17,38 +17,57 @@
|
|||||||
|
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include "QObjectPtr.h"
|
|
||||||
|
|
||||||
#include "net/Mode.h"
|
#include "net/Mode.h"
|
||||||
#include "net/NetJob.h"
|
#include "net/NetJob.h"
|
||||||
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
namespace Meta {
|
namespace Meta {
|
||||||
|
class BaseEntityLoadTask;
|
||||||
class BaseEntity {
|
class BaseEntity {
|
||||||
|
friend BaseEntityLoadTask;
|
||||||
|
|
||||||
public: /* types */
|
public: /* types */
|
||||||
using Ptr = std::shared_ptr<BaseEntity>;
|
using Ptr = std::shared_ptr<BaseEntity>;
|
||||||
enum class LoadStatus { NotLoaded, Local, Remote };
|
enum class LoadStatus { NotLoaded, Local, Remote };
|
||||||
enum class UpdateStatus { NotDone, InProgress, Failed, Succeeded };
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~BaseEntity();
|
virtual ~BaseEntity() = default;
|
||||||
|
|
||||||
virtual void parse(const QJsonObject& obj) = 0;
|
|
||||||
|
|
||||||
virtual QString localFilename() const = 0;
|
virtual QString localFilename() const = 0;
|
||||||
virtual QUrl url() const;
|
virtual QUrl url() const;
|
||||||
|
|
||||||
bool isLoaded() const;
|
bool isLoaded() const;
|
||||||
bool shouldStartRemoteUpdate() const;
|
LoadStatus status() const;
|
||||||
|
|
||||||
void load(Net::Mode loadType);
|
/* for parsers */
|
||||||
Task::Ptr getCurrentTask();
|
void setSha256(QString sha256);
|
||||||
|
|
||||||
protected: /* methods */
|
virtual void parse(const QJsonObject& obj) = 0;
|
||||||
bool loadLocalFile();
|
[[nodiscard]] Task::Ptr loadTask(Net::Mode loadType = Net::Mode::Online);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QString m_sha256; // the expected sha256
|
||||||
|
QString m_file_sha256; // the file sha256
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LoadStatus m_loadStatus = LoadStatus::NotLoaded;
|
LoadStatus m_load_status = LoadStatus::NotLoaded;
|
||||||
UpdateStatus m_updateStatus = UpdateStatus::NotDone;
|
Task::Ptr m_task;
|
||||||
NetJob::Ptr m_updateTask;
|
};
|
||||||
|
|
||||||
|
class BaseEntityLoadTask : public Task {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit BaseEntityLoadTask(BaseEntity* parent, Net::Mode mode);
|
||||||
|
~BaseEntityLoadTask() override = default;
|
||||||
|
|
||||||
|
virtual void executeTask() override;
|
||||||
|
virtual bool canAbort() const override;
|
||||||
|
virtual bool abort() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
BaseEntity* m_entity;
|
||||||
|
Net::Mode m_mode;
|
||||||
|
NetJob::Ptr m_task;
|
||||||
};
|
};
|
||||||
} // namespace Meta
|
} // namespace Meta
|
||||||
|
@ -16,7 +16,10 @@
|
|||||||
#include "Index.h"
|
#include "Index.h"
|
||||||
|
|
||||||
#include "JsonFormat.h"
|
#include "JsonFormat.h"
|
||||||
|
#include "QObjectPtr.h"
|
||||||
#include "VersionList.h"
|
#include "VersionList.h"
|
||||||
|
#include "meta/BaseEntity.h"
|
||||||
|
#include "tasks/SequentialTask.h"
|
||||||
|
|
||||||
namespace Meta {
|
namespace Meta {
|
||||||
Index::Index(QObject* parent) : QAbstractListModel(parent) {}
|
Index::Index(QObject* parent) : QAbstractListModel(parent) {}
|
||||||
@ -51,14 +54,17 @@ QVariant Index::data(const QModelIndex& index, int role) const
|
|||||||
}
|
}
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Index::rowCount(const QModelIndex& parent) const
|
int Index::rowCount(const QModelIndex& parent) const
|
||||||
{
|
{
|
||||||
return parent.isValid() ? 0 : m_lists.size();
|
return parent.isValid() ? 0 : m_lists.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Index::columnCount(const QModelIndex& parent) const
|
int Index::columnCount(const QModelIndex& parent) const
|
||||||
{
|
{
|
||||||
return parent.isValid() ? 0 : 1;
|
return parent.isValid() ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant Index::headerData(int section, Qt::Orientation orientation, int role) const
|
QVariant Index::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
{
|
{
|
||||||
if (orientation == Qt::Horizontal && role == Qt::DisplayRole && section == 0) {
|
if (orientation == Qt::Horizontal && role == Qt::DisplayRole && section == 0) {
|
||||||
@ -79,6 +85,7 @@ VersionList::Ptr Index::get(const QString& uid)
|
|||||||
if (!out) {
|
if (!out) {
|
||||||
out = std::make_shared<VersionList>(uid);
|
out = std::make_shared<VersionList>(uid);
|
||||||
m_uids[uid] = out;
|
m_uids[uid] = out;
|
||||||
|
m_lists.append(out);
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
@ -96,7 +103,7 @@ void Index::parse(const QJsonObject& obj)
|
|||||||
|
|
||||||
void Index::merge(const std::shared_ptr<Index>& other)
|
void Index::merge(const std::shared_ptr<Index>& other)
|
||||||
{
|
{
|
||||||
const QVector<VersionList::Ptr> lists = std::dynamic_pointer_cast<Index>(other)->m_lists;
|
const QVector<VersionList::Ptr> lists = other->m_lists;
|
||||||
// initial load, no need to merge
|
// initial load, no need to merge
|
||||||
if (m_lists.isEmpty()) {
|
if (m_lists.isEmpty()) {
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
@ -123,7 +130,33 @@ void Index::merge(const std::shared_ptr<Index>& other)
|
|||||||
|
|
||||||
void Index::connectVersionList(const int row, const VersionList::Ptr& list)
|
void Index::connectVersionList(const int row, const VersionList::Ptr& list)
|
||||||
{
|
{
|
||||||
connect(list.get(), &VersionList::nameChanged, this,
|
connect(list.get(), &VersionList::nameChanged, this, [this, row] { emit dataChanged(index(row), index(row), { Qt::DisplayRole }); });
|
||||||
[this, row]() { emit dataChanged(index(row), index(row), QVector<int>() << Qt::DisplayRole); });
|
}
|
||||||
|
|
||||||
|
Task::Ptr Index::loadVersion(const QString& uid, const QString& version, Net::Mode mode, bool force)
|
||||||
|
{
|
||||||
|
if (mode == Net::Mode::Offline) {
|
||||||
|
return get(uid, version)->loadTask(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto versionList = get(uid);
|
||||||
|
auto loadTask = makeShared<SequentialTask>(
|
||||||
|
this, tr("Load meta for %1:%2", "This is for the task name that loads the meta index.").arg(uid, version));
|
||||||
|
if (status() != BaseEntity::LoadStatus::Remote || force) {
|
||||||
|
loadTask->addTask(this->loadTask(mode));
|
||||||
|
}
|
||||||
|
loadTask->addTask(versionList->loadTask(mode));
|
||||||
|
loadTask->addTask(versionList->getVersion(version)->loadTask(mode));
|
||||||
|
return loadTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
Version::Ptr Index::getLoadedVersion(const QString& uid, const QString& version)
|
||||||
|
{
|
||||||
|
QEventLoop ev;
|
||||||
|
auto task = loadVersion(uid, version);
|
||||||
|
QObject::connect(task.get(), &Task::finished, &ev, &QEventLoop::quit);
|
||||||
|
task->start();
|
||||||
|
ev.exec();
|
||||||
|
return get(uid, version);
|
||||||
}
|
}
|
||||||
} // namespace Meta
|
} // namespace Meta
|
||||||
|
@ -16,10 +16,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "BaseEntity.h"
|
#include "BaseEntity.h"
|
||||||
#include "meta/VersionList.h"
|
#include "meta/VersionList.h"
|
||||||
|
#include "net/Mode.h"
|
||||||
|
|
||||||
class Task;
|
class Task;
|
||||||
|
|
||||||
@ -30,6 +30,7 @@ class Index : public QAbstractListModel, public BaseEntity {
|
|||||||
public:
|
public:
|
||||||
explicit Index(QObject* parent = nullptr);
|
explicit Index(QObject* parent = nullptr);
|
||||||
explicit Index(const QVector<VersionList::Ptr>& lists, QObject* parent = nullptr);
|
explicit Index(const QVector<VersionList::Ptr>& lists, QObject* parent = nullptr);
|
||||||
|
virtual ~Index() = default;
|
||||||
|
|
||||||
enum { UidRole = Qt::UserRole, NameRole, ListPtrRole };
|
enum { UidRole = Qt::UserRole, NameRole, ListPtrRole };
|
||||||
|
|
||||||
@ -47,8 +48,15 @@ class Index : public QAbstractListModel, public BaseEntity {
|
|||||||
|
|
||||||
QVector<VersionList::Ptr> lists() const { return m_lists; }
|
QVector<VersionList::Ptr> lists() const { return m_lists; }
|
||||||
|
|
||||||
|
Task::Ptr loadVersion(const QString& uid, const QString& version = {}, Net::Mode mode = Net::Mode::Online, bool force = false);
|
||||||
|
|
||||||
|
// this blocks until the version is loaded
|
||||||
|
Version::Ptr getLoadedVersion(const QString& uid, const QString& version);
|
||||||
|
|
||||||
public: // for usage by parsers only
|
public: // for usage by parsers only
|
||||||
void merge(const std::shared_ptr<Index>& other);
|
void merge(const std::shared_ptr<Index>& other);
|
||||||
|
|
||||||
|
protected:
|
||||||
void parse(const QJsonObject& obj) override;
|
void parse(const QJsonObject& obj) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -41,6 +41,7 @@ static std::shared_ptr<Index> parseIndexInternal(const QJsonObject& obj)
|
|||||||
std::transform(objects.begin(), objects.end(), std::back_inserter(lists), [](const QJsonObject& obj) {
|
std::transform(objects.begin(), objects.end(), std::back_inserter(lists), [](const QJsonObject& obj) {
|
||||||
VersionList::Ptr list = std::make_shared<VersionList>(requireString(obj, "uid"));
|
VersionList::Ptr list = std::make_shared<VersionList>(requireString(obj, "uid"));
|
||||||
list->setName(ensureString(obj, "name", QString()));
|
list->setName(ensureString(obj, "name", QString()));
|
||||||
|
list->setSha256(ensureString(obj, "sha256", QString()));
|
||||||
return list;
|
return list;
|
||||||
});
|
});
|
||||||
return std::make_shared<Index>(lists);
|
return std::make_shared<Index>(lists);
|
||||||
@ -58,6 +59,9 @@ static Version::Ptr parseCommonVersion(const QString& uid, const QJsonObject& ob
|
|||||||
parseRequires(obj, &reqs, "requires");
|
parseRequires(obj, &reqs, "requires");
|
||||||
parseRequires(obj, &conflicts, "conflicts");
|
parseRequires(obj, &conflicts, "conflicts");
|
||||||
version->setRequires(reqs, conflicts);
|
version->setRequires(reqs, conflicts);
|
||||||
|
if (auto sha256 = ensureString(obj, "sha256", QString()); !sha256.isEmpty()) {
|
||||||
|
version->setSha256(sha256);
|
||||||
|
}
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,11 +16,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
#include "Exception.h"
|
#include "Exception.h"
|
||||||
#include "meta/BaseEntity.h"
|
|
||||||
|
|
||||||
namespace Meta {
|
namespace Meta {
|
||||||
class Index;
|
class Index;
|
||||||
|
@ -18,12 +18,9 @@
|
|||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
|
||||||
#include "JsonFormat.h"
|
#include "JsonFormat.h"
|
||||||
#include "minecraft/PackProfile.h"
|
|
||||||
|
|
||||||
Meta::Version::Version(const QString& uid, const QString& version) : BaseVersion(), m_uid(uid), m_version(version) {}
|
Meta::Version::Version(const QString& uid, const QString& version) : BaseVersion(), m_uid(uid), m_version(version) {}
|
||||||
|
|
||||||
Meta::Version::~Version() {}
|
|
||||||
|
|
||||||
QString Meta::Version::descriptor()
|
QString Meta::Version::descriptor()
|
||||||
{
|
{
|
||||||
return m_version;
|
return m_version;
|
||||||
@ -71,6 +68,9 @@ void Meta::Version::mergeFromList(const Meta::Version::Ptr& other)
|
|||||||
if (m_volatile != other->m_volatile) {
|
if (m_volatile != other->m_volatile) {
|
||||||
setVolatile(other->m_volatile);
|
setVolatile(other->m_volatile);
|
||||||
}
|
}
|
||||||
|
if (!other->m_sha256.isEmpty()) {
|
||||||
|
m_sha256 = other->m_sha256;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Meta::Version::merge(const Version::Ptr& other)
|
void Meta::Version::merge(const Version::Ptr& other)
|
||||||
|
@ -38,7 +38,7 @@ class Version : public QObject, public BaseVersion, public BaseEntity {
|
|||||||
using Ptr = std::shared_ptr<Version>;
|
using Ptr = std::shared_ptr<Version>;
|
||||||
|
|
||||||
explicit Version(const QString& uid, const QString& version);
|
explicit Version(const QString& uid, const QString& version);
|
||||||
virtual ~Version();
|
virtual ~Version() = default;
|
||||||
|
|
||||||
QString descriptor() override;
|
QString descriptor() override;
|
||||||
QString name() override;
|
QString name() override;
|
||||||
@ -52,7 +52,7 @@ class Version : public QObject, public BaseVersion, public BaseEntity {
|
|||||||
const Meta::RequireSet& requiredSet() const { return m_requires; }
|
const Meta::RequireSet& requiredSet() const { return m_requires; }
|
||||||
VersionFilePtr data() const { return m_data; }
|
VersionFilePtr data() const { return m_data; }
|
||||||
bool isRecommended() const { return m_recommended; }
|
bool isRecommended() const { return m_recommended; }
|
||||||
bool isLoaded() const { return m_data != nullptr; }
|
bool isLoaded() const { return m_data != nullptr && BaseEntity::isLoaded(); }
|
||||||
|
|
||||||
void merge(const Version::Ptr& other);
|
void merge(const Version::Ptr& other);
|
||||||
void mergeFromList(const Version::Ptr& other);
|
void mergeFromList(const Version::Ptr& other);
|
||||||
|
@ -17,8 +17,13 @@
|
|||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
#include "Index.h"
|
||||||
#include "JsonFormat.h"
|
#include "JsonFormat.h"
|
||||||
#include "Version.h"
|
#include "Version.h"
|
||||||
|
#include "meta/BaseEntity.h"
|
||||||
|
#include "net/Mode.h"
|
||||||
|
#include "tasks/SequentialTask.h"
|
||||||
|
|
||||||
namespace Meta {
|
namespace Meta {
|
||||||
VersionList::VersionList(const QString& uid, QObject* parent) : BaseVersionList(parent), m_uid(uid)
|
VersionList::VersionList(const QString& uid, QObject* parent) : BaseVersionList(parent), m_uid(uid)
|
||||||
@ -28,8 +33,11 @@ VersionList::VersionList(const QString& uid, QObject* parent) : BaseVersionList(
|
|||||||
|
|
||||||
Task::Ptr VersionList::getLoadTask()
|
Task::Ptr VersionList::getLoadTask()
|
||||||
{
|
{
|
||||||
load(Net::Mode::Online);
|
auto loadTask =
|
||||||
return getCurrentTask();
|
makeShared<SequentialTask>(this, tr("Load meta for %1", "This is for the task name that loads the meta index.").arg(m_uid));
|
||||||
|
loadTask->addTask(APPLICATION->metadataIndex()->loadTask(Net::Mode::Online));
|
||||||
|
loadTask->addTask(this->loadTask(Net::Mode::Online));
|
||||||
|
return loadTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VersionList::isLoaded()
|
bool VersionList::isLoaded()
|
||||||
@ -92,6 +100,13 @@ QVariant VersionList::data(const QModelIndex& index, int role) const
|
|||||||
return QVariant::fromValue(version);
|
return QVariant::fromValue(version);
|
||||||
case RecommendedRole:
|
case RecommendedRole:
|
||||||
return version->isRecommended();
|
return version->isRecommended();
|
||||||
|
case JavaMajorRole: {
|
||||||
|
auto major = version->version();
|
||||||
|
if (major.startsWith("java")) {
|
||||||
|
major = "Java " + major.mid(4);
|
||||||
|
}
|
||||||
|
return major;
|
||||||
|
}
|
||||||
// FIXME: this should be determined in whatever view/proxy is used...
|
// FIXME: this should be determined in whatever view/proxy is used...
|
||||||
// case LatestRole: return version == getLatestStable();
|
// case LatestRole: return version == getLatestStable();
|
||||||
default:
|
default:
|
||||||
@ -101,10 +116,14 @@ QVariant VersionList::data(const QModelIndex& index, int role) const
|
|||||||
|
|
||||||
BaseVersionList::RoleList VersionList::providesRoles() const
|
BaseVersionList::RoleList VersionList::providesRoles() const
|
||||||
{
|
{
|
||||||
return { VersionPointerRole, VersionRole, VersionIdRole, ParentVersionRole, TypeRole, UidRole,
|
return m_provided_roles;
|
||||||
TimeRole, RequiresRole, SortRole, RecommendedRole, LatestRole, VersionPtrRole };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VersionList::setProvidedRoles(RoleList roles)
|
||||||
|
{
|
||||||
|
m_provided_roles = roles;
|
||||||
|
};
|
||||||
|
|
||||||
QHash<int, QByteArray> VersionList::roleNames() const
|
QHash<int, QByteArray> VersionList::roleNames() const
|
||||||
{
|
{
|
||||||
QHash<int, QByteArray> roles = BaseVersionList::roleNames();
|
QHash<int, QByteArray> roles = BaseVersionList::roleNames();
|
||||||
@ -131,6 +150,8 @@ Version::Ptr VersionList::getVersion(const QString& version)
|
|||||||
if (!out) {
|
if (!out) {
|
||||||
out = std::make_shared<Version>(m_uid, version);
|
out = std::make_shared<Version>(m_uid, version);
|
||||||
m_lookup[version] = out;
|
m_lookup[version] = out;
|
||||||
|
setupAddedVersion(m_versions.size(), out);
|
||||||
|
m_versions.append(out);
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
@ -191,6 +212,9 @@ void VersionList::mergeFromIndex(const VersionList::Ptr& other)
|
|||||||
if (m_name != other->m_name) {
|
if (m_name != other->m_name) {
|
||||||
setName(other->m_name);
|
setName(other->m_name);
|
||||||
}
|
}
|
||||||
|
if (!other->m_sha256.isEmpty()) {
|
||||||
|
m_sha256 = other->m_sha256;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VersionList::merge(const VersionList::Ptr& other)
|
void VersionList::merge(const VersionList::Ptr& other)
|
||||||
@ -198,23 +222,27 @@ void VersionList::merge(const VersionList::Ptr& other)
|
|||||||
if (m_name != other->m_name) {
|
if (m_name != other->m_name) {
|
||||||
setName(other->m_name);
|
setName(other->m_name);
|
||||||
}
|
}
|
||||||
|
if (!other->m_sha256.isEmpty()) {
|
||||||
|
m_sha256 = other->m_sha256;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: do not reset the whole model. maybe?
|
// TODO: do not reset the whole model. maybe?
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
m_versions.clear();
|
|
||||||
if (other->m_versions.isEmpty()) {
|
if (other->m_versions.isEmpty()) {
|
||||||
qWarning() << "Empty list loaded ...";
|
qWarning() << "Empty list loaded ...";
|
||||||
}
|
}
|
||||||
for (const Version::Ptr& version : other->m_versions) {
|
for (auto version : other->m_versions) {
|
||||||
// we already have the version. merge the contents
|
// we already have the version. merge the contents
|
||||||
if (m_lookup.contains(version->version())) {
|
if (m_lookup.contains(version->version())) {
|
||||||
m_lookup.value(version->version())->mergeFromList(version);
|
auto existing = m_lookup.value(version->version());
|
||||||
|
existing->mergeFromList(version);
|
||||||
|
version = existing;
|
||||||
} else {
|
} else {
|
||||||
m_lookup.insert(version->uid(), version);
|
m_lookup.insert(version->version(), version);
|
||||||
}
|
|
||||||
// connect it.
|
// connect it.
|
||||||
setupAddedVersion(m_versions.size(), version);
|
setupAddedVersion(m_versions.size(), version);
|
||||||
m_versions.append(version);
|
m_versions.append(version);
|
||||||
|
}
|
||||||
m_recommended = getBetterVersion(m_recommended, version);
|
m_recommended = getBetterVersion(m_recommended, version);
|
||||||
}
|
}
|
||||||
endResetModel();
|
endResetModel();
|
||||||
@ -222,14 +250,15 @@ void VersionList::merge(const VersionList::Ptr& other)
|
|||||||
|
|
||||||
void VersionList::setupAddedVersion(const int row, const Version::Ptr& version)
|
void VersionList::setupAddedVersion(const int row, const Version::Ptr& version)
|
||||||
{
|
{
|
||||||
// FIXME: do not disconnect from everythin, disconnect only the lambdas here
|
disconnect(version.get(), &Version::requiresChanged, this, nullptr);
|
||||||
version->disconnect();
|
disconnect(version.get(), &Version::timeChanged, this, nullptr);
|
||||||
|
disconnect(version.get(), &Version::typeChanged, this, nullptr);
|
||||||
|
|
||||||
connect(version.get(), &Version::requiresChanged, this,
|
connect(version.get(), &Version::requiresChanged, this,
|
||||||
[this, row]() { emit dataChanged(index(row), index(row), QVector<int>() << RequiresRole); });
|
[this, row]() { emit dataChanged(index(row), index(row), QVector<int>() << RequiresRole); });
|
||||||
connect(version.get(), &Version::timeChanged, this,
|
connect(version.get(), &Version::timeChanged, this,
|
||||||
[this, row]() { emit dataChanged(index(row), index(row), QVector<int>() << TimeRole << SortRole); });
|
[this, row]() { emit dataChanged(index(row), index(row), { TimeRole, SortRole }); });
|
||||||
connect(version.get(), &Version::typeChanged, this,
|
connect(version.get(), &Version::typeChanged, this, [this, row]() { emit dataChanged(index(row), index(row), { TypeRole }); });
|
||||||
[this, row]() { emit dataChanged(index(row), index(row), QVector<int>() << TypeRole); });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseVersion::Ptr VersionList::getRecommended() const
|
BaseVersion::Ptr VersionList::getRecommended() const
|
||||||
@ -237,4 +266,14 @@ BaseVersion::Ptr VersionList::getRecommended() const
|
|||||||
return m_recommended;
|
return m_recommended;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VersionList::waitToLoad()
|
||||||
|
{
|
||||||
|
if (isLoaded())
|
||||||
|
return;
|
||||||
|
QEventLoop ev;
|
||||||
|
auto task = getLoadTask();
|
||||||
|
QObject::connect(task.get(), &Task::finished, &ev, &QEventLoop::quit);
|
||||||
|
task->start();
|
||||||
|
ev.exec();
|
||||||
|
}
|
||||||
} // namespace Meta
|
} // namespace Meta
|
||||||
|
@ -30,13 +30,14 @@ class VersionList : public BaseVersionList, public BaseEntity {
|
|||||||
Q_PROPERTY(QString name READ name NOTIFY nameChanged)
|
Q_PROPERTY(QString name READ name NOTIFY nameChanged)
|
||||||
public:
|
public:
|
||||||
explicit VersionList(const QString& uid, QObject* parent = nullptr);
|
explicit VersionList(const QString& uid, QObject* parent = nullptr);
|
||||||
|
virtual ~VersionList() = default;
|
||||||
|
|
||||||
using Ptr = std::shared_ptr<VersionList>;
|
using Ptr = std::shared_ptr<VersionList>;
|
||||||
|
|
||||||
enum Roles { UidRole = Qt::UserRole + 100, TimeRole, RequiresRole, VersionPtrRole };
|
enum Roles { UidRole = Qt::UserRole + 100, TimeRole, RequiresRole, VersionPtrRole };
|
||||||
|
|
||||||
Task::Ptr getLoadTask() override;
|
|
||||||
bool isLoaded() override;
|
bool isLoaded() override;
|
||||||
|
[[nodiscard]] Task::Ptr getLoadTask() override;
|
||||||
const BaseVersion::Ptr at(int i) const override;
|
const BaseVersion::Ptr at(int i) const override;
|
||||||
int count() const override;
|
int count() const override;
|
||||||
void sortVersions() override;
|
void sortVersions() override;
|
||||||
@ -47,6 +48,8 @@ class VersionList : public BaseVersionList, public BaseEntity {
|
|||||||
RoleList providesRoles() const override;
|
RoleList providesRoles() const override;
|
||||||
QHash<int, QByteArray> roleNames() const override;
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
|
|
||||||
|
void setProvidedRoles(RoleList roles);
|
||||||
|
|
||||||
QString localFilename() const override;
|
QString localFilename() const override;
|
||||||
|
|
||||||
QString uid() const { return m_uid; }
|
QString uid() const { return m_uid; }
|
||||||
@ -58,6 +61,9 @@ class VersionList : public BaseVersionList, public BaseEntity {
|
|||||||
|
|
||||||
QVector<Version::Ptr> versions() const { return m_versions; }
|
QVector<Version::Ptr> versions() const { return m_versions; }
|
||||||
|
|
||||||
|
// this blocks until the version list is loaded
|
||||||
|
void waitToLoad();
|
||||||
|
|
||||||
public: // for usage only by parsers
|
public: // for usage only by parsers
|
||||||
void setName(const QString& name);
|
void setName(const QString& name);
|
||||||
void setVersions(const QVector<Version::Ptr>& versions);
|
void setVersions(const QVector<Version::Ptr>& versions);
|
||||||
@ -79,6 +85,9 @@ class VersionList : public BaseVersionList, public BaseEntity {
|
|||||||
|
|
||||||
Version::Ptr m_recommended;
|
Version::Ptr m_recommended;
|
||||||
|
|
||||||
|
RoleList m_provided_roles = { VersionPointerRole, VersionRole, VersionIdRole, ParentVersionRole, TypeRole, UidRole,
|
||||||
|
TimeRole, RequiresRole, SortRole, RecommendedRole, LatestRole, VersionPtrRole };
|
||||||
|
|
||||||
void setupAddedVersion(int row, const Version::Ptr& version);
|
void setupAddedVersion(int row, const Version::Ptr& version);
|
||||||
};
|
};
|
||||||
} // namespace Meta
|
} // namespace Meta
|
||||||
|
@ -283,8 +283,7 @@ Net::NetRequest::Ptr AssetObject::getDownloadAction()
|
|||||||
if ((!objectFile.isFile()) || (objectFile.size() != size)) {
|
if ((!objectFile.isFile()) || (objectFile.size() != size)) {
|
||||||
auto objectDL = Net::ApiDownload::makeFile(getUrl(), objectFile.filePath());
|
auto objectDL = Net::ApiDownload::makeFile(getUrl(), objectFile.filePath());
|
||||||
if (hash.size()) {
|
if (hash.size()) {
|
||||||
auto rawHash = QByteArray::fromHex(hash.toLatin1());
|
objectDL->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, hash));
|
||||||
objectDL->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawHash));
|
|
||||||
}
|
}
|
||||||
objectDL->setProgress(objectDL->getProgress(), size);
|
objectDL->setProgress(objectDL->getProgress(), size);
|
||||||
return objectDL;
|
return objectDL;
|
||||||
|
@ -56,18 +56,6 @@ Component::Component(PackProfile* parent, const QString& uid)
|
|||||||
m_uid = uid;
|
m_uid = uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
Component::Component(PackProfile* parent, std::shared_ptr<Meta::Version> version)
|
|
||||||
{
|
|
||||||
assert(parent);
|
|
||||||
m_parent = parent;
|
|
||||||
|
|
||||||
m_metaVersion = version;
|
|
||||||
m_uid = version->uid();
|
|
||||||
m_version = m_cachedVersion = version->version();
|
|
||||||
m_cachedName = version->name();
|
|
||||||
m_loaded = version->isLoaded();
|
|
||||||
}
|
|
||||||
|
|
||||||
Component::Component(PackProfile* parent, const QString& uid, std::shared_ptr<VersionFile> file)
|
Component::Component(PackProfile* parent, const QString& uid, std::shared_ptr<VersionFile> file)
|
||||||
{
|
{
|
||||||
assert(parent);
|
assert(parent);
|
||||||
@ -102,9 +90,6 @@ void Component::applyTo(LaunchProfile* profile)
|
|||||||
std::shared_ptr<class VersionFile> Component::getVersionFile() const
|
std::shared_ptr<class VersionFile> Component::getVersionFile() const
|
||||||
{
|
{
|
||||||
if (m_metaVersion) {
|
if (m_metaVersion) {
|
||||||
if (!m_metaVersion->isLoaded()) {
|
|
||||||
m_metaVersion->load(Net::Mode::Online);
|
|
||||||
}
|
|
||||||
return m_metaVersion->data();
|
return m_metaVersion->data();
|
||||||
} else {
|
} else {
|
||||||
return m_file;
|
return m_file;
|
||||||
@ -131,29 +116,35 @@ int Component::getOrder()
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Component::setOrder(int order)
|
void Component::setOrder(int order)
|
||||||
{
|
{
|
||||||
m_orderOverride = true;
|
m_orderOverride = true;
|
||||||
m_order = order;
|
m_order = order;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Component::getID()
|
QString Component::getID()
|
||||||
{
|
{
|
||||||
return m_uid;
|
return m_uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Component::getName()
|
QString Component::getName()
|
||||||
{
|
{
|
||||||
if (!m_cachedName.isEmpty())
|
if (!m_cachedName.isEmpty())
|
||||||
return m_cachedName;
|
return m_cachedName;
|
||||||
return m_uid;
|
return m_uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Component::getVersion()
|
QString Component::getVersion()
|
||||||
{
|
{
|
||||||
return m_cachedVersion;
|
return m_cachedVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Component::getFilename()
|
QString Component::getFilename()
|
||||||
{
|
{
|
||||||
return m_parent->patchFilePathForUid(m_uid);
|
return m_parent->patchFilePathForUid(m_uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
QDateTime Component::getReleaseDateTime()
|
QDateTime Component::getReleaseDateTime()
|
||||||
{
|
{
|
||||||
if (m_metaVersion) {
|
if (m_metaVersion) {
|
||||||
@ -198,17 +189,14 @@ bool Component::isCustom()
|
|||||||
|
|
||||||
bool Component::isCustomizable()
|
bool Component::isCustomizable()
|
||||||
{
|
{
|
||||||
if (m_metaVersion) {
|
return m_metaVersion && getVersionFile();
|
||||||
if (getVersionFile()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Component::isRemovable()
|
bool Component::isRemovable()
|
||||||
{
|
{
|
||||||
return !m_important;
|
return !m_important;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Component::isRevertible()
|
bool Component::isRevertible()
|
||||||
{
|
{
|
||||||
if (isCustom()) {
|
if (isCustom()) {
|
||||||
@ -218,18 +206,18 @@ bool Component::isRevertible()
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Component::isMoveable()
|
bool Component::isMoveable()
|
||||||
{
|
{
|
||||||
// HACK, FIXME: this was too dumb and wouldn't follow dependency constraints anyway. For now hardcoded to 'true'.
|
// HACK, FIXME: this was too dumb and wouldn't follow dependency constraints anyway. For now hardcoded to 'true'.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Component::isVersionChangeable()
|
bool Component::isVersionChangeable()
|
||||||
{
|
{
|
||||||
auto list = getVersionList();
|
auto list = getVersionList();
|
||||||
if (list) {
|
if (list) {
|
||||||
if (!list->isLoaded()) {
|
list->waitToLoad();
|
||||||
list->load(Net::Mode::Online);
|
|
||||||
}
|
|
||||||
return list->count() != 0;
|
return list->count() != 0;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -22,7 +22,6 @@ class Component : public QObject, public ProblemProvider {
|
|||||||
Component(PackProfile* parent, const QString& uid);
|
Component(PackProfile* parent, const QString& uid);
|
||||||
|
|
||||||
// DEPRECATED: remove these constructors?
|
// DEPRECATED: remove these constructors?
|
||||||
Component(PackProfile* parent, std::shared_ptr<Meta::Version> version);
|
|
||||||
Component(PackProfile* parent, const QString& uid, std::shared_ptr<VersionFile> file);
|
Component(PackProfile* parent, const QString& uid, std::shared_ptr<VersionFile> file);
|
||||||
|
|
||||||
virtual ~Component() {}
|
virtual ~Component() {}
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "net/Mode.h"
|
#include "net/Mode.h"
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is responsible for loading the components of a component list AND resolving dependency issues between them
|
* This is responsible for loading the components of a component list AND resolving dependency issues between them
|
||||||
@ -93,9 +94,9 @@ static LoadResult loadComponent(ComponentPtr component, Task::Ptr& loadTask, Net
|
|||||||
component->m_loaded = true;
|
component->m_loaded = true;
|
||||||
result = LoadResult::LoadedLocal;
|
result = LoadResult::LoadedLocal;
|
||||||
} else {
|
} else {
|
||||||
metaVersion->load(netmode);
|
loadTask = APPLICATION->metadataIndex()->loadVersion(component->m_uid, component->m_version, netmode);
|
||||||
loadTask = metaVersion->getCurrentTask();
|
loadTask->start();
|
||||||
if (loadTask)
|
if (netmode == Net::Mode::Online)
|
||||||
result = LoadResult::RequiresRemote;
|
result = LoadResult::RequiresRemote;
|
||||||
else if (metaVersion->isLoaded())
|
else if (metaVersion->isLoaded())
|
||||||
result = LoadResult::LoadedLocal;
|
result = LoadResult::LoadedLocal;
|
||||||
@ -133,21 +134,6 @@ static LoadResult loadPackProfile(ComponentPtr component, Task::Ptr& loadTask, N
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static LoadResult loadIndex(Task::Ptr& loadTask, Net::Mode netmode)
|
|
||||||
{
|
|
||||||
// FIXME: DECIDE. do we want to run the update task anyway?
|
|
||||||
if (APPLICATION->metadataIndex()->isLoaded()) {
|
|
||||||
qDebug() << "Index is already loaded";
|
|
||||||
return LoadResult::LoadedLocal;
|
|
||||||
}
|
|
||||||
APPLICATION->metadataIndex()->load(netmode);
|
|
||||||
loadTask = APPLICATION->metadataIndex()->getCurrentTask();
|
|
||||||
if (loadTask) {
|
|
||||||
return LoadResult::RequiresRemote;
|
|
||||||
}
|
|
||||||
// FIXME: this is assuming the load succeeded... did it really?
|
|
||||||
return LoadResult::LoadedLocal;
|
|
||||||
}
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void ComponentUpdateTask::loadComponents()
|
void ComponentUpdateTask::loadComponents()
|
||||||
@ -156,23 +142,7 @@ void ComponentUpdateTask::loadComponents()
|
|||||||
size_t taskIndex = 0;
|
size_t taskIndex = 0;
|
||||||
size_t componentIndex = 0;
|
size_t componentIndex = 0;
|
||||||
d->remoteLoadSuccessful = true;
|
d->remoteLoadSuccessful = true;
|
||||||
// load the main index (it is needed to determine if components can revert)
|
|
||||||
{
|
|
||||||
// FIXME: tear out as a method? or lambda?
|
|
||||||
Task::Ptr indexLoadTask;
|
|
||||||
auto singleResult = loadIndex(indexLoadTask, d->netmode);
|
|
||||||
result = composeLoadResult(result, singleResult);
|
|
||||||
if (indexLoadTask) {
|
|
||||||
qDebug() << "Remote loading is being run for metadata index";
|
|
||||||
RemoteLoadStatus status;
|
|
||||||
status.type = RemoteLoadStatus::Type::Index;
|
|
||||||
d->remoteLoadStatusList.append(status);
|
|
||||||
connect(indexLoadTask.get(), &Task::succeeded, [=]() { remoteLoadSucceeded(taskIndex); });
|
|
||||||
connect(indexLoadTask.get(), &Task::failed, [=](const QString& error) { remoteLoadFailed(taskIndex, error); });
|
|
||||||
connect(indexLoadTask.get(), &Task::aborted, [=]() { remoteLoadFailed(taskIndex, tr("Aborted")); });
|
|
||||||
taskIndex++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// load all the components OR their lists...
|
// load all the components OR their lists...
|
||||||
for (auto component : d->m_list->d->components) {
|
for (auto component : d->m_list->d->components) {
|
||||||
Task::Ptr loadTask;
|
Task::Ptr loadTask;
|
||||||
@ -206,12 +176,13 @@ void ComponentUpdateTask::loadComponents()
|
|||||||
result = composeLoadResult(result, singleResult);
|
result = composeLoadResult(result, singleResult);
|
||||||
if (loadTask) {
|
if (loadTask) {
|
||||||
qDebug() << "Remote loading is being run for" << component->getName();
|
qDebug() << "Remote loading is being run for" << component->getName();
|
||||||
connect(loadTask.get(), &Task::succeeded, [=]() { remoteLoadSucceeded(taskIndex); });
|
connect(loadTask.get(), &Task::succeeded, this, [this, taskIndex]() { remoteLoadSucceeded(taskIndex); });
|
||||||
connect(loadTask.get(), &Task::failed, [=](const QString& error) { remoteLoadFailed(taskIndex, error); });
|
connect(loadTask.get(), &Task::failed, this, [this, taskIndex](const QString& error) { remoteLoadFailed(taskIndex, error); });
|
||||||
connect(loadTask.get(), &Task::aborted, [=]() { remoteLoadFailed(taskIndex, tr("Aborted")); });
|
connect(loadTask.get(), &Task::aborted, this, [this, taskIndex]() { remoteLoadFailed(taskIndex, tr("Aborted")); });
|
||||||
RemoteLoadStatus status;
|
RemoteLoadStatus status;
|
||||||
status.type = loadType;
|
status.type = loadType;
|
||||||
status.PackProfileIndex = componentIndex;
|
status.PackProfileIndex = componentIndex;
|
||||||
|
status.task = loadTask;
|
||||||
d->remoteLoadStatusList.append(status);
|
d->remoteLoadStatusList.append(status);
|
||||||
taskIndex++;
|
taskIndex++;
|
||||||
}
|
}
|
||||||
@ -518,7 +489,14 @@ void ComponentUpdateTask::resolveDependencies(bool checkOnly)
|
|||||||
|
|
||||||
void ComponentUpdateTask::remoteLoadSucceeded(size_t taskIndex)
|
void ComponentUpdateTask::remoteLoadSucceeded(size_t taskIndex)
|
||||||
{
|
{
|
||||||
|
if (static_cast<size_t>(d->remoteLoadStatusList.size()) < taskIndex) {
|
||||||
|
qWarning() << "Got task index outside of results" << taskIndex;
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto& taskSlot = d->remoteLoadStatusList[taskIndex];
|
auto& taskSlot = d->remoteLoadStatusList[taskIndex];
|
||||||
|
disconnect(taskSlot.task.get(), &Task::succeeded, this, nullptr);
|
||||||
|
disconnect(taskSlot.task.get(), &Task::failed, this, nullptr);
|
||||||
|
disconnect(taskSlot.task.get(), &Task::aborted, this, nullptr);
|
||||||
if (taskSlot.finished) {
|
if (taskSlot.finished) {
|
||||||
qWarning() << "Got multiple results from remote load task" << taskIndex;
|
qWarning() << "Got multiple results from remote load task" << taskIndex;
|
||||||
return;
|
return;
|
||||||
@ -538,7 +516,14 @@ void ComponentUpdateTask::remoteLoadSucceeded(size_t taskIndex)
|
|||||||
|
|
||||||
void ComponentUpdateTask::remoteLoadFailed(size_t taskIndex, const QString& msg)
|
void ComponentUpdateTask::remoteLoadFailed(size_t taskIndex, const QString& msg)
|
||||||
{
|
{
|
||||||
|
if (static_cast<size_t>(d->remoteLoadStatusList.size()) < taskIndex) {
|
||||||
|
qWarning() << "Got task index outside of results" << taskIndex;
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto& taskSlot = d->remoteLoadStatusList[taskIndex];
|
auto& taskSlot = d->remoteLoadStatusList[taskIndex];
|
||||||
|
disconnect(taskSlot.task.get(), &Task::succeeded, this, nullptr);
|
||||||
|
disconnect(taskSlot.task.get(), &Task::failed, this, nullptr);
|
||||||
|
disconnect(taskSlot.task.get(), &Task::aborted, this, nullptr);
|
||||||
if (taskSlot.finished) {
|
if (taskSlot.finished) {
|
||||||
qWarning() << "Got multiple results from remote load task" << taskIndex;
|
qWarning() << "Got multiple results from remote load task" << taskIndex;
|
||||||
return;
|
return;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include "net/Mode.h"
|
#include "net/Mode.h"
|
||||||
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
class PackProfile;
|
class PackProfile;
|
||||||
|
|
||||||
@ -13,6 +14,7 @@ struct RemoteLoadStatus {
|
|||||||
bool finished = false;
|
bool finished = false;
|
||||||
bool succeeded = false;
|
bool succeeded = false;
|
||||||
QString error;
|
QString error;
|
||||||
|
Task::Ptr task;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ComponentUpdateTaskData {
|
struct ComponentUpdateTaskData {
|
||||||
|
@ -164,6 +164,11 @@ void LaunchProfile::applyCompatibleJavaMajors(QList<int>& javaMajor)
|
|||||||
{
|
{
|
||||||
m_compatibleJavaMajors.append(javaMajor);
|
m_compatibleJavaMajors.append(javaMajor);
|
||||||
}
|
}
|
||||||
|
void LaunchProfile::applyCompatibleJavaName(QString javaName)
|
||||||
|
{
|
||||||
|
if (!javaName.isEmpty())
|
||||||
|
m_compatibleJavaName = javaName;
|
||||||
|
}
|
||||||
|
|
||||||
void LaunchProfile::applyLibrary(LibraryPtr library, const RuntimeContext& runtimeContext)
|
void LaunchProfile::applyLibrary(LibraryPtr library, const RuntimeContext& runtimeContext)
|
||||||
{
|
{
|
||||||
@ -334,6 +339,11 @@ const QList<int>& LaunchProfile::getCompatibleJavaMajors() const
|
|||||||
return m_compatibleJavaMajors;
|
return m_compatibleJavaMajors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QString LaunchProfile::getCompatibleJavaName() const
|
||||||
|
{
|
||||||
|
return m_compatibleJavaName;
|
||||||
|
}
|
||||||
|
|
||||||
void LaunchProfile::getLibraryFiles(const RuntimeContext& runtimeContext,
|
void LaunchProfile::getLibraryFiles(const RuntimeContext& runtimeContext,
|
||||||
QStringList& jars,
|
QStringList& jars,
|
||||||
QStringList& nativeJars,
|
QStringList& nativeJars,
|
||||||
|
@ -59,6 +59,7 @@ class LaunchProfile : public ProblemProvider {
|
|||||||
void applyMavenFile(LibraryPtr library, const RuntimeContext& runtimeContext);
|
void applyMavenFile(LibraryPtr library, const RuntimeContext& runtimeContext);
|
||||||
void applyAgent(AgentPtr agent, const RuntimeContext& runtimeContext);
|
void applyAgent(AgentPtr agent, const RuntimeContext& runtimeContext);
|
||||||
void applyCompatibleJavaMajors(QList<int>& javaMajor);
|
void applyCompatibleJavaMajors(QList<int>& javaMajor);
|
||||||
|
void applyCompatibleJavaName(QString javaName);
|
||||||
void applyMainJar(LibraryPtr jar);
|
void applyMainJar(LibraryPtr jar);
|
||||||
void applyProblemSeverity(ProblemSeverity severity);
|
void applyProblemSeverity(ProblemSeverity severity);
|
||||||
/// clear the profile
|
/// clear the profile
|
||||||
@ -80,6 +81,7 @@ class LaunchProfile : public ProblemProvider {
|
|||||||
const QList<LibraryPtr>& getMavenFiles() const;
|
const QList<LibraryPtr>& getMavenFiles() const;
|
||||||
const QList<AgentPtr>& getAgents() const;
|
const QList<AgentPtr>& getAgents() const;
|
||||||
const QList<int>& getCompatibleJavaMajors() const;
|
const QList<int>& getCompatibleJavaMajors() const;
|
||||||
|
const QString getCompatibleJavaName() const;
|
||||||
const LibraryPtr getMainJar() const;
|
const LibraryPtr getMainJar() const;
|
||||||
void getLibraryFiles(const RuntimeContext& runtimeContext,
|
void getLibraryFiles(const RuntimeContext& runtimeContext,
|
||||||
QStringList& jars,
|
QStringList& jars,
|
||||||
@ -150,5 +152,7 @@ class LaunchProfile : public ProblemProvider {
|
|||||||
/// compatible java major versions
|
/// compatible java major versions
|
||||||
QList<int> m_compatibleJavaMajors;
|
QList<int> m_compatibleJavaMajors;
|
||||||
|
|
||||||
|
QString m_compatibleJavaName;
|
||||||
|
|
||||||
ProblemSeverity m_problemSeverity = ProblemSeverity::None;
|
ProblemSeverity m_problemSeverity = ProblemSeverity::None;
|
||||||
};
|
};
|
||||||
|
@ -147,9 +147,8 @@ QList<Net::NetRequest::Ptr> Library::getDownloads(const RuntimeContext& runtimeC
|
|||||||
options |= Net::Download::Option::MakeEternal;
|
options |= Net::Download::Option::MakeEternal;
|
||||||
|
|
||||||
if (sha1.size()) {
|
if (sha1.size()) {
|
||||||
auto rawSha1 = QByteArray::fromHex(sha1.toLatin1());
|
|
||||||
auto dl = Net::ApiDownload::makeCached(url, entry, options);
|
auto dl = Net::ApiDownload::makeCached(url, entry, options);
|
||||||
dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawSha1));
|
dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, sha1));
|
||||||
qDebug() << "Checksummed Download for:" << rawName().serialize() << "storage:" << storage << "url:" << url;
|
qDebug() << "Checksummed Download for:" << rawName().serialize() << "storage:" << storage << "url:" << url;
|
||||||
out.append(dl);
|
out.append(dl);
|
||||||
} else {
|
} else {
|
||||||
|
@ -38,6 +38,8 @@
|
|||||||
#include "MinecraftInstance.h"
|
#include "MinecraftInstance.h"
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "BuildConfig.h"
|
#include "BuildConfig.h"
|
||||||
|
#include "QObjectPtr.h"
|
||||||
|
#include "minecraft/launch/AutoInstallJava.h"
|
||||||
#include "minecraft/launch/CreateGameFolders.h"
|
#include "minecraft/launch/CreateGameFolders.h"
|
||||||
#include "minecraft/launch/ExtractNatives.h"
|
#include "minecraft/launch/ExtractNatives.h"
|
||||||
#include "minecraft/launch/PrintInstanceInfo.h"
|
#include "minecraft/launch/PrintInstanceInfo.h"
|
||||||
@ -134,25 +136,21 @@ void MinecraftInstance::loadSpecificSettings()
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Java Settings
|
// Java Settings
|
||||||
auto javaOverride = m_settings->registerSetting("OverrideJava", false);
|
|
||||||
auto locationOverride = m_settings->registerSetting("OverrideJavaLocation", false);
|
auto locationOverride = m_settings->registerSetting("OverrideJavaLocation", false);
|
||||||
auto argsOverride = m_settings->registerSetting("OverrideJavaArgs", false);
|
auto argsOverride = m_settings->registerSetting("OverrideJavaArgs", false);
|
||||||
|
m_settings->registerSetting("AutomaticJava", false);
|
||||||
// combinations
|
|
||||||
auto javaOrLocation = std::make_shared<OrSetting>("JavaOrLocationOverride", javaOverride, locationOverride);
|
|
||||||
auto javaOrArgs = std::make_shared<OrSetting>("JavaOrArgsOverride", javaOverride, argsOverride);
|
|
||||||
|
|
||||||
if (auto global_settings = globalSettings()) {
|
if (auto global_settings = globalSettings()) {
|
||||||
m_settings->registerOverride(global_settings->getSetting("JavaPath"), javaOrLocation);
|
m_settings->registerOverride(global_settings->getSetting("JavaPath"), locationOverride);
|
||||||
m_settings->registerOverride(global_settings->getSetting("JvmArgs"), javaOrArgs);
|
m_settings->registerOverride(global_settings->getSetting("JvmArgs"), argsOverride);
|
||||||
m_settings->registerOverride(global_settings->getSetting("IgnoreJavaCompatibility"), javaOrLocation);
|
m_settings->registerOverride(global_settings->getSetting("IgnoreJavaCompatibility"), locationOverride);
|
||||||
|
|
||||||
// special!
|
// special!
|
||||||
m_settings->registerPassthrough(global_settings->getSetting("JavaSignature"), javaOrLocation);
|
m_settings->registerPassthrough(global_settings->getSetting("JavaSignature"), locationOverride);
|
||||||
m_settings->registerPassthrough(global_settings->getSetting("JavaArchitecture"), javaOrLocation);
|
m_settings->registerPassthrough(global_settings->getSetting("JavaArchitecture"), locationOverride);
|
||||||
m_settings->registerPassthrough(global_settings->getSetting("JavaRealArchitecture"), javaOrLocation);
|
m_settings->registerPassthrough(global_settings->getSetting("JavaRealArchitecture"), locationOverride);
|
||||||
m_settings->registerPassthrough(global_settings->getSetting("JavaVersion"), javaOrLocation);
|
m_settings->registerPassthrough(global_settings->getSetting("JavaVersion"), locationOverride);
|
||||||
m_settings->registerPassthrough(global_settings->getSetting("JavaVendor"), javaOrLocation);
|
m_settings->registerPassthrough(global_settings->getSetting("JavaVendor"), locationOverride);
|
||||||
|
|
||||||
// Window Size
|
// Window Size
|
||||||
auto windowSetting = m_settings->registerSetting("OverrideWindow", false);
|
auto windowSetting = m_settings->registerSetting("OverrideWindow", false);
|
||||||
@ -196,8 +194,9 @@ void MinecraftInstance::loadSpecificSettings()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Join server on launch, this does not have a global override
|
// Join server on launch, this does not have a global override
|
||||||
m_settings->registerSetting("JoinServerOnLaunch", false);
|
m_settings->registerSetting({ "JoinServerOnLaunch", "JoinOnLaunch" }, false);
|
||||||
m_settings->registerSetting("JoinServerOnLaunchAddress", "");
|
m_settings->registerSetting("JoinServerOnLaunchAddress", "");
|
||||||
|
m_settings->registerSetting("JoinWorldOnLaunch", "");
|
||||||
|
|
||||||
// Use account for instance, this does not have a global override
|
// Use account for instance, this does not have a global override
|
||||||
m_settings->registerSetting("UseAccountForInstance", false);
|
m_settings->registerSetting("UseAccountForInstance", false);
|
||||||
@ -523,8 +522,7 @@ QStringList MinecraftInstance::javaArguments()
|
|||||||
|
|
||||||
if (javaVersion.isModular() && shouldApplyOnlineFixes())
|
if (javaVersion.isModular() && shouldApplyOnlineFixes())
|
||||||
// allow reflective access to java.net - required by the skin fix
|
// allow reflective access to java.net - required by the skin fix
|
||||||
args << "--add-opens"
|
args << "--add-opens" << "java.base/java.net=ALL-UNNAMED";
|
||||||
<< "java.base/java.net=ALL-UNNAMED";
|
|
||||||
|
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
@ -608,7 +606,7 @@ QProcessEnvironment MinecraftInstance::createLaunchEnvironment()
|
|||||||
// dlsym variant is only needed for OpenGL and not included in the vulkan layer
|
// dlsym variant is only needed for OpenGL and not included in the vulkan layer
|
||||||
appendLib("libMangoHud_dlsym.so");
|
appendLib("libMangoHud_dlsym.so");
|
||||||
appendLib("libMangoHud_opengl.so");
|
appendLib("libMangoHud_opengl.so");
|
||||||
appendLib(mangoHudLib.fileName());
|
preloadList << mangoHudLibString;
|
||||||
}
|
}
|
||||||
|
|
||||||
env.insert("LD_PRELOAD", preloadList.join(QLatin1String(":")));
|
env.insert("LD_PRELOAD", preloadList.join(QLatin1String(":")));
|
||||||
@ -656,7 +654,7 @@ static QString replaceTokensIn(QString text, QMap<QString, QString> with)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList MinecraftInstance::processMinecraftArgs(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) const
|
QStringList MinecraftInstance::processMinecraftArgs(AuthSessionPtr session, MinecraftTarget::Ptr targetToJoin) const
|
||||||
{
|
{
|
||||||
auto profile = m_components->getProfile();
|
auto profile = m_components->getProfile();
|
||||||
QString args_pattern = profile->getMinecraftArguments();
|
QString args_pattern = profile->getMinecraftArguments();
|
||||||
@ -664,12 +662,16 @@ QStringList MinecraftInstance::processMinecraftArgs(AuthSessionPtr session, Mine
|
|||||||
args_pattern += " --tweakClass " + tweaker;
|
args_pattern += " --tweakClass " + tweaker;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (serverToJoin && !serverToJoin->address.isEmpty()) {
|
if (targetToJoin) {
|
||||||
|
if (!targetToJoin->address.isEmpty()) {
|
||||||
if (profile->hasTrait("feature:is_quick_play_multiplayer")) {
|
if (profile->hasTrait("feature:is_quick_play_multiplayer")) {
|
||||||
args_pattern += " --quickPlayMultiplayer " + serverToJoin->address + ':' + QString::number(serverToJoin->port);
|
args_pattern += " --quickPlayMultiplayer " + targetToJoin->address + ':' + QString::number(targetToJoin->port);
|
||||||
} else {
|
} else {
|
||||||
args_pattern += " --server " + serverToJoin->address;
|
args_pattern += " --server " + targetToJoin->address;
|
||||||
args_pattern += " --port " + QString::number(serverToJoin->port);
|
args_pattern += " --port " + QString::number(targetToJoin->port);
|
||||||
|
}
|
||||||
|
} else if (!targetToJoin->world.isEmpty() && profile->hasTrait("feature:is_quick_play_singleplayer")) {
|
||||||
|
args_pattern += " --quickPlaySingleplayer " + targetToJoin->world;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -713,7 +715,7 @@ QStringList MinecraftInstance::processMinecraftArgs(AuthSessionPtr session, Mine
|
|||||||
return parts;
|
return parts;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin)
|
QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftTarget::Ptr targetToJoin)
|
||||||
{
|
{
|
||||||
QString launchScript;
|
QString launchScript;
|
||||||
|
|
||||||
@ -732,9 +734,13 @@ QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftS
|
|||||||
launchScript += "appletClass " + appletClass + "\n";
|
launchScript += "appletClass " + appletClass + "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (serverToJoin && !serverToJoin->address.isEmpty()) {
|
if (targetToJoin) {
|
||||||
launchScript += "serverAddress " + serverToJoin->address + "\n";
|
if (!targetToJoin->address.isEmpty()) {
|
||||||
launchScript += "serverPort " + QString::number(serverToJoin->port) + "\n";
|
launchScript += "serverAddress " + targetToJoin->address + "\n";
|
||||||
|
launchScript += "serverPort " + QString::number(targetToJoin->port) + "\n";
|
||||||
|
} else if (!targetToJoin->world.isEmpty()) {
|
||||||
|
launchScript += "worldName " + targetToJoin->world + "\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// generic minecraft params
|
// generic minecraft params
|
||||||
@ -787,16 +793,15 @@ QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftS
|
|||||||
return launchScript;
|
return launchScript;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin)
|
QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, MinecraftTarget::Ptr targetToJoin)
|
||||||
{
|
{
|
||||||
QStringList out;
|
QStringList out;
|
||||||
out << "Main Class:"
|
out << "Main Class:" << " " + getMainClass() << "";
|
||||||
<< " " + getMainClass() << "";
|
out << "Native path:" << " " + getNativePath() << "";
|
||||||
out << "Native path:"
|
|
||||||
<< " " + getNativePath() << "";
|
|
||||||
|
|
||||||
auto profile = m_components->getProfile();
|
auto profile = m_components->getProfile();
|
||||||
|
|
||||||
|
// traits
|
||||||
auto alltraits = traits();
|
auto alltraits = traits();
|
||||||
if (alltraits.size()) {
|
if (alltraits.size()) {
|
||||||
out << "Traits:";
|
out << "Traits:";
|
||||||
@ -806,6 +811,7 @@ QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, Minecr
|
|||||||
out << "";
|
out << "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// native libraries
|
||||||
auto settings = this->settings();
|
auto settings = this->settings();
|
||||||
bool nativeOpenAL = settings->get("UseNativeOpenAL").toBool();
|
bool nativeOpenAL = settings->get("UseNativeOpenAL").toBool();
|
||||||
bool nativeGLFW = settings->get("UseNativeGLFW").toBool();
|
bool nativeGLFW = settings->get("UseNativeGLFW").toBool();
|
||||||
@ -841,6 +847,7 @@ QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, Minecr
|
|||||||
out << "";
|
out << "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mods and core mods
|
||||||
auto printModList = [&](const QString& label, ModFolderModel& model) {
|
auto printModList = [&](const QString& label, ModFolderModel& model) {
|
||||||
if (model.size()) {
|
if (model.size()) {
|
||||||
out << QString("%1:").arg(label);
|
out << QString("%1:").arg(label);
|
||||||
@ -869,6 +876,7 @@ QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, Minecr
|
|||||||
printModList("Mods", *(loaderModList().get()));
|
printModList("Mods", *(loaderModList().get()));
|
||||||
printModList("Core Mods", *(coreModList().get()));
|
printModList("Core Mods", *(coreModList().get()));
|
||||||
|
|
||||||
|
// jar mods
|
||||||
auto& jarMods = profile->getJarMods();
|
auto& jarMods = profile->getJarMods();
|
||||||
if (jarMods.size()) {
|
if (jarMods.size()) {
|
||||||
out << "Jar Mods:";
|
out << "Jar Mods:";
|
||||||
@ -884,11 +892,13 @@ QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, Minecr
|
|||||||
out << "";
|
out << "";
|
||||||
}
|
}
|
||||||
|
|
||||||
auto params = processMinecraftArgs(nullptr, serverToJoin);
|
// minecraft arguments
|
||||||
|
auto params = processMinecraftArgs(nullptr, targetToJoin);
|
||||||
out << "Params:";
|
out << "Params:";
|
||||||
out << " " + params.join(' ');
|
out << " " + params.join(' ');
|
||||||
out << "";
|
out << "";
|
||||||
|
|
||||||
|
// window size
|
||||||
QString windowParams;
|
QString windowParams;
|
||||||
if (settings->get("LaunchMaximized").toBool()) {
|
if (settings->get("LaunchMaximized").toBool()) {
|
||||||
out << "Window size: max (if available)";
|
out << "Window size: max (if available)";
|
||||||
@ -1034,7 +1044,7 @@ Task::Ptr MinecraftInstance::createUpdateTask(Net::Mode mode)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin)
|
shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPtr session, MinecraftTarget::Ptr targetToJoin)
|
||||||
{
|
{
|
||||||
updateRuntimeContext();
|
updateRuntimeContext();
|
||||||
// FIXME: get rid of shared_from_this ...
|
// FIXME: get rid of shared_from_this ...
|
||||||
@ -1048,26 +1058,28 @@ shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPt
|
|||||||
process->appendStep(makeShared<TextPrint>(pptr, "Minecraft folder is:\n" + gameRoot() + "\n\n", MessageLevel::Launcher));
|
process->appendStep(makeShared<TextPrint>(pptr, "Minecraft folder is:\n" + gameRoot() + "\n\n", MessageLevel::Launcher));
|
||||||
}
|
}
|
||||||
|
|
||||||
// check java
|
|
||||||
{
|
|
||||||
process->appendStep(makeShared<CheckJava>(pptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the .minecraft folder and server-resource-packs (workaround for Minecraft bug MCL-3732)
|
// create the .minecraft folder and server-resource-packs (workaround for Minecraft bug MCL-3732)
|
||||||
{
|
{
|
||||||
process->appendStep(makeShared<CreateGameFolders>(pptr));
|
process->appendStep(makeShared<CreateGameFolders>(pptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!serverToJoin && settings()->get("JoinServerOnLaunch").toBool()) {
|
if (!targetToJoin && settings()->get("JoinOnLaunch").toBool()) {
|
||||||
QString fullAddress = settings()->get("JoinServerOnLaunchAddress").toString();
|
QString fullAddress = settings()->get("JoinServerOnLaunchAddress").toString();
|
||||||
serverToJoin.reset(new MinecraftServerTarget(MinecraftServerTarget::parse(fullAddress)));
|
if (!fullAddress.isEmpty()) {
|
||||||
|
targetToJoin.reset(new MinecraftTarget(MinecraftTarget::parse(fullAddress, false)));
|
||||||
|
} else {
|
||||||
|
QString world = settings()->get("JoinWorldOnLaunch").toString();
|
||||||
|
if (!world.isEmpty()) {
|
||||||
|
targetToJoin.reset(new MinecraftTarget(MinecraftTarget::parse(world, true)));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (serverToJoin && serverToJoin->port == 25565) {
|
if (targetToJoin && targetToJoin->port == 25565) {
|
||||||
// Resolve server address to join on launch
|
// Resolve server address to join on launch
|
||||||
auto step = makeShared<LookupServerAddress>(pptr);
|
auto step = makeShared<LookupServerAddress>(pptr);
|
||||||
step->setLookupAddress(serverToJoin->address);
|
step->setLookupAddress(targetToJoin->address);
|
||||||
step->setOutputAddressPtr(serverToJoin);
|
step->setOutputAddressPtr(targetToJoin);
|
||||||
process->appendStep(step);
|
process->appendStep(step);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1088,6 +1100,12 @@ shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPt
|
|||||||
process->appendStep(makeShared<Update>(pptr, Net::Mode::Offline));
|
process->appendStep(makeShared<Update>(pptr, Net::Mode::Offline));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check java
|
||||||
|
{
|
||||||
|
process->appendStep(makeShared<AutoInstallJava>(pptr));
|
||||||
|
process->appendStep(makeShared<CheckJava>(pptr));
|
||||||
|
}
|
||||||
|
|
||||||
// if there are any jar mods
|
// if there are any jar mods
|
||||||
{
|
{
|
||||||
process->appendStep(makeShared<ModMinecraftJar>(pptr));
|
process->appendStep(makeShared<ModMinecraftJar>(pptr));
|
||||||
@ -1100,7 +1118,7 @@ shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPt
|
|||||||
|
|
||||||
// print some instance info here...
|
// print some instance info here...
|
||||||
{
|
{
|
||||||
process->appendStep(makeShared<PrintInstanceInfo>(pptr, session, serverToJoin));
|
process->appendStep(makeShared<PrintInstanceInfo>(pptr, session, targetToJoin));
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract native jars if needed
|
// extract native jars if needed
|
||||||
@ -1123,7 +1141,7 @@ shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPt
|
|||||||
auto step = makeShared<LauncherPartLaunch>(pptr);
|
auto step = makeShared<LauncherPartLaunch>(pptr);
|
||||||
step->setWorkingDirectory(gameRoot());
|
step->setWorkingDirectory(gameRoot());
|
||||||
step->setAuthSession(session);
|
step->setAuthSession(session);
|
||||||
step->setServerToJoin(serverToJoin);
|
step->setTargetToJoin(targetToJoin);
|
||||||
process->appendStep(step);
|
process->appendStep(step);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#include "BaseInstance.h"
|
#include "BaseInstance.h"
|
||||||
#include "minecraft/launch/MinecraftServerTarget.h"
|
#include "minecraft/launch/MinecraftTarget.h"
|
||||||
#include "minecraft/mod/Mod.h"
|
#include "minecraft/mod/Mod.h"
|
||||||
|
|
||||||
class ModFolderModel;
|
class ModFolderModel;
|
||||||
@ -56,7 +56,7 @@ class MinecraftInstance : public BaseInstance {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
MinecraftInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString& rootDir);
|
MinecraftInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString& rootDir);
|
||||||
virtual ~MinecraftInstance() {};
|
virtual ~MinecraftInstance() = default;
|
||||||
virtual void saveNow() override;
|
virtual void saveNow() override;
|
||||||
|
|
||||||
void loadSpecificSettings() override;
|
void loadSpecificSettings() override;
|
||||||
@ -121,11 +121,11 @@ class MinecraftInstance : public BaseInstance {
|
|||||||
|
|
||||||
////// Launch stuff //////
|
////// Launch stuff //////
|
||||||
Task::Ptr createUpdateTask(Net::Mode mode) override;
|
Task::Ptr createUpdateTask(Net::Mode mode) override;
|
||||||
shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) override;
|
shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account, MinecraftTarget::Ptr targetToJoin) override;
|
||||||
QStringList extraArguments() override;
|
QStringList extraArguments() override;
|
||||||
QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) override;
|
QStringList verboseDescription(AuthSessionPtr session, MinecraftTarget::Ptr targetToJoin) override;
|
||||||
QList<Mod*> getJarMods() const;
|
QList<Mod*> getJarMods() const;
|
||||||
QString createLaunchScript(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin);
|
QString createLaunchScript(AuthSessionPtr session, MinecraftTarget::Ptr targetToJoin);
|
||||||
/// get arguments passed to java
|
/// get arguments passed to java
|
||||||
QStringList javaArguments();
|
QStringList javaArguments();
|
||||||
QString getLauncher();
|
QString getLauncher();
|
||||||
@ -155,7 +155,7 @@ class MinecraftInstance : public BaseInstance {
|
|||||||
virtual QString getMainClass() const;
|
virtual QString getMainClass() const;
|
||||||
|
|
||||||
// FIXME: remove
|
// FIXME: remove
|
||||||
virtual QStringList processMinecraftArgs(AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) const;
|
virtual QStringList processMinecraftArgs(AuthSessionPtr account, MinecraftTarget::Ptr targetToJoin) const;
|
||||||
|
|
||||||
virtual JavaVersion getJavaVersion();
|
virtual JavaVersion getJavaVersion();
|
||||||
|
|
||||||
|
@ -16,32 +16,22 @@
|
|||||||
#include "MinecraftUpdate.h"
|
#include "MinecraftUpdate.h"
|
||||||
#include "MinecraftInstance.h"
|
#include "MinecraftInstance.h"
|
||||||
|
|
||||||
#include <QDataStream>
|
|
||||||
#include <QFile>
|
|
||||||
#include <QFileInfo>
|
|
||||||
#include <QTextStream>
|
|
||||||
|
|
||||||
#include <FileSystem.h>
|
|
||||||
#include "BaseInstance.h"
|
|
||||||
#include "minecraft/Library.h"
|
|
||||||
#include "minecraft/PackProfile.h"
|
#include "minecraft/PackProfile.h"
|
||||||
|
|
||||||
|
#include "tasks/SequentialTask.h"
|
||||||
#include "update/AssetUpdateTask.h"
|
#include "update/AssetUpdateTask.h"
|
||||||
#include "update/FMLLibrariesTask.h"
|
#include "update/FMLLibrariesTask.h"
|
||||||
#include "update/FoldersTask.h"
|
#include "update/FoldersTask.h"
|
||||||
#include "update/LibrariesTask.h"
|
#include "update/LibrariesTask.h"
|
||||||
|
|
||||||
#include <meta/Index.h>
|
MinecraftUpdate::MinecraftUpdate(MinecraftInstance* inst, QObject* parent) : SequentialTask(parent), m_inst(inst) {}
|
||||||
#include <meta/Version.h>
|
|
||||||
|
|
||||||
MinecraftUpdate::MinecraftUpdate(MinecraftInstance* inst, QObject* parent) : Task(parent), m_inst(inst) {}
|
|
||||||
|
|
||||||
void MinecraftUpdate::executeTask()
|
void MinecraftUpdate::executeTask()
|
||||||
{
|
{
|
||||||
m_tasks.clear();
|
m_queue.clear();
|
||||||
// create folders
|
// create folders
|
||||||
{
|
{
|
||||||
m_tasks.append(makeShared<FoldersTask>(m_inst));
|
addTask(makeShared<FoldersTask>(m_inst));
|
||||||
}
|
}
|
||||||
|
|
||||||
// add metadata update task if necessary
|
// add metadata update task if necessary
|
||||||
@ -50,121 +40,24 @@ void MinecraftUpdate::executeTask()
|
|||||||
components->reload(Net::Mode::Online);
|
components->reload(Net::Mode::Online);
|
||||||
auto task = components->getCurrentTask();
|
auto task = components->getCurrentTask();
|
||||||
if (task) {
|
if (task) {
|
||||||
m_tasks.append(task);
|
addTask(task);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// libraries download
|
// libraries download
|
||||||
{
|
{
|
||||||
m_tasks.append(makeShared<LibrariesTask>(m_inst));
|
addTask(makeShared<LibrariesTask>(m_inst));
|
||||||
}
|
}
|
||||||
|
|
||||||
// FML libraries download and copy into the instance
|
// FML libraries download and copy into the instance
|
||||||
{
|
{
|
||||||
m_tasks.append(makeShared<FMLLibrariesTask>(m_inst));
|
addTask(makeShared<FMLLibrariesTask>(m_inst));
|
||||||
}
|
}
|
||||||
|
|
||||||
// assets update
|
// assets update
|
||||||
{
|
{
|
||||||
m_tasks.append(makeShared<AssetUpdateTask>(m_inst));
|
addTask(makeShared<AssetUpdateTask>(m_inst));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_preFailure.isEmpty()) {
|
SequentialTask::executeTask();
|
||||||
emitFailed(m_preFailure);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MinecraftUpdate::next()
|
|
||||||
{
|
|
||||||
if (m_abort) {
|
|
||||||
emitFailed(tr("Aborted by user."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (m_failed_out_of_order) {
|
|
||||||
emitFailed(m_fail_reason);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_currentTask++;
|
|
||||||
if (m_currentTask > 0) {
|
|
||||||
auto task = m_tasks[m_currentTask - 1];
|
|
||||||
disconnect(task.get(), &Task::succeeded, this, &MinecraftUpdate::subtaskSucceeded);
|
|
||||||
disconnect(task.get(), &Task::failed, this, &MinecraftUpdate::subtaskFailed);
|
|
||||||
disconnect(task.get(), &Task::aborted, this, &Task::abort);
|
|
||||||
disconnect(task.get(), &Task::progress, this, &MinecraftUpdate::progress);
|
|
||||||
disconnect(task.get(), &Task::stepProgress, this, &MinecraftUpdate::propagateStepProgress);
|
|
||||||
disconnect(task.get(), &Task::status, this, &MinecraftUpdate::setStatus);
|
|
||||||
disconnect(task.get(), &Task::details, this, &MinecraftUpdate::setDetails);
|
|
||||||
}
|
|
||||||
if (m_currentTask == m_tasks.size()) {
|
|
||||||
emitSucceeded();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto task = m_tasks[m_currentTask];
|
|
||||||
// if the task is already finished by the time we look at it, skip it
|
|
||||||
if (task->isFinished()) {
|
|
||||||
qCritical() << "MinecraftUpdate: Skipping finished subtask" << m_currentTask << ":" << task.get();
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
connect(task.get(), &Task::succeeded, this, &MinecraftUpdate::subtaskSucceeded);
|
|
||||||
connect(task.get(), &Task::failed, this, &MinecraftUpdate::subtaskFailed);
|
|
||||||
connect(task.get(), &Task::aborted, this, &Task::abort);
|
|
||||||
connect(task.get(), &Task::progress, this, &MinecraftUpdate::progress);
|
|
||||||
connect(task.get(), &Task::stepProgress, this, &MinecraftUpdate::propagateStepProgress);
|
|
||||||
connect(task.get(), &Task::status, this, &MinecraftUpdate::setStatus);
|
|
||||||
connect(task.get(), &Task::details, this, &MinecraftUpdate::setDetails);
|
|
||||||
// if the task is already running, do not start it again
|
|
||||||
if (!task->isRunning()) {
|
|
||||||
task->start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MinecraftUpdate::subtaskSucceeded()
|
|
||||||
{
|
|
||||||
if (isFinished()) {
|
|
||||||
qCritical() << "MinecraftUpdate: Subtask" << sender() << "succeeded, but work was already done!";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto senderTask = QObject::sender();
|
|
||||||
auto currentTask = m_tasks[m_currentTask].get();
|
|
||||||
if (senderTask != currentTask) {
|
|
||||||
qDebug() << "MinecraftUpdate: Subtask" << sender() << "succeeded out of order.";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MinecraftUpdate::subtaskFailed(QString error)
|
|
||||||
{
|
|
||||||
if (isFinished()) {
|
|
||||||
qCritical() << "MinecraftUpdate: Subtask" << sender() << "failed, but work was already done!";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto senderTask = QObject::sender();
|
|
||||||
auto currentTask = m_tasks[m_currentTask].get();
|
|
||||||
if (senderTask != currentTask) {
|
|
||||||
qDebug() << "MinecraftUpdate: Subtask" << sender() << "failed out of order.";
|
|
||||||
m_failed_out_of_order = true;
|
|
||||||
m_fail_reason = error;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
emitFailed(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MinecraftUpdate::abort()
|
|
||||||
{
|
|
||||||
if (!m_abort) {
|
|
||||||
m_abort = true;
|
|
||||||
auto task = m_tasks[m_currentTask];
|
|
||||||
if (task->canAbort()) {
|
|
||||||
return task->abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MinecraftUpdate::canAbort() const
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
@ -15,43 +15,19 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QList>
|
#include "tasks/SequentialTask.h"
|
||||||
#include <QObject>
|
|
||||||
#include <QUrl>
|
|
||||||
|
|
||||||
#include <quazip/quazip.h>
|
|
||||||
#include "minecraft/VersionFilterData.h"
|
|
||||||
#include "net/NetJob.h"
|
|
||||||
#include "tasks/Task.h"
|
|
||||||
|
|
||||||
class MinecraftVersion;
|
|
||||||
class MinecraftInstance;
|
class MinecraftInstance;
|
||||||
|
|
||||||
// FIXME: This looks very similar to a SequentialTask. Maybe we can reduce code duplications? :^)
|
// this needs to be a task because components->reload does stuff that may block
|
||||||
|
class MinecraftUpdate : public SequentialTask {
|
||||||
class MinecraftUpdate : public Task {
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit MinecraftUpdate(MinecraftInstance* inst, QObject* parent = 0);
|
explicit MinecraftUpdate(MinecraftInstance* inst, QObject* parent = 0);
|
||||||
virtual ~MinecraftUpdate() {};
|
virtual ~MinecraftUpdate() = default;
|
||||||
|
|
||||||
void executeTask() override;
|
void executeTask() override;
|
||||||
bool canAbort() const override;
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
bool abort() override;
|
|
||||||
void subtaskSucceeded();
|
|
||||||
void subtaskFailed(QString error);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void next();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MinecraftInstance* m_inst = nullptr;
|
MinecraftInstance* m_inst = nullptr;
|
||||||
QList<Task::Ptr> m_tasks;
|
|
||||||
QString m_preFailure;
|
|
||||||
int m_currentTask = -1;
|
|
||||||
bool m_abort = false;
|
|
||||||
bool m_failed_out_of_order = false;
|
|
||||||
QString m_fail_reason;
|
|
||||||
};
|
};
|
||||||
|
@ -185,6 +185,9 @@ void MojangVersionFormat::readVersionProperties(const QJsonObject& in, VersionFi
|
|||||||
out->compatibleJavaMajors.append(requireInteger(compatible));
|
out->compatibleJavaMajors.append(requireInteger(compatible));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (in.contains("compatibleJavaName")) {
|
||||||
|
out->compatibleJavaName = requireString(in.value("compatibleJavaName"));
|
||||||
|
}
|
||||||
|
|
||||||
if (in.contains("downloads")) {
|
if (in.contains("downloads")) {
|
||||||
auto downloadsObj = requireObject(in, "downloads");
|
auto downloadsObj = requireObject(in, "downloads");
|
||||||
@ -259,6 +262,9 @@ void MojangVersionFormat::writeVersionProperties(const VersionFile* in, QJsonObj
|
|||||||
}
|
}
|
||||||
out.insert("compatibleJavaMajors", compatibleJavaMajorsOut);
|
out.insert("compatibleJavaMajors", compatibleJavaMajorsOut);
|
||||||
}
|
}
|
||||||
|
if (!in->compatibleJavaName.isEmpty()) {
|
||||||
|
writeString(out, "compatibleJavaName", in->compatibleJavaName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonDocument MojangVersionFormat::versionFileToJson(const VersionFilePtr& patch)
|
QJsonDocument MojangVersionFormat::versionFileToJson(const VersionFilePtr& patch)
|
||||||
|
@ -36,6 +36,8 @@
|
|||||||
#include "OneSixVersionFormat.h"
|
#include "OneSixVersionFormat.h"
|
||||||
#include <Json.h>
|
#include <Json.h>
|
||||||
#include <minecraft/MojangVersionFormat.h>
|
#include <minecraft/MojangVersionFormat.h>
|
||||||
|
#include <QList>
|
||||||
|
#include "java/JavaMetadata.h"
|
||||||
#include "minecraft/Agent.h"
|
#include "minecraft/Agent.h"
|
||||||
#include "minecraft/ParseUtils.h"
|
#include "minecraft/ParseUtils.h"
|
||||||
|
|
||||||
@ -255,6 +257,13 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument& doc
|
|||||||
out->m_volatile = requireBoolean(root, "volatile");
|
out->m_volatile = requireBoolean(root, "volatile");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (root.contains("runtimes")) {
|
||||||
|
out->runtimes = {};
|
||||||
|
for (auto runtime : ensureArray(root, "runtimes")) {
|
||||||
|
out->runtimes.append(Java::parseJavaMeta(ensureObject(runtime)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* removed features that shouldn't be used */
|
/* removed features that shouldn't be used */
|
||||||
if (root.contains("tweakers")) {
|
if (root.contains("tweakers")) {
|
||||||
out->addProblem(ProblemSeverity::Error, QObject::tr("Version file contains unsupported element 'tweakers'"));
|
out->addProblem(ProblemSeverity::Error, QObject::tr("Version file contains unsupported element 'tweakers'"));
|
||||||
|
@ -73,6 +73,7 @@ void VersionFile::applyTo(LaunchProfile* profile, const RuntimeContext& runtimeC
|
|||||||
profile->applyMods(mods);
|
profile->applyMods(mods);
|
||||||
profile->applyTraits(traits);
|
profile->applyTraits(traits);
|
||||||
profile->applyCompatibleJavaMajors(compatibleJavaMajors);
|
profile->applyCompatibleJavaMajors(compatibleJavaMajors);
|
||||||
|
profile->applyCompatibleJavaName(compatibleJavaName);
|
||||||
|
|
||||||
for (auto library : libraries) {
|
for (auto library : libraries) {
|
||||||
profile->applyLibrary(library, runtimeContext);
|
profile->applyLibrary(library, runtimeContext);
|
||||||
|
@ -36,6 +36,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QList>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
@ -45,6 +47,7 @@
|
|||||||
#include "Agent.h"
|
#include "Agent.h"
|
||||||
#include "Library.h"
|
#include "Library.h"
|
||||||
#include "ProblemProvider.h"
|
#include "ProblemProvider.h"
|
||||||
|
#include "java/JavaMetadata.h"
|
||||||
#include "minecraft/Rule.h"
|
#include "minecraft/Rule.h"
|
||||||
|
|
||||||
class PackProfile;
|
class PackProfile;
|
||||||
@ -98,6 +101,9 @@ class VersionFile : public ProblemContainer {
|
|||||||
/// Mojang: list of compatible java majors
|
/// Mojang: list of compatible java majors
|
||||||
QList<int> compatibleJavaMajors;
|
QList<int> compatibleJavaMajors;
|
||||||
|
|
||||||
|
/// Mojang: the name of recommended java version
|
||||||
|
QString compatibleJavaName;
|
||||||
|
|
||||||
/// Mojang: type of the Minecraft version
|
/// Mojang: type of the Minecraft version
|
||||||
QString type;
|
QString type;
|
||||||
|
|
||||||
@ -149,6 +155,8 @@ class VersionFile : public ProblemContainer {
|
|||||||
/// is volatile -- may be removed as soon as it is no longer needed by something else
|
/// is volatile -- may be removed as soon as it is no longer needed by something else
|
||||||
bool m_volatile = false;
|
bool m_volatile = false;
|
||||||
|
|
||||||
|
QList<Java::MetadataPtr> runtimes;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Mojang: DEPRECATED list of 'downloads' - client jar, server jar, windows server exe, maybe more.
|
// Mojang: DEPRECATED list of 'downloads' - client jar, server jar, windows server exe, maybe more.
|
||||||
QMap<QString, std::shared_ptr<MojangDownloadInfo>> mojangDownloads;
|
QMap<QString, std::shared_ptr<MojangDownloadInfo>> mojangDownloads;
|
||||||
|
@ -74,6 +74,8 @@ void MSADeviceCodeStep::perform()
|
|||||||
m_task->setAskRetry(false);
|
m_task->setAskRetry(false);
|
||||||
m_task->addNetAction(m_request);
|
m_task->addNetAction(m_request);
|
||||||
|
|
||||||
|
connect(m_task.get(), &Task::finished, this, &MSADeviceCodeStep::deviceAutorizationFinished);
|
||||||
|
|
||||||
m_task->start();
|
m_task->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
242
launcher/minecraft/launch/AutoInstallJava.cpp
Normal file
242
launcher/minecraft/launch/AutoInstallJava.cpp
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This file incorporates work covered by the following copyright and
|
||||||
|
* permission notice:
|
||||||
|
*
|
||||||
|
* Copyright 2013-2021 MultiMC Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "AutoInstallJava.h"
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
#include "FileSystem.h"
|
||||||
|
#include "MessageLevel.h"
|
||||||
|
#include "SysInfo.h"
|
||||||
|
#include "java/JavaInstall.h"
|
||||||
|
#include "java/JavaInstallList.h"
|
||||||
|
#include "java/JavaUtils.h"
|
||||||
|
#include "java/JavaVersion.h"
|
||||||
|
#include "java/download/ArchiveDownloadTask.h"
|
||||||
|
#include "java/download/ManifestDownloadTask.h"
|
||||||
|
#include "meta/Index.h"
|
||||||
|
#include "minecraft/MinecraftInstance.h"
|
||||||
|
#include "minecraft/PackProfile.h"
|
||||||
|
#include "net/Mode.h"
|
||||||
|
|
||||||
|
AutoInstallJava::AutoInstallJava(LaunchTask* parent)
|
||||||
|
: LaunchStep(parent)
|
||||||
|
, m_instance(std::dynamic_pointer_cast<MinecraftInstance>(m_parent->instance()))
|
||||||
|
, m_supported_arch(SysInfo::getSupportedJavaArchitecture()) {};
|
||||||
|
|
||||||
|
void AutoInstallJava::executeTask()
|
||||||
|
{
|
||||||
|
auto settings = m_instance->settings();
|
||||||
|
if (!APPLICATION->settings()->get("AutomaticJavaSwitch").toBool() ||
|
||||||
|
(settings->get("OverrideJavaLocation").toBool() && QFileInfo::exists(settings->get("JavaPath").toString()))) {
|
||||||
|
emitSucceeded();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto packProfile = m_instance->getPackProfile();
|
||||||
|
if (!APPLICATION->settings()->get("AutomaticJavaDownload").toBool()) {
|
||||||
|
auto javas = APPLICATION->javalist();
|
||||||
|
m_current_task = javas->getLoadTask();
|
||||||
|
connect(m_current_task.get(), &Task::finished, this, [this, javas, packProfile] {
|
||||||
|
for (auto i = 0; i < javas->count(); i++) {
|
||||||
|
auto java = std::dynamic_pointer_cast<JavaInstall>(javas->at(i));
|
||||||
|
if (java && packProfile->getProfile()->getCompatibleJavaMajors().contains(java->id.major())) {
|
||||||
|
if (!java->is_64bit) {
|
||||||
|
emit logLine(tr("The automatic Java mechanism detected a 32-bit installation of Java."), MessageLevel::Info);
|
||||||
|
}
|
||||||
|
setJavaPath(java->path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emit logLine(tr("No compatible Java version was found. Using the default one."), MessageLevel::Warning);
|
||||||
|
emitSucceeded();
|
||||||
|
});
|
||||||
|
connect(m_current_task.get(), &Task::progress, this, &AutoInstallJava::setProgress);
|
||||||
|
connect(m_current_task.get(), &Task::stepProgress, this, &AutoInstallJava::propagateStepProgress);
|
||||||
|
connect(m_current_task.get(), &Task::status, this, &AutoInstallJava::setStatus);
|
||||||
|
connect(m_current_task.get(), &Task::details, this, &AutoInstallJava::setDetails);
|
||||||
|
emit progressReportingRequest();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (m_supported_arch.isEmpty()) {
|
||||||
|
emit logLine(tr("Your system (%1-%2) is not compatible with automatic Java installation. Using the default Java path.")
|
||||||
|
.arg(SysInfo::currentSystem(), SysInfo::useQTForArch()),
|
||||||
|
MessageLevel::Warning);
|
||||||
|
emitSucceeded();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto wantedJavaName = packProfile->getProfile()->getCompatibleJavaName();
|
||||||
|
if (wantedJavaName.isEmpty()) {
|
||||||
|
emit logLine(tr("Your meta information is out of date or doesn't have the information necessary to determine what installation of "
|
||||||
|
"Java should be used. "
|
||||||
|
"Using the default Java path."),
|
||||||
|
MessageLevel::Warning);
|
||||||
|
emitSucceeded();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QDir javaDir(APPLICATION->javaPath());
|
||||||
|
auto wantedJavaPath = javaDir.absoluteFilePath(wantedJavaName);
|
||||||
|
if (QFileInfo::exists(wantedJavaPath)) {
|
||||||
|
setJavaPathFromPartial();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto versionList = APPLICATION->metadataIndex()->get("net.minecraft.java");
|
||||||
|
m_current_task = versionList->getLoadTask();
|
||||||
|
connect(m_current_task.get(), &Task::succeeded, this, &AutoInstallJava::tryNextMajorJava);
|
||||||
|
connect(m_current_task.get(), &Task::failed, this, &AutoInstallJava::emitFailed);
|
||||||
|
connect(m_current_task.get(), &Task::progress, this, &AutoInstallJava::setProgress);
|
||||||
|
connect(m_current_task.get(), &Task::stepProgress, this, &AutoInstallJava::propagateStepProgress);
|
||||||
|
connect(m_current_task.get(), &Task::status, this, &AutoInstallJava::setStatus);
|
||||||
|
connect(m_current_task.get(), &Task::details, this, &AutoInstallJava::setDetails);
|
||||||
|
if (!m_current_task->isRunning()) {
|
||||||
|
m_current_task->start();
|
||||||
|
}
|
||||||
|
emit progressReportingRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutoInstallJava::setJavaPath(QString path)
|
||||||
|
{
|
||||||
|
auto settings = m_instance->settings();
|
||||||
|
settings->set("OverrideJavaLocation", true);
|
||||||
|
settings->set("JavaPath", path);
|
||||||
|
settings->set("AutomaticJava", true);
|
||||||
|
emit logLine(tr("Compatible Java found at: %1.").arg(path), MessageLevel::Info);
|
||||||
|
emitSucceeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutoInstallJava::setJavaPathFromPartial()
|
||||||
|
{
|
||||||
|
auto packProfile = m_instance->getPackProfile();
|
||||||
|
auto javaName = packProfile->getProfile()->getCompatibleJavaName();
|
||||||
|
QDir javaDir(APPLICATION->javaPath());
|
||||||
|
// just checking if the executable is there should suffice
|
||||||
|
// but if needed this can be achieved through refreshing the javalist
|
||||||
|
// and retrieving the path that contains the java name
|
||||||
|
auto relativeBinary = FS::PathCombine(javaName, "bin", JavaUtils::javaExecutable);
|
||||||
|
auto finalPath = javaDir.absoluteFilePath(relativeBinary);
|
||||||
|
if (QFileInfo::exists(finalPath)) {
|
||||||
|
setJavaPath(finalPath);
|
||||||
|
} else {
|
||||||
|
emit logLine(tr("No compatible Java version was found (the binary file does not exist). Using the default one."),
|
||||||
|
MessageLevel::Warning);
|
||||||
|
emitSucceeded();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutoInstallJava::downloadJava(Meta::Version::Ptr version, QString javaName)
|
||||||
|
{
|
||||||
|
auto runtimes = version->data()->runtimes;
|
||||||
|
for (auto java : runtimes) {
|
||||||
|
if (java->runtimeOS == m_supported_arch && java->name() == javaName) {
|
||||||
|
QDir javaDir(APPLICATION->javaPath());
|
||||||
|
auto final_path = javaDir.absoluteFilePath(java->m_name);
|
||||||
|
switch (java->downloadType) {
|
||||||
|
case Java::DownloadType::Manifest:
|
||||||
|
m_current_task = makeShared<Java::ManifestDownloadTask>(java->url, final_path, java->checksumType, java->checksumHash);
|
||||||
|
break;
|
||||||
|
case Java::DownloadType::Archive:
|
||||||
|
m_current_task = makeShared<Java::ArchiveDownloadTask>(java->url, final_path, java->checksumType, java->checksumHash);
|
||||||
|
break;
|
||||||
|
case Java::DownloadType::Unknown:
|
||||||
|
emitFailed(tr("Could not determine Java download type!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto deletePath = [final_path] { FS::deletePath(final_path); };
|
||||||
|
connect(m_current_task.get(), &Task::failed, this, [this, deletePath](QString reason) {
|
||||||
|
deletePath();
|
||||||
|
emitFailed(reason);
|
||||||
|
});
|
||||||
|
connect(this, &Task::aborted, this, [this, deletePath] {
|
||||||
|
m_current_task->abort();
|
||||||
|
deletePath();
|
||||||
|
});
|
||||||
|
connect(m_current_task.get(), &Task::succeeded, this, &AutoInstallJava::setJavaPathFromPartial);
|
||||||
|
connect(m_current_task.get(), &Task::failed, this, &AutoInstallJava::tryNextMajorJava);
|
||||||
|
connect(m_current_task.get(), &Task::progress, this, &AutoInstallJava::setProgress);
|
||||||
|
connect(m_current_task.get(), &Task::stepProgress, this, &AutoInstallJava::propagateStepProgress);
|
||||||
|
connect(m_current_task.get(), &Task::status, this, &AutoInstallJava::setStatus);
|
||||||
|
connect(m_current_task.get(), &Task::details, this, &AutoInstallJava::setDetails);
|
||||||
|
m_current_task->start();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tryNextMajorJava();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutoInstallJava::tryNextMajorJava()
|
||||||
|
{
|
||||||
|
if (!isRunning())
|
||||||
|
return;
|
||||||
|
auto versionList = APPLICATION->metadataIndex()->get("net.minecraft.java");
|
||||||
|
auto packProfile = m_instance->getPackProfile();
|
||||||
|
auto wantedJavaName = packProfile->getProfile()->getCompatibleJavaName();
|
||||||
|
auto majorJavaVersions = packProfile->getProfile()->getCompatibleJavaMajors();
|
||||||
|
if (m_majorJavaVersionIndex >= majorJavaVersions.length()) {
|
||||||
|
emit logLine(
|
||||||
|
tr("No versions of Java were found for your operating system: %1-%2").arg(SysInfo::currentSystem(), SysInfo::useQTForArch()),
|
||||||
|
MessageLevel::Warning);
|
||||||
|
emit logLine(tr("No compatible version of Java was found. Using the default one."), MessageLevel::Warning);
|
||||||
|
emitSucceeded();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto majorJavaVersion = majorJavaVersions[m_majorJavaVersionIndex];
|
||||||
|
m_majorJavaVersionIndex++;
|
||||||
|
|
||||||
|
auto javaMajor = versionList->getVersion(QString("java%1").arg(majorJavaVersion));
|
||||||
|
|
||||||
|
if (javaMajor->isLoaded()) {
|
||||||
|
downloadJava(javaMajor, wantedJavaName);
|
||||||
|
} else {
|
||||||
|
m_current_task = APPLICATION->metadataIndex()->loadVersion("net.minecraft.java", javaMajor->version(), Net::Mode::Online);
|
||||||
|
connect(m_current_task.get(), &Task::succeeded, this,
|
||||||
|
[this, javaMajor, wantedJavaName] { downloadJava(javaMajor, wantedJavaName); });
|
||||||
|
connect(m_current_task.get(), &Task::failed, this, &AutoInstallJava::tryNextMajorJava);
|
||||||
|
connect(m_current_task.get(), &Task::progress, this, &AutoInstallJava::setProgress);
|
||||||
|
connect(m_current_task.get(), &Task::stepProgress, this, &AutoInstallJava::propagateStepProgress);
|
||||||
|
connect(m_current_task.get(), &Task::status, this, &AutoInstallJava::setStatus);
|
||||||
|
connect(m_current_task.get(), &Task::details, this, &AutoInstallJava::setDetails);
|
||||||
|
if (!m_current_task->isRunning()) {
|
||||||
|
m_current_task->start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool AutoInstallJava::abort()
|
||||||
|
{
|
||||||
|
if (m_current_task && m_current_task->canAbort())
|
||||||
|
return m_current_task->abort();
|
||||||
|
return true;
|
||||||
|
}
|
68
launcher/minecraft/launch/AutoInstallJava.h
Normal file
68
launcher/minecraft/launch/AutoInstallJava.h
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This file incorporates work covered by the following copyright and
|
||||||
|
* permission notice:
|
||||||
|
*
|
||||||
|
* Copyright 2013-2021 MultiMC Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <launch/LaunchStep.h>
|
||||||
|
#include <launch/LaunchTask.h>
|
||||||
|
#include "java/JavaMetadata.h"
|
||||||
|
#include "meta/Version.h"
|
||||||
|
#include "minecraft/MinecraftInstance.h"
|
||||||
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
|
class AutoInstallJava : public LaunchStep {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit AutoInstallJava(LaunchTask* parent);
|
||||||
|
~AutoInstallJava() override = default;
|
||||||
|
|
||||||
|
void executeTask() override;
|
||||||
|
bool canAbort() const override { return m_current_task ? m_current_task->canAbort() : false; }
|
||||||
|
bool abort() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void setJavaPath(QString path);
|
||||||
|
void setJavaPathFromPartial();
|
||||||
|
void downloadJava(Meta::Version::Ptr version, QString javaName);
|
||||||
|
void tryNextMajorJava();
|
||||||
|
|
||||||
|
private:
|
||||||
|
MinecraftInstancePtr m_instance;
|
||||||
|
Task::Ptr m_current_task;
|
||||||
|
|
||||||
|
qsizetype m_majorJavaVersionIndex = 0;
|
||||||
|
const QString m_supported_arch;
|
||||||
|
};
|
@ -90,7 +90,7 @@ void LauncherPartLaunch::executeTask()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_launchScript = minecraftInstance->createLaunchScript(m_session, m_serverToJoin);
|
m_launchScript = minecraftInstance->createLaunchScript(m_session, m_targetToJoin);
|
||||||
QStringList args = minecraftInstance->javaArguments();
|
QStringList args = minecraftInstance->javaArguments();
|
||||||
QString allArgs = args.join(", ");
|
QString allArgs = args.join(", ");
|
||||||
emit logLine("Java Arguments:\n[" + m_parent->censorPrivateInfo(allArgs) + "]\n\n", MessageLevel::Launcher);
|
emit logLine("Java Arguments:\n[" + m_parent->censorPrivateInfo(allArgs) + "]\n\n", MessageLevel::Launcher);
|
||||||
|
@ -19,13 +19,13 @@
|
|||||||
#include <launch/LaunchStep.h>
|
#include <launch/LaunchStep.h>
|
||||||
#include <minecraft/auth/AuthSession.h>
|
#include <minecraft/auth/AuthSession.h>
|
||||||
|
|
||||||
#include "MinecraftServerTarget.h"
|
#include "MinecraftTarget.h"
|
||||||
|
|
||||||
class LauncherPartLaunch : public LaunchStep {
|
class LauncherPartLaunch : public LaunchStep {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit LauncherPartLaunch(LaunchTask* parent);
|
explicit LauncherPartLaunch(LaunchTask* parent);
|
||||||
virtual ~LauncherPartLaunch() {};
|
virtual ~LauncherPartLaunch() = default;
|
||||||
|
|
||||||
virtual void executeTask();
|
virtual void executeTask();
|
||||||
virtual bool abort();
|
virtual bool abort();
|
||||||
@ -34,7 +34,7 @@ class LauncherPartLaunch : public LaunchStep {
|
|||||||
void setWorkingDirectory(const QString& wd);
|
void setWorkingDirectory(const QString& wd);
|
||||||
void setAuthSession(AuthSessionPtr session) { m_session = session; }
|
void setAuthSession(AuthSessionPtr session) { m_session = session; }
|
||||||
|
|
||||||
void setServerToJoin(MinecraftServerTargetPtr serverToJoin) { m_serverToJoin = std::move(serverToJoin); }
|
void setTargetToJoin(MinecraftTarget::Ptr targetToJoin) { m_targetToJoin = std::move(targetToJoin); }
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_state(LoggedProcess::State state);
|
void on_state(LoggedProcess::State state);
|
||||||
@ -44,7 +44,7 @@ class LauncherPartLaunch : public LaunchStep {
|
|||||||
QString m_command;
|
QString m_command;
|
||||||
AuthSessionPtr m_session;
|
AuthSessionPtr m_session;
|
||||||
QString m_launchScript;
|
QString m_launchScript;
|
||||||
MinecraftServerTargetPtr m_serverToJoin;
|
MinecraftTarget::Ptr m_targetToJoin;
|
||||||
|
|
||||||
bool mayProceed = false;
|
bool mayProceed = false;
|
||||||
};
|
};
|
||||||
|
@ -13,13 +13,18 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "MinecraftServerTarget.h"
|
#include "MinecraftTarget.h"
|
||||||
|
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
// FIXME: the way this is written, it can't ever do any sort of validation and can accept total junk
|
// FIXME: the way this is written, it can't ever do any sort of validation and can accept total junk
|
||||||
MinecraftServerTarget MinecraftServerTarget::parse(const QString& fullAddress)
|
MinecraftTarget MinecraftTarget::parse(const QString& fullAddress, bool useWorld)
|
||||||
{
|
{
|
||||||
|
if (useWorld) {
|
||||||
|
MinecraftTarget target;
|
||||||
|
target.world = fullAddress;
|
||||||
|
return target;
|
||||||
|
}
|
||||||
QStringList split = fullAddress.split(":");
|
QStringList split = fullAddress.split(":");
|
||||||
|
|
||||||
// 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.
|
||||||
@ -56,5 +61,5 @@ MinecraftServerTarget MinecraftServerTarget::parse(const QString& fullAddress)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return MinecraftServerTarget{ realAddress, realPort };
|
return MinecraftTarget{ realAddress, realPort };
|
||||||
}
|
}
|
@ -19,11 +19,11 @@
|
|||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
struct MinecraftServerTarget {
|
struct MinecraftTarget {
|
||||||
QString address;
|
QString address;
|
||||||
quint16 port;
|
quint16 port;
|
||||||
|
|
||||||
static MinecraftServerTarget parse(const QString& fullAddress);
|
QString world;
|
||||||
|
static MinecraftTarget parse(const QString& fullAddress, bool useWorld);
|
||||||
|
using Ptr = std::shared_ptr<MinecraftTarget>;
|
||||||
};
|
};
|
||||||
|
|
||||||
using MinecraftServerTargetPtr = std::shared_ptr<MinecraftServerTarget>;
|
|
@ -129,6 +129,6 @@ void PrintInstanceInfo::executeTask()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
logLines(log, MessageLevel::Launcher);
|
logLines(log, MessageLevel::Launcher);
|
||||||
logLines(instance->verboseDescription(m_session, m_serverToJoin), MessageLevel::Launcher);
|
logLines(instance->verboseDescription(m_session, m_targetToJoin), MessageLevel::Launcher);
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
}
|
}
|
||||||
|
@ -16,22 +16,21 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <launch/LaunchStep.h>
|
#include <launch/LaunchStep.h>
|
||||||
#include <memory>
|
|
||||||
#include "minecraft/auth/AuthSession.h"
|
#include "minecraft/auth/AuthSession.h"
|
||||||
#include "minecraft/launch/MinecraftServerTarget.h"
|
#include "minecraft/launch/MinecraftTarget.h"
|
||||||
|
|
||||||
// FIXME: temporary wrapper for existing task.
|
// FIXME: temporary wrapper for existing task.
|
||||||
class PrintInstanceInfo : public LaunchStep {
|
class PrintInstanceInfo : public LaunchStep {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit PrintInstanceInfo(LaunchTask* parent, AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin)
|
explicit PrintInstanceInfo(LaunchTask* parent, AuthSessionPtr session, MinecraftTarget::Ptr targetToJoin)
|
||||||
: LaunchStep(parent), m_session(session), m_serverToJoin(serverToJoin) {};
|
: LaunchStep(parent), m_session(session), m_targetToJoin(targetToJoin) {};
|
||||||
virtual ~PrintInstanceInfo() {};
|
virtual ~PrintInstanceInfo() = default;
|
||||||
|
|
||||||
virtual void executeTask();
|
virtual void executeTask();
|
||||||
virtual bool canAbort() const { return false; }
|
virtual bool canAbort() const { return false; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AuthSessionPtr m_session;
|
AuthSessionPtr m_session;
|
||||||
MinecraftServerTargetPtr m_serverToJoin;
|
MinecraftTarget::Ptr m_targetToJoin;
|
||||||
};
|
};
|
||||||
|
@ -34,7 +34,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "VerifyJavaInstall.h"
|
#include "VerifyJavaInstall.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
#include "MessageLevel.h"
|
||||||
|
#include "java/JavaInstall.h"
|
||||||
|
#include "java/JavaInstallList.h"
|
||||||
#include "java/JavaVersion.h"
|
#include "java/JavaVersion.h"
|
||||||
#include "minecraft/MinecraftInstance.h"
|
#include "minecraft/MinecraftInstance.h"
|
||||||
#include "minecraft/PackProfile.h"
|
#include "minecraft/PackProfile.h"
|
||||||
@ -46,6 +51,15 @@ void VerifyJavaInstall::executeTask()
|
|||||||
auto settings = instance->settings();
|
auto settings = instance->settings();
|
||||||
auto storedVersion = settings->get("JavaVersion").toString();
|
auto storedVersion = settings->get("JavaVersion").toString();
|
||||||
auto ignoreCompatibility = settings->get("IgnoreJavaCompatibility").toBool();
|
auto ignoreCompatibility = settings->get("IgnoreJavaCompatibility").toBool();
|
||||||
|
auto javaArchitecture = settings->get("JavaArchitecture").toString();
|
||||||
|
auto maxMemAlloc = settings->get("MaxMemAlloc").toInt();
|
||||||
|
|
||||||
|
if (javaArchitecture == "32" && maxMemAlloc > 2048) {
|
||||||
|
emit logLine(tr("Max memory allocation exceeds the supported value.\n"
|
||||||
|
"The selected installation of Java is 32-bit and doesn't support more than 2048MiB of RAM.\n"
|
||||||
|
"The instance may not start due to this."),
|
||||||
|
MessageLevel::Error);
|
||||||
|
}
|
||||||
|
|
||||||
auto compatibleMajors = packProfile->getProfile()->getCompatibleJavaMajors();
|
auto compatibleMajors = packProfile->getProfile()->getCompatibleJavaMajors();
|
||||||
|
|
||||||
|
@ -32,8 +32,7 @@ void AssetUpdateTask::executeTask()
|
|||||||
auto hexSha1 = assets->sha1.toLatin1();
|
auto hexSha1 = assets->sha1.toLatin1();
|
||||||
qDebug() << "Asset index SHA1:" << hexSha1;
|
qDebug() << "Asset index SHA1:" << hexSha1;
|
||||||
auto dl = Net::ApiDownload::makeCached(indexUrl, entry);
|
auto dl = Net::ApiDownload::makeCached(indexUrl, entry);
|
||||||
auto rawSha1 = QByteArray::fromHex(assets->sha1.toLatin1());
|
dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, assets->sha1));
|
||||||
dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawSha1));
|
|
||||||
job->addNetAction(dl);
|
job->addNetAction(dl);
|
||||||
|
|
||||||
downloadJob.reset(job);
|
downloadJob.reset(job);
|
||||||
|
@ -343,9 +343,7 @@ QString PackInstallTask::getVersionForLoader(QString uid)
|
|||||||
return Q_NULLPTR;
|
return Q_NULLPTR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!vlist->isLoaded()) {
|
vlist->waitToLoad();
|
||||||
vlist->load(Net::Mode::Online);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_version.loader.recommended || m_version.loader.latest) {
|
if (m_version.loader.recommended || m_version.loader.latest) {
|
||||||
for (int i = 0; i < vlist->versions().size(); i++) {
|
for (int i = 0; i < vlist->versions().size(); i++) {
|
||||||
@ -638,8 +636,7 @@ void PackInstallTask::installConfigs()
|
|||||||
|
|
||||||
auto dl = Net::ApiDownload::makeCached(url, entry);
|
auto dl = Net::ApiDownload::makeCached(url, entry);
|
||||||
if (!m_version.configs.sha1.isEmpty()) {
|
if (!m_version.configs.sha1.isEmpty()) {
|
||||||
auto rawSha1 = QByteArray::fromHex(m_version.configs.sha1.toLatin1());
|
dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, m_version.configs.sha1));
|
||||||
dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawSha1));
|
|
||||||
}
|
}
|
||||||
jobPtr->addNetAction(dl);
|
jobPtr->addNetAction(dl);
|
||||||
archivePath = entry->getFullPath();
|
archivePath = entry->getFullPath();
|
||||||
@ -758,8 +755,7 @@ void PackInstallTask::downloadMods()
|
|||||||
|
|
||||||
auto dl = Net::ApiDownload::makeCached(url, entry);
|
auto dl = Net::ApiDownload::makeCached(url, entry);
|
||||||
if (!mod.md5.isEmpty()) {
|
if (!mod.md5.isEmpty()) {
|
||||||
auto rawMd5 = QByteArray::fromHex(mod.md5.toLatin1());
|
dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Md5, mod.md5));
|
||||||
dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Md5, rawMd5));
|
|
||||||
}
|
}
|
||||||
jobPtr->addNetAction(dl);
|
jobPtr->addNetAction(dl);
|
||||||
} else if (mod.type == ModType::Decomp) {
|
} else if (mod.type == ModType::Decomp) {
|
||||||
@ -769,8 +765,7 @@ void PackInstallTask::downloadMods()
|
|||||||
|
|
||||||
auto dl = Net::ApiDownload::makeCached(url, entry);
|
auto dl = Net::ApiDownload::makeCached(url, entry);
|
||||||
if (!mod.md5.isEmpty()) {
|
if (!mod.md5.isEmpty()) {
|
||||||
auto rawMd5 = QByteArray::fromHex(mod.md5.toLatin1());
|
dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Md5, mod.md5));
|
||||||
dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Md5, rawMd5));
|
|
||||||
}
|
}
|
||||||
jobPtr->addNetAction(dl);
|
jobPtr->addNetAction(dl);
|
||||||
} else {
|
} else {
|
||||||
@ -783,8 +778,7 @@ void PackInstallTask::downloadMods()
|
|||||||
|
|
||||||
auto dl = Net::ApiDownload::makeCached(url, entry);
|
auto dl = Net::ApiDownload::makeCached(url, entry);
|
||||||
if (!mod.md5.isEmpty()) {
|
if (!mod.md5.isEmpty()) {
|
||||||
auto rawMd5 = QByteArray::fromHex(mod.md5.toLatin1());
|
dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Md5, mod.md5));
|
||||||
dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Md5, rawMd5));
|
|
||||||
}
|
}
|
||||||
jobPtr->addNetAction(dl);
|
jobPtr->addNetAction(dl);
|
||||||
|
|
||||||
@ -1075,36 +1069,7 @@ void PackInstallTask::install()
|
|||||||
|
|
||||||
static Meta::Version::Ptr getComponentVersion(const QString& uid, const QString& version)
|
static Meta::Version::Ptr getComponentVersion(const QString& uid, const QString& version)
|
||||||
{
|
{
|
||||||
auto vlist = APPLICATION->metadataIndex()->get(uid);
|
return APPLICATION->metadataIndex()->getLoadedVersion(uid, version);
|
||||||
if (!vlist)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
if (!vlist->isLoaded()) {
|
|
||||||
QEventLoop loadVersionLoop;
|
|
||||||
auto task = vlist->getLoadTask();
|
|
||||||
QObject::connect(task.get(), &Task::finished, &loadVersionLoop, &QEventLoop::quit);
|
|
||||||
if (!task->isRunning())
|
|
||||||
task->start();
|
|
||||||
|
|
||||||
loadVersionLoop.exec();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ver = vlist->getVersion(version);
|
|
||||||
if (!ver)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
if (!ver->isLoaded()) {
|
|
||||||
QEventLoop loadVersionLoop;
|
|
||||||
ver->load(Net::Mode::Online);
|
|
||||||
auto task = ver->getCurrentTask();
|
|
||||||
QObject::connect(task.get(), &Task::finished, &loadVersionLoop, &QEventLoop::quit);
|
|
||||||
if (!task->isRunning())
|
|
||||||
task->start();
|
|
||||||
|
|
||||||
loadVersionLoop.exec();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ver;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ATLauncher
|
} // namespace ATLauncher
|
||||||
|
@ -246,7 +246,7 @@ void FlamePackExportTask::makeApiRequest()
|
|||||||
pendingHashes.clear();
|
pendingHashes.clear();
|
||||||
getProjectsInfo();
|
getProjectsInfo();
|
||||||
});
|
});
|
||||||
connect(task.get(), &NetJob::failed, this, &FlamePackExportTask::getProjectsInfo);
|
connect(task.get(), &Task::failed, this, &FlamePackExportTask::getProjectsInfo);
|
||||||
task->start();
|
task->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include "ModrinthPackExportTask.h"
|
#include "ModrinthPackExportTask.h"
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
#include <QCryptographicHash>
|
#include <QCryptographicHash>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
@ -28,6 +29,7 @@
|
|||||||
#include "minecraft/mod/MetadataHandler.h"
|
#include "minecraft/mod/MetadataHandler.h"
|
||||||
#include "minecraft/mod/ModFolderModel.h"
|
#include "minecraft/mod/ModFolderModel.h"
|
||||||
#include "modplatform/helpers/HashUtils.h"
|
#include "modplatform/helpers/HashUtils.h"
|
||||||
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
const QStringList ModrinthPackExportTask::PREFIXES({ "mods/", "coremods/", "resourcepacks/", "texturepacks/", "shaderpacks/" });
|
const QStringList ModrinthPackExportTask::PREFIXES({ "mods/", "coremods/", "resourcepacks/", "texturepacks/", "shaderpacks/" });
|
||||||
const QStringList ModrinthPackExportTask::FILE_EXTENSIONS({ "jar", "litemod", "zip" });
|
const QStringList ModrinthPackExportTask::FILE_EXTENSIONS({ "jar", "litemod", "zip" });
|
||||||
@ -154,8 +156,8 @@ void ModrinthPackExportTask::makeApiRequest()
|
|||||||
setStatus(tr("Finding versions for hashes..."));
|
setStatus(tr("Finding versions for hashes..."));
|
||||||
auto response = std::make_shared<QByteArray>();
|
auto response = std::make_shared<QByteArray>();
|
||||||
task = api.currentVersions(pendingHashes.values(), "sha512", response);
|
task = api.currentVersions(pendingHashes.values(), "sha512", response);
|
||||||
connect(task.get(), &NetJob::succeeded, [this, response]() { parseApiResponse(response); });
|
connect(task.get(), &Task::succeeded, [this, response]() { parseApiResponse(response); });
|
||||||
connect(task.get(), &NetJob::failed, this, &ModrinthPackExportTask::emitFailed);
|
connect(task.get(), &Task::failed, this, &ModrinthPackExportTask::emitFailed);
|
||||||
task->start();
|
task->start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,8 +114,7 @@ void Technic::SolderPackInstallTask::fileListSucceeded()
|
|||||||
|
|
||||||
auto dl = Net::ApiDownload::makeFile(mod.url, path);
|
auto dl = Net::ApiDownload::makeFile(mod.url, path);
|
||||||
if (!mod.md5.isEmpty()) {
|
if (!mod.md5.isEmpty()) {
|
||||||
auto rawMd5 = QByteArray::fromHex(mod.md5.toLatin1());
|
dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Md5, mod.md5));
|
||||||
dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Md5, rawMd5));
|
|
||||||
}
|
}
|
||||||
m_filesNetJob->addNetAction(dl);
|
m_filesNetJob->addNetAction(dl);
|
||||||
|
|
||||||
|
@ -43,6 +43,9 @@
|
|||||||
namespace Net {
|
namespace Net {
|
||||||
class ChecksumValidator : public Validator {
|
class ChecksumValidator : public Validator {
|
||||||
public:
|
public:
|
||||||
|
ChecksumValidator(QCryptographicHash::Algorithm algorithm, QString expectedHex)
|
||||||
|
: Net::ChecksumValidator(algorithm, QByteArray::fromHex(expectedHex.toLatin1()))
|
||||||
|
{}
|
||||||
ChecksumValidator(QCryptographicHash::Algorithm algorithm, QByteArray expected = QByteArray())
|
ChecksumValidator(QCryptographicHash::Algorithm algorithm, QByteArray expected = QByteArray())
|
||||||
: m_checksum(algorithm), m_expected(expected) {};
|
: m_checksum(algorithm), m_expected(expected) {};
|
||||||
virtual ~ChecksumValidator() = default;
|
virtual ~ChecksumValidator() = default;
|
||||||
|
@ -353,5 +353,11 @@
|
|||||||
<file>scalable/instances/neoforged.svg</file>
|
<file>scalable/instances/neoforged.svg</file>
|
||||||
<file>128x128/instances/forge.png</file> <!-- LGPL3 Forge Development LLC -->
|
<file>128x128/instances/forge.png</file> <!-- LGPL3 Forge Development LLC -->
|
||||||
<file>128x128/instances/liteloader.png</file> <!-- CC-BY-SA 4.0 LiteLoader -->
|
<file>128x128/instances/liteloader.png</file> <!-- CC-BY-SA 4.0 LiteLoader -->
|
||||||
|
|
||||||
|
<!-- java providers -->
|
||||||
|
<file>scalable/adoptium.svg</file> <!-- The Adoptium Logo is a registered trademark of the Eclipse Foundation. -->
|
||||||
|
<file>scalable/azul.svg</file> <!-- Azul, Zulu, Azul Systems, the Azul Systems logo, Azul Zulu are either registered trademarks or trademarks of Azul Systems, registered in the U.S. and elsewhere. -->
|
||||||
|
<file>scalable/mojang.svg</file> <!-- The Mojang Logo is a registered trademark of Mojang AB. -->
|
||||||
|
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
180
launcher/resources/multimc/scalable/adoptium.svg
Normal file
180
launcher/resources/multimc/scalable/adoptium.svg
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
sodipodi:docname="Eclipse_Adoptium_Logo_A_only_no_outline.svg"
|
||||||
|
inkscape:version="1.3 (0e150ed6c4, 2023-07-21)"
|
||||||
|
id="svg8"
|
||||||
|
version="1.1"
|
||||||
|
viewBox="0 0 800 800"
|
||||||
|
height="800"
|
||||||
|
width="800"
|
||||||
|
inkscape:export-filename="Eclipse_Adoptium_Logo.png"
|
||||||
|
inkscape:export-xdpi="61.439999"
|
||||||
|
inkscape:export-ydpi="61.439999"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||||
|
<defs
|
||||||
|
id="defs2">
|
||||||
|
<clipPath
|
||||||
|
clipPathUnits="userSpaceOnUse"
|
||||||
|
id="clipPath242">
|
||||||
|
<path
|
||||||
|
d="m 987.855,678.469 -0.019,-0.008 -107.453,233.098 -81.121,-175.989 235.718,-106.09 0.01,0.02 c -21.01,10.078 -37.838,27.52 -47.135,48.969 z"
|
||||||
|
id="path240" />
|
||||||
|
</clipPath>
|
||||||
|
<linearGradient
|
||||||
|
x1="0"
|
||||||
|
y1="0"
|
||||||
|
x2="1"
|
||||||
|
y2="0"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(-481.882,253.823,253.823,481.882,1152.35,658.95)"
|
||||||
|
spreadMethod="pad"
|
||||||
|
id="linearGradient248">
|
||||||
|
<stop
|
||||||
|
style="stop-opacity:1;stop-color:#421644"
|
||||||
|
offset="0"
|
||||||
|
id="stop244" />
|
||||||
|
<stop
|
||||||
|
style="stop-opacity:1;stop-color:#151530"
|
||||||
|
offset="1"
|
||||||
|
id="stop246" />
|
||||||
|
</linearGradient>
|
||||||
|
<clipPath
|
||||||
|
clipPathUnits="userSpaceOnUse"
|
||||||
|
id="clipPath258">
|
||||||
|
<path
|
||||||
|
d="m 1164.62,758.102 0.08,0.039 -194.618,422.029 c -0.547,1.32 -1.184,2.59 -1.789,3.88 l -1.453,3.16 -0.059,-0.03 c -0.324,0.65 -0.703,1.27 -1.054,1.9 7.382,-13.68 11.589,-29.34 11.589,-45.98 0,-14.34 -3.191,-27.91 -8.777,-40.15 l 0.059,-0.03 -88.215,-191.361 107.453,-233.098 0.019,0.008 c 14.915,-34.387 49.125,-58.457 89.005,-58.457 53.57,0 96.99,43.429 96.99,97 0,14.707 -3.37,28.597 -9.23,41.09 z"
|
||||||
|
id="path256" />
|
||||||
|
</clipPath>
|
||||||
|
<linearGradient
|
||||||
|
x1="0"
|
||||||
|
y1="0"
|
||||||
|
x2="1"
|
||||||
|
y2="0"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(265.274,-595.434,-595.434,-265.274,846.292,1230.46)"
|
||||||
|
spreadMethod="pad"
|
||||||
|
id="linearGradient264">
|
||||||
|
<stop
|
||||||
|
style="stop-opacity:1;stop-color:#a21058"
|
||||||
|
offset="0"
|
||||||
|
id="stop260" />
|
||||||
|
<stop
|
||||||
|
style="stop-opacity:1;stop-color:#421644"
|
||||||
|
offset="1"
|
||||||
|
id="stop262" />
|
||||||
|
</linearGradient>
|
||||||
|
<clipPath
|
||||||
|
clipPathUnits="userSpaceOnUse"
|
||||||
|
id="clipPath274">
|
||||||
|
<path
|
||||||
|
d="m 880.316,1240.11 c -37.687,0 -70.273,-21.54 -86.328,-52.93 l -0.058,0.03 -1.457,-3.16 c -0.606,-1.29 -1.239,-2.56 -1.785,-3.88 l -194.622,-422.029 0.079,-0.039 c -5.86,-12.493 -9.227,-26.383 -9.227,-41.09 0,-53.571 43.418,-97 96.992,-97 39.871,0 74.09,24.07 89.004,58.457 l 0.02,-0.008 195.664,424.459 -0.059,0.03 c 5.586,12.24 8.777,25.81 8.777,40.15 0,53.58 -43.425,97.01 -97,97.01 z"
|
||||||
|
id="path272" />
|
||||||
|
</clipPath>
|
||||||
|
<linearGradient
|
||||||
|
x1="0"
|
||||||
|
y1="0"
|
||||||
|
x2="1"
|
||||||
|
y2="0"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(259.548,595.434,595.434,-259.548,649.304,625.36)"
|
||||||
|
spreadMethod="pad"
|
||||||
|
id="linearGradient280">
|
||||||
|
<stop
|
||||||
|
style="stop-opacity:1;stop-color:#ee1a6d"
|
||||||
|
offset="0"
|
||||||
|
id="stop276" />
|
||||||
|
<stop
|
||||||
|
style="stop-opacity:1;stop-color:#a21058"
|
||||||
|
offset="1"
|
||||||
|
id="stop278" />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
height="100mm"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-x="1912"
|
||||||
|
inkscape:window-height="1057"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:document-rotation="0"
|
||||||
|
inkscape:current-layer="g216"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:cy="396.88538"
|
||||||
|
inkscape:cx="322.07976"
|
||||||
|
inkscape:zoom="0.72187089"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
borderopacity="1.0"
|
||||||
|
bordercolor="#666666"
|
||||||
|
pagecolor="#494949"
|
||||||
|
id="base"
|
||||||
|
inkscape:showpageshadow="0"
|
||||||
|
inkscape:pagecheckerboard="1"
|
||||||
|
inkscape:deskcolor="#505050" />
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
id="layer1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
inkscape:label="Layer 1">
|
||||||
|
<g
|
||||||
|
inkscape:export-ydpi="96"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
transform="matrix(0.0826697,0,0,-0.0826697,-36.864228,126.62103)"
|
||||||
|
id="g216">
|
||||||
|
<g
|
||||||
|
id="g236"
|
||||||
|
transform="matrix(13.679999,0,0,13.679976,-6760.5652,-16025.746)">
|
||||||
|
<g
|
||||||
|
clip-path="url(#clipPath242)"
|
||||||
|
id="g238">
|
||||||
|
<path
|
||||||
|
id="path250"
|
||||||
|
style="fill:url(#linearGradient248);fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||||
|
d="m 987.855,678.469 -0.019,-0.008 -107.453,233.098 -81.121,-175.989 235.718,-106.09 0.01,0.02 c -21.01,10.078 -37.838,27.52 -47.135,48.969" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g252"
|
||||||
|
transform="matrix(13.679999,0,0,13.679976,-6760.5652,-16025.746)">
|
||||||
|
<g
|
||||||
|
clip-path="url(#clipPath258)"
|
||||||
|
id="g254">
|
||||||
|
<path
|
||||||
|
id="path266"
|
||||||
|
style="fill:url(#linearGradient264);fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||||
|
d="m 1164.62,758.102 0.08,0.039 -194.618,422.029 c -0.547,1.32 -1.184,2.59 -1.789,3.88 l -1.453,3.16 -0.059,-0.03 c -0.324,0.65 -0.703,1.27 -1.054,1.9 7.382,-13.68 11.589,-29.34 11.589,-45.98 0,-14.34 -3.191,-27.91 -8.777,-40.15 l 0.059,-0.03 -88.215,-191.361 107.453,-233.098 0.019,0.008 c 14.915,-34.387 49.125,-58.457 89.005,-58.457 53.57,0 96.99,43.429 96.99,97 0,14.707 -3.37,28.597 -9.23,41.09" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
id="g268"
|
||||||
|
transform="matrix(1.2000009,0,0,1.1999989,-853.84911,665.71675)">
|
||||||
|
<g
|
||||||
|
clip-path="url(#clipPath274)"
|
||||||
|
id="g270"
|
||||||
|
transform="matrix(11.39999,0,0,11.39999,-4922.2595,-13909.564)">
|
||||||
|
<path
|
||||||
|
id="path282"
|
||||||
|
style="fill:url(#linearGradient280);fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||||
|
d="m 880.316,1240.11 c -37.687,0 -70.273,-21.54 -86.328,-52.93 l -0.058,0.03 -1.457,-3.16 c -0.606,-1.29 -1.239,-2.56 -1.785,-3.88 l -194.622,-422.029 0.079,-0.039 c -5.86,-12.493 -9.227,-26.383 -9.227,-41.09 0,-53.571 43.418,-97 96.992,-97 39.871,0 74.09,24.07 89.004,58.457 l 0.02,-0.008 195.664,424.459 -0.059,0.03 c 5.586,12.24 8.777,25.81 8.777,40.15 0,53.58 -43.425,97.01 -97,97.01" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 6.7 KiB |
17
launcher/resources/multimc/scalable/azul.svg
Normal file
17
launcher/resources/multimc/scalable/azul.svg
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64" fill="none" style="scroll-behavior: auto !important;">
|
||||||
|
<path d="M26.792 4.49429L7.62244 44.4309C7.20797 45.2944 8.12743 46.1903 8.97988 45.7536L28.26 35.8772C28.6557 35.6745 29.1376 35.7574 29.4429 36.0805L53.2128 61.2399C53.994 62.0668 55.3295 61.1553 54.844 60.1264L28.5979 4.50031C28.2386 3.73874 27.1564 3.73514 26.792 4.49429Z" fill="#00374A"/>
|
||||||
|
<path d="M26.792 4.49429L7.62244 44.4309C7.20797 45.2944 8.12743 46.1903 8.97988 45.7536L28.26 35.8772C28.6557 35.6745 29.1376 35.7574 29.4429 36.0805L53.2128 61.2399C53.994 62.0668 55.3295 61.1553 54.844 60.1264L28.5979 4.50031C28.2386 3.73874 27.1564 3.73514 26.792 4.49429Z" fill="url(#paint0_linear_3578_2134)" fill-opacity="0.7" style="mix-blend-mode:overlay"/>
|
||||||
|
<path d="M34.0172 15.5765L60.9237 19.1042C61.9046 19.2329 62.1231 20.5555 61.2357 20.9928L33.4872 34.6659L9.3254 45.9918C8.34481 46.4514 7.43514 45.2419 8.14881 44.4273L33.135 15.909C33.3551 15.6578 33.686 15.5331 34.0172 15.5765Z" fill="#006588"/>
|
||||||
|
<path d="M34.0172 15.5765L60.9237 19.1042C61.9046 19.2329 62.1231 20.5555 61.2357 20.9928L33.4872 34.6659L9.3254 45.9918C8.34481 46.4514 7.43514 45.2419 8.14881 44.4273L33.135 15.909C33.3551 15.6578 33.686 15.5331 34.0172 15.5765Z" fill="url(#paint1_linear_3578_2134)" fill-opacity="0.7" style="mix-blend-mode:overlay"/>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="paint0_linear_3578_2134" x1="31.2618" y1="2.59998" x2="31.2618" y2="65.8" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="white" stop-opacity="0"/>
|
||||||
|
<stop offset="1" stop-color="white"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint1_linear_3578_2134" x1="46.2268" y1="4.17812" x2="31.5574" y2="56.1518" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="white" stop-opacity="0"/>
|
||||||
|
<stop offset="1" stop-color="white"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.9 KiB |
55
launcher/resources/multimc/scalable/mojang.svg
Normal file
55
launcher/resources/multimc/scalable/mojang.svg
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
version="1.1"
|
||||||
|
width="800"
|
||||||
|
height="800"
|
||||||
|
viewBox="0 0 800 800"
|
||||||
|
xml:space="preserve"
|
||||||
|
style="scroll-behavior: auto !important;"
|
||||||
|
id="svg4"
|
||||||
|
sodipodi:docname="Mojang_Studios_Logo_(2020,_icon).svg"
|
||||||
|
inkscape:export-filename="Mojang_Studios_Logo_(2020,_icon).png"
|
||||||
|
inkscape:export-xdpi="61.439999"
|
||||||
|
inkscape:export-ydpi="61.439999"
|
||||||
|
inkscape:version="1.3 (0e150ed6c4, 2023-07-21)"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
|
||||||
|
id="namedview4"
|
||||||
|
pagecolor="#505050"
|
||||||
|
bordercolor="#ffffff"
|
||||||
|
borderopacity="1"
|
||||||
|
inkscape:showpageshadow="0"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pagecheckerboard="1"
|
||||||
|
inkscape:deskcolor="#505050"
|
||||||
|
inkscape:zoom="1.46625"
|
||||||
|
inkscape:cx="374.08355"
|
||||||
|
inkscape:cy="369.30946"
|
||||||
|
inkscape:window-width="2560"
|
||||||
|
inkscape:window-height="1369"
|
||||||
|
inkscape:window-x="6392"
|
||||||
|
inkscape:window-y="802"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="g3" /> <desc
|
||||||
|
id="desc1">Created with Fabric.js 3.6.3</desc> <defs
|
||||||
|
id="defs1"> </defs> <g
|
||||||
|
transform="matrix(2 0 0 2 399.75 399.75)"
|
||||||
|
id="g4"> <g
|
||||||
|
style=""
|
||||||
|
id="g3"> <g
|
||||||
|
transform="matrix(3.37 0 0 3.37 0 0)"
|
||||||
|
id="g1"> <polygon
|
||||||
|
style="display:inline;opacity:1;fill:#f0313b;fill-rule:nonzero;stroke:#f0313b;stroke-width:8;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0"
|
||||||
|
vector-effect="non-scaling-stroke"
|
||||||
|
points="50,50 50,-50 -50,-50 -50,50 "
|
||||||
|
id="polygon1" /> </g> <g
|
||||||
|
transform="matrix(3.78 0 0 3.78 0.01 0)"
|
||||||
|
id="g2"> <path
|
||||||
|
style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,255,255); fill-rule: nonzero; opacity: 1;"
|
||||||
|
vector-effect="non-scaling-stroke"
|
||||||
|
transform=" translate(-44.68, -41.16)"
|
||||||
|
d="M 13.51988 41.11152 q 0 -12.31086 0.0047 -24.62173 c 0.00469 -2.87722 0.16418 -3.03875 3.01027 -3.04146 q 21.527 -0.02051 43.054 -0.01353 c 2.06114 0.0004 2.36366 0.32134 2.39718 2.42144 c 0.0238 1.49194 -0.01523 2.98567 0.03993 4.47616 a 6.77817 6.77817 0 0 0 6.69647 6.91868 c 1.65784 0.11443 3.328 0.04044 4.99213 0.07612 c 1.797 0.03852 2.04939 0.30467 2.12207 2.13943 c 0.01137 0.28664 0.01239 0.57383 0.01247 0.86076 q 0.00432 17.64834 0.00423 35.29668 c -0.00158 3.2118 -0.0499 3.24957 -3.28974 3.26017 q -3.78871 0.01236 -7.57745 -0.01166 c -2.96088 -0.02069 -3.03087 -0.09046 -3.032 -2.98084 q -0.00659 -16.87367 -0.00343 -33.74735 c 0 -0.40175 0.01018 -0.80387 -0.00321 -1.20519 a 3.329 3.329 0 0 0 -3.548 -3.56756 c -1.08962 -0.032 -2.18238 -0.03167 -3.27158 0.01034 a 3.34773 3.34773 0 0 0 -3.482 3.47659 c -0.03516 0.62965 -0.02128 1.26231 -0.02172 1.8936 q -0.00641 9.21165 -0.01056 18.42326 c -0.00046 0.68869 0.01794 1.37909 -0.02307 2.06567 c -0.075 1.25525 -0.44257 1.71282 -1.65149 1.72825 q -5.25132 0.06705 -10.50391 -0.00754 c -1.2165 -0.01879 -1.58169 -0.48679 -1.66785 -1.72683 c -0.03575 -0.51435 -0.01843 -1.03265 -0.019 -1.54914 q -0.0112 -9.81428 -0.0222 -19.62854 a 13.12088 13.12088 0 0 0 -0.05025 -1.71908 a 3.25128 3.25128 0 0 0 -3.10179 -2.93609 a 33.39881 33.39881 0 0 0 -3.95853 0.00271 a 3.1568 3.1568 0 0 0 -3.15611 3.21043 c -0.05842 1.26029 -0.03349 2.52474 -0.03457 3.78735 q -0.01343 15.66842 -0.02277 31.33681 c -0.00035 0.45913 0.01748 0.92 -0.01557 1.377 c -0.09 1.24451 -0.45629 1.713 -1.67232 1.72878 q -5.25117 0.06813 -10.50381 -0.01831 c -1.23915 -0.02079 -1.58295 -0.457 -1.6812 -1.71692 c -0.04454 -0.5709 -0.02489 -1.1472 -0.025 -1.72107 q -0.00183 -12.13872 -0.00083 -24.27744 Z"
|
||||||
|
stroke-linecap="round"
|
||||||
|
id="path1" /> </g> </g> </g> </svg>
|
After Width: | Height: | Size: 3.8 KiB |
@ -592,8 +592,7 @@ void TranslationsModel::downloadTranslation(QString key)
|
|||||||
entry->setStale(true);
|
entry->setStale(true);
|
||||||
|
|
||||||
auto dl = Net::Download::makeCached(QUrl(BuildConfig.TRANSLATIONS_BASE_URL + lang->file_name), entry);
|
auto dl = Net::Download::makeCached(QUrl(BuildConfig.TRANSLATIONS_BASE_URL + lang->file_name), entry);
|
||||||
auto rawHash = QByteArray::fromHex(lang->file_sha1.toLatin1());
|
dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, lang->file_sha1));
|
||||||
dl->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawHash));
|
|
||||||
dl->setProgress(dl->getProgress(), lang->file_size);
|
dl->setProgress(dl->getProgress(), lang->file_size);
|
||||||
|
|
||||||
d->m_dl_job.reset(new NetJob("Translation for " + key, APPLICATION->network()));
|
d->m_dl_job.reset(new NetJob("Translation for " + key, APPLICATION->network()));
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user