Merge remote-tracking branch 'prismlauncher/release-9.x' into develop
This commit is contained in:
parent
2c014a075d
commit
491cb1e5a2
19
.github/workflows/build.yml
vendored
19
.github/workflows/build.yml
vendored
@ -59,14 +59,14 @@ jobs:
|
|||||||
qt_ver: 5
|
qt_ver: 5
|
||||||
qt_host: linux
|
qt_host: linux
|
||||||
qt_arch: ""
|
qt_arch: ""
|
||||||
qt_version: "5.12.8"
|
qt_version: "5.15.2"
|
||||||
qt_modules: "qtnetworkauth"
|
qt_modules: "qtnetworkauth"
|
||||||
|
|
||||||
- os: ubuntu-20.04
|
- os: ubuntu-20.04
|
||||||
qt_ver: 6
|
qt_ver: 6
|
||||||
qt_host: linux
|
qt_host: linux
|
||||||
qt_arch: ""
|
qt_arch: ""
|
||||||
qt_version: "6.2.4"
|
qt_version: "6.5.3"
|
||||||
qt_modules: "qt5compat qtimageformats qtnetworkauth"
|
qt_modules: "qt5compat qtimageformats qtnetworkauth"
|
||||||
|
|
||||||
- os: windows-2022
|
- os: windows-2022
|
||||||
@ -173,7 +173,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Retrieve ccache cache (Windows MinGW-w64)
|
- name: Retrieve ccache cache (Windows MinGW-w64)
|
||||||
if: runner.os == 'Windows' && matrix.msystem != '' && inputs.build_type == 'Debug'
|
if: runner.os == 'Windows' && matrix.msystem != '' && inputs.build_type == 'Debug'
|
||||||
uses: actions/cache@v4.1.1
|
uses: actions/cache@v4.2.0
|
||||||
with:
|
with:
|
||||||
path: '${{ github.workspace }}\.ccache'
|
path: '${{ github.workspace }}\.ccache'
|
||||||
key: ${{ matrix.os }}-mingw-w64-ccache-${{ github.run_id }}
|
key: ${{ matrix.os }}-mingw-w64-ccache-${{ github.run_id }}
|
||||||
@ -206,7 +206,7 @@ jobs:
|
|||||||
if: runner.os == 'Linux'
|
if: runner.os == 'Linux'
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get -y update
|
sudo apt-get -y update
|
||||||
sudo apt-get -y install ninja-build extra-cmake-modules scdoc appstream
|
sudo apt-get -y install ninja-build extra-cmake-modules scdoc appstream libxcb-cursor-dev
|
||||||
|
|
||||||
- name: Install Dependencies (macOS)
|
- name: Install Dependencies (macOS)
|
||||||
if: runner.os == 'macOS'
|
if: runner.os == 'macOS'
|
||||||
@ -633,19 +633,24 @@ jobs:
|
|||||||
flatpak:
|
flatpak:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
image: bilelmoussaoui/flatpak-github-actions:kde-6.7
|
image: ghcr.io/flathub-infra/flatpak-github-actions:kde-6.8
|
||||||
options: --privileged
|
options: --privileged
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
if: inputs.build_type == 'Debug'
|
if: inputs.build_type == 'Debug'
|
||||||
with:
|
with:
|
||||||
submodules: "true"
|
submodules: true
|
||||||
|
|
||||||
|
- name: Set short version
|
||||||
|
shell: bash
|
||||||
|
run: echo "VERSION=${GITHUB_SHA::7}" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Build Flatpak (Linux)
|
- name: Build Flatpak (Linux)
|
||||||
if: inputs.build_type == 'Debug'
|
if: inputs.build_type == 'Debug'
|
||||||
uses: flatpak/flatpak-github-actions/flatpak-builder@v6
|
uses: flatpak/flatpak-github-actions/flatpak-builder@v6
|
||||||
with:
|
with:
|
||||||
bundle: "Shattered Prism.flatpak"
|
bundle: ShatteredPrism-${{ runner.os }}-${{ env.VERSION }}-Flatpak.flatpak
|
||||||
manifest-path: flatpak/org.lunaislazier.ShatteredPrism.yml
|
manifest-path: flatpak/org.lunaislazier.ShatteredPrism.yml
|
||||||
|
|
||||||
nix:
|
nix:
|
||||||
|
@ -181,7 +181,7 @@ set(Launcher_FMLLIBS_BASE_URL "https://files.prismlauncher.org/fmllibs/" CACHE S
|
|||||||
|
|
||||||
######## Set version numbers ########
|
######## Set version numbers ########
|
||||||
set(Launcher_VERSION_MAJOR 1)
|
set(Launcher_VERSION_MAJOR 1)
|
||||||
set(Launcher_VERSION_MINOR 4)
|
set(Launcher_VERSION_MINOR 5)
|
||||||
|
|
||||||
set(Launcher_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}")
|
set(Launcher_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}")
|
||||||
set(Launcher_VERSION_NAME4 "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.0.0")
|
set(Launcher_VERSION_NAME4 "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.0.0")
|
||||||
@ -389,8 +389,8 @@ if(UNIX AND APPLE)
|
|||||||
set(MACOSX_SPARKLE_UPDATE_PUBLIC_KEY "" CACHE STRING "Public key for Sparkle update feed")
|
set(MACOSX_SPARKLE_UPDATE_PUBLIC_KEY "" CACHE STRING "Public key for Sparkle update feed")
|
||||||
set(MACOSX_SPARKLE_UPDATE_FEED_URL "" CACHE STRING "URL for Sparkle update feed")
|
set(MACOSX_SPARKLE_UPDATE_FEED_URL "" CACHE STRING "URL for Sparkle update feed")
|
||||||
|
|
||||||
set(MACOSX_SPARKLE_DOWNLOAD_URL "https://github.com/sparkle-project/Sparkle/releases/download/2.5.2/Sparkle-2.5.2.tar.xz" CACHE STRING "URL to Sparkle release archive")
|
set(MACOSX_SPARKLE_DOWNLOAD_URL "https://github.com/sparkle-project/Sparkle/releases/download/2.6.4/Sparkle-2.6.4.tar.xz" CACHE STRING "URL to Sparkle release archive")
|
||||||
set(MACOSX_SPARKLE_SHA256 "572dd67ae398a466f19f343a449e1890bac1ef74885b4739f68f979a8a89884b" CACHE STRING "SHA256 checksum for Sparkle release archive")
|
set(MACOSX_SPARKLE_SHA256 "50612a06038abc931f16011d7903b8326a362c1074dabccb718404ce8e585f0b" CACHE STRING "SHA256 checksum for Sparkle release archive")
|
||||||
set(MACOSX_SPARKLE_DIR "${CMAKE_BINARY_DIR}/frameworks/Sparkle")
|
set(MACOSX_SPARKLE_DIR "${CMAKE_BINARY_DIR}/frameworks/Sparkle")
|
||||||
|
|
||||||
# directories to look for dependencies
|
# directories to look for dependencies
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
<string>A Minecraft mod wants to access your microphone.</string>
|
<string>A Minecraft mod wants to access your microphone.</string>
|
||||||
<key>NSDownloadsFolderUsageDescription</key>
|
<key>NSDownloadsFolderUsageDescription</key>
|
||||||
<string>Shattered Prism uses access to your Downloads folder to help you more quickly add mods that can't be automatically downloaded to your instance. You can change where Shattered Prism scans for downloaded mods in Settings or the prompt that appears.</string>
|
<string>Shattered Prism uses access to your Downloads folder to help you more quickly add mods that can't be automatically downloaded to your instance. You can change where Shattered Prism scans for downloaded mods in Settings or the prompt that appears.</string>
|
||||||
|
<key>NSLocalNetworkUsageDescription</key>
|
||||||
|
<string>Minecraft uses the local network to find and connect to LAN servers.</string>
|
||||||
<key>NSPrincipalClass</key>
|
<key>NSPrincipalClass</key>
|
||||||
<string>NSApplication</string>
|
<string>NSApplication</string>
|
||||||
<key>NSHighResolutionCapable</key>
|
<key>NSHighResolutionCapable</key>
|
||||||
|
20
flatpak/flite.json
Normal file
20
flatpak/flite.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"name": "flite",
|
||||||
|
"config-opts": [
|
||||||
|
"--enable-shared",
|
||||||
|
"--with-audio=pulseaudio"
|
||||||
|
],
|
||||||
|
"no-parallel-make": true,
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/festvox/flite.git",
|
||||||
|
"tag": "v2.2",
|
||||||
|
"commit": "e9e2e37c329dbe98bfeb27a1828ef9a71fa84f88",
|
||||||
|
"x-checker-data": {
|
||||||
|
"type": "git",
|
||||||
|
"tag-pattern": "^v([\\d.]+)$"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -1,22 +1,18 @@
|
|||||||
{
|
{
|
||||||
"name": "libdecor",
|
"name": "libdecor",
|
||||||
"buildsystem": "meson",
|
"buildsystem": "meson",
|
||||||
"config-opts": [
|
"config-opts": [
|
||||||
"-Ddemo=false"
|
"-Ddemo=false"
|
||||||
],
|
],
|
||||||
"sources": [
|
"sources": [
|
||||||
{
|
{
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://gitlab.freedesktop.org/libdecor/libdecor.git",
|
"url": "https://gitlab.freedesktop.org/libdecor/libdecor.git",
|
||||||
"commit": "73260393a97291c887e1074ab7f318e031be0ac6"
|
"commit": "c2bd8ad6fa42c0cb17553ce77ad8a87d1f543b1f"
|
||||||
},
|
}
|
||||||
{
|
],
|
||||||
"type": "patch",
|
"cleanup": [
|
||||||
"path": "patches/weird_libdecor.patch"
|
"/include",
|
||||||
}
|
"/lib/pkgconfig"
|
||||||
],
|
]
|
||||||
"cleanup": [
|
|
||||||
"/include",
|
|
||||||
"/lib/pkgconfig"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
id: org.lunaislazier.ShatteredPrism
|
id: org.lunaislazier.ShatteredPrism
|
||||||
runtime: org.kde.Platform
|
runtime: org.kde.Platform
|
||||||
runtime-version: 6.7
|
runtime-version: '6.8'
|
||||||
sdk: org.kde.Sdk
|
sdk: org.kde.Sdk
|
||||||
sdk-extensions:
|
sdk-extensions:
|
||||||
- org.freedesktop.Sdk.Extension.openjdk17
|
- org.freedesktop.Sdk.Extension.openjdk17
|
||||||
@ -19,6 +19,12 @@ finish-args:
|
|||||||
- --filesystem=xdg-download:ro
|
- --filesystem=xdg-download:ro
|
||||||
# FTBApp import
|
# FTBApp import
|
||||||
- --filesystem=~/.ftba:ro
|
- --filesystem=~/.ftba:ro
|
||||||
|
# Userspace visibility for manual hugepages configuration
|
||||||
|
# Required for -XX:+UseLargePages
|
||||||
|
- --filesystem=/sys/kernel/mm/hugepages:ro
|
||||||
|
# Userspace visibility for transparent hugepages configuration
|
||||||
|
# Required for -XX:+UseTransparentHugePages
|
||||||
|
- --filesystem=/sys/kernel/mm/transparent_hugepage:ro
|
||||||
|
|
||||||
modules:
|
modules:
|
||||||
# Might be needed by some Controller mods (see https://github.com/isXander/Controlify/issues/31)
|
# Might be needed by some Controller mods (see https://github.com/isXander/Controlify/issues/31)
|
||||||
@ -27,11 +33,16 @@ modules:
|
|||||||
# Needed for proper Wayland support
|
# Needed for proper Wayland support
|
||||||
- libdecor.json
|
- libdecor.json
|
||||||
|
|
||||||
|
# Text to Speech in the game
|
||||||
|
- flite.json
|
||||||
|
|
||||||
- name: shatteredprism
|
- name: shatteredprism
|
||||||
buildsystem: cmake-ninja
|
buildsystem: cmake-ninja
|
||||||
builddir: true
|
builddir: true
|
||||||
config-opts:
|
config-opts:
|
||||||
- -DLauncher_BUILD_PLATFORM=flatpak
|
- -DLauncher_BUILD_PLATFORM=flatpak
|
||||||
|
# This allows us to manage and update Java independently of this Flatpak
|
||||||
|
- -DLauncher_ENABLE_JAVA_DOWNLOADER=ON
|
||||||
- -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
- -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||||
build-options:
|
build-options:
|
||||||
env:
|
env:
|
||||||
@ -47,18 +58,14 @@ modules:
|
|||||||
config-opts:
|
config-opts:
|
||||||
- -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
- -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||||
- -DBUILD_SHARED_LIBS:BOOL=ON
|
- -DBUILD_SHARED_LIBS:BOOL=ON
|
||||||
- -DGLFW_USE_WAYLAND:BOOL=ON
|
- -DGLFW_BUILD_WAYLAND:BOOL=ON
|
||||||
- -DGLFW_BUILD_DOCS:BOOL=OFF
|
- -DGLFW_BUILD_DOCS:BOOL=OFF
|
||||||
sources:
|
sources:
|
||||||
- type: git
|
- type: git
|
||||||
url: https://github.com/glfw/glfw.git
|
url: https://github.com/glfw/glfw.git
|
||||||
commit: 3fa2360720eeba1964df3c0ecf4b5df8648a8e52
|
commit: 7b6aead9fb88b3623e3b3725ebb42670cbe4c579 # 3.4
|
||||||
- type: patch
|
- type: patch
|
||||||
path: patches/0003-Don-t-crash-on-calls-to-focus-or-icon.patch
|
path: patches/0009-Defer-setting-cursor-position-until-the-cursor-is-lo.patch
|
||||||
- type: patch
|
|
||||||
path: patches/0005-Add-warning-about-being-an-unofficial-patch.patch
|
|
||||||
- type: patch
|
|
||||||
path: patches/0007-Platform-Prefer-Wayland-over-X11.patch
|
|
||||||
cleanup:
|
cleanup:
|
||||||
- /include
|
- /include
|
||||||
- /lib/cmake
|
- /lib/cmake
|
||||||
@ -68,8 +75,8 @@ modules:
|
|||||||
buildsystem: autotools
|
buildsystem: autotools
|
||||||
sources:
|
sources:
|
||||||
- type: archive
|
- type: archive
|
||||||
url: https://xorg.freedesktop.org/archive/individual/app/xrandr-1.5.2.tar.xz
|
url: https://xorg.freedesktop.org/archive/individual/app/xrandr-1.5.3.tar.xz
|
||||||
sha256: c8bee4790d9058bacc4b6246456c58021db58a87ddda1a9d0139bf5f18f1f240
|
sha256: f8dd7566adb74147fab9964680b6bbadee87cf406a7fcff51718a5e6949b841c
|
||||||
x-checker-data:
|
x-checker-data:
|
||||||
type: anitya
|
type: anitya
|
||||||
project-id: 14957
|
project-id: 14957
|
||||||
@ -91,8 +98,8 @@ modules:
|
|||||||
sources:
|
sources:
|
||||||
- type: archive
|
- type: archive
|
||||||
dest-filename: gamemode.tar.gz
|
dest-filename: gamemode.tar.gz
|
||||||
url: https://api.github.com/repos/FeralInteractive/gamemode/tarball/1.8.1
|
url: https://api.github.com/repos/FeralInteractive/gamemode/tarball/1.8.2
|
||||||
sha256: 969cf85b5ca3944f3e315cd73a0ee9bea4f9c968cd7d485e9f4745bc1e679c4e
|
sha256: 2886d4ce543c78bd2a364316d5e7fd59ef06b71de63f896b37c6d3dc97658f60
|
||||||
x-checker-data:
|
x-checker-data:
|
||||||
type: json
|
type: json
|
||||||
url: https://api.github.com/repos/FeralInteractive/gamemode/releases/latest
|
url: https://api.github.com/repos/FeralInteractive/gamemode/releases/latest
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
diff --git a/src/wl_window.c b/src/wl_window.c
|
|
||||||
index 52d3b9eb..4ac4eb5d 100644
|
|
||||||
--- a/src/wl_window.c
|
|
||||||
+++ b/src/wl_window.c
|
|
||||||
@@ -2117,8 +2117,7 @@ void _glfwSetWindowTitleWayland(_GLFWwindow* window, const char* title)
|
|
||||||
void _glfwSetWindowIconWayland(_GLFWwindow* window,
|
|
||||||
int count, const GLFWimage* images)
|
|
||||||
{
|
|
||||||
- _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
|
|
||||||
- "Wayland: The platform does not support setting the window icon");
|
|
||||||
+ fprintf(stderr, "!!! Ignoring Error: Wayland: The platform does not support setting the window icon\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void _glfwGetWindowPosWayland(_GLFWwindow* window, int* xpos, int* ypos)
|
|
||||||
@@ -2361,8 +2360,7 @@ void _glfwRequestWindowAttentionWayland(_GLFWwindow* window)
|
|
||||||
|
|
||||||
void _glfwFocusWindowWayland(_GLFWwindow* window)
|
|
||||||
{
|
|
||||||
- _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
|
|
||||||
- "Wayland: The platform does not support setting the input focus");
|
|
||||||
+ fprintf(stderr, "!!! Ignoring Error: Wayland: The platform does not support setting the input focus\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void _glfwSetWindowMonitorWayland(_GLFWwindow* window,
|
|
@ -1,17 +0,0 @@
|
|||||||
diff --git a/src/init.c b/src/init.c
|
|
||||||
index 06dbb3f2..a7c6da86 100644
|
|
||||||
--- a/src/init.c
|
|
||||||
+++ b/src/init.c
|
|
||||||
@@ -449,6 +449,12 @@ GLFWAPI int glfwInit(void)
|
|
||||||
_glfw.initialized = GLFW_TRUE;
|
|
||||||
|
|
||||||
glfwDefaultWindowHints();
|
|
||||||
+
|
|
||||||
+ fprintf(stderr, "!!! Patched GLFW from https://github.com/Admicos/minecraft-wayland\n"
|
|
||||||
+ "!!! If any issues with the window, or some issues with rendering, occur, "
|
|
||||||
+ "first try with the built-in GLFW, and if that solves the issue, report there first.\n"
|
|
||||||
+ "!!! Use outside Minecraft is untested, and things might break.\n");
|
|
||||||
+
|
|
||||||
return GLFW_TRUE;
|
|
||||||
}
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
|||||||
diff --git a/src/platform.c b/src/platform.c
|
|
||||||
index c5966ae7..3e7442f9 100644
|
|
||||||
--- a/src/platform.c
|
|
||||||
+++ b/src/platform.c
|
|
||||||
@@ -49,12 +49,12 @@ static const struct
|
|
||||||
#if defined(_GLFW_COCOA)
|
|
||||||
{ GLFW_PLATFORM_COCOA, _glfwConnectCocoa },
|
|
||||||
#endif
|
|
||||||
-#if defined(_GLFW_X11)
|
|
||||||
- { GLFW_PLATFORM_X11, _glfwConnectX11 },
|
|
||||||
-#endif
|
|
||||||
#if defined(_GLFW_WAYLAND)
|
|
||||||
{ GLFW_PLATFORM_WAYLAND, _glfwConnectWayland },
|
|
||||||
#endif
|
|
||||||
+#if defined(_GLFW_X11)
|
|
||||||
+ { GLFW_PLATFORM_X11, _glfwConnectX11 },
|
|
||||||
+#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
GLFWbool _glfwSelectPlatform(int desiredID, _GLFWplatform* platform)
|
|
@ -0,0 +1,59 @@
|
|||||||
|
From 9997ae55a47de469ea26f8437c30b51483abda5f Mon Sep 17 00:00:00 2001
|
||||||
|
From: Dan Klishch <danilklishch@gmail.com>
|
||||||
|
Date: Sat, 30 Sep 2023 23:38:05 -0400
|
||||||
|
Subject: Defer setting cursor position until the cursor is locked
|
||||||
|
|
||||||
|
---
|
||||||
|
src/wl_platform.h | 3 +++
|
||||||
|
src/wl_window.c | 14 ++++++++++++--
|
||||||
|
2 files changed, 15 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/wl_platform.h b/src/wl_platform.h
|
||||||
|
index ca34f66e..cd1f227f 100644
|
||||||
|
--- a/src/wl_platform.h
|
||||||
|
+++ b/src/wl_platform.h
|
||||||
|
@@ -403,6 +403,9 @@ typedef struct _GLFWwindowWayland
|
||||||
|
int scaleSize;
|
||||||
|
int compositorPreferredScale;
|
||||||
|
|
||||||
|
+ double askedCursorPosX, askedCursorPosY;
|
||||||
|
+ GLFWbool didAskForSetCursorPos;
|
||||||
|
+
|
||||||
|
struct zwp_relative_pointer_v1* relativePointer;
|
||||||
|
struct zwp_locked_pointer_v1* lockedPointer;
|
||||||
|
struct zwp_confined_pointer_v1* confinedPointer;
|
||||||
|
diff --git a/src/wl_window.c b/src/wl_window.c
|
||||||
|
index 1de26558..0df16747 100644
|
||||||
|
--- a/src/wl_window.c
|
||||||
|
+++ b/src/wl_window.c
|
||||||
|
@@ -2586,8 +2586,9 @@ void _glfwGetCursorPosWayland(_GLFWwindow* window, double* xpos, double* ypos)
|
||||||
|
|
||||||
|
void _glfwSetCursorPosWayland(_GLFWwindow* window, double x, double y)
|
||||||
|
{
|
||||||
|
- _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
|
||||||
|
- "Wayland: The platform does not support setting the cursor position");
|
||||||
|
+ window->wl.didAskForSetCursorPos = true;
|
||||||
|
+ window->wl.askedCursorPosX = x;
|
||||||
|
+ window->wl.askedCursorPosY = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _glfwSetCursorModeWayland(_GLFWwindow* window, int mode)
|
||||||
|
@@ -2819,6 +2820,15 @@ static const struct zwp_relative_pointer_v1_listener relativePointerListener =
|
||||||
|
static void lockedPointerHandleLocked(void* userData,
|
||||||
|
struct zwp_locked_pointer_v1* lockedPointer)
|
||||||
|
{
|
||||||
|
+ _GLFWwindow* window = userData;
|
||||||
|
+
|
||||||
|
+ if (window->wl.didAskForSetCursorPos)
|
||||||
|
+ {
|
||||||
|
+ window->wl.didAskForSetCursorPos = false;
|
||||||
|
+ zwp_locked_pointer_v1_set_cursor_position_hint(window->wl.lockedPointer,
|
||||||
|
+ wl_fixed_from_double(window->wl.askedCursorPosX),
|
||||||
|
+ wl_fixed_from_double(window->wl.askedCursorPosY));
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lockedPointerHandleUnlocked(void* userData,
|
||||||
|
--
|
||||||
|
2.42.0
|
||||||
|
|
@ -1,40 +0,0 @@
|
|||||||
diff --git a/src/libdecor.c b/src/libdecor.c
|
|
||||||
index a9c1106..1aa38b3 100644
|
|
||||||
--- a/src/libdecor.c
|
|
||||||
+++ b/src/libdecor.c
|
|
||||||
@@ -1391,22 +1391,32 @@ calculate_priority(const struct libdecor_plugin_description *plugin_description)
|
|
||||||
static bool
|
|
||||||
check_symbol_conflicts(const struct libdecor_plugin_description *plugin_description)
|
|
||||||
{
|
|
||||||
+ bool ret = true;
|
|
||||||
char * const *symbol;
|
|
||||||
+ void* main_prog = dlopen(NULL, RTLD_LAZY);
|
|
||||||
+ if (!main_prog) {
|
|
||||||
+ fprintf(stderr, "Plugin \"%s\" couldn't check conflicting symbols: \"%s\".\n",
|
|
||||||
+ plugin_description->description, dlerror());
|
|
||||||
+ return false;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
|
|
||||||
symbol = plugin_description->conflicting_symbols;
|
|
||||||
while (*symbol) {
|
|
||||||
dlerror();
|
|
||||||
- dlsym (RTLD_DEFAULT, *symbol);
|
|
||||||
+ dlsym (main_prog, *symbol);
|
|
||||||
if (!dlerror()) {
|
|
||||||
fprintf(stderr, "Plugin \"%s\" uses conflicting symbol \"%s\".\n",
|
|
||||||
plugin_description->description, *symbol);
|
|
||||||
- return false;
|
|
||||||
+ ret = false;
|
|
||||||
+ break;
|
|
||||||
}
|
|
||||||
|
|
||||||
symbol++;
|
|
||||||
}
|
|
||||||
|
|
||||||
- return true;
|
|
||||||
+ dlclose(main_prog);
|
|
||||||
+ return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct plugin_loader *
|
|
@ -48,6 +48,7 @@
|
|||||||
#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 "tasks/Task.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"
|
||||||
@ -1092,6 +1093,9 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
|||||||
bool Application::createSetupWizard()
|
bool Application::createSetupWizard()
|
||||||
{
|
{
|
||||||
bool javaRequired = [&]() {
|
bool javaRequired = [&]() {
|
||||||
|
if (BuildConfig.JAVA_DOWNLOADER_ENABLED && m_settings->get("AutomaticJavaDownload").toBool()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
bool ignoreJavaWizard = m_settings->get("IgnoreJavaWizard").toBool();
|
bool ignoreJavaWizard = m_settings->get("IgnoreJavaWizard").toBool();
|
||||||
if (ignoreJavaWizard) {
|
if (ignoreJavaWizard) {
|
||||||
return false;
|
return false;
|
||||||
@ -1104,10 +1108,7 @@ bool Application::createSetupWizard()
|
|||||||
}
|
}
|
||||||
QString currentJavaPath = settings()->get("JavaPath").toString();
|
QString currentJavaPath = settings()->get("JavaPath").toString();
|
||||||
QString actualPath = FS::ResolveExecutable(currentJavaPath);
|
QString actualPath = FS::ResolveExecutable(currentJavaPath);
|
||||||
if (actualPath.isNull()) {
|
return actualPath.isNull();
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}();
|
}();
|
||||||
bool askjava = BuildConfig.JAVA_DOWNLOADER_ENABLED && !javaRequired && !m_settings->get("AutomaticJavaDownload").toBool() &&
|
bool askjava = BuildConfig.JAVA_DOWNLOADER_ENABLED && !javaRequired && !m_settings->get("AutomaticJavaDownload").toBool() &&
|
||||||
!m_settings->get("AutomaticJavaSwitch").toBool() && !m_settings->get("UserAskedAboutAutomaticJavaDownload").toBool();
|
!m_settings->get("AutomaticJavaSwitch").toBool() && !m_settings->get("UserAskedAboutAutomaticJavaDownload").toBool();
|
||||||
@ -1426,6 +1427,7 @@ bool Application::launch(InstancePtr instance, bool online, bool demo, Minecraft
|
|||||||
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.";
|
||||||
} else if (instance->canLaunch()) {
|
} else if (instance->canLaunch()) {
|
||||||
|
QMutexLocker locker(&m_instanceExtrasMutex);
|
||||||
auto& extras = m_instanceExtras[instance->id()];
|
auto& extras = m_instanceExtras[instance->id()];
|
||||||
auto window = extras.window;
|
auto window = extras.window;
|
||||||
if (window) {
|
if (window) {
|
||||||
@ -1450,7 +1452,7 @@ bool Application::launch(InstancePtr instance, bool online, bool demo, Minecraft
|
|||||||
connect(controller.get(), &LaunchController::failed, this, &Application::controllerFailed);
|
connect(controller.get(), &LaunchController::failed, this, &Application::controllerFailed);
|
||||||
connect(controller.get(), &LaunchController::aborted, this, [this] { controllerFailed(tr("Aborted")); });
|
connect(controller.get(), &LaunchController::aborted, this, [this] { controllerFailed(tr("Aborted")); });
|
||||||
addRunningInstance();
|
addRunningInstance();
|
||||||
controller->start();
|
QMetaObject::invokeMethod(controller.get(), &Task::start, Qt::QueuedConnection);
|
||||||
return true;
|
return true;
|
||||||
} else if (instance->isRunning()) {
|
} else if (instance->isRunning()) {
|
||||||
showInstanceWindow(instance, "console");
|
showInstanceWindow(instance, "console");
|
||||||
@ -1468,9 +1470,11 @@ bool Application::kill(InstancePtr instance)
|
|||||||
qWarning() << "Attempted to kill instance" << instance->id() << ", which isn't running.";
|
qWarning() << "Attempted to kill instance" << instance->id() << ", which isn't running.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
QMutexLocker locker(&m_instanceExtrasMutex);
|
||||||
auto& extras = m_instanceExtras[instance->id()];
|
auto& extras = m_instanceExtras[instance->id()];
|
||||||
// NOTE: copy of the shared pointer keeps it alive
|
// NOTE: copy of the shared pointer keeps it alive
|
||||||
auto controller = extras.controller;
|
auto controller = extras.controller;
|
||||||
|
locker.unlock();
|
||||||
if (controller) {
|
if (controller) {
|
||||||
return controller->abort();
|
return controller->abort();
|
||||||
}
|
}
|
||||||
@ -1524,12 +1528,14 @@ void Application::controllerSucceeded()
|
|||||||
if (!controller)
|
if (!controller)
|
||||||
return;
|
return;
|
||||||
auto id = controller->id();
|
auto id = controller->id();
|
||||||
|
|
||||||
|
QMutexLocker locker(&m_instanceExtrasMutex);
|
||||||
auto& extras = m_instanceExtras[id];
|
auto& extras = m_instanceExtras[id];
|
||||||
|
|
||||||
// on success, do...
|
// on success, do...
|
||||||
if (controller->instance()->settings()->get("AutoCloseConsole").toBool()) {
|
if (controller->instance()->settings()->get("AutoCloseConsole").toBool()) {
|
||||||
if (extras.window) {
|
if (extras.window) {
|
||||||
extras.window->close();
|
QMetaObject::invokeMethod(extras.window, &QWidget::close, Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
extras.controller.reset();
|
extras.controller.reset();
|
||||||
@ -1549,6 +1555,7 @@ void Application::controllerFailed(const QString& error)
|
|||||||
if (!controller)
|
if (!controller)
|
||||||
return;
|
return;
|
||||||
auto id = controller->id();
|
auto id = controller->id();
|
||||||
|
QMutexLocker locker(&m_instanceExtrasMutex);
|
||||||
auto& extras = m_instanceExtras[id];
|
auto& extras = m_instanceExtras[id];
|
||||||
|
|
||||||
// on failure, do... nothing
|
// on failure, do... nothing
|
||||||
@ -1606,6 +1613,7 @@ InstanceWindow* Application::showInstanceWindow(InstancePtr instance, QString pa
|
|||||||
if (!instance)
|
if (!instance)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
auto id = instance->id();
|
auto id = instance->id();
|
||||||
|
QMutexLocker locker(&m_instanceExtrasMutex);
|
||||||
auto& extras = m_instanceExtras[id];
|
auto& extras = m_instanceExtras[id];
|
||||||
auto& window = extras.window;
|
auto& window = extras.window;
|
||||||
|
|
||||||
@ -1643,6 +1651,7 @@ void Application::on_windowClose()
|
|||||||
m_openWindows--;
|
m_openWindows--;
|
||||||
auto instWindow = qobject_cast<InstanceWindow*>(QObject::sender());
|
auto instWindow = qobject_cast<InstanceWindow*>(QObject::sender());
|
||||||
if (instWindow) {
|
if (instWindow) {
|
||||||
|
QMutexLocker locker(&m_instanceExtrasMutex);
|
||||||
auto& extras = m_instanceExtras[instWindow->instanceId()];
|
auto& extras = m_instanceExtras[instWindow->instanceId()];
|
||||||
extras.window = nullptr;
|
extras.window = nullptr;
|
||||||
if (extras.controller) {
|
if (extras.controller) {
|
||||||
@ -1890,7 +1899,7 @@ bool Application::handleDataMigration(const QString& currentData,
|
|||||||
matcher->add(std::make_shared<SimplePrefixMatcher>("themes/"));
|
matcher->add(std::make_shared<SimplePrefixMatcher>("themes/"));
|
||||||
|
|
||||||
ProgressDialog diag;
|
ProgressDialog diag;
|
||||||
DataMigrationTask task(nullptr, oldData, currentData, matcher);
|
DataMigrationTask task(oldData, currentData, matcher);
|
||||||
if (diag.execWithTask(&task)) {
|
if (diag.execWithTask(&task)) {
|
||||||
qDebug() << "<> Migration succeeded";
|
qDebug() << "<> Migration succeeded";
|
||||||
setDoNotMigrate();
|
setDoNotMigrate();
|
||||||
@ -1929,3 +1938,31 @@ const QString Application::javaPath()
|
|||||||
{
|
{
|
||||||
return m_settings->get("JavaDir").toString();
|
return m_settings->get("JavaDir").toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::addQSavePath(QString path)
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&m_qsaveResourcesMutex);
|
||||||
|
m_qsaveResources[path] = m_qsaveResources.value(path, 0) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::removeQSavePath(QString path)
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&m_qsaveResourcesMutex);
|
||||||
|
auto count = m_qsaveResources.value(path, 0) - 1;
|
||||||
|
if (count <= 0) {
|
||||||
|
m_qsaveResources.remove(path);
|
||||||
|
} else {
|
||||||
|
m_qsaveResources[path] = count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Application::checkQSavePath(QString path)
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&m_qsaveResourcesMutex);
|
||||||
|
for (auto partialPath : m_qsaveResources.keys()) {
|
||||||
|
if (path.startsWith(partialPath) && m_qsaveResources.value(partialPath, 0) > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
@ -42,6 +42,7 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QFlag>
|
#include <QFlag>
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
|
#include <QMutex>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@ -278,6 +279,7 @@ class Application : public QApplication {
|
|||||||
shared_qobject_ptr<LaunchController> controller;
|
shared_qobject_ptr<LaunchController> controller;
|
||||||
};
|
};
|
||||||
std::map<QString, InstanceXtras> m_instanceExtras;
|
std::map<QString, InstanceXtras> m_instanceExtras;
|
||||||
|
mutable QMutex m_instanceExtrasMutex;
|
||||||
|
|
||||||
// main state variables
|
// main state variables
|
||||||
size_t m_openWindows = 0;
|
size_t m_openWindows = 0;
|
||||||
@ -303,4 +305,13 @@ class Application : public QApplication {
|
|||||||
QList<QUrl> m_urlsToImport;
|
QList<QUrl> m_urlsToImport;
|
||||||
QString m_instanceIdToShowWindowOf;
|
QString m_instanceIdToShowWindowOf;
|
||||||
std::unique_ptr<QFile> logFile;
|
std::unique_ptr<QFile> logFile;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void addQSavePath(QString);
|
||||||
|
void removeQSavePath(QString);
|
||||||
|
bool checkQSavePath(QString);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QHash<QString, int> m_qsaveResources;
|
||||||
|
mutable QMutex m_qsaveResourcesMutex;
|
||||||
};
|
};
|
||||||
|
@ -30,6 +30,7 @@ set(CORE_SOURCES
|
|||||||
StringUtils.cpp
|
StringUtils.cpp
|
||||||
QVariantUtils.h
|
QVariantUtils.h
|
||||||
RuntimeContext.h
|
RuntimeContext.h
|
||||||
|
PSaveFile.h
|
||||||
|
|
||||||
# Basic instance manipulation tasks (derived from InstanceTask)
|
# Basic instance manipulation tasks (derived from InstanceTask)
|
||||||
InstanceCreationTask.h
|
InstanceCreationTask.h
|
||||||
|
@ -12,11 +12,8 @@
|
|||||||
|
|
||||||
#include <QtConcurrent>
|
#include <QtConcurrent>
|
||||||
|
|
||||||
DataMigrationTask::DataMigrationTask(QObject* parent,
|
DataMigrationTask::DataMigrationTask(const QString& sourcePath, const QString& targetPath, const IPathMatcher::Ptr pathMatcher)
|
||||||
const QString& sourcePath,
|
: Task(), m_sourcePath(sourcePath), m_targetPath(targetPath), m_pathMatcher(pathMatcher), m_copy(sourcePath, targetPath)
|
||||||
const QString& targetPath,
|
|
||||||
const IPathMatcher::Ptr pathMatcher)
|
|
||||||
: Task(parent), m_sourcePath(sourcePath), m_targetPath(targetPath), m_pathMatcher(pathMatcher), m_copy(sourcePath, targetPath)
|
|
||||||
{
|
{
|
||||||
m_copy.matcher(m_pathMatcher.get()).whitelist(true);
|
m_copy.matcher(m_pathMatcher.get()).whitelist(true);
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
class DataMigrationTask : public Task {
|
class DataMigrationTask : public Task {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit DataMigrationTask(QObject* parent, const QString& sourcePath, const QString& targetPath, IPathMatcher::Ptr pathmatcher);
|
explicit DataMigrationTask(const QString& sourcePath, const QString& targetPath, IPathMatcher::Ptr pathmatcher);
|
||||||
~DataMigrationTask() override = default;
|
~DataMigrationTask() override = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -45,7 +45,6 @@
|
|||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QSaveFile>
|
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QStorageInfo>
|
#include <QStorageInfo>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
@ -54,6 +53,7 @@
|
|||||||
#include <system_error>
|
#include <system_error>
|
||||||
|
|
||||||
#include "DesktopServices.h"
|
#include "DesktopServices.h"
|
||||||
|
#include "PSaveFile.h"
|
||||||
#include "StringUtils.h"
|
#include "StringUtils.h"
|
||||||
|
|
||||||
#if defined Q_OS_WIN32
|
#if defined Q_OS_WIN32
|
||||||
@ -191,8 +191,8 @@ void ensureExists(const QDir& dir)
|
|||||||
void write(const QString& filename, const QByteArray& data)
|
void write(const QString& filename, const QByteArray& data)
|
||||||
{
|
{
|
||||||
ensureExists(QFileInfo(filename).dir());
|
ensureExists(QFileInfo(filename).dir());
|
||||||
QSaveFile file(filename);
|
PSaveFile file(filename);
|
||||||
if (!file.open(QSaveFile::WriteOnly)) {
|
if (!file.open(PSaveFile::WriteOnly)) {
|
||||||
throw FileSystemException("Couldn't open " + filename + " for writing: " + file.errorString());
|
throw FileSystemException("Couldn't open " + filename + " for writing: " + file.errorString());
|
||||||
}
|
}
|
||||||
if (data.size() != file.write(data)) {
|
if (data.size() != file.write(data)) {
|
||||||
@ -213,8 +213,8 @@ void appendSafe(const QString& filename, const QByteArray& data)
|
|||||||
buffer = QByteArray();
|
buffer = QByteArray();
|
||||||
}
|
}
|
||||||
buffer.append(data);
|
buffer.append(data);
|
||||||
QSaveFile file(filename);
|
PSaveFile file(filename);
|
||||||
if (!file.open(QSaveFile::WriteOnly)) {
|
if (!file.open(PSaveFile::WriteOnly)) {
|
||||||
throw FileSystemException("Couldn't open " + filename + " for writing: " + file.errorString());
|
throw FileSystemException("Couldn't open " + filename + " for writing: " + file.errorString());
|
||||||
}
|
}
|
||||||
if (buffer.size() != file.write(buffer)) {
|
if (buffer.size() != file.write(buffer)) {
|
||||||
@ -971,8 +971,7 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
|
|||||||
if (!args.empty())
|
if (!args.empty())
|
||||||
argstring = " \"" + args.join("\" \"") + "\"";
|
argstring = " \"" + args.join("\" \"") + "\"";
|
||||||
|
|
||||||
stream << "#!/bin/bash"
|
stream << "#!/bin/bash" << "\n";
|
||||||
<< "\n";
|
|
||||||
stream << "\"" << target << "\" " << argstring << "\n";
|
stream << "\"" << target << "\" " << argstring << "\n";
|
||||||
|
|
||||||
stream.flush();
|
stream.flush();
|
||||||
@ -1016,12 +1015,9 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
|
|||||||
if (!args.empty())
|
if (!args.empty())
|
||||||
argstring = " '" + args.join("' '") + "'";
|
argstring = " '" + args.join("' '") + "'";
|
||||||
|
|
||||||
stream << "[Desktop Entry]"
|
stream << "[Desktop Entry]" << "\n";
|
||||||
<< "\n";
|
stream << "Type=Application" << "\n";
|
||||||
stream << "Type=Application"
|
stream << "Categories=Game;ActionGame;AdventureGame;Simulation" << "\n";
|
||||||
<< "\n";
|
|
||||||
stream << "Categories=Game;ActionGame;AdventureGame;Simulation"
|
|
||||||
<< "\n";
|
|
||||||
stream << "Exec=\"" << target.toLocal8Bit() << "\"" << argstring.toLocal8Bit() << "\n";
|
stream << "Exec=\"" << target.toLocal8Bit() << "\"" << argstring.toLocal8Bit() << "\n";
|
||||||
stream << "Name=" << name.toLocal8Bit() << "\n";
|
stream << "Name=" << name.toLocal8Bit() << "\n";
|
||||||
if (!icon.isEmpty()) {
|
if (!icon.isEmpty()) {
|
||||||
|
@ -61,6 +61,6 @@ void InstanceCreationTask::executeTask()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!m_abort)
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
}
|
}
|
||||||
|
@ -69,9 +69,11 @@ bool InstanceImportTask::abort()
|
|||||||
if (!canAbort())
|
if (!canAbort())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (task)
|
bool wasAborted = false;
|
||||||
task->abort();
|
if (m_task)
|
||||||
return Task::abort();
|
wasAborted = m_task->abort();
|
||||||
|
Task::abort();
|
||||||
|
return wasAborted;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceImportTask::executeTask()
|
void InstanceImportTask::executeTask()
|
||||||
@ -104,7 +106,7 @@ void InstanceImportTask::downloadFromUrl()
|
|||||||
connect(filesNetJob.get(), &NetJob::stepProgress, this, &InstanceImportTask::propagateStepProgress);
|
connect(filesNetJob.get(), &NetJob::stepProgress, this, &InstanceImportTask::propagateStepProgress);
|
||||||
connect(filesNetJob.get(), &NetJob::failed, this, &InstanceImportTask::emitFailed);
|
connect(filesNetJob.get(), &NetJob::failed, this, &InstanceImportTask::emitFailed);
|
||||||
connect(filesNetJob.get(), &NetJob::aborted, this, &InstanceImportTask::emitAborted);
|
connect(filesNetJob.get(), &NetJob::aborted, this, &InstanceImportTask::emitAborted);
|
||||||
task.reset(filesNetJob);
|
m_task.reset(filesNetJob);
|
||||||
filesNetJob->start();
|
filesNetJob->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,7 +195,7 @@ void InstanceImportTask::processZipPack()
|
|||||||
stepProgress(*progressStep);
|
stepProgress(*progressStep);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(zipTask.get(), &Task::succeeded, this, &InstanceImportTask::extractFinished);
|
connect(zipTask.get(), &Task::succeeded, this, &InstanceImportTask::extractFinished, Qt::QueuedConnection);
|
||||||
connect(zipTask.get(), &Task::aborted, this, &InstanceImportTask::emitAborted);
|
connect(zipTask.get(), &Task::aborted, this, &InstanceImportTask::emitAborted);
|
||||||
connect(zipTask.get(), &Task::failed, this, [this, progressStep](QString reason) {
|
connect(zipTask.get(), &Task::failed, this, [this, progressStep](QString reason) {
|
||||||
progressStep->state = TaskStepState::Failed;
|
progressStep->state = TaskStepState::Failed;
|
||||||
@ -210,12 +212,13 @@ void InstanceImportTask::processZipPack()
|
|||||||
progressStep->status = status;
|
progressStep->status = status;
|
||||||
stepProgress(*progressStep);
|
stepProgress(*progressStep);
|
||||||
});
|
});
|
||||||
task.reset(zipTask);
|
m_task.reset(zipTask);
|
||||||
zipTask->start();
|
zipTask->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceImportTask::extractFinished()
|
void InstanceImportTask::extractFinished()
|
||||||
{
|
{
|
||||||
|
setAbortable(false);
|
||||||
QDir extractDir(m_stagingPath);
|
QDir extractDir(m_stagingPath);
|
||||||
|
|
||||||
qDebug() << "Fixing permissions for extracted pack files...";
|
qDebug() << "Fixing permissions for extracted pack files...";
|
||||||
@ -289,8 +292,11 @@ void InstanceImportTask::processFlame()
|
|||||||
inst_creation_task->setGroup(m_instGroup);
|
inst_creation_task->setGroup(m_instGroup);
|
||||||
inst_creation_task->setConfirmUpdate(shouldConfirmUpdate());
|
inst_creation_task->setConfirmUpdate(shouldConfirmUpdate());
|
||||||
|
|
||||||
connect(inst_creation_task.get(), &Task::succeeded, this, [this, inst_creation_task] {
|
auto weak = inst_creation_task.toWeakRef();
|
||||||
setOverride(inst_creation_task->shouldOverride(), inst_creation_task->originalInstanceID());
|
connect(inst_creation_task.get(), &Task::succeeded, this, [this, weak] {
|
||||||
|
if (auto sp = weak.lock()) {
|
||||||
|
setOverride(sp->shouldOverride(), sp->originalInstanceID());
|
||||||
|
}
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
});
|
});
|
||||||
connect(inst_creation_task.get(), &Task::failed, this, &InstanceImportTask::emitFailed);
|
connect(inst_creation_task.get(), &Task::failed, this, &InstanceImportTask::emitFailed);
|
||||||
@ -299,11 +305,12 @@ void InstanceImportTask::processFlame()
|
|||||||
connect(inst_creation_task.get(), &Task::status, this, &InstanceImportTask::setStatus);
|
connect(inst_creation_task.get(), &Task::status, this, &InstanceImportTask::setStatus);
|
||||||
connect(inst_creation_task.get(), &Task::details, this, &InstanceImportTask::setDetails);
|
connect(inst_creation_task.get(), &Task::details, this, &InstanceImportTask::setDetails);
|
||||||
|
|
||||||
connect(this, &Task::aborted, inst_creation_task.get(), &InstanceCreationTask::abort);
|
|
||||||
connect(inst_creation_task.get(), &Task::aborted, this, &Task::abort);
|
connect(inst_creation_task.get(), &Task::aborted, this, &Task::abort);
|
||||||
connect(inst_creation_task.get(), &Task::abortStatusChanged, this, &Task::setAbortable);
|
connect(inst_creation_task.get(), &Task::abortStatusChanged, this, &Task::setAbortable);
|
||||||
|
|
||||||
inst_creation_task->start();
|
m_task.reset(inst_creation_task);
|
||||||
|
setAbortable(true);
|
||||||
|
m_task->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceImportTask::processTechnic()
|
void InstanceImportTask::processTechnic()
|
||||||
@ -350,7 +357,7 @@ void InstanceImportTask::processMultiMC()
|
|||||||
|
|
||||||
void InstanceImportTask::processModrinth()
|
void InstanceImportTask::processModrinth()
|
||||||
{
|
{
|
||||||
ModrinthCreationTask* inst_creation_task = nullptr;
|
shared_qobject_ptr<ModrinthCreationTask> inst_creation_task = nullptr;
|
||||||
if (!m_extra_info.isEmpty()) {
|
if (!m_extra_info.isEmpty()) {
|
||||||
auto pack_id_it = m_extra_info.constFind("pack_id");
|
auto pack_id_it = m_extra_info.constFind("pack_id");
|
||||||
Q_ASSERT(pack_id_it != m_extra_info.constEnd());
|
Q_ASSERT(pack_id_it != m_extra_info.constEnd());
|
||||||
@ -367,7 +374,7 @@ void InstanceImportTask::processModrinth()
|
|||||||
original_instance_id = original_instance_id_it.value();
|
original_instance_id = original_instance_id_it.value();
|
||||||
|
|
||||||
inst_creation_task =
|
inst_creation_task =
|
||||||
new ModrinthCreationTask(m_stagingPath, m_globalSettings, m_parent, pack_id, pack_version_id, original_instance_id);
|
makeShared<ModrinthCreationTask>(m_stagingPath, m_globalSettings, m_parent, pack_id, pack_version_id, original_instance_id);
|
||||||
} else {
|
} else {
|
||||||
QString pack_id;
|
QString pack_id;
|
||||||
if (!m_sourceUrl.isEmpty()) {
|
if (!m_sourceUrl.isEmpty()) {
|
||||||
@ -376,7 +383,7 @@ void InstanceImportTask::processModrinth()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Find a way to get the ID in directly imported ZIPs
|
// FIXME: Find a way to get the ID in directly imported ZIPs
|
||||||
inst_creation_task = new ModrinthCreationTask(m_stagingPath, m_globalSettings, m_parent, pack_id);
|
inst_creation_task = makeShared<ModrinthCreationTask>(m_stagingPath, m_globalSettings, m_parent, pack_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
inst_creation_task->setName(*this);
|
inst_creation_task->setName(*this);
|
||||||
@ -384,20 +391,23 @@ void InstanceImportTask::processModrinth()
|
|||||||
inst_creation_task->setGroup(m_instGroup);
|
inst_creation_task->setGroup(m_instGroup);
|
||||||
inst_creation_task->setConfirmUpdate(shouldConfirmUpdate());
|
inst_creation_task->setConfirmUpdate(shouldConfirmUpdate());
|
||||||
|
|
||||||
connect(inst_creation_task, &Task::succeeded, this, [this, inst_creation_task] {
|
auto weak = inst_creation_task.toWeakRef();
|
||||||
setOverride(inst_creation_task->shouldOverride(), inst_creation_task->originalInstanceID());
|
connect(inst_creation_task.get(), &Task::succeeded, this, [this, weak] {
|
||||||
|
if (auto sp = weak.lock()) {
|
||||||
|
setOverride(sp->shouldOverride(), sp->originalInstanceID());
|
||||||
|
}
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
});
|
});
|
||||||
connect(inst_creation_task, &Task::failed, this, &InstanceImportTask::emitFailed);
|
connect(inst_creation_task.get(), &Task::failed, this, &InstanceImportTask::emitFailed);
|
||||||
connect(inst_creation_task, &Task::progress, this, &InstanceImportTask::setProgress);
|
connect(inst_creation_task.get(), &Task::progress, this, &InstanceImportTask::setProgress);
|
||||||
connect(inst_creation_task, &Task::stepProgress, this, &InstanceImportTask::propagateStepProgress);
|
connect(inst_creation_task.get(), &Task::stepProgress, this, &InstanceImportTask::propagateStepProgress);
|
||||||
connect(inst_creation_task, &Task::status, this, &InstanceImportTask::setStatus);
|
connect(inst_creation_task.get(), &Task::status, this, &InstanceImportTask::setStatus);
|
||||||
connect(inst_creation_task, &Task::details, this, &InstanceImportTask::setDetails);
|
connect(inst_creation_task.get(), &Task::details, this, &InstanceImportTask::setDetails);
|
||||||
connect(inst_creation_task, &Task::finished, inst_creation_task, &InstanceCreationTask::deleteLater);
|
|
||||||
|
|
||||||
connect(this, &Task::aborted, inst_creation_task, &InstanceCreationTask::abort);
|
connect(inst_creation_task.get(), &Task::aborted, this, &Task::abort);
|
||||||
connect(inst_creation_task, &Task::aborted, this, &Task::abort);
|
connect(inst_creation_task.get(), &Task::abortStatusChanged, this, &Task::setAbortable);
|
||||||
connect(inst_creation_task, &Task::abortStatusChanged, this, &Task::setAbortable);
|
|
||||||
|
|
||||||
inst_creation_task->start();
|
m_task.reset(inst_creation_task);
|
||||||
|
setAbortable(true);
|
||||||
|
m_task->start();
|
||||||
}
|
}
|
||||||
|
@ -40,16 +40,13 @@
|
|||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include "InstanceTask.h"
|
#include "InstanceTask.h"
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <optional>
|
|
||||||
|
|
||||||
class QuaZip;
|
class QuaZip;
|
||||||
|
|
||||||
class InstanceImportTask : public InstanceTask {
|
class InstanceImportTask : public InstanceTask {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit InstanceImportTask(const QUrl& sourceUrl, QWidget* parent = nullptr, QMap<QString, QString>&& extra_info = {});
|
explicit InstanceImportTask(const QUrl& sourceUrl, QWidget* parent = nullptr, QMap<QString, QString>&& extra_info = {});
|
||||||
|
virtual ~InstanceImportTask() = default;
|
||||||
bool abort() override;
|
bool abort() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -70,7 +67,7 @@ class InstanceImportTask : public InstanceTask {
|
|||||||
private: /* data */
|
private: /* data */
|
||||||
QUrl m_sourceUrl;
|
QUrl m_sourceUrl;
|
||||||
QString m_archivePath;
|
QString m_archivePath;
|
||||||
Task::Ptr task;
|
Task::Ptr m_task;
|
||||||
enum class ModpackType {
|
enum class ModpackType {
|
||||||
Unknown,
|
Unknown,
|
||||||
MultiMC,
|
MultiMC,
|
||||||
|
@ -116,7 +116,7 @@ void JavaCommon::TestCheck::run()
|
|||||||
emit finished();
|
emit finished();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
checker.reset(new JavaChecker(m_path, "", 0, 0, 0, 0, this));
|
checker.reset(new JavaChecker(m_path, "", 0, 0, 0, 0));
|
||||||
connect(checker.get(), &JavaChecker::checkFinished, this, &JavaCommon::TestCheck::checkFinished);
|
connect(checker.get(), &JavaChecker::checkFinished, this, &JavaCommon::TestCheck::checkFinished);
|
||||||
checker->start();
|
checker->start();
|
||||||
}
|
}
|
||||||
@ -128,7 +128,7 @@ void JavaCommon::TestCheck::checkFinished(const JavaChecker::Result& result)
|
|||||||
emit finished();
|
emit finished();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
checker.reset(new JavaChecker(m_path, m_args, m_maxMem, m_maxMem, result.javaVersion.requiresPermGen() ? m_permGen : 0, 0, this));
|
checker.reset(new JavaChecker(m_path, m_args, m_maxMem, m_maxMem, result.javaVersion.requiresPermGen() ? m_permGen : 0, 0));
|
||||||
connect(checker.get(), &JavaChecker::checkFinished, this, &JavaCommon::TestCheck::checkFinishedWithArgs);
|
connect(checker.get(), &JavaChecker::checkFinished, this, &JavaCommon::TestCheck::checkFinishedWithArgs);
|
||||||
checker->start();
|
checker->start();
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@
|
|||||||
#include "launch/steps/TextPrint.h"
|
#include "launch/steps/TextPrint.h"
|
||||||
#include "tasks/Task.h"
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
LaunchController::LaunchController(QObject* parent) : Task(parent) {}
|
LaunchController::LaunchController() : Task() {}
|
||||||
|
|
||||||
void LaunchController::executeTask()
|
void LaunchController::executeTask()
|
||||||
{
|
{
|
||||||
|
@ -49,7 +49,7 @@ class LaunchController : public Task {
|
|||||||
public:
|
public:
|
||||||
void executeTask() override;
|
void executeTask() override;
|
||||||
|
|
||||||
LaunchController(QObject* parent = nullptr);
|
LaunchController();
|
||||||
virtual ~LaunchController() = default;
|
virtual ~LaunchController() = default;
|
||||||
|
|
||||||
void setInstance(InstancePtr instance) { m_instance = instance; }
|
void setInstance(InstancePtr instance) { m_instance = instance; }
|
||||||
|
@ -39,8 +39,16 @@ if [ "x$DEPS_LIST" = "x" ]; then
|
|||||||
# Just to be sure...
|
# Just to be sure...
|
||||||
chmod +x "${LAUNCHER_DIR}/bin/${LAUNCHER_NAME}"
|
chmod +x "${LAUNCHER_DIR}/bin/${LAUNCHER_NAME}"
|
||||||
|
|
||||||
|
ARGS=("${LAUNCHER_DIR}/${LAUNCHER_NAME}" "${LAUNCHER_DIR}/bin/${LAUNCHER_NAME}")
|
||||||
|
|
||||||
|
if [ -f portable.txt ]; then
|
||||||
|
ARGS+=("-d" "${LAUNCHER_DIR}")
|
||||||
|
fi
|
||||||
|
|
||||||
|
ARGS+=("$@")
|
||||||
|
|
||||||
# Run the launcher
|
# Run the launcher
|
||||||
exec -a "${LAUNCHER_DIR}/${LAUNCHER_NAME}" "${LAUNCHER_DIR}/bin/${LAUNCHER_NAME}" -d "${LAUNCHER_DIR}" "$@"
|
exec -a "${ARGS[@]}"
|
||||||
|
|
||||||
# Run the launcher in valgrind
|
# Run the launcher in valgrind
|
||||||
# valgrind --log-file="valgrind.log" --leak-check=full --track-origins=yes "${LAUNCHER_DIR}/bin/${LAUNCHER_NAME}" -d "${LAUNCHER_DIR}" "$@"
|
# valgrind --log-file="valgrind.log" --leak-check=full --track-origins=yes "${LAUNCHER_DIR}/bin/${LAUNCHER_NAME}" -d "${LAUNCHER_DIR}" "$@"
|
||||||
|
@ -378,7 +378,7 @@ std::optional<QStringList> extractDir(QString fileCompressed, QString dir)
|
|||||||
if (fileInfo.size() == 22) {
|
if (fileInfo.size() == 22) {
|
||||||
return QStringList();
|
return QStringList();
|
||||||
}
|
}
|
||||||
qWarning() << "Could not open archive for unzipping:" << fileCompressed << "Error:" << zip.getZipError();
|
qWarning() << "Could not open archive for unpacking:" << fileCompressed << "Error:" << zip.getZipError();
|
||||||
;
|
;
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
@ -395,7 +395,7 @@ std::optional<QStringList> extractDir(QString fileCompressed, QString subdir, QS
|
|||||||
if (fileInfo.size() == 22) {
|
if (fileInfo.size() == 22) {
|
||||||
return QStringList();
|
return QStringList();
|
||||||
}
|
}
|
||||||
qWarning() << "Could not open archive for unzipping:" << fileCompressed << "Error:" << zip.getZipError();
|
qWarning() << "Could not open archive for unpacking:" << fileCompressed << "Error:" << zip.getZipError();
|
||||||
;
|
;
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
@ -412,7 +412,7 @@ bool extractFile(QString fileCompressed, QString file, QString target)
|
|||||||
if (fileInfo.size() == 22) {
|
if (fileInfo.size() == 22) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
qWarning() << "Could not open archive for unzipping:" << fileCompressed << "Error:" << zip.getZipError();
|
qWarning() << "Could not open archive for unpacking:" << fileCompressed << "Error:" << zip.getZipError();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return extractRelFile(&zip, file, target);
|
return extractRelFile(&zip, file, target);
|
||||||
@ -577,7 +577,7 @@ auto ExtractZipTask::extractZip() -> ZipResult
|
|||||||
|
|
||||||
auto relative_file_name = QDir::fromNativeSeparators(file_name.mid(m_subdirectory.size()));
|
auto relative_file_name = QDir::fromNativeSeparators(file_name.mid(m_subdirectory.size()));
|
||||||
auto original_name = relative_file_name;
|
auto original_name = relative_file_name;
|
||||||
setStatus("Unziping: " + relative_file_name);
|
setStatus("Unpacking: " + relative_file_name);
|
||||||
|
|
||||||
// Fix subdirs/files ending with a / getting transformed into absolute paths
|
// Fix subdirs/files ending with a / getting transformed into absolute paths
|
||||||
if (relative_file_name.startsWith('/'))
|
if (relative_file_name.startsWith('/'))
|
||||||
|
71
launcher/PSaveFile.h
Normal file
71
launcher/PSaveFile.h
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
// 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 <QFileInfo>
|
||||||
|
#include <QSaveFile>
|
||||||
|
#include "Application.h"
|
||||||
|
|
||||||
|
#if defined(LAUNCHER_APPLICATION)
|
||||||
|
|
||||||
|
/* PSaveFile
|
||||||
|
* A class that mimics QSaveFile for Windows.
|
||||||
|
*
|
||||||
|
* When reading resources, we need to avoid accessing temporary files
|
||||||
|
* generated by QSaveFile. If we start reading such a file, we may
|
||||||
|
* inadvertently keep it open while QSaveFile is trying to remove it,
|
||||||
|
* or we might detect the file just before it is removed, leading to
|
||||||
|
* race conditions and errors.
|
||||||
|
*
|
||||||
|
* Unfortunately, QSaveFile doesn't provide a way to retrieve the
|
||||||
|
* temporary file name or to set a specific template for the temporary
|
||||||
|
* file name it uses. By default, QSaveFile appends a `.XXXXXX` suffix
|
||||||
|
* to the original file name, where the `XXXXXX` part is dynamically
|
||||||
|
* generated to ensure uniqueness.
|
||||||
|
*
|
||||||
|
* This class acts like a lock by adding and removing the target file
|
||||||
|
* name into/from a global string set, helping to manage access to
|
||||||
|
* files during critical operations.
|
||||||
|
*
|
||||||
|
* Note: Please do not use the `setFileName` function directly, as it
|
||||||
|
* is not virtual and cannot be overridden.
|
||||||
|
*/
|
||||||
|
class PSaveFile : public QSaveFile {
|
||||||
|
public:
|
||||||
|
PSaveFile(const QString& name) : QSaveFile(name) { addPath(name); }
|
||||||
|
PSaveFile(const QString& name, QObject* parent) : QSaveFile(name, parent) { addPath(name); }
|
||||||
|
virtual ~PSaveFile()
|
||||||
|
{
|
||||||
|
if (auto app = APPLICATION_DYN) {
|
||||||
|
app->removeQSavePath(m_absoluteFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void addPath(const QString& path)
|
||||||
|
{
|
||||||
|
m_absoluteFilePath = QFileInfo(path).absoluteFilePath() + "."; // add dot for tmp files only
|
||||||
|
if (auto app = APPLICATION_DYN) {
|
||||||
|
app->addQSavePath(m_absoluteFilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QString m_absoluteFilePath;
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
#define PSaveFile QSaveFile
|
||||||
|
#endif
|
@ -81,9 +81,9 @@ QString getSupportedJavaArchitecture()
|
|||||||
if (arch == "arm64")
|
if (arch == "arm64")
|
||||||
return "mac-os-arm64";
|
return "mac-os-arm64";
|
||||||
if (arch.contains("64"))
|
if (arch.contains("64"))
|
||||||
return "mac-os-64";
|
return "mac-os-x64";
|
||||||
if (arch.contains("86"))
|
if (arch.contains("86"))
|
||||||
return "mac-os-86";
|
return "mac-os-x86";
|
||||||
// Unknown, maybe something new, appending arch
|
// Unknown, maybe something new, appending arch
|
||||||
return "mac-os-" + arch;
|
return "mac-os-" + arch;
|
||||||
} else if (sys == "linux") {
|
} else if (sys == "linux") {
|
||||||
|
@ -44,8 +44,8 @@
|
|||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include "java/JavaUtils.h"
|
#include "java/JavaUtils.h"
|
||||||
|
|
||||||
JavaChecker::JavaChecker(QString path, QString args, int minMem, int maxMem, int permGen, int id, QObject* parent)
|
JavaChecker::JavaChecker(QString path, QString args, int minMem, int maxMem, int permGen, int id)
|
||||||
: Task(parent), m_path(path), m_args(args), m_minMem(minMem), m_maxMem(maxMem), m_permGen(permGen), m_id(id)
|
: Task(), m_path(path), m_args(args), m_minMem(minMem), m_maxMem(maxMem), m_permGen(permGen), m_id(id)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void JavaChecker::executeTask()
|
void JavaChecker::executeTask()
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "JavaVersion.h"
|
#include "JavaVersion.h"
|
||||||
#include "QObjectPtr.h"
|
#include "QObjectPtr.h"
|
||||||
@ -26,7 +25,7 @@ class JavaChecker : public Task {
|
|||||||
enum class Validity { Errored, ReturnedInvalidData, Valid } validity = Validity::Errored;
|
enum class Validity { Errored, ReturnedInvalidData, Valid } validity = Validity::Errored;
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit JavaChecker(QString path, QString args, int minMem = 0, int maxMem = 0, int permGen = 0, int id = 0, QObject* parent = 0);
|
explicit JavaChecker(QString path, QString args, int minMem = 0, int maxMem = 0, int permGen = 0, int id = 0);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void checkFinished(const Result& result);
|
void checkFinished(const Result& result);
|
||||||
|
@ -163,7 +163,7 @@ void JavaListLoadTask::executeTask()
|
|||||||
JavaUtils ju;
|
JavaUtils ju;
|
||||||
QList<QString> candidate_paths = m_only_managed_versions ? getPrismJavaBundle() : ju.FindJavaPaths();
|
QList<QString> candidate_paths = m_only_managed_versions ? getPrismJavaBundle() : ju.FindJavaPaths();
|
||||||
|
|
||||||
ConcurrentTask::Ptr job(new ConcurrentTask(this, "Java detection", APPLICATION->settings()->get("NumberOfConcurrentTasks").toInt()));
|
ConcurrentTask::Ptr job(new ConcurrentTask("Java detection", APPLICATION->settings()->get("NumberOfConcurrentTasks").toInt()));
|
||||||
m_job.reset(job);
|
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);
|
||||||
@ -171,7 +171,7 @@ void JavaListLoadTask::executeTask()
|
|||||||
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) {
|
||||||
auto checker = new JavaChecker(candidate, "", 0, 0, 0, id, this);
|
auto checker = new JavaChecker(candidate, "", 0, 0, 0, id);
|
||||||
connect(checker, &JavaChecker::checkFinished, [this](const JavaChecker::Result& result) { m_results << result; });
|
connect(checker, &JavaChecker::checkFinished, [this](const JavaChecker::Result& result) { m_results << result; });
|
||||||
job->addTask(Task::Ptr(checker));
|
job->addTask(Task::Ptr(checker));
|
||||||
id++;
|
id++;
|
||||||
|
@ -102,6 +102,8 @@ QProcessEnvironment CleanEnviroment()
|
|||||||
QString newValue = stripVariableEntries(key, value, rawenv.value("LAUNCHER_" + key));
|
QString newValue = stripVariableEntries(key, value, rawenv.value("LAUNCHER_" + key));
|
||||||
|
|
||||||
qDebug() << "Env: stripped" << key << value << "to" << newValue;
|
qDebug() << "Env: stripped" << key << value << "to" << newValue;
|
||||||
|
|
||||||
|
value = newValue;
|
||||||
}
|
}
|
||||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
||||||
// Strip IBus
|
// Strip IBus
|
||||||
|
@ -86,11 +86,10 @@ void ManifestDownloadTask::downloadJava(const QJsonDocument& doc)
|
|||||||
if (type == "directory") {
|
if (type == "directory") {
|
||||||
FS::ensureFolderPathExists(file);
|
FS::ensureFolderPathExists(file);
|
||||||
} else if (type == "link") {
|
} else if (type == "link") {
|
||||||
// this is linux only !
|
// this is *nix only !
|
||||||
auto path = Json::ensureString(meta, "target");
|
auto path = Json::ensureString(meta, "target");
|
||||||
if (!path.isEmpty()) {
|
if (!path.isEmpty()) {
|
||||||
auto target = FS::PathCombine(file, "../" + path);
|
QFile::link(path, file);
|
||||||
QFile(target).link(file);
|
|
||||||
}
|
}
|
||||||
} else if (type == "file") {
|
} else if (type == "file") {
|
||||||
// TODO download compressed version if it exists ?
|
// TODO download compressed version if it exists ?
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
#include "LaunchStep.h"
|
#include "LaunchStep.h"
|
||||||
#include "LaunchTask.h"
|
#include "LaunchTask.h"
|
||||||
|
|
||||||
LaunchStep::LaunchStep(LaunchTask* parent) : Task(parent), m_parent(parent)
|
LaunchStep::LaunchStep(LaunchTask* parent) : Task(), m_parent(parent)
|
||||||
{
|
{
|
||||||
connect(this, &LaunchStep::readyForLaunch, parent, &LaunchTask::onReadyForLaunch);
|
connect(this, &LaunchStep::readyForLaunch, parent, &LaunchTask::onReadyForLaunch);
|
||||||
connect(this, &LaunchStep::logLine, parent, &LaunchTask::onLogLine);
|
connect(this, &LaunchStep::logLine, parent, &LaunchTask::onLogLine);
|
||||||
|
@ -94,7 +94,7 @@ 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(realJavaPath, "", 0, 0, 0, 0, this));
|
m_JavaChecker.reset(new JavaChecker(realJavaPath, "", 0, 0, 0, 0));
|
||||||
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->start();
|
m_JavaChecker->start();
|
||||||
|
@ -140,8 +140,8 @@ Task::Ptr Index::loadVersion(const QString& uid, const QString& version, Net::Mo
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto versionList = get(uid);
|
auto versionList = get(uid);
|
||||||
auto loadTask = makeShared<SequentialTask>(
|
auto loadTask =
|
||||||
this, tr("Load meta for %1:%2", "This is for the task name that loads the meta index.").arg(uid, version));
|
makeShared<SequentialTask>(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) {
|
if (status() != BaseEntity::LoadStatus::Remote || force) {
|
||||||
loadTask->addTask(this->loadTask(mode));
|
loadTask->addTask(this->loadTask(mode));
|
||||||
}
|
}
|
||||||
|
@ -34,8 +34,7 @@ VersionList::VersionList(const QString& uid, QObject* parent) : BaseVersionList(
|
|||||||
|
|
||||||
Task::Ptr VersionList::getLoadTask()
|
Task::Ptr VersionList::getLoadTask()
|
||||||
{
|
{
|
||||||
auto loadTask =
|
auto loadTask = makeShared<SequentialTask>(tr("Load meta for %1", "This is for the task name that loads the meta index.").arg(m_uid));
|
||||||
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(APPLICATION->metadataIndex()->loadTask(Net::Mode::Online));
|
||||||
loadTask->addTask(this->loadTask(Net::Mode::Online));
|
loadTask->addTask(this->loadTask(Net::Mode::Online));
|
||||||
return loadTask;
|
return loadTask;
|
||||||
|
@ -222,11 +222,12 @@ bool Component::isMoveable()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Component::isVersionChangeable()
|
bool Component::isVersionChangeable(bool wait)
|
||||||
{
|
{
|
||||||
auto list = getVersionList();
|
auto list = getVersionList();
|
||||||
if (list) {
|
if (list) {
|
||||||
list->waitToLoad();
|
if (wait)
|
||||||
|
list->waitToLoad();
|
||||||
return list->count() != 0;
|
return list->count() != 0;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -72,7 +72,7 @@ class Component : public QObject, public ProblemProvider {
|
|||||||
bool isRevertible();
|
bool isRevertible();
|
||||||
bool isRemovable();
|
bool isRemovable();
|
||||||
bool isCustom();
|
bool isCustom();
|
||||||
bool isVersionChangeable();
|
bool isVersionChangeable(bool wait = true);
|
||||||
bool isKnownModloader();
|
bool isKnownModloader();
|
||||||
QStringList knownConflictingComponents();
|
QStringList knownConflictingComponents();
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
* If the component list changes, start over.
|
* If the component list changes, start over.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ComponentUpdateTask::ComponentUpdateTask(Mode mode, Net::Mode netmode, PackProfile* list, QObject* parent) : Task(parent)
|
ComponentUpdateTask::ComponentUpdateTask(Mode mode, Net::Mode netmode, PackProfile* list) : Task()
|
||||||
{
|
{
|
||||||
d.reset(new ComponentUpdateTaskData);
|
d.reset(new ComponentUpdateTaskData);
|
||||||
d->m_profile = list;
|
d->m_profile = list;
|
||||||
|
@ -14,7 +14,7 @@ class ComponentUpdateTask : public Task {
|
|||||||
enum class Mode { Launch, Resolution };
|
enum class Mode { Launch, Resolution };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ComponentUpdateTask(Mode mode, Net::Mode netmode, PackProfile* list, QObject* parent = 0);
|
explicit ComponentUpdateTask(Mode mode, Net::Mode netmode, PackProfile* list);
|
||||||
virtual ~ComponentUpdateTask();
|
virtual ~ComponentUpdateTask();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -1141,7 +1141,7 @@ shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPt
|
|||||||
// load meta
|
// load meta
|
||||||
{
|
{
|
||||||
auto mode = session->status != AuthSession::PlayableOffline ? Net::Mode::Online : Net::Mode::Offline;
|
auto mode = session->status != AuthSession::PlayableOffline ? Net::Mode::Online : Net::Mode::Offline;
|
||||||
process->appendStep(makeShared<TaskStepWrapper>(pptr, makeShared<MinecraftLoadAndCheck>(this, mode, pptr)));
|
process->appendStep(makeShared<TaskStepWrapper>(pptr, makeShared<MinecraftLoadAndCheck>(this, mode)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// check java
|
// check java
|
||||||
|
@ -2,9 +2,7 @@
|
|||||||
#include "MinecraftInstance.h"
|
#include "MinecraftInstance.h"
|
||||||
#include "PackProfile.h"
|
#include "PackProfile.h"
|
||||||
|
|
||||||
MinecraftLoadAndCheck::MinecraftLoadAndCheck(MinecraftInstance* inst, Net::Mode netmode, QObject* parent)
|
MinecraftLoadAndCheck::MinecraftLoadAndCheck(MinecraftInstance* inst, Net::Mode netmode) : m_inst(inst), m_netmode(netmode) {}
|
||||||
: Task(parent), m_inst(inst), m_netmode(netmode)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void MinecraftLoadAndCheck::executeTask()
|
void MinecraftLoadAndCheck::executeTask()
|
||||||
{
|
{
|
||||||
|
@ -23,7 +23,7 @@ class MinecraftInstance;
|
|||||||
class MinecraftLoadAndCheck : public Task {
|
class MinecraftLoadAndCheck : public Task {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit MinecraftLoadAndCheck(MinecraftInstance* inst, Net::Mode netmode, QObject* parent = nullptr);
|
explicit MinecraftLoadAndCheck(MinecraftInstance* inst, Net::Mode netmode);
|
||||||
virtual ~MinecraftLoadAndCheck() = default;
|
virtual ~MinecraftLoadAndCheck() = default;
|
||||||
void executeTask() override;
|
void executeTask() override;
|
||||||
|
|
||||||
|
@ -38,7 +38,6 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
#include <QSaveFile>
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
#include <FileSystem.h>
|
#include <FileSystem.h>
|
||||||
@ -57,6 +56,7 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
|
#include "PSaveFile.h"
|
||||||
|
|
||||||
using std::nullopt;
|
using std::nullopt;
|
||||||
using std::optional;
|
using std::optional;
|
||||||
@ -183,7 +183,7 @@ bool putLevelDatDataToFS(const QFileInfo& file, QByteArray& data)
|
|||||||
if (fullFilePath.isNull()) {
|
if (fullFilePath.isNull()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
QSaveFile f(fullFilePath);
|
PSaveFile f(fullFilePath);
|
||||||
if (!f.open(QIODevice::WriteOnly)) {
|
if (!f.open(QIODevice::WriteOnly)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
#include <Application.h>
|
#include <Application.h>
|
||||||
|
|
||||||
AuthFlow::AuthFlow(AccountData* data, Action action, QObject* parent, const std::optional<QString> password) : Task(parent), m_data(data)
|
AuthFlow::AuthFlow(AccountData* data, Action action, const std::optional<QString> password) : Task(), m_data(data)
|
||||||
{
|
{
|
||||||
if (data->type == AccountType::MSA) {
|
if (data->type == AccountType::MSA) {
|
||||||
if (action == Action::DeviceCode) {
|
if (action == Action::DeviceCode) {
|
||||||
|
@ -20,7 +20,6 @@ class AuthFlow : public Task {
|
|||||||
|
|
||||||
explicit AuthFlow(AccountData* data,
|
explicit AuthFlow(AccountData* data,
|
||||||
Action action = Action::Refresh,
|
Action action = Action::Refresh,
|
||||||
QObject* parent = 0,
|
|
||||||
std::optional<QString> password = std::nullopt);
|
std::optional<QString> password = std::nullopt);
|
||||||
virtual ~AuthFlow() = default;
|
virtual ~AuthFlow() = default;
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@
|
|||||||
|
|
||||||
MinecraftAccount::MinecraftAccount(QObject* parent) : QObject(parent)
|
MinecraftAccount::MinecraftAccount(QObject* parent) : QObject(parent)
|
||||||
{
|
{
|
||||||
data.internalId = QUuid::createUuid().toString(QUuid::Id128);
|
data.internalId = QUuid::createUuid().toString().remove(QRegularExpression("[{}-]"));
|
||||||
}
|
}
|
||||||
|
|
||||||
MinecraftAccountPtr MinecraftAccount::loadFromJsonV3(const QJsonObject& json)
|
MinecraftAccountPtr MinecraftAccount::loadFromJsonV3(const QJsonObject& json)
|
||||||
@ -138,7 +138,7 @@ shared_qobject_ptr<AuthFlow> MinecraftAccount::login(bool useDeviceCode, std::op
|
|||||||
{
|
{
|
||||||
Q_ASSERT(m_currentTask.get() == nullptr);
|
Q_ASSERT(m_currentTask.get() == nullptr);
|
||||||
|
|
||||||
m_currentTask.reset(new AuthFlow(&data, useDeviceCode ? AuthFlow::Action::DeviceCode : AuthFlow::Action::Login, this, password));
|
m_currentTask.reset(new AuthFlow(&data, useDeviceCode ? AuthFlow::Action::DeviceCode : AuthFlow::Action::Login, password));
|
||||||
connect(m_currentTask.get(), &Task::succeeded, this, &MinecraftAccount::authSucceeded);
|
connect(m_currentTask.get(), &Task::succeeded, this, &MinecraftAccount::authSucceeded);
|
||||||
connect(m_currentTask.get(), &Task::failed, this, &MinecraftAccount::authFailed);
|
connect(m_currentTask.get(), &Task::failed, this, &MinecraftAccount::authFailed);
|
||||||
connect(m_currentTask.get(), &Task::aborted, this, [this] { authFailed(tr("Aborted")); });
|
connect(m_currentTask.get(), &Task::aborted, this, [this] { authFailed(tr("Aborted")); });
|
||||||
@ -152,7 +152,7 @@ shared_qobject_ptr<AuthFlow> MinecraftAccount::refresh()
|
|||||||
return m_currentTask;
|
return m_currentTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_currentTask.reset(new AuthFlow(&data, AuthFlow::Action::Refresh, this));
|
m_currentTask.reset(new AuthFlow(&data, AuthFlow::Action::Refresh));
|
||||||
|
|
||||||
connect(m_currentTask.get(), &Task::succeeded, this, &MinecraftAccount::authSucceeded);
|
connect(m_currentTask.get(), &Task::succeeded, this, &MinecraftAccount::authSucceeded);
|
||||||
connect(m_currentTask.get(), &Task::failed, this, &MinecraftAccount::authFailed);
|
connect(m_currentTask.get(), &Task::failed, this, &MinecraftAccount::authFailed);
|
||||||
|
@ -75,12 +75,12 @@ 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);
|
connect(m_task.get(), &Task::finished, this, &MSADeviceCodeStep::deviceAuthorizationFinished);
|
||||||
|
|
||||||
m_task->start();
|
m_task->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DeviceAutorizationResponse {
|
struct DeviceAuthorizationResponse {
|
||||||
QString device_code;
|
QString device_code;
|
||||||
QString user_code;
|
QString user_code;
|
||||||
QString verification_uri;
|
QString verification_uri;
|
||||||
@ -91,17 +91,17 @@ struct DeviceAutorizationResponse {
|
|||||||
QString error_description;
|
QString error_description;
|
||||||
};
|
};
|
||||||
|
|
||||||
DeviceAutorizationResponse parseDeviceAutorizationResponse(const QByteArray& data)
|
DeviceAuthorizationResponse parseDeviceAuthorizationResponse(const QByteArray& data)
|
||||||
{
|
{
|
||||||
QJsonParseError err;
|
QJsonParseError err;
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(data, &err);
|
QJsonDocument doc = QJsonDocument::fromJson(data, &err);
|
||||||
if (err.error != QJsonParseError::NoError) {
|
if (err.error != QJsonParseError::NoError) {
|
||||||
qWarning() << "Failed to parse device autorization response due to err:" << err.errorString();
|
qWarning() << "Failed to parse device authorization response due to err:" << err.errorString();
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!doc.isObject()) {
|
if (!doc.isObject()) {
|
||||||
qWarning() << "Device autorization response is not an object";
|
qWarning() << "Device authorization response is not an object";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto obj = doc.object();
|
auto obj = doc.object();
|
||||||
@ -112,9 +112,9 @@ DeviceAutorizationResponse parseDeviceAutorizationResponse(const QByteArray& dat
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void MSADeviceCodeStep::deviceAutorizationFinished()
|
void MSADeviceCodeStep::deviceAuthorizationFinished()
|
||||||
{
|
{
|
||||||
auto rsp = parseDeviceAutorizationResponse(*m_response);
|
auto rsp = parseDeviceAuthorizationResponse(*m_response);
|
||||||
if (!rsp.error.isEmpty() || !rsp.error_description.isEmpty()) {
|
if (!rsp.error.isEmpty() || !rsp.error_description.isEmpty()) {
|
||||||
qWarning() << "Device authorization failed:" << rsp.error;
|
qWarning() << "Device authorization failed:" << rsp.error;
|
||||||
emit finished(AccountTaskState::STATE_FAILED_HARD,
|
emit finished(AccountTaskState::STATE_FAILED_HARD,
|
||||||
@ -210,12 +210,12 @@ AuthenticationResponse parseAuthenticationResponse(const QByteArray& data)
|
|||||||
QJsonParseError err;
|
QJsonParseError err;
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(data, &err);
|
QJsonDocument doc = QJsonDocument::fromJson(data, &err);
|
||||||
if (err.error != QJsonParseError::NoError) {
|
if (err.error != QJsonParseError::NoError) {
|
||||||
qWarning() << "Failed to parse device autorization response due to err:" << err.errorString();
|
qWarning() << "Failed to parse device authorization response due to err:" << err.errorString();
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!doc.isObject()) {
|
if (!doc.isObject()) {
|
||||||
qWarning() << "Device autorization response is not an object";
|
qWarning() << "Device authorization response is not an object";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto obj = doc.object();
|
auto obj = doc.object();
|
||||||
|
@ -58,7 +58,7 @@ class MSADeviceCodeStep : public AuthStep {
|
|||||||
void authorizeWithBrowser(QString url, QString code, int expiresIn);
|
void authorizeWithBrowser(QString url, QString code, int expiresIn);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void deviceAutorizationFinished();
|
void deviceAuthorizationFinished();
|
||||||
void startPoolTimer();
|
void startPoolTimer();
|
||||||
void authenticateUser();
|
void authenticateUser();
|
||||||
void authenticationFinished();
|
void authenticationFinished();
|
||||||
|
@ -85,8 +85,7 @@ class CustomOAuthOobReplyHandler : public QOAuthOobReplyHandler {
|
|||||||
MSAStep::MSAStep(AccountData* data, bool silent) : AuthStep(data), m_silent(silent)
|
MSAStep::MSAStep(AccountData* data, bool silent) : AuthStep(data), m_silent(silent)
|
||||||
{
|
{
|
||||||
m_clientId = APPLICATION->getMSAClientID();
|
m_clientId = APPLICATION->getMSAClientID();
|
||||||
if (QCoreApplication::applicationFilePath().startsWith("/tmp/.mount_") ||
|
if (QCoreApplication::applicationFilePath().startsWith("/tmp/.mount_") || APPLICATION->isPortable() || !isSchemeHandlerRegistered())
|
||||||
QFile::exists(FS::PathCombine(APPLICATION->root(), "portable.txt")) || !isSchemeHandlerRegistered())
|
|
||||||
|
|
||||||
{
|
{
|
||||||
auto replyHandler = new QOAuthHttpServerReplyHandler(this);
|
auto replyHandler = new QOAuthHttpServerReplyHandler(this);
|
||||||
|
@ -57,9 +57,7 @@
|
|||||||
#include "tasks/SequentialTask.h"
|
#include "tasks/SequentialTask.h"
|
||||||
|
|
||||||
AutoInstallJava::AutoInstallJava(LaunchTask* parent)
|
AutoInstallJava::AutoInstallJava(LaunchTask* parent)
|
||||||
: LaunchStep(parent)
|
: LaunchStep(parent), m_instance(m_parent->instance()), m_supported_arch(SysInfo::getSupportedJavaArchitecture()) {};
|
||||||
, m_instance(m_parent->instance())
|
|
||||||
, m_supported_arch(SysInfo::getSupportedJavaArchitecture()) {};
|
|
||||||
|
|
||||||
void AutoInstallJava::executeTask()
|
void AutoInstallJava::executeTask()
|
||||||
{
|
{
|
||||||
@ -78,7 +76,7 @@ void AutoInstallJava::executeTask()
|
|||||||
auto java = std::dynamic_pointer_cast<JavaInstall>(javas->at(i));
|
auto java = std::dynamic_pointer_cast<JavaInstall>(javas->at(i));
|
||||||
if (java && packProfile->getProfile()->getCompatibleJavaMajors().contains(java->id.major())) {
|
if (java && packProfile->getProfile()->getCompatibleJavaMajors().contains(java->id.major())) {
|
||||||
if (!java->is_64bit) {
|
if (!java->is_64bit) {
|
||||||
emit logLine(tr("The automatic Java mechanism detected a 32-bit installation of Java."), MessageLevel::Info);
|
emit logLine(tr("The automatic Java mechanism detected a 32-bit installation of Java."), MessageLevel::Launcher);
|
||||||
}
|
}
|
||||||
setJavaPath(java->path);
|
setJavaPath(java->path);
|
||||||
return;
|
return;
|
||||||
@ -136,7 +134,7 @@ void AutoInstallJava::setJavaPath(QString path)
|
|||||||
settings->set("OverrideJavaLocation", true);
|
settings->set("OverrideJavaLocation", true);
|
||||||
settings->set("JavaPath", path);
|
settings->set("JavaPath", path);
|
||||||
settings->set("AutomaticJava", true);
|
settings->set("AutomaticJava", true);
|
||||||
emit logLine(tr("Compatible Java found at: %1.").arg(path), MessageLevel::Info);
|
emit logLine(tr("Compatible Java found at: %1.").arg(path), MessageLevel::Launcher);
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,7 +177,7 @@ void AutoInstallJava::downloadJava(Meta::Version::Ptr version, QString javaName)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#if defined(Q_OS_MACOS)
|
#if defined(Q_OS_MACOS)
|
||||||
auto seq = makeShared<SequentialTask>(this, tr("Install Java"));
|
auto seq = makeShared<SequentialTask>(tr("Install Java"));
|
||||||
seq->addTask(m_current_task);
|
seq->addTask(m_current_task);
|
||||||
seq->addTask(makeShared<Java::SymlinkTask>(final_path));
|
seq->addTask(makeShared<Java::SymlinkTask>(final_path));
|
||||||
m_current_task = seq;
|
m_current_task = seq;
|
||||||
|
@ -261,7 +261,7 @@ bool ResourceFolderModel::update()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResourceFolderModel::resolveResource(Resource* res)
|
void ResourceFolderModel::resolveResource(Resource::Ptr res)
|
||||||
{
|
{
|
||||||
if (!res->shouldResolve()) {
|
if (!res->shouldResolve()) {
|
||||||
return;
|
return;
|
||||||
@ -277,11 +277,14 @@ void ResourceFolderModel::resolveResource(Resource* res)
|
|||||||
m_active_parse_tasks.insert(ticket, task);
|
m_active_parse_tasks.insert(ticket, task);
|
||||||
|
|
||||||
connect(
|
connect(
|
||||||
task.get(), &Task::succeeded, this, [=] { onParseSucceeded(ticket, res->internal_id()); }, Qt::ConnectionType::QueuedConnection);
|
task.get(), &Task::succeeded, this, [this, ticket, res] { onParseSucceeded(ticket, res->internal_id()); },
|
||||||
connect(task.get(), &Task::failed, this, [=] { onParseFailed(ticket, res->internal_id()); }, Qt::ConnectionType::QueuedConnection);
|
Qt::ConnectionType::QueuedConnection);
|
||||||
|
connect(
|
||||||
|
task.get(), &Task::failed, this, [this, ticket, res] { onParseFailed(ticket, res->internal_id()); },
|
||||||
|
Qt::ConnectionType::QueuedConnection);
|
||||||
connect(
|
connect(
|
||||||
task.get(), &Task::finished, this,
|
task.get(), &Task::finished, this,
|
||||||
[=] {
|
[this, ticket] {
|
||||||
m_active_parse_tasks.remove(ticket);
|
m_active_parse_tasks.remove(ticket);
|
||||||
emit parseFinished();
|
emit parseFinished();
|
||||||
},
|
},
|
||||||
@ -317,7 +320,7 @@ void ResourceFolderModel::onUpdateSucceeded()
|
|||||||
void ResourceFolderModel::onParseSucceeded(int ticket, QString resource_id)
|
void ResourceFolderModel::onParseSucceeded(int ticket, QString resource_id)
|
||||||
{
|
{
|
||||||
auto iter = m_active_parse_tasks.constFind(ticket);
|
auto iter = m_active_parse_tasks.constFind(ticket);
|
||||||
if (iter == m_active_parse_tasks.constEnd())
|
if (iter == m_active_parse_tasks.constEnd() || !m_resources_index.contains(resource_id))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int row = m_resources_index[resource_id];
|
int row = m_resources_index[resource_id];
|
||||||
@ -629,7 +632,7 @@ QString ResourceFolderModel::instDirPath() const
|
|||||||
void ResourceFolderModel::onParseFailed(int ticket, QString resource_id)
|
void ResourceFolderModel::onParseFailed(int ticket, QString resource_id)
|
||||||
{
|
{
|
||||||
auto iter = m_active_parse_tasks.constFind(ticket);
|
auto iter = m_active_parse_tasks.constFind(ticket);
|
||||||
if (iter == m_active_parse_tasks.constEnd())
|
if (iter == m_active_parse_tasks.constEnd() || !m_resources_index.contains(resource_id))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto removed_index = m_resources_index[resource_id];
|
auto removed_index = m_resources_index[resource_id];
|
||||||
|
@ -76,7 +76,7 @@ class ResourceFolderModel : public QAbstractListModel {
|
|||||||
virtual bool update();
|
virtual bool update();
|
||||||
|
|
||||||
/** Creates a new parse task, if needed, for 'res' and start it.*/
|
/** Creates a new parse task, if needed, for 'res' and start it.*/
|
||||||
virtual void resolveResource(Resource* res);
|
virtual void resolveResource(Resource::Ptr res);
|
||||||
|
|
||||||
[[nodiscard]] qsizetype size() const { return m_resources.size(); }
|
[[nodiscard]] qsizetype size() const { return m_resources.size(); }
|
||||||
[[nodiscard]] bool empty() const { return size() == 0; }
|
[[nodiscard]] bool empty() const { return size() == 0; }
|
||||||
@ -285,7 +285,7 @@ void ResourceFolderModel::applyUpdates(QSet<QString>& current_set, QSet<QString>
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_resources[row].reset(new_resource);
|
m_resources[row].reset(new_resource);
|
||||||
resolveResource(m_resources.at(row).get());
|
resolveResource(m_resources.at(row));
|
||||||
emit dataChanged(index(row, 0), index(row, columnCount(QModelIndex()) - 1));
|
emit dataChanged(index(row, 0), index(row, columnCount(QModelIndex()) - 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -333,7 +333,7 @@ void ResourceFolderModel::applyUpdates(QSet<QString>& current_set, QSet<QString>
|
|||||||
for (auto& added : added_set) {
|
for (auto& added : added_set) {
|
||||||
auto res = new_resources[added];
|
auto res = new_resources[added];
|
||||||
m_resources.append(res);
|
m_resources.append(res);
|
||||||
resolveResource(m_resources.last().get());
|
resolveResource(m_resources.last());
|
||||||
}
|
}
|
||||||
|
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include "minecraft/mod/Resource.h"
|
#include "minecraft/mod/Resource.h"
|
||||||
|
|
||||||
@ -25,16 +26,12 @@ class BasicFolderLoadTask : public Task {
|
|||||||
[[nodiscard]] ResultPtr result() const { return m_result; }
|
[[nodiscard]] ResultPtr result() const { return m_result; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BasicFolderLoadTask(QDir dir) : Task(nullptr, false), m_dir(dir), m_result(new Result), m_thread_to_spawn_into(thread())
|
BasicFolderLoadTask(QDir dir) : Task(false), m_dir(dir), m_result(new Result), m_thread_to_spawn_into(thread())
|
||||||
{
|
{
|
||||||
m_create_func = [](QFileInfo const& entry) -> Resource::Ptr { return makeShared<Resource>(entry); };
|
m_create_func = [](QFileInfo const& entry) -> Resource::Ptr { return makeShared<Resource>(entry); };
|
||||||
}
|
}
|
||||||
BasicFolderLoadTask(QDir dir, std::function<Resource::Ptr(QFileInfo const&)> create_function)
|
BasicFolderLoadTask(QDir dir, std::function<Resource::Ptr(QFileInfo const&)> create_function)
|
||||||
: Task(nullptr, false)
|
: Task(false), m_dir(dir), m_result(new Result), m_create_func(std::move(create_function)), m_thread_to_spawn_into(thread())
|
||||||
, m_dir(dir)
|
|
||||||
, m_result(new Result)
|
|
||||||
, m_create_func(std::move(create_function))
|
|
||||||
, m_thread_to_spawn_into(thread())
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
[[nodiscard]] bool canAbort() const override { return true; }
|
[[nodiscard]] bool canAbort() const override { return true; }
|
||||||
@ -52,6 +49,9 @@ class BasicFolderLoadTask : public Task {
|
|||||||
m_dir.refresh();
|
m_dir.refresh();
|
||||||
for (auto entry : m_dir.entryInfoList()) {
|
for (auto entry : m_dir.entryInfoList()) {
|
||||||
auto filePath = entry.absoluteFilePath();
|
auto filePath = entry.absoluteFilePath();
|
||||||
|
if (auto app = APPLICATION_DYN; app && app->checkQSavePath(filePath)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
auto newFilePath = FS::getUniqueResourceName(filePath);
|
auto newFilePath = FS::getUniqueResourceName(filePath);
|
||||||
if (newFilePath != filePath) {
|
if (newFilePath != filePath) {
|
||||||
FS::move(filePath, newFilePath);
|
FS::move(filePath, newFilePath);
|
||||||
|
@ -52,11 +52,10 @@ static bool checkDependencies(std::shared_ptr<GetModDependenciesTask::PackDepend
|
|||||||
(!loaders || !sel->version.loaders || sel->version.loaders & loaders);
|
(!loaders || !sel->version.loaders || sel->version.loaders & loaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
GetModDependenciesTask::GetModDependenciesTask(QObject* parent,
|
GetModDependenciesTask::GetModDependenciesTask(BaseInstance* instance,
|
||||||
BaseInstance* instance,
|
|
||||||
ModFolderModel* folder,
|
ModFolderModel* folder,
|
||||||
QList<std::shared_ptr<PackDependency>> selected)
|
QList<std::shared_ptr<PackDependency>> selected)
|
||||||
: SequentialTask(parent, tr("Get dependencies"))
|
: SequentialTask(tr("Get dependencies"))
|
||||||
, m_selected(selected)
|
, m_selected(selected)
|
||||||
, m_flame_provider{ ModPlatform::ResourceProvider::FLAME, std::make_shared<ResourceDownload::FlameModModel>(*instance),
|
, m_flame_provider{ ModPlatform::ResourceProvider::FLAME, std::make_shared<ResourceDownload::FlameModModel>(*instance),
|
||||||
std::make_shared<FlameAPI>() }
|
std::make_shared<FlameAPI>() }
|
||||||
@ -185,7 +184,7 @@ Task::Ptr GetModDependenciesTask::prepareDependencyTask(const ModPlatform::Depen
|
|||||||
auto provider = providerName == m_flame_provider.name ? m_flame_provider : m_modrinth_provider;
|
auto provider = providerName == m_flame_provider.name ? m_flame_provider : m_modrinth_provider;
|
||||||
|
|
||||||
auto tasks = makeShared<SequentialTask>(
|
auto tasks = makeShared<SequentialTask>(
|
||||||
this, QString("DependencyInfo: %1").arg(dep.addonId.toString().isEmpty() ? dep.version : dep.addonId.toString()));
|
QString("DependencyInfo: %1").arg(dep.addonId.toString().isEmpty() ? dep.version : dep.addonId.toString()));
|
||||||
|
|
||||||
if (!dep.addonId.toString().isEmpty()) {
|
if (!dep.addonId.toString().isEmpty()) {
|
||||||
tasks->addTask(getProjectInfoTask(pDep));
|
tasks->addTask(getProjectInfoTask(pDep));
|
||||||
|
@ -61,10 +61,7 @@ class GetModDependenciesTask : public SequentialTask {
|
|||||||
std::shared_ptr<ResourceAPI> api;
|
std::shared_ptr<ResourceAPI> api;
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit GetModDependenciesTask(QObject* parent,
|
explicit GetModDependenciesTask(BaseInstance* instance, ModFolderModel* folder, QList<std::shared_ptr<PackDependency>> selected);
|
||||||
BaseInstance* instance,
|
|
||||||
ModFolderModel* folder,
|
|
||||||
QList<std::shared_ptr<PackDependency>> selected);
|
|
||||||
|
|
||||||
auto getDependecies() const -> QList<std::shared_ptr<PackDependency>> { return m_pack_dependencies; }
|
auto getDependecies() const -> QList<std::shared_ptr<PackDependency>> { return m_pack_dependencies; }
|
||||||
QHash<QString, PackDependencyExtraInfo> getExtraInfo();
|
QHash<QString, PackDependencyExtraInfo> getExtraInfo();
|
||||||
|
@ -157,7 +157,7 @@ bool validate(QFileInfo file)
|
|||||||
|
|
||||||
} // namespace DataPackUtils
|
} // namespace DataPackUtils
|
||||||
|
|
||||||
LocalDataPackParseTask::LocalDataPackParseTask(int token, DataPack& dp) : Task(nullptr, false), m_token(token), m_data_pack(dp) {}
|
LocalDataPackParseTask::LocalDataPackParseTask(int token, DataPack& dp) : Task(false), m_token(token), m_data_pack(dp) {}
|
||||||
|
|
||||||
bool LocalDataPackParseTask::abort()
|
bool LocalDataPackParseTask::abort()
|
||||||
{
|
{
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QJsonValue>
|
#include <QJsonValue>
|
||||||
|
#include <QRegularExpression>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
@ -15,6 +16,8 @@
|
|||||||
#include "minecraft/mod/ModDetails.h"
|
#include "minecraft/mod/ModDetails.h"
|
||||||
#include "settings/INIFile.h"
|
#include "settings/INIFile.h"
|
||||||
|
|
||||||
|
static QRegularExpression newlineRegex("\r\n|\n|\r");
|
||||||
|
|
||||||
namespace ModUtils {
|
namespace ModUtils {
|
||||||
|
|
||||||
// NEW format
|
// NEW format
|
||||||
@ -487,11 +490,11 @@ bool processZIP(Mod& mod, [[maybe_unused]] ProcessingLevel level)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// quick and dirty line-by-line parser
|
// quick and dirty line-by-line parser
|
||||||
auto manifestLines = file.readAll().split('\n');
|
auto manifestLines = QString(file.readAll()).split(newlineRegex);
|
||||||
QString manifestVersion = "";
|
QString manifestVersion = "";
|
||||||
for (auto& line : manifestLines) {
|
for (auto& line : manifestLines) {
|
||||||
if (QString(line).startsWith("Implementation-Version: ")) {
|
if (line.startsWith("Implementation-Version: ", Qt::CaseInsensitive)) {
|
||||||
manifestVersion = QString(line).remove("Implementation-Version: ");
|
manifestVersion = line.remove("Implementation-Version: ", Qt::CaseInsensitive);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -730,7 +733,7 @@ bool loadIconFile(const Mod& mod, QPixmap* pixmap)
|
|||||||
} // namespace ModUtils
|
} // namespace ModUtils
|
||||||
|
|
||||||
LocalModParseTask::LocalModParseTask(int token, ResourceType type, const QFileInfo& modFile)
|
LocalModParseTask::LocalModParseTask(int token, ResourceType type, const QFileInfo& modFile)
|
||||||
: Task(nullptr, false), m_token(token), m_type(type), m_modFile(modFile), m_result(new Result())
|
: Task(false), m_token(token), m_type(type), m_modFile(modFile), m_result(new Result())
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool LocalModParseTask::abort()
|
bool LocalModParseTask::abort()
|
||||||
|
@ -358,9 +358,7 @@ bool validate(QFileInfo file)
|
|||||||
|
|
||||||
} // namespace ResourcePackUtils
|
} // namespace ResourcePackUtils
|
||||||
|
|
||||||
LocalResourcePackParseTask::LocalResourcePackParseTask(int token, ResourcePack& rp)
|
LocalResourcePackParseTask::LocalResourcePackParseTask(int token, ResourcePack& rp) : Task(false), m_token(token), m_resource_pack(rp) {}
|
||||||
: Task(nullptr, false), m_token(token), m_resource_pack(rp)
|
|
||||||
{}
|
|
||||||
|
|
||||||
bool LocalResourcePackParseTask::abort()
|
bool LocalResourcePackParseTask::abort()
|
||||||
{
|
{
|
||||||
|
@ -93,7 +93,7 @@ bool validate(QFileInfo file)
|
|||||||
|
|
||||||
} // namespace ShaderPackUtils
|
} // namespace ShaderPackUtils
|
||||||
|
|
||||||
LocalShaderPackParseTask::LocalShaderPackParseTask(int token, ShaderPack& sp) : Task(nullptr, false), m_token(token), m_shader_pack(sp) {}
|
LocalShaderPackParseTask::LocalShaderPackParseTask(int token, ShaderPack& sp) : Task(false), m_token(token), m_shader_pack(sp) {}
|
||||||
|
|
||||||
bool LocalShaderPackParseTask::abort()
|
bool LocalShaderPackParseTask::abort()
|
||||||
{
|
{
|
||||||
|
@ -230,8 +230,7 @@ bool validate(QFileInfo file)
|
|||||||
|
|
||||||
} // namespace TexturePackUtils
|
} // namespace TexturePackUtils
|
||||||
|
|
||||||
LocalTexturePackParseTask::LocalTexturePackParseTask(int token, TexturePack& rp) : Task(nullptr, false), m_token(token), m_texture_pack(rp)
|
LocalTexturePackParseTask::LocalTexturePackParseTask(int token, TexturePack& rp) : Task(false), m_token(token), m_texture_pack(rp) {}
|
||||||
{}
|
|
||||||
|
|
||||||
bool LocalTexturePackParseTask::abort()
|
bool LocalTexturePackParseTask::abort()
|
||||||
{
|
{
|
||||||
|
@ -170,7 +170,7 @@ bool validate(QFileInfo file)
|
|||||||
|
|
||||||
} // namespace WorldSaveUtils
|
} // namespace WorldSaveUtils
|
||||||
|
|
||||||
LocalWorldSaveParseTask::LocalWorldSaveParseTask(int token, WorldSave& save) : Task(nullptr, false), m_token(token), m_save(save) {}
|
LocalWorldSaveParseTask::LocalWorldSaveParseTask(int token, WorldSave& save) : Task(false), m_token(token), m_save(save) {}
|
||||||
|
|
||||||
bool LocalWorldSaveParseTask::abort()
|
bool LocalWorldSaveParseTask::abort()
|
||||||
{
|
{
|
||||||
|
@ -36,13 +36,14 @@
|
|||||||
|
|
||||||
#include "ModFolderLoadTask.h"
|
#include "ModFolderLoadTask.h"
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include "minecraft/mod/MetadataHandler.h"
|
#include "minecraft/mod/MetadataHandler.h"
|
||||||
|
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
|
||||||
ModFolderLoadTask::ModFolderLoadTask(QDir mods_dir, QDir index_dir, bool is_indexed, bool clean_orphan)
|
ModFolderLoadTask::ModFolderLoadTask(QDir mods_dir, QDir index_dir, bool is_indexed, bool clean_orphan)
|
||||||
: Task(nullptr, false)
|
: Task(false)
|
||||||
, m_mods_dir(mods_dir)
|
, m_mods_dir(mods_dir)
|
||||||
, m_index_dir(index_dir)
|
, m_index_dir(index_dir)
|
||||||
, m_is_indexed(is_indexed)
|
, m_is_indexed(is_indexed)
|
||||||
@ -65,6 +66,9 @@ void ModFolderLoadTask::executeTask()
|
|||||||
m_mods_dir.refresh();
|
m_mods_dir.refresh();
|
||||||
for (auto entry : m_mods_dir.entryInfoList()) {
|
for (auto entry : m_mods_dir.entryInfoList()) {
|
||||||
auto filePath = entry.absoluteFilePath();
|
auto filePath = entry.absoluteFilePath();
|
||||||
|
if (auto app = APPLICATION_DYN; app && app->checkQSavePath(filePath)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
auto newFilePath = FS::getUniqueResourceName(filePath);
|
auto newFilePath = FS::getUniqueResourceName(filePath);
|
||||||
if (newFilePath != filePath) {
|
if (newFilePath != filePath) {
|
||||||
FS::move(filePath, newFilePath);
|
FS::move(filePath, newFilePath);
|
||||||
|
@ -16,7 +16,7 @@ class CheckUpdateTask : public Task {
|
|||||||
std::list<Version>& mcVersions,
|
std::list<Version>& mcVersions,
|
||||||
QList<ModPlatform::ModLoaderType> loadersList,
|
QList<ModPlatform::ModLoaderType> loadersList,
|
||||||
std::shared_ptr<ModFolderModel> mods_folder)
|
std::shared_ptr<ModFolderModel> mods_folder)
|
||||||
: Task(nullptr), m_mods(mods), m_game_versions(mcVersions), m_loaders_list(loadersList), m_mods_folder(mods_folder) {};
|
: Task(), m_mods(mods), m_game_versions(mcVersions), m_loaders_list(loadersList), m_mods_folder(mods_folder) {};
|
||||||
|
|
||||||
struct UpdatableMod {
|
struct UpdatableMod {
|
||||||
QString name;
|
QString name;
|
||||||
|
@ -19,31 +19,32 @@ static ModrinthAPI modrinth_api;
|
|||||||
static FlameAPI flame_api;
|
static FlameAPI flame_api;
|
||||||
|
|
||||||
EnsureMetadataTask::EnsureMetadataTask(Mod* mod, QDir dir, ModPlatform::ResourceProvider prov)
|
EnsureMetadataTask::EnsureMetadataTask(Mod* mod, QDir dir, ModPlatform::ResourceProvider prov)
|
||||||
: Task(nullptr), m_index_dir(dir), m_provider(prov), m_hashing_task(nullptr), m_current_task(nullptr)
|
: Task(), m_index_dir(dir), m_provider(prov), m_hashingTask(nullptr), m_current_task(nullptr)
|
||||||
{
|
{
|
||||||
auto hash_task = createNewHash(mod);
|
auto hashTask = createNewHash(mod);
|
||||||
if (!hash_task)
|
if (!hashTask)
|
||||||
return;
|
return;
|
||||||
connect(hash_task.get(), &Hashing::Hasher::resultsReady, [this, mod](QString hash) { m_mods.insert(hash, mod); });
|
connect(hashTask.get(), &Hashing::Hasher::resultsReady, [this, mod](QString hash) { m_mods.insert(hash, mod); });
|
||||||
connect(hash_task.get(), &Task::failed, [this, mod] { emitFail(mod, "", RemoveFromList::No); });
|
connect(hashTask.get(), &Task::failed, [this, mod] { emitFail(mod, "", RemoveFromList::No); });
|
||||||
hash_task->start();
|
m_hashingTask = hashTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
EnsureMetadataTask::EnsureMetadataTask(QList<Mod*>& mods, QDir dir, ModPlatform::ResourceProvider prov)
|
EnsureMetadataTask::EnsureMetadataTask(QList<Mod*>& mods, QDir dir, ModPlatform::ResourceProvider prov)
|
||||||
: Task(nullptr), m_index_dir(dir), m_provider(prov), m_current_task(nullptr)
|
: Task(), m_index_dir(dir), m_provider(prov), m_current_task(nullptr)
|
||||||
{
|
{
|
||||||
m_hashing_task.reset(new ConcurrentTask(this, "MakeHashesTask", APPLICATION->settings()->get("NumberOfConcurrentTasks").toInt()));
|
auto hashTask = makeShared<ConcurrentTask>("MakeHashesTask", APPLICATION->settings()->get("NumberOfConcurrentTasks").toInt());
|
||||||
|
m_hashingTask = hashTask;
|
||||||
for (auto* mod : mods) {
|
for (auto* mod : mods) {
|
||||||
auto hash_task = createNewHash(mod);
|
auto hash_task = createNewHash(mod);
|
||||||
if (!hash_task)
|
if (!hash_task)
|
||||||
continue;
|
continue;
|
||||||
connect(hash_task.get(), &Hashing::Hasher::resultsReady, [this, mod](QString hash) { m_mods.insert(hash, mod); });
|
connect(hash_task.get(), &Hashing::Hasher::resultsReady, [this, mod](QString hash) { m_mods.insert(hash, mod); });
|
||||||
connect(hash_task.get(), &Task::failed, [this, mod] { emitFail(mod, "", RemoveFromList::No); });
|
connect(hash_task.get(), &Task::failed, [this, mod] { emitFail(mod, "", RemoveFromList::No); });
|
||||||
m_hashing_task->addTask(hash_task);
|
hashTask->addTask(hash_task);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EnsureMetadataTask::EnsureMetadataTask(QHash<QString, Mod*>& mods, QDir dir, ModPlatform::ResourceProvider prov)
|
EnsureMetadataTask::EnsureMetadataTask(QHash<QString, Mod*>& mods, QDir dir, ModPlatform::ResourceProvider prov)
|
||||||
: Task(nullptr), m_mods(mods), m_index_dir(dir), m_provider(prov), m_current_task(nullptr)
|
: Task(), m_mods(mods), m_index_dir(dir), m_provider(prov), m_current_task(nullptr)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Hashing::Hasher::Ptr EnsureMetadataTask::createNewHash(Mod* mod)
|
Hashing::Hasher::Ptr EnsureMetadataTask::createNewHash(Mod* mod)
|
||||||
|
@ -20,7 +20,7 @@ class EnsureMetadataTask : public Task {
|
|||||||
|
|
||||||
~EnsureMetadataTask() = default;
|
~EnsureMetadataTask() = default;
|
||||||
|
|
||||||
Task::Ptr getHashingTask() { return m_hashing_task; }
|
Task::Ptr getHashingTask() { return m_hashingTask; }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
bool abort() override;
|
bool abort() override;
|
||||||
@ -58,6 +58,6 @@ class EnsureMetadataTask : public Task {
|
|||||||
ModPlatform::ResourceProvider m_provider;
|
ModPlatform::ResourceProvider m_provider;
|
||||||
|
|
||||||
QHash<QString, ModPlatform::IndexedVersion> m_temp_versions;
|
QHash<QString, ModPlatform::IndexedVersion> m_temp_versions;
|
||||||
ConcurrentTask::Ptr m_hashing_task;
|
Task::Ptr m_hashingTask;
|
||||||
Task::Ptr m_current_task;
|
Task::Ptr m_current_task;
|
||||||
};
|
};
|
||||||
|
@ -31,6 +31,19 @@ static const QMap<QString, IndexedVersionType::VersionType> s_indexed_version_ty
|
|||||||
{ "alpha", IndexedVersionType::VersionType::Alpha }
|
{ "alpha", IndexedVersionType::VersionType::Alpha }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const QList<ModLoaderType> loaderList = { NeoForge, Forge, Cauldron, LiteLoader, Quilt, Fabric };
|
||||||
|
|
||||||
|
QList<ModLoaderType> modLoaderTypesToList(ModLoaderTypes flags)
|
||||||
|
{
|
||||||
|
QList<ModLoaderType> flagList;
|
||||||
|
for (auto flag : loaderList) {
|
||||||
|
if (flags.testFlag(flag)) {
|
||||||
|
flagList.append(flag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return flagList;
|
||||||
|
}
|
||||||
|
|
||||||
IndexedVersionType::IndexedVersionType(const QString& type) : IndexedVersionType(enumFromString(type)) {}
|
IndexedVersionType::IndexedVersionType(const QString& type) : IndexedVersionType(enumFromString(type)) {}
|
||||||
|
|
||||||
IndexedVersionType::IndexedVersionType(const IndexedVersionType::VersionType& type)
|
IndexedVersionType::IndexedVersionType(const IndexedVersionType::VersionType& type)
|
||||||
|
@ -32,6 +32,7 @@ namespace ModPlatform {
|
|||||||
|
|
||||||
enum ModLoaderType { NeoForge = 1 << 0, Forge = 1 << 1, Cauldron = 1 << 2, LiteLoader = 1 << 3, Fabric = 1 << 4, Quilt = 1 << 5 };
|
enum ModLoaderType { NeoForge = 1 << 0, Forge = 1 << 1, Cauldron = 1 << 2, LiteLoader = 1 << 3, Fabric = 1 << 4, Quilt = 1 << 5 };
|
||||||
Q_DECLARE_FLAGS(ModLoaderTypes, ModLoaderType)
|
Q_DECLARE_FLAGS(ModLoaderTypes, ModLoaderType)
|
||||||
|
QList<ModLoaderType> modLoaderTypesToList(ModLoaderTypes flags);
|
||||||
|
|
||||||
enum class ResourceProvider { MODRINTH, FLAME };
|
enum class ResourceProvider { MODRINTH, FLAME };
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ void Flame::FileResolvingTask::netJobFinished()
|
|||||||
<< " reason: " << parse_error.errorString();
|
<< " reason: " << parse_error.errorString();
|
||||||
qWarning() << *m_result;
|
qWarning() << *m_result;
|
||||||
|
|
||||||
failed(parse_error.errorString());
|
getFlameProjects();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,21 +270,35 @@ std::optional<ModPlatform::IndexedVersion> FlameAPI::getLatestVersion(QList<ModP
|
|||||||
QList<ModPlatform::ModLoaderType> instanceLoaders,
|
QList<ModPlatform::ModLoaderType> instanceLoaders,
|
||||||
ModPlatform::ModLoaderTypes modLoaders)
|
ModPlatform::ModLoaderTypes modLoaders)
|
||||||
{
|
{
|
||||||
// edge case: mod has installed for forge but the instance is fabric => fabric version will be prioritizated on update
|
QHash<ModPlatform::ModLoaderType, ModPlatform::IndexedVersion> bestMatch;
|
||||||
auto bestVersion = [&versions](ModPlatform::ModLoaderTypes loader) {
|
auto checkVersion = [&bestMatch](const ModPlatform::IndexedVersion& version, const ModPlatform::ModLoaderType& loader) {
|
||||||
std::optional<ModPlatform::IndexedVersion> ver;
|
if (bestMatch.contains(loader)) {
|
||||||
for (auto file_tmp : versions) {
|
auto best = bestMatch.value(loader);
|
||||||
if (file_tmp.loaders & loader && (!ver.has_value() || file_tmp.date > ver->date)) {
|
if (version.date > best.date) {
|
||||||
ver = file_tmp;
|
bestMatch[loader] = version;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bestMatch[loader] = version;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for (auto file_tmp : versions) {
|
||||||
|
auto loaders = ModPlatform::modLoaderTypesToList(file_tmp.loaders);
|
||||||
|
if (loaders.isEmpty()) {
|
||||||
|
checkVersion(file_tmp, ModPlatform::ModLoaderType(0));
|
||||||
|
} else {
|
||||||
|
for (auto loader : loaders) {
|
||||||
|
checkVersion(file_tmp, loader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ver;
|
}
|
||||||
};
|
// edge case: mod has installed for forge but the instance is fabric => fabric version will be prioritizated on update
|
||||||
for (auto l : instanceLoaders) {
|
auto currentLoaders = instanceLoaders + ModPlatform::modLoaderTypesToList(modLoaders);
|
||||||
auto ver = bestVersion(l);
|
currentLoaders.append(ModPlatform::ModLoaderType(0)); // add a fallback in case the versions do not define a loader
|
||||||
if (ver.has_value()) {
|
|
||||||
return ver;
|
for (auto loader : currentLoaders) {
|
||||||
|
if (bestMatch.contains(loader)) {
|
||||||
|
return bestMatch.value(loader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return bestVersion(modLoaders);
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -444,6 +444,7 @@ bool FlameCreationTask::createInstance()
|
|||||||
setError(tr("Unable to resolve mod IDs:\n") + reason);
|
setError(tr("Unable to resolve mod IDs:\n") + reason);
|
||||||
loop.quit();
|
loop.quit();
|
||||||
});
|
});
|
||||||
|
connect(m_mod_id_resolver.get(), &Flame::FileResolvingTask::aborted, &loop, &QEventLoop::quit);
|
||||||
connect(m_mod_id_resolver.get(), &Flame::FileResolvingTask::progress, this, &FlameCreationTask::setProgress);
|
connect(m_mod_id_resolver.get(), &Flame::FileResolvingTask::progress, this, &FlameCreationTask::setProgress);
|
||||||
connect(m_mod_id_resolver.get(), &Flame::FileResolvingTask::status, this, &FlameCreationTask::setStatus);
|
connect(m_mod_id_resolver.get(), &Flame::FileResolvingTask::status, this, &FlameCreationTask::setStatus);
|
||||||
connect(m_mod_id_resolver.get(), &Flame::FileResolvingTask::stepProgress, this, &FlameCreationTask::propagateStepProgress);
|
connect(m_mod_id_resolver.get(), &Flame::FileResolvingTask::stepProgress, this, &FlameCreationTask::propagateStepProgress);
|
||||||
@ -676,7 +677,7 @@ void FlameCreationTask::validateZIPResources(QEventLoop& loop)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto task = makeShared<ConcurrentTask>(this, "CreateModMetadata", APPLICATION->settings()->get("NumberOfConcurrentTasks").toInt());
|
auto task = makeShared<ConcurrentTask>("CreateModMetadata", APPLICATION->settings()->get("NumberOfConcurrentTasks").toInt());
|
||||||
auto results = m_mod_id_resolver->getResults().files;
|
auto results = m_mod_id_resolver->getResults().files;
|
||||||
auto folder = FS::PathCombine(m_stagingPath, "minecraft", "mods", ".index");
|
auto folder = FS::PathCombine(m_stagingPath, "minecraft", "mods", ".index");
|
||||||
for (auto file : results) {
|
for (auto file : results) {
|
||||||
|
@ -103,8 +103,7 @@ void FlamePackExportTask::collectHashes()
|
|||||||
setStatus(tr("Finding file hashes..."));
|
setStatus(tr("Finding file hashes..."));
|
||||||
setProgress(1, 5);
|
setProgress(1, 5);
|
||||||
auto allMods = mcInstance->loaderModList()->allMods();
|
auto allMods = mcInstance->loaderModList()->allMods();
|
||||||
ConcurrentTask::Ptr hashingTask(
|
ConcurrentTask::Ptr hashingTask(new ConcurrentTask("MakeHashesTask", APPLICATION->settings()->get("NumberOfConcurrentTasks").toInt()));
|
||||||
new ConcurrentTask(this, "MakeHashesTask", APPLICATION->settings()->get("NumberOfConcurrentTasks").toInt()));
|
|
||||||
task.reset(hashingTask);
|
task.reset(hashingTask);
|
||||||
for (const QFileInfo& file : files) {
|
for (const QFileInfo& file : files) {
|
||||||
const QString relative = gameRoot.relativeFilePath(file.absoluteFilePath());
|
const QString relative = gameRoot.relativeFilePath(file.absoluteFilePath());
|
||||||
|
@ -43,11 +43,16 @@ Task::Ptr NetworkResourceAPI::searchProjects(SearchArgs&& args, SearchCallbacks&
|
|||||||
callbacks.on_succeed(doc);
|
callbacks.on_succeed(doc);
|
||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(netJob.get(), &NetJob::failed, [netJob, callbacks](const QString& reason) {
|
// Capture a weak_ptr instead of a shared_ptr to avoid circular dependency issues.
|
||||||
|
// This prevents the lambda from extending the lifetime of the shared resource,
|
||||||
|
// as it only temporarily locks the resource when needed.
|
||||||
|
auto weak = netJob.toWeakRef();
|
||||||
|
QObject::connect(netJob.get(), &NetJob::failed, [weak, callbacks](const QString& reason) {
|
||||||
int network_error_code = -1;
|
int network_error_code = -1;
|
||||||
if (auto* failed_action = netJob->getFailedActions().at(0); failed_action)
|
if (auto netJob = weak.lock()) {
|
||||||
network_error_code = failed_action->replyStatusCode();
|
if (auto* failed_action = netJob->getFailedActions().at(0); failed_action)
|
||||||
|
network_error_code = failed_action->replyStatusCode();
|
||||||
|
}
|
||||||
callbacks.on_fail(reason, network_error_code);
|
callbacks.on_fail(reason, network_error_code);
|
||||||
});
|
});
|
||||||
QObject::connect(netJob.get(), &NetJob::aborted, [callbacks] { callbacks.on_abort(); });
|
QObject::connect(netJob.get(), &NetJob::aborted, [callbacks] { callbacks.on_abort(); });
|
||||||
@ -102,11 +107,17 @@ Task::Ptr NetworkResourceAPI::getProjectVersions(VersionSearchArgs&& args, Versi
|
|||||||
|
|
||||||
callbacks.on_succeed(doc, args.pack);
|
callbacks.on_succeed(doc, args.pack);
|
||||||
});
|
});
|
||||||
QObject::connect(netJob.get(), &NetJob::failed, [netJob, callbacks](const QString& reason) {
|
|
||||||
int network_error_code = -1;
|
|
||||||
if (auto* failed_action = netJob->getFailedActions().at(0); failed_action)
|
|
||||||
network_error_code = failed_action->replyStatusCode();
|
|
||||||
|
|
||||||
|
// Capture a weak_ptr instead of a shared_ptr to avoid circular dependency issues.
|
||||||
|
// This prevents the lambda from extending the lifetime of the shared resource,
|
||||||
|
// as it only temporarily locks the resource when needed.
|
||||||
|
auto weak = netJob.toWeakRef();
|
||||||
|
QObject::connect(netJob.get(), &NetJob::failed, [weak, callbacks](const QString& reason) {
|
||||||
|
int network_error_code = -1;
|
||||||
|
if (auto netJob = weak.lock()) {
|
||||||
|
if (auto* failed_action = netJob->getFailedActions().at(0); failed_action)
|
||||||
|
network_error_code = failed_action->replyStatusCode();
|
||||||
|
}
|
||||||
callbacks.on_fail(reason, network_error_code);
|
callbacks.on_fail(reason, network_error_code);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -153,11 +164,17 @@ Task::Ptr NetworkResourceAPI::getDependencyVersion(DependencySearchArgs&& args,
|
|||||||
|
|
||||||
callbacks.on_succeed(doc, args.dependency);
|
callbacks.on_succeed(doc, args.dependency);
|
||||||
});
|
});
|
||||||
QObject::connect(netJob.get(), &NetJob::failed, [netJob, callbacks](const QString& reason) {
|
|
||||||
int network_error_code = -1;
|
|
||||||
if (auto* failed_action = netJob->getFailedActions().at(0); failed_action)
|
|
||||||
network_error_code = failed_action->replyStatusCode();
|
|
||||||
|
|
||||||
|
// Capture a weak_ptr instead of a shared_ptr to avoid circular dependency issues.
|
||||||
|
// This prevents the lambda from extending the lifetime of the shared resource,
|
||||||
|
// as it only temporarily locks the resource when needed.
|
||||||
|
auto weak = netJob.toWeakRef();
|
||||||
|
QObject::connect(netJob.get(), &NetJob::failed, [weak, callbacks](const QString& reason) {
|
||||||
|
int network_error_code = -1;
|
||||||
|
if (auto netJob = weak.lock()) {
|
||||||
|
if (auto* failed_action = netJob->getFailedActions().at(0); failed_action)
|
||||||
|
network_error_code = failed_action->replyStatusCode();
|
||||||
|
}
|
||||||
callbacks.on_fail(reason, network_error_code);
|
callbacks.on_fail(reason, network_error_code);
|
||||||
});
|
});
|
||||||
return netJob;
|
return netJob;
|
||||||
|
@ -138,7 +138,7 @@ void PackInstallTask::install()
|
|||||||
if (unzipMcDir.exists()) {
|
if (unzipMcDir.exists()) {
|
||||||
// ok, found minecraft dir, move contents to instance dir
|
// ok, found minecraft dir, move contents to instance dir
|
||||||
if (!FS::move(m_stagingPath + "/unzip/minecraft", m_stagingPath + "/minecraft")) {
|
if (!FS::move(m_stagingPath + "/unzip/minecraft", m_stagingPath + "/minecraft")) {
|
||||||
emitFailed(tr("Failed to move unzipped Minecraft!"));
|
emitFailed(tr("Failed to move unpacked Minecraft!"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ Task::Ptr ModrinthAPI::currentVersions(const QStringList& hashes, QString hash_f
|
|||||||
auto body_raw = body.toJson();
|
auto body_raw = body.toJson();
|
||||||
|
|
||||||
netJob->addNetAction(Net::ApiUpload::makeByteArray(QString(BuildConfig.MODRINTH_PROD_URL + "/version_files"), response, body_raw));
|
netJob->addNetAction(Net::ApiUpload::makeByteArray(QString(BuildConfig.MODRINTH_PROD_URL + "/version_files"), response, body_raw));
|
||||||
|
netJob->setAskRetry(false);
|
||||||
return netJob;
|
return netJob;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "QObjectPtr.h"
|
#include "QObjectPtr.h"
|
||||||
#include "ResourceDownloadTask.h"
|
#include "ResourceDownloadTask.h"
|
||||||
|
|
||||||
|
#include "modplatform/ModIndex.h"
|
||||||
#include "modplatform/helpers/HashUtils.h"
|
#include "modplatform/helpers/HashUtils.h"
|
||||||
|
|
||||||
#include "tasks/ConcurrentTask.h"
|
#include "tasks/ConcurrentTask.h"
|
||||||
@ -40,7 +41,7 @@ void ModrinthCheckUpdate::executeTask()
|
|||||||
setProgress(0, 9);
|
setProgress(0, 9);
|
||||||
|
|
||||||
auto hashing_task =
|
auto hashing_task =
|
||||||
makeShared<ConcurrentTask>(this, "MakeModrinthHashesTask", APPLICATION->settings()->get("NumberOfConcurrentTasks").toInt());
|
makeShared<ConcurrentTask>("MakeModrinthHashesTask", APPLICATION->settings()->get("NumberOfConcurrentTasks").toInt());
|
||||||
for (auto* mod : m_mods) {
|
for (auto* mod : m_mods) {
|
||||||
auto hash = mod->metadata()->hash;
|
auto hash = mod->metadata()->hash;
|
||||||
|
|
||||||
@ -91,20 +92,15 @@ void ModrinthCheckUpdate::checkVersionsResponse(std::shared_ptr<QByteArray> resp
|
|||||||
// it means this specific version is not available
|
// it means this specific version is not available
|
||||||
if (project_obj.isEmpty()) {
|
if (project_obj.isEmpty()) {
|
||||||
qDebug() << "Mod " << m_mappings.find(hash).value()->name() << " got an empty response." << "Hash: " << hash;
|
qDebug() << "Mod " << m_mappings.find(hash).value()->name() << " got an empty response." << "Hash: " << hash;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sometimes a version may have multiple files, one with "forge" and one with "fabric",
|
// Sometimes a version may have multiple files, one with "forge" and one with "fabric",
|
||||||
// so we may want to filter it
|
// so we may want to filter it
|
||||||
QString loader_filter;
|
QString loader_filter;
|
||||||
static auto flags = { ModPlatform::ModLoaderType::NeoForge, ModPlatform::ModLoaderType::Forge,
|
for (auto flag : ModPlatform::modLoaderTypesToList(loader)) {
|
||||||
ModPlatform::ModLoaderType::Quilt, ModPlatform::ModLoaderType::Fabric };
|
loader_filter = ModPlatform::getModLoaderAsString(flag);
|
||||||
for (auto flag : flags) {
|
break;
|
||||||
if (loader.testFlag(flag)) {
|
|
||||||
loader_filter = ModPlatform::getModLoaderAsString(flag);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Currently, we rely on a couple heuristics to determine whether an update is actually available or not:
|
// Currently, we rely on a couple heuristics to determine whether an update is actually available or not:
|
||||||
|
@ -261,12 +261,14 @@ bool ModrinthCreationTask::createInstance()
|
|||||||
mod->setDetails(d);
|
mod->setDetails(d);
|
||||||
mods[file.hash.toHex()] = mod;
|
mods[file.hash.toHex()] = mod;
|
||||||
}
|
}
|
||||||
|
if (file.downloads.empty()) {
|
||||||
|
setError(tr("The file '%1' is missing a download link. This is invalid in the pack format.").arg(fileName));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
qDebug() << "Will try to download" << file.downloads.front() << "to" << file_path;
|
qDebug() << "Will try to download" << file.downloads.front() << "to" << file_path;
|
||||||
auto dl = Net::ApiDownload::makeFile(file.downloads.dequeue(), file_path);
|
auto dl = Net::ApiDownload::makeFile(file.downloads.dequeue(), file_path);
|
||||||
dl->addValidator(new Net::ChecksumValidator(file.hashAlgorithm, file.hash));
|
dl->addValidator(new Net::ChecksumValidator(file.hashAlgorithm, file.hash));
|
||||||
downloadMods->addNetAction(dl);
|
downloadMods->addNetAction(dl);
|
||||||
|
|
||||||
if (!file.downloads.empty()) {
|
if (!file.downloads.empty()) {
|
||||||
// FIXME: This really needs to be put into a ConcurrentTask of
|
// FIXME: This really needs to be put into a ConcurrentTask of
|
||||||
// MultipleOptionsTask's , once those exist :)
|
// MultipleOptionsTask's , once those exist :)
|
||||||
|
@ -72,7 +72,7 @@ auto stringEntry(toml::table table, QString entry_name) -> QString
|
|||||||
{
|
{
|
||||||
auto node = table[StringUtils::toStdString(entry_name)];
|
auto node = table[StringUtils::toStdString(entry_name)];
|
||||||
if (!node) {
|
if (!node) {
|
||||||
qCritical() << "Failed to read str property '" + entry_name + "' in mod metadata.";
|
qWarning() << "Failed to read str property '" + entry_name + "' in mod metadata.";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ auto intEntry(toml::table table, QString entry_name) -> int
|
|||||||
{
|
{
|
||||||
auto node = table[StringUtils::toStdString(entry_name)];
|
auto node = table[StringUtils::toStdString(entry_name)];
|
||||||
if (!node) {
|
if (!node) {
|
||||||
qCritical() << "Failed to read int property '" + entry_name + "' in mod metadata.";
|
qWarning() << "Failed to read int property '" + entry_name + "' in mod metadata.";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,11 +186,8 @@ void V1::updateModIndex(QDir& index_dir, Mod& mod)
|
|||||||
}
|
}
|
||||||
|
|
||||||
toml::array loaders;
|
toml::array loaders;
|
||||||
for (auto loader : { ModPlatform::NeoForge, ModPlatform::Forge, ModPlatform::Cauldron, ModPlatform::LiteLoader, ModPlatform::Fabric,
|
for (auto loader : ModPlatform::modLoaderTypesToList(mod.loaders)) {
|
||||||
ModPlatform::Quilt }) {
|
loaders.push_back(getModLoaderAsString(loader).toStdString());
|
||||||
if (mod.loaders & loader) {
|
|
||||||
loaders.push_back(getModLoaderAsString(loader).toStdString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
toml::array mcVersions;
|
toml::array mcVersions;
|
||||||
for (auto version : mod.mcVersions) {
|
for (auto version : mod.mcVersions) {
|
||||||
|
@ -55,7 +55,7 @@ Task::State FileSink::init(QNetworkRequest& request)
|
|||||||
}
|
}
|
||||||
|
|
||||||
wroteAnyData = false;
|
wroteAnyData = false;
|
||||||
m_output_file.reset(new QSaveFile(m_filename));
|
m_output_file.reset(new PSaveFile(m_filename));
|
||||||
if (!m_output_file->open(QIODevice::WriteOnly)) {
|
if (!m_output_file->open(QIODevice::WriteOnly)) {
|
||||||
qCCritical(taskNetLogC) << "Could not open " + m_filename + " for writing";
|
qCCritical(taskNetLogC) << "Could not open " + m_filename + " for writing";
|
||||||
return Task::State::Failed;
|
return Task::State::Failed;
|
||||||
|
@ -35,8 +35,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QSaveFile>
|
#include "PSaveFile.h"
|
||||||
|
|
||||||
#include "Sink.h"
|
#include "Sink.h"
|
||||||
|
|
||||||
namespace Net {
|
namespace Net {
|
||||||
@ -60,6 +59,6 @@ class FileSink : public Sink {
|
|||||||
protected:
|
protected:
|
||||||
QString m_filename;
|
QString m_filename;
|
||||||
bool wroteAnyData = false;
|
bool wroteAnyData = false;
|
||||||
std::unique_ptr<QSaveFile> m_output_file;
|
std::unique_ptr<PSaveFile> m_output_file;
|
||||||
};
|
};
|
||||||
} // namespace Net
|
} // namespace Net
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
NetJob::NetJob(QString job_name, shared_qobject_ptr<QNetworkAccessManager> network, int max_concurrent)
|
NetJob::NetJob(QString job_name, shared_qobject_ptr<QNetworkAccessManager> network, int max_concurrent)
|
||||||
: ConcurrentTask(nullptr, job_name), m_network(network)
|
: ConcurrentTask(job_name), m_network(network)
|
||||||
{
|
{
|
||||||
#if defined(LAUNCHER_APPLICATION)
|
#if defined(LAUNCHER_APPLICATION)
|
||||||
if (APPLICATION_DYN && max_concurrent < 0)
|
if (APPLICATION_DYN && max_concurrent < 0)
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
[Icon Theme]
|
[Icon Theme]
|
||||||
Name=Legacy
|
Name=Legacy
|
||||||
Comment=Default Icons
|
Comment=Default Icons
|
||||||
Inherits=default
|
|
||||||
Directories=8x8,16x16,22x22,24x24,32x32,32x32/instances,48x48,50x50/instances,64x64,128x128/instances,256x256,scalable,scalable/instances
|
Directories=8x8,16x16,22x22,24x24,32x32,32x32/instances,48x48,50x50/instances,64x64,128x128/instances,256x256,scalable,scalable/instances
|
||||||
|
|
||||||
[8x8]
|
[8x8]
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include "tasks/Task.h"
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
ConcurrentTask::ConcurrentTask(QObject* parent, QString task_name, int max_concurrent) : Task(parent), m_total_max_size(max_concurrent)
|
ConcurrentTask::ConcurrentTask(QString task_name, int max_concurrent) : Task(), m_total_max_size(max_concurrent)
|
||||||
{
|
{
|
||||||
setObjectName(task_name);
|
setObjectName(task_name);
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ class ConcurrentTask : public Task {
|
|||||||
public:
|
public:
|
||||||
using Ptr = shared_qobject_ptr<ConcurrentTask>;
|
using Ptr = shared_qobject_ptr<ConcurrentTask>;
|
||||||
|
|
||||||
explicit ConcurrentTask(QObject* parent = nullptr, QString task_name = "", int max_concurrent = 6);
|
explicit ConcurrentTask(QString task_name = "", int max_concurrent = 6);
|
||||||
~ConcurrentTask() override;
|
~ConcurrentTask() override;
|
||||||
|
|
||||||
// safe to call before starting the task
|
// safe to call before starting the task
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
MultipleOptionsTask::MultipleOptionsTask(QObject* parent, const QString& task_name) : ConcurrentTask(parent, task_name, 1) {}
|
MultipleOptionsTask::MultipleOptionsTask(const QString& task_name) : ConcurrentTask(task_name, 1) {}
|
||||||
|
|
||||||
void MultipleOptionsTask::executeNextSubTask()
|
void MultipleOptionsTask::executeNextSubTask()
|
||||||
{
|
{
|
||||||
|
@ -42,7 +42,7 @@
|
|||||||
class MultipleOptionsTask : public ConcurrentTask {
|
class MultipleOptionsTask : public ConcurrentTask {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit MultipleOptionsTask(QObject* parent = nullptr, const QString& task_name = "");
|
explicit MultipleOptionsTask(const QString& task_name = "");
|
||||||
~MultipleOptionsTask() override = default;
|
~MultipleOptionsTask() override = default;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include "tasks/ConcurrentTask.h"
|
#include "tasks/ConcurrentTask.h"
|
||||||
|
|
||||||
SequentialTask::SequentialTask(QObject* parent, QString task_name) : ConcurrentTask(parent, task_name, 1) {}
|
SequentialTask::SequentialTask(QString task_name) : ConcurrentTask(task_name, 1) {}
|
||||||
|
|
||||||
void SequentialTask::subTaskFailed(Task::Ptr task, const QString& msg)
|
void SequentialTask::subTaskFailed(Task::Ptr task, const QString& msg)
|
||||||
{
|
{
|
||||||
|
@ -47,7 +47,7 @@
|
|||||||
class SequentialTask : public ConcurrentTask {
|
class SequentialTask : public ConcurrentTask {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit SequentialTask(QObject* parent = nullptr, QString task_name = "");
|
explicit SequentialTask(QString task_name = "");
|
||||||
~SequentialTask() override = default;
|
~SequentialTask() override = default;
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
|
|
||||||
Q_LOGGING_CATEGORY(taskLogC, "launcher.task")
|
Q_LOGGING_CATEGORY(taskLogC, "launcher.task")
|
||||||
|
|
||||||
Task::Task(QObject* parent, bool show_debug) : QObject(parent), m_show_debug(show_debug)
|
Task::Task(bool show_debug) : m_show_debug(show_debug)
|
||||||
{
|
{
|
||||||
m_uid = QUuid::createUuid();
|
m_uid = QUuid::createUuid();
|
||||||
setAutoDelete(false);
|
setAutoDelete(false);
|
||||||
|
@ -87,7 +87,7 @@ class Task : public QObject, public QRunnable {
|
|||||||
enum class State { Inactive, Running, Succeeded, Failed, AbortedByUser };
|
enum class State { Inactive, Running, Succeeded, Failed, AbortedByUser };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Task(QObject* parent = 0, bool show_debug_log = true);
|
explicit Task(bool show_debug_log = true);
|
||||||
virtual ~Task() = default;
|
virtual ~Task() = default;
|
||||||
|
|
||||||
bool isRunning() const;
|
bool isRunning() const;
|
||||||
|
@ -102,7 +102,7 @@ QString getCreditsHtml()
|
|||||||
stream << QString("<p>d-513 %1</p>\n").arg(getGitHub("d-513"));
|
stream << QString("<p>d-513 %1</p>\n").arg(getGitHub("d-513"));
|
||||||
stream << QString("<p>txtsd %1</p>\n").arg(getWebsite("https://ihavea.quest"));
|
stream << QString("<p>txtsd %1</p>\n").arg(getWebsite("https://ihavea.quest"));
|
||||||
stream << QString("<p>timoreo %1</p>\n").arg(getGitHub("timoreo22"));
|
stream << QString("<p>timoreo %1</p>\n").arg(getGitHub("timoreo22"));
|
||||||
stream << QString("<p>Ezekiel Smith (ZekeSmith) %1</p>\n").arg(getGitHub("ZekeSmith"));
|
stream << QString("<p>ZekeZ %1</p>\n").arg(getGitHub("ZekeZDev"));
|
||||||
stream << QString("<p>cozyGalvinism %1</p>\n").arg(getGitHub("cozyGalvinism"));
|
stream << QString("<p>cozyGalvinism %1</p>\n").arg(getGitHub("cozyGalvinism"));
|
||||||
stream << QString("<p>DioEgizio %1</p>\n").arg(getGitHub("DioEgizio"));
|
stream << QString("<p>DioEgizio %1</p>\n").arg(getGitHub("DioEgizio"));
|
||||||
stream << QString("<p>flowln %1</p>\n").arg(getGitHub("flowln"));
|
stream << QString("<p>flowln %1</p>\n").arg(getGitHub("flowln"));
|
||||||
@ -126,7 +126,7 @@ QString getCreditsHtml()
|
|||||||
|
|
||||||
stream << "<h3>" << QObject::tr("With thanks to", "About Credits") << "</h3>\n";
|
stream << "<h3>" << QObject::tr("With thanks to", "About Credits") << "</h3>\n";
|
||||||
stream << QString("<p>Boba %1</p>\n").arg(getWebsite("https://bobaonline.neocities.org/"));
|
stream << QString("<p>Boba %1</p>\n").arg(getWebsite("https://bobaonline.neocities.org/"));
|
||||||
stream << QString("<p>Davi Rafael %1</p>\n").arg(getWebsite("https://auti.one/"));
|
stream << QString("<p>AutiOne %1</p>\n").arg(getWebsite("https://auti.one/"));
|
||||||
stream << QString("<p>Fulmine %1</p>\n").arg(getWebsite("https://fulmine.xyz/"));
|
stream << QString("<p>Fulmine %1</p>\n").arg(getWebsite("https://fulmine.xyz/"));
|
||||||
stream << QString("<p>ely %1</p>\n").arg(getGitHub("elyrodso"));
|
stream << QString("<p>ely %1</p>\n").arg(getGitHub("elyrodso"));
|
||||||
stream << QString("<p>gon sawa %1</p>\n").arg(getGitHub("gonsawa"));
|
stream << QString("<p>gon sawa %1</p>\n").arg(getGitHub("gonsawa"));
|
||||||
|
@ -46,11 +46,13 @@ BlockedModsDialog::BlockedModsDialog(QWidget* parent, const QString& title, cons
|
|||||||
: QDialog(parent), ui(new Ui::BlockedModsDialog), m_mods(mods), m_hash_type(hash_type)
|
: QDialog(parent), ui(new Ui::BlockedModsDialog), m_mods(mods), m_hash_type(hash_type)
|
||||||
{
|
{
|
||||||
m_hashing_task = shared_qobject_ptr<ConcurrentTask>(
|
m_hashing_task = shared_qobject_ptr<ConcurrentTask>(
|
||||||
new ConcurrentTask(this, "MakeHashesTask", APPLICATION->settings()->get("NumberOfConcurrentTasks").toInt()));
|
new ConcurrentTask("MakeHashesTask", APPLICATION->settings()->get("NumberOfConcurrentTasks").toInt()));
|
||||||
connect(m_hashing_task.get(), &Task::finished, this, &BlockedModsDialog::hashTaskFinished);
|
connect(m_hashing_task.get(), &Task::finished, this, &BlockedModsDialog::hashTaskFinished);
|
||||||
|
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
ui->buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("Cancel"));
|
||||||
|
ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("OK"));
|
||||||
m_openMissingButton = ui->buttonBox->addButton(tr("Open Missing"), QDialogButtonBox::ActionRole);
|
m_openMissingButton = ui->buttonBox->addButton(tr("Open Missing"), QDialogButtonBox::ActionRole);
|
||||||
connect(m_openMissingButton, &QPushButton::clicked, this, [this]() { openAll(true); });
|
connect(m_openMissingButton, &QPushButton::clicked, this, [this]() { openAll(true); });
|
||||||
|
|
||||||
|
@ -109,6 +109,9 @@ CopyInstanceDialog::CopyInstanceDialog(InstancePtr original, QWidget* parent)
|
|||||||
|
|
||||||
auto HelpButton = ui->buttonBox->button(QDialogButtonBox::Help);
|
auto HelpButton = ui->buttonBox->button(QDialogButtonBox::Help);
|
||||||
connect(HelpButton, &QPushButton::clicked, this, &CopyInstanceDialog::help);
|
connect(HelpButton, &QPushButton::clicked, this, &CopyInstanceDialog::help);
|
||||||
|
HelpButton->setText(tr("Help"));
|
||||||
|
ui->buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("Cancel"));
|
||||||
|
ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("OK"));
|
||||||
}
|
}
|
||||||
|
|
||||||
CopyInstanceDialog::~CopyInstanceDialog()
|
CopyInstanceDialog::~CopyInstanceDialog()
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include "EditAccountDialog.h"
|
#include "EditAccountDialog.h"
|
||||||
#include <DesktopServices.h>
|
#include <DesktopServices.h>
|
||||||
|
#include <QPushButton>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include "ui_EditAccountDialog.h"
|
#include "ui_EditAccountDialog.h"
|
||||||
|
|
||||||
@ -27,6 +28,9 @@ EditAccountDialog::EditAccountDialog(const QString& text, QWidget* parent, int f
|
|||||||
|
|
||||||
ui->userTextBox->setEnabled(flags & UsernameField);
|
ui->userTextBox->setEnabled(flags & UsernameField);
|
||||||
ui->passTextBox->setEnabled(flags & PasswordField);
|
ui->passTextBox->setEnabled(flags & PasswordField);
|
||||||
|
|
||||||
|
ui->buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("Cancel"));
|
||||||
|
ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("OK"));
|
||||||
}
|
}
|
||||||
|
|
||||||
EditAccountDialog::~EditAccountDialog()
|
EditAccountDialog::~EditAccountDialog()
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
#include <icons/IconList.h>
|
#include <icons/IconList.h>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
#include <QPushButton>
|
||||||
#include <QSaveFile>
|
#include <QSaveFile>
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
#include <QStack>
|
#include <QStack>
|
||||||
@ -85,6 +86,9 @@ ExportInstanceDialog::ExportInstanceDialog(InstancePtr instance, QWidget* parent
|
|||||||
auto headerView = ui->treeView->header();
|
auto headerView = ui->treeView->header();
|
||||||
headerView->setSectionResizeMode(QHeaderView::ResizeToContents);
|
headerView->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||||
headerView->setSectionResizeMode(0, QHeaderView::Stretch);
|
headerView->setSectionResizeMode(0, QHeaderView::Stretch);
|
||||||
|
|
||||||
|
ui->buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("Cancel"));
|
||||||
|
ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("OK"));
|
||||||
}
|
}
|
||||||
|
|
||||||
ExportInstanceDialog::~ExportInstanceDialog()
|
ExportInstanceDialog::~ExportInstanceDialog()
|
||||||
|
@ -103,6 +103,9 @@ ExportPackDialog::ExportPackDialog(InstancePtr instance, QWidget* parent, ModPla
|
|||||||
QHeaderView* headerView = ui->files->header();
|
QHeaderView* headerView = ui->files->header();
|
||||||
headerView->setSectionResizeMode(QHeaderView::ResizeToContents);
|
headerView->setSectionResizeMode(QHeaderView::ResizeToContents);
|
||||||
headerView->setSectionResizeMode(0, QHeaderView::Stretch);
|
headerView->setSectionResizeMode(0, QHeaderView::Stretch);
|
||||||
|
|
||||||
|
ui->buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("Cancel"));
|
||||||
|
ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("OK"));
|
||||||
}
|
}
|
||||||
|
|
||||||
ExportPackDialog::~ExportPackDialog()
|
ExportPackDialog::~ExportPackDialog()
|
||||||
|
@ -64,6 +64,9 @@ ExportToModListDialog::ExportToModListDialog(QString name, QList<Mod*> mods, QWi
|
|||||||
this->ui->finalText->selectAll();
|
this->ui->finalText->selectAll();
|
||||||
this->ui->finalText->copy();
|
this->ui->finalText->copy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ui->buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("Cancel"));
|
||||||
|
ui->buttonBox->button(QDialogButtonBox::Save)->setText(tr("Save"));
|
||||||
triggerImp();
|
triggerImp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,6 +63,9 @@ IconPickerDialog::IconPickerDialog(QWidget* parent) : QDialog(parent), ui(new Ui
|
|||||||
auto buttonAdd = ui->buttonBox->addButton(tr("Add Icon"), QDialogButtonBox::ResetRole);
|
auto buttonAdd = ui->buttonBox->addButton(tr("Add Icon"), QDialogButtonBox::ResetRole);
|
||||||
buttonRemove = ui->buttonBox->addButton(tr("Remove Icon"), QDialogButtonBox::ResetRole);
|
buttonRemove = ui->buttonBox->addButton(tr("Remove Icon"), QDialogButtonBox::ResetRole);
|
||||||
|
|
||||||
|
ui->buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("Cancel"));
|
||||||
|
ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("OK"));
|
||||||
|
|
||||||
connect(buttonAdd, SIGNAL(clicked(bool)), SLOT(addNewIcon()));
|
connect(buttonAdd, SIGNAL(clicked(bool)), SLOT(addNewIcon()));
|
||||||
connect(buttonRemove, SIGNAL(clicked(bool)), SLOT(removeSelectedIcon()));
|
connect(buttonRemove, SIGNAL(clicked(bool)), SLOT(removeSelectedIcon()));
|
||||||
|
|
||||||
|
@ -45,6 +45,9 @@ ImportResourceDialog::ImportResourceDialog(QString file_path, PackedResourceType
|
|||||||
ui->label->setText(
|
ui->label->setText(
|
||||||
tr("Choose the instance you would like to import this %1 to.").arg(ResourceUtils::getPackedTypeName(m_resource_type)));
|
tr("Choose the instance you would like to import this %1 to.").arg(ResourceUtils::getPackedTypeName(m_resource_type)));
|
||||||
ui->label_file_path->setText(tr("File: %1").arg(m_file_path));
|
ui->label_file_path->setText(tr("File: %1").arg(m_file_path));
|
||||||
|
|
||||||
|
ui->buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("Cancel"));
|
||||||
|
ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("OK"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImportResourceDialog::activated(QModelIndex index)
|
void ImportResourceDialog::activated(QModelIndex index)
|
||||||
|
@ -104,6 +104,8 @@ InstallLoaderDialog::InstallLoaderDialog(std::shared_ptr<PackProfile> profile, c
|
|||||||
|
|
||||||
buttons->setOrientation(Qt::Horizontal);
|
buttons->setOrientation(Qt::Horizontal);
|
||||||
buttons->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
|
buttons->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
|
||||||
|
buttons->button(QDialogButtonBox::Ok)->setText(tr("Ok"));
|
||||||
|
buttons->button(QDialogButtonBox::Cancel)->setText(tr("Cancel"));
|
||||||
connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||||
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||||
buttonLayout->addWidget(buttons);
|
buttonLayout->addWidget(buttons);
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user