Compare commits

...

106 commits
develop ... 9.2

Author SHA1 Message Date
Alexandru Ionut Tripon
fdfdf2eef1
Merge pull request #3224 from Trial97/backport_fix_auto_mod_provider
[backport]Fix automatically choose mod provider option
2024-12-19 10:34:01 +02:00
Trial97
bbfa5a5ed1
Fix automatically choose mod provider option
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
2024-12-19 09:23:51 +02:00
Alexandru Ionut Tripon
43dc330e55
Merge pull request #3223 from Trial97/backport_fix_flame_loader_match
[backport]fix the flame loaders match
2024-12-18 23:30:10 +02:00
Trial97
0c962dff59
fix the flame loaders match
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
2024-12-18 22:53:18 +02:00
timoreo
ca0dd583ba
Merge pull request #3222 from PrismLauncher/backport-3197-to-release-9.x
[Backport release-9.x] Do not fail curseforge import if modrinth file check fails
2024-12-18 19:53:32 +01:00
Trial97
7bb686c85b Do not fail curseforge import if modrinth file check fails
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit a1c1c0b769)
2024-12-18 18:53:13 +00:00
timoreo
f8d3d8399d
Merge pull request #3221 from PrismLauncher/backport-3214-to-release-9.x
[Backport release-9.x] Correct symbolic link destination on manifest (Mojang) Java download
2024-12-18 19:42:58 +01:00
Kenneth Chew
9cb2a3ab2d Correct symbolic link destination on manifest Java download
Signed-off-by: Kenneth Chew <79120643+kthchew@users.noreply.github.com>
(cherry picked from commit 8d53242952)
2024-12-18 18:42:39 +00:00
Alexandru Ionut Tripon
072c495ec6
Merge pull request #3206 from PrismLauncher/backport-3202-to-release-9.x
[Backport release-9.x] [macOS] Update Sparkle to v2.6.4
2024-12-14 18:39:04 +02:00
Kenneth Chew
335941fb46 Update Sparkle to v2.6.4
Signed-off-by: Kenneth Chew <79120643+kthchew@users.noreply.github.com>
(cherry picked from commit b6cd46ad27)
2024-12-14 16:36:04 +00:00
Alexandru Ionut Tripon
ebeff36da5
Merge pull request #3205 from PrismLauncher/backport-3199-to-release-9.x
[Backport release-9.x] Fix tab order in launcher settings
2024-12-14 18:34:38 +02:00
Kenneth Chew
1d29f63bec Fix tab order in launcher settings
Signed-off-by: Kenneth Chew <79120643+kthchew@users.noreply.github.com>
(cherry picked from commit c3712ba648)
2024-12-14 16:32:21 +00:00
Alexandru Ionut Tripon
87dc1bb6a6
Merge pull request #3204 from PrismLauncher/backport-3198-to-release-9.x
[Backport release-9.x] [macOS] Add local network usage description
2024-12-14 18:19:20 +02:00
Alexandru Ionut Tripon
a85720b8d6
Merge pull request #3203 from PrismLauncher/backport-3181-to-release-9.x
[Backport release-9.x] fix crash with invalid mrpack format
2024-12-14 18:19:09 +02:00
Kenneth Chew
4c28a94de1 Add local network usage description
Signed-off-by: Kenneth Chew <79120643+kthchew@users.noreply.github.com>
(cherry picked from commit c3e44554ab)
2024-12-14 16:16:49 +00:00
Trial97
344ae87f25 fix crash with invalid mrpack format
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 1dd0728a58)
2024-12-14 16:16:06 +00:00
Alexandru Ionut Tripon
577999bd35
Merge pull request #3183 from PrismLauncher/backport-3170-to-release-9.x
[Backport release-9.x] [Linux] Don't use fallback icon search paths
2024-12-09 09:15:53 +02:00
leia uwu
887db29f35 fix icon theme search paths
using fallback search paths breaks qadwaitadecorations

Signed-off-by: leia uwu <leia@tutamail.com>
(cherry picked from commit 614574f15c)
2024-12-09 07:14:38 +00:00
Alexandru Ionut Tripon
7865b8128e
Merge pull request #3169 from PrismLauncher/backport-3166-to-release-9.x
[Backport release-9.x] chore(deps): update actions/cache action to v4.2.0
2024-12-06 08:47:51 +02:00
renovate[bot]
a58f125535 chore(deps): update actions/cache action to v4.2.0
(cherry picked from commit 94c893bd86)
2024-12-06 06:47:20 +00:00
Alexandru Ionut Tripon
d1a05d312d
Merge pull request #3158 from PrismLauncher/backport-3119-to-release-9.x
[Backport release-9.x] Sync Flatpak manifest with Flathub's
2024-12-02 17:30:57 +02:00
guihkx
bbf21e5824 ci(flatpak): update build artifact name
Just aligning the name of the Flatpak package with other build artifacts.

Signed-off-by: guihkx <626206+guihkx@users.noreply.github.com>
(cherry picked from commit e0faee7f26)
2024-12-02 15:30:33 +00:00
guihkx
73b4223b61 flatpak: update KDE runtime to 6.8
This also switches to the Docker image provided and maintained by
Flathub collaborators through the 'flathub-infra' organization on
GitHub, because it looks better maintained at the moment.

Signed-off-by: guihkx <626206+guihkx@users.noreply.github.com>
(cherry picked from commit f6770a847a)
2024-12-02 15:30:33 +00:00
guihkx
686e0b7b18 flatpak: update xrandr to 1.5.3
Signed-off-by: guihkx <626206+guihkx@users.noreply.github.com>
(cherry picked from commit 4a50e94967)
2024-12-02 15:30:33 +00:00
Alexandru Ionut Tripon
189878e7e3
Merge pull request #3157 from PrismLauncher/backport-3135-to-release-9.x
[Backport release-9.x] Make FTB Import note italic to match others
2024-12-02 16:25:06 +02:00
Trial97
af74d5f410 Make FTB Import note italic to match others
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit a09af619ce)
2024-12-02 14:17:44 +00:00
Tayou
cdfd0b1002
Merge pull request #3156 from PrismLauncher/backport-3152-to-release-9.x
[Backport release-9.x] Fix system icons on Linux
2024-12-02 15:02:21 +01:00
leia uwu
9791c306dc fix: icon search paths memory leak
Signed-off-by: leia uwu <leia@tutamail.com>
(cherry picked from commit 3f67ef968b)
2024-12-02 14:00:59 +00:00
leia uwu
e7e9265c40 fix: fix system icons
This sets the fallback icon theme to the current(system default) icon theme before
launcher specific themes are applied

And removes `Inherits` line of multimc/legacy icon theme because it can end up making it
inherit a default theme set from /usr/share/icons/default/index.theme
instead of the user configured theme (probably a qt bug?)

Signed-off-by: leia uwu <leia@tutamail.com>
(cherry picked from commit fd9c80db62)
2024-12-02 14:00:59 +00:00
Alexandru Ionut Tripon
e0c323a190
Merge pull request #3138 from PrismLauncher/backport-3130-to-release-9.x
[Backport release-9.x] Improve MANIFEST.MF parsing
2024-11-25 12:09:01 +02:00
Kationor
a914747416 Improve MANIFEST.MF parsing
Previously, we would only properly parse LF-encoded manifests, and even
those only if they used the recommended casing.

This commit allows the parser to recognise CR and CRLF newlines, and
also makes the name comparison case insensitive to align with the
specification. (Though not completely: we still don't support multiline
values)

Signed-off-by: Kationor <n96211028@gmail.com>
(cherry picked from commit b40a1973bf)
2024-11-25 10:05:19 +00:00
Alexandru Ionut Tripon
d453240a94
Merge pull request #3105 from Trial97/backport_3019
[Backport release-9.x] fixed double deletion for tasks
2024-11-15 10:35:25 +02:00
Trial97
4c4017d7ca remove task parent from constuctor
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
2024-11-15 09:35:36 +02:00
Alexandru Ionut Tripon
2a4c4ed8ea
Merge pull request #3103 from PrismLauncher/backport-3024-to-release-9.x
[Backport release-9.x] fix leak on resource search
2024-11-15 08:55:46 +02:00
Alexandru Ionut Tripon
947fbf7d64
Merge pull request #3102 from PrismLauncher/backport-3070-to-release-9.x
[Backport release-9.x] Add scrollbar to Settings -> Launcher -> Features
2024-11-15 08:55:17 +02:00
Trial97
1c94a3e3e5 fix leak on resource search
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 8e7d84d05b)
2024-11-15 05:48:32 +00:00
TheKodeToad
eefeb5799d Add scrollbar to Settings -> Launcher -> Features
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
(cherry picked from commit 71e55f8829)
2024-11-15 05:40:31 +00:00
timoreo
6c6a4625ab
Merge pull request #3101 from PrismLauncher/backport-3096-to-release-9.x
[Backport release-9.x] Fix file remaingin open after program closure
2024-11-15 06:15:22 +01:00
timoreo
6d2a96f6a7
Merge pull request #3098 from Trial97/resource_backport
Fix crash caused by invalid resource pointer
2024-11-15 06:15:06 +01:00
Trial97
ea9029d7b6 Fix file remaingin open after program closure
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit ce61ed2f86)
2024-11-15 05:14:42 +00:00
Trial97
76602391f4 Fix crash caused by invalid resource pointer
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
2024-11-14 16:26:21 +02:00
Alexandru Ionut Tripon
509f8c7307
Merge pull request #3079 from PrismLauncher/backport-3074-to-release-9.x
[Backport release-9.x] Close the window using the invokeMethod to not block
2024-11-07 23:48:40 +02:00
Trial97
984daa450b Close the window using the invokeMethod to not block
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 9601fbf2d5)
2024-11-07 21:48:30 +00:00
Tayou
04e1a97d59
Merge pull request #3077 from PrismLauncher/backport-3036-to-release-9.x
[Backport release-9.x] Fix installed typo
2024-11-07 17:31:15 +01:00
Trial97
1dce1360bd Fix installed typo
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 670c932f32)
2024-11-07 16:31:03 +00:00
timoreo
87d5b96760
Merge pull request #3061 from PrismLauncher/backport-3060-to-release-9.x
[Backport release-9.x] ci: bump linux qt version
2024-11-05 11:26:18 +01:00
Rachel Powers
7f074ca7b9 ci: libxcb-curcsor_dev ?
Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com>
(cherry picked from commit ba6743d134)
2024-11-05 10:25:53 +00:00
Rachel Powers
c0394c52b7 ci: bump linux qt version
Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com>
(cherry picked from commit d63a336411)
2024-11-05 10:25:53 +00:00
Alexandru Ionut Tripon
53bc20f13f
Merge pull request #3052 from PrismLauncher/backport-3042-to-release-9.x
[Backport release-9.x] use isPortable to determine if the MSAStep should check for url handler
2024-11-03 11:56:20 +02:00
Trial97
40af3cf3d2 use isPortable to determine if the MSAStep should check for url handler
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 99cfb62370)
2024-11-03 09:56:08 +00:00
Alexandru Ionut Tripon
3977918c5b
Merge pull request #3051 from PrismLauncher/backport-3045-to-release-9.x
[Backport release-9.x] disable retry for modrinth currentVersions API
2024-11-03 11:56:07 +02:00
Trial97
484d90899f disable retry for modrinth currentVersions API
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 6f2f3c2d3b)
2024-11-03 09:55:50 +00:00
Tayou
0f5eb03839
Merge pull request #3034 from PrismLauncher/backport-3010-to-release-9.x 2024-10-30 21:57:18 +01:00
Trial97
d21cda1880 lock m_instanceExtras
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 11d4d948aa)
2024-10-30 20:56:30 +00:00
Alexandru Ionut Tripon
52a321b93b
Merge pull request #3033 from PrismLauncher/backport-3030-to-release-9.x
[Backport release-9.x] Fix system detection for Intel Macs
2024-10-30 21:21:49 +02:00
Trial97
dd8dec8be8 fix macos system detection
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 14c95b9d37)
2024-10-30 19:16:53 +00:00
Tayou
23d6f8aaed
Merge pull request #3028 from PrismLauncher/backport-3027-to-release-9.x 2024-10-29 23:15:22 +01:00
Ben Westover
d105d76f2a Fix some typos
Signed-off-by: Ben Westover <me@benthetechguy.net>
(cherry picked from commit f6511c601e)
2024-10-29 22:06:15 +00:00
Ben Westover
698a838b56 Shorten metainfo.xml app summary
Signed-off-by: Ben Westover <me@benthetechguy.net>
(cherry picked from commit fd109c4740)
2024-10-29 22:06:15 +00:00
Alexandru Ionut Tripon
1129b4160c
Merge pull request #3022 from PrismLauncher/backport-2989-to-release-9.x
[Backport release-9.x] add extra protection against empty download link
2024-10-28 23:00:19 +02:00
Trial97
63a6f823fd add qassert
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 94f65f8727)
2024-10-28 20:59:25 +00:00
Trial97
db32b2ad99 remove message box
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 9cdda4377b)
2024-10-28 20:59:25 +00:00
Trial97
c3cf5d31da replace currentData with itemData on QComboBox::currentIndexChanged slots
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 0cafac84ac)
2024-10-28 20:59:25 +00:00
Trial97
1e696328bb fix #3001
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit b593ff09e9)
2024-10-28 20:59:25 +00:00
Trial97
1d9c97803a rename snake_case to camelCase
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 44894a29b1)
2024-10-28 20:59:25 +00:00
Trial97
3d55236fdf add extra protection against empty download link
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 8daa1219a5)
2024-10-28 20:59:25 +00:00
Alexandru Ionut Tripon
42190819ae
Merge pull request #3020 from PrismLauncher/backport-2837-to-release-9.x
[Backport release-9.x] translate standard buttons
2024-10-28 22:36:29 +02:00
Trial97
130714a9ab translate standard buttons
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit bd82737efb)
2024-10-28 20:34:51 +00:00
Tayou
bf57d77075
Merge pull request #3017 from PrismLauncher/backport-3002-to-release-9.x 2024-10-28 14:24:25 +01:00
Trial97
98fe035442 replace unzipping with unpacking
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 9eb1ce3ad7)
2024-10-28 13:23:42 +00:00
Trial97
8e4994590b fix unzipping typo
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 685d3c79ac)
2024-10-28 13:23:42 +00:00
Tayou
0722dba820
Merge pull request #3016 from PrismLauncher/backport-3009-to-release-9.x 2024-10-28 14:04:52 +01:00
Trial97
9560447c92 swap search with filter button for modpacks
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 61448a61ea)
2024-10-28 13:04:39 +00:00
Alexandru Ionut Tripon
4d89512ca1
Merge pull request #3013 from PrismLauncher/backport-3008-to-release-9.x
[Backport release-9.x] change contributors name
2024-10-27 22:30:02 +02:00
Trial97
42a6bd1151 change ZekeZ name
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit c4cd7cf6c1)
2024-10-27 19:31:56 +00:00
Trial97
f06505b138 change contributors name
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit f373a5cea0)
2024-10-27 19:31:56 +00:00
seth
d854087089
Merge pull request #2997 from PrismLauncher/backport-2992-to-release-9.x
[Backport release-9.x] Sync Flake with Nixpkgs
2024-10-25 21:20:31 -04:00
seth
31031ec923 chore(nix): use self for version
Signed-off-by: seth <getchoo@tuta.io>
(cherry picked from commit 63b10738b2)
2024-10-26 00:57:00 +00:00
seth
5f06517b62 chore(nix): sync with nixpkgs
Signed-off-by: seth <getchoo@tuta.io>
(cherry picked from commit a5c554cf6e)
2024-10-26 00:57:00 +00:00
Tayou
dde5fc47d3
Merge pull request #2987 from Trial97/bump_9.2 2024-10-25 09:53:49 +02:00
Alexandru Ionut Tripon
76d5f632dc
Merge pull request #2993 from PrismLauncher/backport-2982-to-release-9.x
[Backport release-9.x] Use Launcher log level in AutoInstallJava
2024-10-25 09:46:30 +03:00
TheKodeToad
27c6596bcb Use Launcher log level in AutoInstallJava
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
(cherry picked from commit d8702e1357)
2024-10-25 06:42:32 +00:00
Alexandru Ionut Tripon
e2f5fb27a6
Merge pull request #2991 from PrismLauncher/backport-2963-to-release-9.x
[Backport release-9.x] chore(deps): update actions/cache action to v4.1.2
2024-10-25 09:33:52 +03:00
renovate[bot]
98819a0d02 chore(deps): update actions/cache action to v4.1.2
(cherry picked from commit 210d0d8aa2)
2024-10-25 06:30:00 +00:00
seth
2dde2c4bec
Merge pull request #2990 from PrismLauncher/backport-2980-to-release-9.x
[Backport release-9.x] Sync with Flathub manifest
2024-10-25 02:20:10 -04:00
Arcitec
008d69e5e5 fix: bring back Flathub manifest improvements to the repo
- Brings back all manifest improvements, such as the incredibly important Mojang Java Downloader (without it, the Flatpak doesn't work), and important fixes for Wayland.

Signed-off-by: Arcitec <38923130+Arcitec@users.noreply.github.com>
(cherry picked from commit 4ce025c0a2)
2024-10-25 06:19:25 +00:00
Trial97
a839258c07
bump develop to 9.2
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
2024-10-25 00:19:06 +03:00
Alexandru Ionut Tripon
89041531e1
Merge pull request #2981 from PrismLauncher/backport-2975-to-release-9.x
[Backport release-9.x] fix: don't hang the ui for a full version load
2024-10-24 15:09:19 +03:00
Rachel Powers
729cec5f45 fix don't hang the ui for a full version load
Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com>
(cherry picked from commit 7bd04ae928)
2024-10-24 10:24:53 +00:00
TheKodeToad
80d675d2e6
Merge pull request #2974 from PrismLauncher/backport-2972-to-release-9.x
[Backport release-9.x] Fix launching Minecraft in portable Linux
2024-10-23 22:39:58 +01:00
TheKodeToad
fb7d19941f Fix CleanEnviroment()'s usage of stripVariableEntries
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
(cherry picked from commit e7cd8fe078)
2024-10-23 21:30:57 +00:00
Alexandru Ionut Tripon
877ab62c2f
Merge pull request #2964 from PrismLauncher/backport-2958-to-release-9.x
[Backport release-9.x] skip parsing open QSaveFile temprary files as resources
2024-10-22 17:41:45 +03:00
Trial97
b983ae0fb0 fix small leak
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 836aebc0d9)
2024-10-22 14:41:34 +00:00
Trial97
85422427b9 Replaced QSet with QHash
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 73d33f93b3)
2024-10-22 14:41:34 +00:00
Trial97
51a71d0471 skip QSaveFile temprary files
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 562c301326)
2024-10-22 14:41:34 +00:00
Alexandru Ionut Tripon
25eaa4eba6
Merge pull request #2959 from PrismLauncher/backport-2954-to-release-9.x
[Backport release-9.x] do not try to import skin if path is empty
2024-10-22 00:15:10 +03:00
Alexandru Ionut Tripon
6da14d66bb Update launcher/ui/dialogs/skins/SkinManageDialog.cpp
Co-authored-by: TheKodeToad <TheKodeToad@proton.me>
Signed-off-by: Alexandru Ionut Tripon <alexandru.tripon97@gmail.com>
(cherry picked from commit 69028969f1)
2024-10-21 21:14:30 +00:00
Trial97
199c5497d3 do not try to import skin if path is empty
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 9a5b773e69)
2024-10-21 21:14:30 +00:00
Alexandru Ionut Tripon
740db2db02
Merge pull request #2956 from PrismLauncher/backport-2953-to-release-9.x
[Backport release-9.x] Fix removing portable.txt on Linux portable build
2024-10-21 22:46:49 +03:00
TheKodeToad
577f8074e1 Fix removing portable.txt on Linux portable build
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
(cherry picked from commit f3f4c44620)
2024-10-21 19:45:10 +00:00
Alexandru Ionut Tripon
c5e7bb90c5
Merge pull request #2952 from PrismLauncher/backport-2947-to-release-9.x
[Backport release-9.x] do not require java if auto-download is enabled
2024-10-21 18:04:53 +03:00
Trial97
1cf91fa5d9 do not require java if auto-download is enabled
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit fcadbbb739)
2024-10-21 15:02:54 +00:00
Tayou
3bf4fbf8f4
Merge pull request #2951 from PrismLauncher/backport-2948-to-release-9.x 2024-10-21 16:55:28 +02:00
TheKodeToad
ff97affa72 Fix /norestart
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
(cherry picked from commit 78e24962f9)
2024-10-21 14:54:35 +00:00
Alexandru Ionut Tripon
e8c9722a53
Merge pull request #2939 from PrismLauncher/backport-2938-to-release-9.x
[Backport release-9.x] fix sparkle signature
2024-10-21 00:08:40 +03:00
Trial97
9a810dfa6e fix sparkle signature
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 0586d38e03)
2024-10-20 21:07:55 +00:00
144 changed files with 1136 additions and 879 deletions

View file

@ -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'
@ -410,9 +410,8 @@ jobs:
if: matrix.name == 'macOS' if: matrix.name == 'macOS'
run: | run: |
if [ '${{ secrets.SPARKLE_ED25519_KEY }}' != '' ]; then if [ '${{ secrets.SPARKLE_ED25519_KEY }}' != '' ]; then
brew install openssl@3
echo '${{ secrets.SPARKLE_ED25519_KEY }}' > ed25519-priv.pem echo '${{ secrets.SPARKLE_ED25519_KEY }}' > ed25519-priv.pem
signature=$(/usr/local/opt/openssl@3/bin/openssl pkeyutl -sign -rawin -in ${{ github.workspace }}/PrismLauncher.zip -inkey ed25519-priv.pem | openssl base64 | tr -d \\n) signature=$(/opt/homebrew/opt/openssl@3/bin/openssl pkeyutl -sign -rawin -in ${{ github.workspace }}/PrismLauncher.zip -inkey ed25519-priv.pem | openssl base64 | tr -d \\n)
rm ed25519-priv.pem rm ed25519-priv.pem
cat >> $GITHUB_STEP_SUMMARY << EOF cat >> $GITHUB_STEP_SUMMARY << EOF
### Artifact Information :information_source: ### Artifact Information :information_source:
@ -634,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: "Prism Launcher.flatpak" bundle: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-Flatpak.flatpak
manifest-path: flatpak/org.prismlauncher.PrismLauncher.yml manifest-path: flatpak/org.prismlauncher.PrismLauncher.yml
nix: nix:

View file

@ -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 9) set(Launcher_VERSION_MAJOR 9)
set(Launcher_VERSION_MINOR 0) set(Launcher_VERSION_MINOR 2)
set(Launcher_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}") set(Launcher_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}")
set(Launcher_VERSION_NAME4 "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.0.0") set(Launcher_VERSION_NAME4 "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.0.0")
@ -397,8 +397,8 @@ if(UNIX AND APPLE)
set(MACOSX_SPARKLE_UPDATE_PUBLIC_KEY "v55ZWWD6QlPoXGV6VLzOTZxZUggWeE51X8cRQyQh6vA=" CACHE STRING "Public key for Sparkle update feed") set(MACOSX_SPARKLE_UPDATE_PUBLIC_KEY "v55ZWWD6QlPoXGV6VLzOTZxZUggWeE51X8cRQyQh6vA=" CACHE STRING "Public key for Sparkle update feed")
set(MACOSX_SPARKLE_UPDATE_FEED_URL "https://prismlauncher.org/feed/appcast.xml" CACHE STRING "URL for Sparkle update feed") set(MACOSX_SPARKLE_UPDATE_FEED_URL "https://prismlauncher.org/feed/appcast.xml" 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

View file

@ -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>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 Prism scans for downloaded mods in Settings or the prompt that appears.</string> <string>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 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>

View file

@ -85,18 +85,12 @@
formatter = forAllSystems (system: nixpkgsFor.${system}.nixfmt-rfc-style); formatter = forAllSystems (system: nixpkgsFor.${system}.nixfmt-rfc-style);
overlays.default = overlays.default = final: prev: {
final: prev:
let
version = builtins.substring 0 8 self.lastModifiedDate or "dirty";
in
{
prismlauncher-unwrapped = prev.callPackage ./nix/unwrapped.nix { prismlauncher-unwrapped = prev.callPackage ./nix/unwrapped.nix {
inherit inherit
libnbtplusplus libnbtplusplus
nix-filter nix-filter
self self
version
; ;
}; };

20
flatpak/flite.json Normal file
View 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.]+)$"
}
}
]
}

View file

@ -8,11 +8,7 @@
{ {
"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",
"path": "patches/weird_libdecor.patch"
} }
], ],
"cleanup": [ "cleanup": [

View file

@ -1,6 +1,6 @@
id: org.prismlauncher.PrismLauncher id: org.prismlauncher.PrismLauncher
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: prismlauncher - name: prismlauncher
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

View file

@ -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,

View file

@ -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;
}

View file

@ -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)

View file

@ -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

View file

@ -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 *

View file

@ -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"
@ -1071,6 +1072,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;
@ -1083,10 +1087,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();
@ -1380,6 +1381,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) {
@ -1404,7 +1406,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");
@ -1422,9 +1424,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();
} }
@ -1478,12 +1482,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();
@ -1503,6 +1509,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
@ -1560,6 +1567,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;
@ -1597,6 +1605,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) {
@ -1844,7 +1853,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();
@ -1883,3 +1892,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;
}

View file

@ -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;
}; };

View file

@ -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

View file

@ -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);
} }

View file

@ -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:

View file

@ -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()) {

View file

@ -61,6 +61,6 @@ void InstanceCreationTask::executeTask()
return; return;
} }
} }
if (!m_abort)
emitSucceeded(); emitSucceeded();
} }

View file

@ -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();
} }

View file

@ -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,

View file

@ -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();
} }

View file

@ -61,7 +61,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()
{ {

View file

@ -47,7 +47,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; }

View file

@ -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}" "$@"

View file

@ -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
View 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

View file

@ -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") {

View file

@ -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()

View file

@ -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);

View file

@ -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++;

View file

@ -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

View file

@ -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 ?

View file

@ -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);

View file

@ -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();

View file

@ -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));
} }

View file

@ -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;

View file

@ -222,10 +222,11 @@ 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) {
if (wait)
list->waitToLoad(); list->waitToLoad();
return list->count() != 0; return list->count() != 0;
} }

View file

@ -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();

View file

@ -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;

View file

@ -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:

View file

@ -1093,7 +1093,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

View file

@ -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()
{ {

View file

@ -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;

View file

@ -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;
} }

View file

@ -19,7 +19,7 @@
#include <Application.h> #include <Application.h>
AuthFlow::AuthFlow(AccountData* data, Action action, QObject* parent) : Task(parent), m_data(data) AuthFlow::AuthFlow(AccountData* data, Action action) : Task(), m_data(data)
{ {
if (data->type == AccountType::MSA) { if (data->type == AccountType::MSA) {
if (action == Action::DeviceCode) { if (action == Action::DeviceCode) {

View file

@ -17,7 +17,7 @@ class AuthFlow : public Task {
public: public:
enum class Action { Refresh, Login, DeviceCode }; enum class Action { Refresh, Login, DeviceCode };
explicit AuthFlow(AccountData* data, Action action = Action::Refresh, QObject* parent = 0); explicit AuthFlow(AccountData* data, Action action = Action::Refresh);
virtual ~AuthFlow() = default; virtual ~AuthFlow() = default;
void executeTask() override; void executeTask() override;

View file

@ -121,7 +121,7 @@ shared_qobject_ptr<AuthFlow> MinecraftAccount::login(bool useDeviceCode)
{ {
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)); m_currentTask.reset(new AuthFlow(&data, useDeviceCode ? AuthFlow::Action::DeviceCode : AuthFlow::Action::Login));
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")); });
@ -135,7 +135,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);

View file

@ -74,12 +74,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;
@ -90,17 +90,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();
@ -111,9 +111,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,
@ -208,12 +208,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();

View file

@ -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();

View file

@ -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);

View file

@ -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;

View file

@ -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];

View file

@ -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();

View file

@ -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);

View file

@ -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));

View file

@ -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();

View file

@ -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()
{ {

View file

@ -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()

View file

@ -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()
{ {

View file

@ -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()
{ {

View file

@ -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()
{ {

View file

@ -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()
{ {

View file

@ -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);

View file

@ -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;

View file

@ -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)

View file

@ -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;
}; };

View file

@ -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)

View file

@ -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 };

View file

@ -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;
} }

View file

@ -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;
} }
return ver;
}; };
for (auto l : instanceLoaders) { for (auto file_tmp : versions) {
auto ver = bestVersion(l); auto loaders = ModPlatform::modLoaderTypesToList(file_tmp.loaders);
if (ver.has_value()) { if (loaders.isEmpty()) {
return ver; checkVersion(file_tmp, ModPlatform::ModLoaderType(0));
} else {
for (auto loader : loaders) {
checkVersion(file_tmp, loader);
} }
} }
return bestVersion(modLoaders); }
// edge case: mod has installed for forge but the instance is fabric => fabric version will be prioritizated on update
auto currentLoaders = instanceLoaders + ModPlatform::modLoaderTypesToList(modLoaders);
currentLoaders.append(ModPlatform::ModLoaderType(0)); // add a fallback in case the versions do not define a loader
for (auto loader : currentLoaders) {
if (bestMatch.contains(loader)) {
return bestMatch.value(loader);
}
}
return {};
} }

View file

@ -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) {

View file

@ -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());

View file

@ -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 netJob = weak.lock()) {
if (auto* failed_action = netJob->getFailedActions().at(0); failed_action) if (auto* failed_action = netJob->getFailedActions().at(0); failed_action)
network_error_code = failed_action->replyStatusCode(); 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) {
// 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 netJob = weak.lock()) {
if (auto* failed_action = netJob->getFailedActions().at(0); failed_action) if (auto* failed_action = netJob->getFailedActions().at(0); failed_action)
network_error_code = failed_action->replyStatusCode(); 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) {
// 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 netJob = weak.lock()) {
if (auto* failed_action = netJob->getFailedActions().at(0); failed_action) if (auto* failed_action = netJob->getFailedActions().at(0); failed_action)
network_error_code = failed_action->replyStatusCode(); network_error_code = failed_action->replyStatusCode();
}
callbacks.on_fail(reason, network_error_code); callbacks.on_fail(reason, network_error_code);
}); });
return netJob; return netJob;

View file

@ -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;
} }
} }

View file

@ -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;
} }

View file

@ -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,21 +92,16 @@ 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 };
for (auto flag : flags) {
if (loader.testFlag(flag)) {
loader_filter = ModPlatform::getModLoaderAsString(flag); loader_filter = ModPlatform::getModLoaderAsString(flag);
break; 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:
// - The file needs to be preferred: It is either the primary file, or the one found via (explicit) usage of the // - The file needs to be preferred: It is either the primary file, or the one found via (explicit) usage of the

View file

@ -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 :)

View file

@ -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,12 +186,9 @@ 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 }) {
if (mod.loaders & loader) {
loaders.push_back(getModLoaderAsString(loader).toStdString()); loaders.push_back(getModLoaderAsString(loader).toStdString());
} }
}
toml::array mcVersions; toml::array mcVersions;
for (auto version : mod.mcVersions) { for (auto version : mod.mcVersions) {
mcVersions.push_back(version.toStdString()); mcVersions.push_back(version.toStdString());

View file

@ -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;

View file

@ -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

View file

@ -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)

View file

@ -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]

View file

@ -39,7 +39,6 @@
#include <QDebug> #include <QDebug>
#include <QFile> #include <QFile>
#include <QSaveFile>
#include <QStringList> #include <QStringList>
#include <QTemporaryFile> #include <QTemporaryFile>
#include <QTextStream> #include <QTextStream>

View file

@ -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);
} }

View file

@ -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

View file

@ -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()
{ {

View file

@ -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:

View file

@ -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)
{ {

View file

@ -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:

View file

@ -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);

View file

@ -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;

View file

@ -77,7 +77,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"));
@ -101,7 +101,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"));

View file

@ -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); });

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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();
} }

View file

@ -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()));

Some files were not shown because too many files have changed in this diff Show more