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
1151 changed files with 26954 additions and 52303 deletions

View file

@ -5,7 +5,6 @@ AllowShortIfStatementsOnASingleLine: false
ColumnLimit: 140
---
Language: Cpp
AccessModifierOffset: -1
AlignConsecutiveMacros: None
AlignConsecutiveAssignments: None
BraceWrapping:
@ -16,4 +15,3 @@ BraceWrapping:
BreakBeforeBraces: Custom
BreakConstructorInitializers: BeforeComma
Cpp11BracedListStyle: false
QualifierAlignment: Left

View file

@ -1,32 +1,5 @@
FormatStyle: file
Checks:
"bugprone-*,clang-analyzer-*,cppcoreguidelines-*,hicpp-*,misc-*,modernize-*,performance-*,portability-*,readability-*,
-*-magic-numbers,
-*-non-private-member-variables-in-classes,
-*-special-member-functions,
-bugprone-easily-swappable-parameters,
-cppcoreguidelines-owning-memory,
-cppcoreguidelines-pro-type-static-cast-downcast,
-modernize-use-nodiscard,
-modernize-use-trailing-return-type,
-portability-avoid-pragma-once,
-readability-avoid-unconditional-preprocessor-if,
-readability-function-cognitive-complexity,
-readability-identifier-length,
-readability-redundant-access-specifiers"
- modernize-use-using
- readability-avoid-const-params-in-decls
CheckOptions:
misc-include-cleaner.MissingIncludes: false
readability-identifier-naming.DefaultCase: "camelBack"
readability-identifier-naming.NamespaceCase: "CamelCase"
readability-identifier-naming.ClassCase: "CamelCase"
readability-identifier-naming.ClassConstantCase: "CamelCase"
readability-identifier-naming.EnumCase: "CamelCase"
readability-identifier-naming.EnumConstantCase: "CamelCase"
readability-identifier-naming.MacroDefinitionCase: "UPPER_CASE"
readability-identifier-naming.ClassMemberPrefix: "m_"
readability-identifier-naming.StaticConstantPrefix: "s_"
readability-identifier-naming.StaticVariablePrefix: "s_"
readability-identifier-naming.GlobalConstantPrefix: "g_"
readability-implicit-bool-conversion.AllowPointerConditions: true
SystemHeaders: false

View file

@ -1,22 +1,8 @@
# EditorConfig specs and documentation: https://EditorConfig.org
# top-most EditorConfig file
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
insert_final_newline = true
trim_trailing_whitespace = true
[*.{yml,nix}]
indent_size = 2
# C++ Code Style settings
[*.{c++,cc,cpp,cppm,cxx,h,h++,hh,hpp,hxx,inl,ipp,ixx,tlh,tli}]
cpp_generate_documentation_comments = doxygen_slash_star
[CMakeLists.txt]
ij_continuation_indent_size = 4
# EditorConfig specs and documentation: https://EditorConfig.org
# top-most EditorConfig file
root = true
# C++ Code Style settings
[*.{c++,cc,cpp,cppm,cxx,h,h++,hh,hpp,hxx,inl,ipp,ixx,tlh,tli}]
cpp_generate_documentation_comments = doxygen_slash_star

2
.envrc
View file

@ -1,2 +1,2 @@
use nix
use flake
watch_file nix/*.nix

View file

@ -5,9 +5,3 @@ bbb3b3e6f6e3c0f95873f22e6d0a4aaf350f49d9
# (nix) alejandra -> nixfmt
4c81d8c53d09196426568c4a31a4e752ed05397a
# reformat codebase
1d468ac35ad88d8c77cc83f25e3704d9bd7df01b
# format a part of codebase
5c8481a118c8fefbfe901001d7828eaf6866eac4

View file

@ -1,6 +1,6 @@
name: Bug Report
description: File a bug report
labels: ["bug: unconfirmed", "status: needs triage"]
labels: [bug]
body:
- type: markdown
attributes:
@ -23,14 +23,14 @@ body:
- macOS
- Linux
- Other
- type: input
- type: textarea
attributes:
label: Version of Prism Launcher
description: The version of Prism Launcher used in the bug report.
placeholder: Prism Launcher 5.0
validations:
required: true
- type: input
- type: textarea
attributes:
label: Version of Qt
description: The version of Qt used in the bug report. You can find it in Help -> About Prism Launcher -> About Qt.

View file

@ -1,7 +1,7 @@
# Template based on https://gitlab.archlinux.org/archlinux/rfcs/-/blob/0ba3b61e987e197f8d1901709409b8564958f78a/rfcs/0000-template.rst
name: Request for Comment (RFC)
description: Propose a larger change and start a discussion.
labels: ["type: enhancement", "status: needs discussion", "status: needs triage"]
labels: [rfc]
body:
- type: markdown
attributes:
@ -44,8 +44,8 @@ body:
attributes:
label: Unresolved Questions
description: |
Are there any portions of your proposal which need to be discussed with the community before the RFC can proceed?
Be careful here -- an RFC with a lot of remaining questions is likely to be stalled.
Are there any portions of your proposal which need to be discussed with the community before the RFC can proceed?
Be careful here -- an RFC with a lot of remaining questions is likely to be stalled.
If your RFC is mostly unresolved questions and not too much substance, it may not be ready.
placeholder: Do a lot of users care about the cat?
validations:

View file

@ -1,6 +1,6 @@
name: Suggestion
description: Make a suggestion
labels: ["type: enhancement", "status: needs triage"]
labels: [enhancement]
body:
- type: markdown
attributes:

View file

@ -1,153 +0,0 @@
name: Package for Linux
description: Create Linux packages for Prism Launcher
inputs:
version:
description: Launcher version
required: true
build-type:
description: Type for the build
required: true
default: Debug
artifact-name:
description: Name of the uploaded artifact
required: true
default: Linux
qt-version:
description: Version of Qt to use
required: true
gpg-private-key:
description: Private key for AppImage signing
required: false
gpg-private-key-id:
description: ID for the gpg-private-key, to select the signing key
required: false
runs:
using: composite
steps:
- name: Cleanup Qt installation on Linux
shell: bash
run: |
rm -rf "$QT_PLUGIN_PATH"/printsupport
rm -rf "$QT_PLUGIN_PATH"/sqldrivers
rm -rf "$QT_PLUGIN_PATH"/help
rm -rf "$QT_PLUGIN_PATH"/designer
rm -rf "$QT_PLUGIN_PATH"/qmltooling
rm -rf "$QT_PLUGIN_PATH"/qmlls
rm -rf "$QT_PLUGIN_PATH"/qmllint
rm -rf "$QT_PLUGIN_PATH"/platformthemes/libqgtk3.so
- name: Setup build variables
shell: bash
run: |
# Fixup architecture naming for AppImages
dpkg_arch="$(dpkg-architecture -q DEB_HOST_ARCH_CPU)"
case "$dpkg_arch" in
"amd64")
APPIMAGE_ARCH="x86_64"
;;
"arm64")
APPIMAGE_ARCH="aarch64"
;;
*)
echo "# 🚨 The Debian architecture \"$deb_arch\" is not recognized!" >> "$GITHUB_STEP_SUMMARY"
exit 1
;;
esac
echo "APPIMAGE_ARCH=$APPIMAGE_ARCH" >> "$GITHUB_ENV"
# Used for the file paths of libraries
echo "DEB_HOST_MULTIARCH=$(dpkg-architecture -q DEB_HOST_MULTIARCH)" >> "$GITHUB_ENV"
- name: Package AppImage
shell: bash
env:
VERSION: ${{ github.ref_type == 'tag' && github.ref_name || inputs.version }}
BUILD_DIR: build
INSTALL_APPIMAGE_DIR: install-appdir
GPG_PRIVATE_KEY: ${{ inputs.gpg-private-key }}
run: |
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }} --prefix ${{ env.INSTALL_APPIMAGE_DIR }}
if [ '${{ inputs.gpg-private-key-id }}' != '' ]; then
echo "$GPG_PRIVATE_KEY" > privkey.asc
gpg --import privkey.asc
gpg --export --armor ${{ inputs.gpg-private-key-id }} > pubkey.asc
else
echo ":warning: Skipped code signing for Linux AppImage, as gpg key was not present." >> $GITHUB_STEP_SUMMARY
fi
sharun lib4bin \
--hard-links \
--with-hooks \
--dst-dir "$INSTALL_APPIMAGE_DIR" \
"$INSTALL_APPIMAGE_DIR"/bin/* "$QT_PLUGIN_PATH"/*/*.so
cp ~/bin/AppImageUpdate.AppImage "$INSTALL_APPIMAGE_DIR"/bin/
# FIXME(@getchoo): gamemode doesn't seem to be very portable with DBus. Find a way to make it work!
find "$INSTALL_APPIMAGE_DIR" -name '*gamemode*' -exec rm {} +
#disable OpenGL and Vulkan launcher features until https://github.com/VHSgunzo/sharun/issues/35
echo "PRISMLAUNCHER_DISABLE_GLVULKAN=1" >> "$INSTALL_APPIMAGE_DIR"/.env
#makes the launcher use portals for file picking
echo "QT_QPA_PLATFORMTHEME=xdgdesktopportal" >> "$INSTALL_APPIMAGE_DIR"/.env
ln -s org.prismlauncher.PrismLauncher.metainfo.xml "$INSTALL_APPIMAGE_DIR"/share/metainfo/org.prismlauncher.PrismLauncher.appdata.xml
ln -s share/applications/org.prismlauncher.PrismLauncher.desktop "$INSTALL_APPIMAGE_DIR"
ln -s share/icons/hicolor/256x256/apps/org.prismlauncher.PrismLauncher.png "$INSTALL_APPIMAGE_DIR"
mv "$INSTALL_APPIMAGE_DIR"/{sharun,AppRun}
ls -la "$INSTALL_APPIMAGE_DIR"
if [[ "${{ github.ref_type }}" == "tag" ]]; then
APPIMAGE_DEST="PrismLauncher-Linux-$APPIMAGE_ARCH.AppImage"
else
APPIMAGE_DEST="PrismLauncher-Linux-$VERSION-${{ inputs.build-type }}-$APPIMAGE_ARCH.AppImage"
fi
mkappimage \
--updateinformation "gh-releases-zsync|${{ github.repository_owner }}|${{ github.event.repository.name }}|latest|PrismLauncher-Linux-$APPIMAGE_ARCH.AppImage.zsync" \
"$INSTALL_APPIMAGE_DIR" \
"$APPIMAGE_DEST"
- name: Package portable tarball
shell: bash
env:
BUILD_DIR: build
INSTALL_PORTABLE_DIR: install-portable
run: |
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }} --prefix ${{ env.INSTALL_PORTABLE_DIR }}
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable
sharun lib4bin \
--with-hooks \
--hard-links \
--dst-dir "$INSTALL_PORTABLE_DIR" \
"$INSTALL_PORTABLE_DIR"/bin/* "$QT_PLUGIN_PATH"/*/*.so
# FIXME(@getchoo): gamemode doesn't seem to be very portable with DBus. Find a way to make it work!
find "$INSTALL_PORTABLE_DIR" -name '*gamemode*' -exec rm {} +
for l in $(find ${{ env.INSTALL_PORTABLE_DIR }} -type f -o -type l); do l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_PORTABLE_DIR }}/}; l=${l#./}; echo $l; done > ${{ env.INSTALL_PORTABLE_DIR }}/manifest.txt
cd ${{ env.INSTALL_PORTABLE_DIR }}
tar -czf ../PrismLauncher-portable.tar.gz *
- name: Upload binary tarball
uses: actions/upload-artifact@v7
with:
name: PrismLauncher-${{ inputs.artifact-name }}-Qt6-Portable-${{ inputs.version }}-${{ inputs.build-type }}
path: PrismLauncher-portable.tar.gz
- name: Upload AppImage
uses: actions/upload-artifact@v7
with:
name: PrismLauncher-${{ runner.os }}-${{ inputs.version }}-${{ inputs.build-type }}-${{ env.APPIMAGE_ARCH }}.AppImage
path: PrismLauncher-${{ runner.os }}-*${{ env.APPIMAGE_ARCH }}.AppImage
- name: Upload AppImage Zsync
uses: actions/upload-artifact@v7
with:
name: PrismLauncher-${{ runner.os }}-${{ inputs.version }}-${{ inputs.build-type }}-${{ env.APPIMAGE_ARCH }}.AppImage.zsync
path: PrismLauncher-${{ runner.os }}-*${{ env.APPIMAGE_ARCH }}.AppImage.zsync

View file

@ -1,147 +0,0 @@
name: Package for macOS
description: Create a macOS package for Prism Launcher
inputs:
version:
description: Launcher version
required: true
build-type:
description: Type for the build
required: true
default: Debug
artifact-name:
description: Name of the uploaded artifact
required: true
default: macOS
apple-codesign-cert:
description: Certificate for signing macOS builds
required: false
apple-codesign-password:
description: Password for signing macOS builds
required: false
apple-codesign-id:
description: Certificate ID for signing macOS builds
required: false
apple-notarize-apple-id:
description: Apple ID used for notarizing macOS builds
required: false
apple-notarize-team-id:
description: Team ID used for notarizing macOS builds
required: false
apple-notarize-password:
description: Password used for notarizing macOS builds
required: false
sparkle-ed25519-key:
description: Private key for signing Sparkle updates
required: false
runs:
using: composite
steps:
- name: Fetch codesign certificate
shell: bash
run: |
echo '${{ inputs.apple-codesign-cert }}' | base64 --decode > codesign.p12
if [ -n '${{ inputs.apple-codesign-id }}' ]; then
security create-keychain -p '${{ inputs.apple-codesign-password }}' build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p '${{ inputs.apple-codesign-password }}' build.keychain
security import codesign.p12 -k build.keychain -P '${{ inputs.apple-codesign-password }}' -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k '${{ inputs.apple-codesign-password }}' build.keychain
else
echo ":warning: Using ad-hoc code signing for macOS, as certificate was not present." >> $GITHUB_STEP_SUMMARY
fi
- name: Package
shell: bash
env:
BUILD_DIR: build
INSTALL_DIR: install
run: |
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }}
cd ${{ env.INSTALL_DIR }}
chmod +x "PrismLauncher.app/Contents/MacOS/prismlauncher"
if [ -n '${{ inputs.apple-codesign-id }}' ]; then
APPLE_CODESIGN_ID='${{ inputs.apple-codesign-id }}'
ENTITLEMENTS_FILE='../program_info/App.entitlements'
else
APPLE_CODESIGN_ID='-'
ENTITLEMENTS_FILE='../program_info/AdhocSignedApp.entitlements'
fi
sudo codesign --sign "$APPLE_CODESIGN_ID" --deep --force --entitlements "$ENTITLEMENTS_FILE" --options runtime "PrismLauncher.app/Contents/MacOS/prismlauncher"
mv "PrismLauncher.app" "Prism Launcher.app"
- name: Notarize
shell: bash
env:
INSTALL_DIR: install
run: |
cd ${{ env.INSTALL_DIR }}
if [ -n '${{ inputs.apple-notarize-password }}' ]; then
ditto -c -k --sequesterRsrc --keepParent "Prism Launcher.app" ../PrismLauncher.zip
xcrun notarytool submit ../PrismLauncher.zip \
--wait --progress \
--apple-id '${{ inputs.apple-notarize-apple-id }}' \
--team-id '${{ inputs.apple-notarize-team-id }}' \
--password '${{ inputs.apple-notarize-password }}'
xcrun stapler staple "Prism Launcher.app"
else
echo ":warning: Skipping notarization as credentials are not present." >> $GITHUB_STEP_SUMMARY
fi
ditto -c -k --sequesterRsrc --keepParent "Prism Launcher.app" ../PrismLauncher.zip
- name: Create DMG
shell: bash
env:
INSTALL_DIR: install
run: |
cd ${{ env.INSTALL_DIR }}
mkdir -p src
cp -R "Prism Launcher.app" src/
ln -s /Applications src/
hdiutil create \
-volname "Prism Launcher ${{ inputs.version }}" \
-srcfolder src \
-ov -format ULMO \
"../PrismLauncher.dmg"
- name: Make Sparkle signature
shell: bash
run: |
if [ '${{ inputs.sparkle-ed25519-key }}' != '' ]; then
echo '${{ inputs.sparkle-ed25519-key }}' > ed25519-priv.pem
signature_zip=$(/opt/homebrew/opt/openssl@3/bin/openssl pkeyutl -sign -rawin -in ${{ github.workspace }}/PrismLauncher.zip -inkey ed25519-priv.pem | openssl base64 | tr -d \\n)
signature_dmg=$(/opt/homebrew/opt/openssl@3/bin/openssl pkeyutl -sign -rawin -in ${{ github.workspace }}/PrismLauncher.dmg -inkey ed25519-priv.pem | openssl base64 | tr -d \\n)
rm ed25519-priv.pem
cat >> $GITHUB_STEP_SUMMARY << EOF
### Artifact Information :information_source:
- :memo: Sparkle Signature (ed25519): \`$signature_zip\` (ZIP)
- :memo: Sparkle Signature (ed25519): \`$signature_dmg\` (DMG)
EOF
else
cat >> $GITHUB_STEP_SUMMARY << EOF
### Artifact Information :information_source:
- :warning: Sparkle Signature (ed25519): No private key available (likely a pull request or fork)
EOF
fi
- name: Upload binary tarball
uses: actions/upload-artifact@v7
with:
name: PrismLauncher-${{ inputs.artifact-name }}-${{ inputs.version }}-${{ inputs.build-type }}
path: PrismLauncher.zip
- name: Upload disk image
uses: actions/upload-artifact@v7
with:
name: PrismLauncher-${{ inputs.artifact-name }}-${{ inputs.version }}-${{ inputs.build-type }}.dmg
path: PrismLauncher.dmg

View file

@ -1,186 +0,0 @@
name: Package for Windows
description: Create a Windows package for Prism Launcher
inputs:
version:
description: Launcher version
required: true
build-type:
description: Type for the build
required: true
default: Debug
artifact-name:
description: Name of the uploaded artifact
required: true
msystem:
description: MSYS2 subsystem to use
required: false
azure-client-id:
description: Client ID for the Azure Signer Application
required: true
azure-tenant-id:
description: Tenant ID for the Azure Signer Application
required: true
azure-subscription-id:
description: Subscription ID for the Azure Signer Application
required: true
runs:
using: composite
steps:
- name: Package (MinGW)
if: ${{ inputs.msystem != '' }}
shell: msys2 {0}
env:
BUILD_DIR: build
INSTALL_DIR: install
run: |
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }}
touch ${{ env.INSTALL_DIR }}/manifest.txt
for l in $(find ${{ env.INSTALL_DIR }} -type f); do l=$(cygpath -u $l); l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_DIR }}/}; l=${l#./}; echo $l; done >> ${{ env.INSTALL_DIR }}/manifest.txt
- name: Package (MSVC)
if: ${{ inputs.msystem == '' }}
shell: pwsh
env:
BUILD_DIR: build
INSTALL_DIR: install
run: |
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }}
cd ${{ github.workspace }}
Get-ChildItem ${{ env.INSTALL_DIR }} -Recurse | ForEach FullName | Resolve-Path -Relative | %{ $_.TrimStart('.\') } | %{ $_.TrimStart('${{ env.INSTALL_DIR }}') } | %{ $_.TrimStart('\') } | Out-File -FilePath ${{ env.INSTALL_DIR }}/manifest.txt
- name: Emit warning for unsigned builds
if: ${{ env.CI_HAS_ACCESS_TO_AZURE == '' || inputs.azure-client-id == '' }}
shell: pwsh
run: |
":warning: Skipped code signing for Windows, as certificate was not present." >> $env:GITHUB_STEP_SUMMARY
- name: Login to Azure
if: ${{ env.CI_HAS_ACCESS_TO_AZURE != '' && inputs.azure-client-id != '' }}
uses: azure/login@v3
with:
client-id: ${{ inputs.azure-client-id }}
tenant-id: ${{ inputs.azure-tenant-id }}
subscription-id: ${{ inputs.azure-subscription-id }}
- name: Sign executables
if: ${{ env.CI_HAS_ACCESS_TO_AZURE != '' && inputs.azure-client-id != '' }}
uses: azure/artifact-signing-action@v2
with:
endpoint: https://eus.codesigning.azure.net/
trusted-signing-account-name: PrismLauncher
certificate-profile-name: PrismLauncher
files-folder: ${{ github.workspace }}\install\
files-folder-filter: dll,exe
files-folder-recurse: true
files-folder-depth: 2
# recommended in https://github.com/Azure/artifact-signing-action#timestamping-1
timestamp-rfc3161: 'http://timestamp.acs.microsoft.com'
timestamp-digest: 'SHA256'
# TODO(@getchoo): Is this all really needed???
# https://github.com/Azure/trusted-signing-action/blob/fc390cf8ed0f14e248a542af1d838388a47c7a7c/docs/OIDC.md
exclude-environment-credential: true
exclude-workload-identity-credential: true
exclude-managed-identity-credential: true
exclude-shared-token-cache-credential: true
exclude-visual-studio-credential: true
exclude-visual-studio-code-credential: true
exclude-azure-cli-credential: false
exclude-azure-powershell-credential: true
exclude-azure-developer-cli-credential: true
exclude-interactive-browser-credential: true
- name: Package (MinGW, portable)
if: ${{ inputs.msystem != '' }}
shell: msys2 {0}
env:
BUILD_DIR: build
INSTALL_DIR: install
INSTALL_PORTABLE_DIR: install-portable
run: |
cp -r ${{ env.INSTALL_DIR }} ${{ env.INSTALL_PORTABLE_DIR }} # cmake install on Windows is slow, let's just copy instead
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable
for l in $(find ${{ env.INSTALL_PORTABLE_DIR }} -type f); do l=$(cygpath -u $l); l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_PORTABLE_DIR }}/}; l=${l#./}; echo $l; done >> ${{ env.INSTALL_PORTABLE_DIR }}/manifest.txt
- name: Package (MSVC, portable)
if: ${{ inputs.msystem == '' }}
shell: pwsh
env:
BUILD_DIR: build
INSTALL_DIR: install
INSTALL_PORTABLE_DIR: install-portable
run: |
cp -r ${{ env.INSTALL_DIR }} ${{ env.INSTALL_PORTABLE_DIR }} # cmake install on Windows is slow, let's just copy instead
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable
Get-ChildItem ${{ env.INSTALL_PORTABLE_DIR }} -Recurse | ForEach FullName | Resolve-Path -Relative | %{ $_.TrimStart('.\') } | %{ $_.TrimStart('${{ env.INSTALL_PORTABLE_DIR }}') } | %{ $_.TrimStart('\') } | Out-File -FilePath ${{ env.INSTALL_DIR }}/manifest.txt
- name: Package (installer)
shell: pwsh
env:
BUILD_DIR: build
INSTALL_DIR: install
NSCURL_VERSION: "v24.9.26.122"
NSCURL_SHA256: "AEE6C4BE3CB6455858E9C1EE4B3AFE0DB9960FA03FE99CCDEDC28390D57CCBB0"
run: |
New-Item -Name NSISPlugins -ItemType Directory
Invoke-Webrequest https://github.com/negrutiu/nsis-nscurl/releases/download/"${{ env.NSCURL_VERSION }}"/NScurl.zip -OutFile NSISPlugins\NScurl.zip
$nscurl_hash = Get-FileHash NSISPlugins\NScurl.zip -Algorithm Sha256 | Select-Object -ExpandProperty Hash
if ( $nscurl_hash -ne "${{ env.nscurl_sha256 }}") {
echo "::error:: NSCurl.zip sha256 mismatch"
exit 1
}
Expand-Archive -Path NSISPlugins\NScurl.zip -DestinationPath NSISPlugins\NScurl
cd ${{ env.INSTALL_DIR }}
makensis -NOCD "${{ github.workspace }}/${{ env.BUILD_DIR }}/program_info/win_install.nsi"
- name: Sign installer
if: ${{ env.CI_HAS_ACCESS_TO_AZURE != '' && inputs.azure-client-id != '' }}
uses: azure/artifact-signing-action@v2
with:
endpoint: https://eus.codesigning.azure.net/
trusted-signing-account-name: PrismLauncher
certificate-profile-name: PrismLauncher
files: |
${{ github.workspace }}\PrismLauncher-Setup.exe
# recommended in https://github.com/Azure/artifact-signing-action#timestamping-1
timestamp-rfc3161: 'http://timestamp.acs.microsoft.com'
timestamp-digest: 'SHA256'
# TODO(@getchoo): Is this all really needed???
# https://github.com/Azure/trusted-signing-action/blob/fc390cf8ed0f14e248a542af1d838388a47c7a7c/docs/OIDC.md
exclude-environment-credential: true
exclude-workload-identity-credential: true
exclude-managed-identity-credential: true
exclude-shared-token-cache-credential: true
exclude-visual-studio-credential: true
exclude-visual-studio-code-credential: true
exclude-azure-cli-credential: false
exclude-azure-powershell-credential: true
exclude-azure-developer-cli-credential: true
exclude-interactive-browser-credential: true
- name: Upload binary zip
uses: actions/upload-artifact@v7
with:
name: PrismLauncher-${{ inputs.artifact-name }}-${{ inputs.version }}-${{ inputs.build-type }}
path: install/**
- name: Upload portable zip
uses: actions/upload-artifact@v7
with:
name: PrismLauncher-${{ inputs.artifact-name }}-Portable-${{ inputs.version }}-${{ inputs.build-type }}
path: install-portable/**
- name: Upload installer
uses: actions/upload-artifact@v7
with:
name: PrismLauncher-${{ inputs.artifact-name }}-Setup-${{ inputs.version }}-${{ inputs.build-type }}
path: PrismLauncher-Setup.exe

View file

@ -1,81 +0,0 @@
name: Setup Dependencies
description: Install and setup dependencies for building Prism Launcher
inputs:
build-type:
description: Type for the build
required: true
default: Debug
artifact-name:
description: Name of the uploaded artifact
required: true
msystem:
description: MSYS2 subsystem to use
required: false
vcvars-arch:
description: Visual Studio architecture to use
required: false
qt-architecture:
description: Qt architecture
required: false
qt-version:
description: Version of Qt to use
required: true
outputs:
build-type:
description: Type of build used
value: ${{ inputs.build-type }}
qt-version:
description: Version of Qt used
value: ${{ inputs.qt-version }}
runs:
using: composite
steps:
- name: Setup Linux dependencies
if: ${{ runner.os == 'Linux' }}
uses: ./.github/actions/setup-dependencies/linux
- name: Setup macOS dependencies
if: ${{ runner.os == 'macOS' }}
uses: ./.github/actions/setup-dependencies/macos
with:
build-type: ${{ inputs.build-type }}
- name: Setup Windows dependencies
if: ${{ runner.os == 'Windows' }}
uses: ./.github/actions/setup-dependencies/windows
with:
build-type: ${{ inputs.build-type }}
msystem: ${{ inputs.msystem }}
vcvars-arch: ${{ inputs.vcvars-arch }}
# TODO(@getchoo): Get this working on MSYS2!
- name: Setup ccache
if: ${{ (runner.os != 'Windows' || inputs.msystem == '') && inputs.build-type == 'Debug' }}
uses: hendrikmuhs/ccache-action@v1.2.23
with:
variant: sccache
create-symlink: ${{ runner.os != 'Windows' }}
key: ${{ runner.os }}-${{ runner.arch }}-${{ inputs.artifact-name }}-sccache
- name: Use ccache on debug builds
if: ${{ inputs.build-type == 'Debug' }}
shell: bash
env:
# Only use ccache on MSYS2
CCACHE_VARIANT: ${{ (runner.os == 'Windows' && inputs.msystem != '') && 'ccache' || 'sccache' }}
run: |
echo "CMAKE_C_COMPILER_LAUNCHER=$CCACHE_VARIANT" >> "$GITHUB_ENV"
echo "CMAKE_CXX_COMPILER_LAUNCHER=$CCACHE_VARIANT" >> "$GITHUB_ENV"
- name: Install Qt
if: ${{ inputs.msystem == '' }}
uses: jurplel/install-qt-action@v4
with:
aqtversion: "==3.1.*"
version: ${{ inputs.qt-version }}
modules: qtimageformats qtnetworkauth
cache: ${{ inputs.build-type == 'Debug' }}

View file

@ -1,54 +0,0 @@
name: Setup Linux dependencies
description: Install and setup dependencies for building Prism Launcher
runs:
using: composite
steps:
- name: Install host dependencies
shell: bash
run: |
sudo apt-get -y update
sudo apt-get -y install \
dpkg-dev \
ninja-build extra-cmake-modules pkg-config scdoc \
cmark gamemode-dev libarchive-dev libcmark-dev libqrencode-dev zlib1g-dev \
libxcb-cursor-dev libtomlplusplus-dev
- name: Setup AppImage tooling
shell: bash
env:
GH_TOKEN: ${{ github.token }}
run: |
# Determinate AppImage architecture to use
dpkg_arch="$(dpkg-architecture -q DEB_HOST_ARCH_CPU)"
case "$dpkg_arch" in
"amd64")
APPIMAGE_ARCH="x86_64"
;;
"arm64")
APPIMAGE_ARCH="aarch64"
;;
*)
echo "# 🚨 The Debian architecture \"$deb_arch\" is not recognized!" >> "$GITHUB_STEP_SUMMARY"
exit 1
;;
esac
gh release download \
--repo VHSgunzo/sharun \
--pattern "sharun-$APPIMAGE_ARCH-aio" \
--output ~/bin/sharun
# FIXME!: revert this to probonopd/go-appimage once https://github.com/probonopd/go-appimage/pull/377 is merged!
gh release download continuous \
--repo DioEgizio/go-appimage \
--pattern "mkappimage-*-$APPIMAGE_ARCH.AppImage" \
--output ~/bin/mkappimage
gh release download \
--repo AppImageCommunity/AppImageUpdate \
--pattern "AppImageUpdate-$APPIMAGE_ARCH.AppImage" \
--output ~/bin/AppImageUpdate.AppImage
chmod +x ~/bin/*
echo "$HOME/bin" >> "$GITHUB_PATH"

View file

@ -1,47 +0,0 @@
name: Setup macOS dependencies
inputs:
build-type:
description: Type for the build
required: true
default: Debug
runs:
using: composite
steps:
- name: Install dependencies
shell: bash
run: |
brew update
brew install ninja extra-cmake-modules temurin@17 mono
- name: Set JAVA_HOME
shell: bash
run: |
echo "JAVA_HOME=$(/usr/libexec/java_home -v 17)" >> "$GITHUB_ENV"
- name: Setup vcpkg cache
if: ${{ inputs.build-type == 'Debug' }}
shell: bash
env:
USERNAME: ${{ github.repository_owner }}
GITHUB_TOKEN: ${{ github.token }}
FEED_URL: https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json
run: |
mono `vcpkg fetch nuget | tail -n 1` \
sources add \
-Source "$FEED_URL" \
-StorePasswordInClearText \
-Name GitHubPackages \
-UserName "$USERNAME" \
-Password "$GITHUB_TOKEN"
mono `vcpkg fetch nuget | tail -n 1` \
setapikey "$GITHUB_TOKEN" \
-Source "$FEED_URL"
echo "VCPKG_BINARY_SOURCES=clear;nuget,$FEED_URL,readwrite" >> "$GITHUB_ENV"
- name: Setup vcpkg environment
shell: bash
run: |
echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> "$GITHUB_ENV"

View file

@ -1,108 +0,0 @@
name: Setup Windows Dependencies
description: Install and setup dependencies for building Prism Launcher
inputs:
build-type:
description: Type for the build
required: true
default: Debug
msystem:
description: MSYS2 subsystem to use
required: false
vcvars-arch:
description: Visual Studio architecture to use
required: true
default: amd64
runs:
using: composite
steps:
# NOTE: Installed on MinGW as well for SignTool
- name: Enter VS Developer shell
if: ${{ runner.os == 'Windows' }}
uses: ilammy/msvc-dev-cmd@v1
with:
arch: ${{ inputs.vcvars-arch }}
vsversion: 2022
- name: Setup Java (MSVC)
uses: actions/setup-java@v5
with:
# NOTE(@getchoo): We should probably stay on Zulu.
# Temurin doesn't have Java 17 builds for WoA
distribution: zulu
java-version: 17
- name: Setup vcpkg cache (MSVC)
if: ${{ inputs.msystem == '' && inputs.build-type == 'Debug' }}
shell: pwsh
env:
USERNAME: ${{ github.repository_owner }}
GITHUB_TOKEN: ${{ github.token }}
FEED_URL: https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json
run: |
.$(vcpkg fetch nuget) `
sources add `
-Source "$env:FEED_URL" `
-StorePasswordInClearText `
-Name GitHubPackages `
-UserName "$env:USERNAME" `
-Password "$env:GITHUB_TOKEN"
.$(vcpkg fetch nuget) `
setapikey "$env:GITHUB_TOKEN" `
-Source "$env:FEED_URL"
"VCPKG_BINARY_SOURCES=clear;nuget,$env:FEED_URL,readwrite" | Out-File -Append $env:GITHUB_ENV
- name: Setup vcpkg environment (MSVC)
if: ${{ inputs.msystem == '' }}
shell: bash
run: |
echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> "$GITHUB_ENV"
- name: Setup MSYS2 (MinGW)
if: ${{ inputs.msystem != '' }}
uses: msys2/setup-msys2@v2
with:
msystem: ${{ inputs.msystem }}
update: true
install: >-
git
pacboy: >-
toolchain:p
ccache:p
cmake:p
extra-cmake-modules:p
ninja:p
qt6-base:p
qt6-svg:p
qt6-imageformats:p
qt6-networkauth:p
cmark:p
qrencode:p
tomlplusplus:p
libarchive:p
- name: List pacman packages (MinGW)
if: ${{ inputs.msystem != '' }}
shell: msys2 {0}
run: |
pacman -Qe
- name: Retrieve ccache cache (MinGW)
if: ${{ inputs.msystem != '' && inputs.build-type == 'Debug' }}
uses: actions/cache@v5.0.5
with:
path: '${{ github.workspace }}\.ccache'
key: ${{ runner.os }}-mingw-w64-ccache-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-mingw-w64-ccache
- name: Setup ccache (MinGW)
if: ${{ inputs.msystem != '' && inputs.build-type == 'Debug' }}
shell: msys2 {0}
run: |
ccache --set-config=cache_dir='${{ github.workspace }}\.ccache'
ccache --set-config=max_size='500M'
ccache --set-config=compression=true
ccache -p # Show config

View file

@ -8,7 +8,8 @@ on:
# the GitHub repository. This means that it should not evaluate user input in a
# way that allows code injection.
permissions: {}
permissions:
contents: read
jobs:
backport:
@ -18,13 +19,13 @@ jobs:
actions: write # for korthout/backport-action to create PR with workflow changes
name: Backport Pull Request
if: github.repository_owner == 'PrismLauncher' && github.event.pull_request.merged == true && (github.event_name != 'labeled' || startsWith('backport', github.event.label.name))
runs-on: ubuntu-slim
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Create backport PRs
uses: korthout/backport-action@v4.5
uses: korthout/backport-action@v3.1.0
with:
# Config README: https://github.com/korthout/backport-action#backport-action
pull_description: |-

View file

@ -1,257 +0,0 @@
name: Blocked/Stacked Pull Requests Automation
on:
pull_request_target:
types:
- opened
- reopened
- edited
- synchronize
workflow_dispatch:
inputs:
pr_id:
description: Local Pull Request number to work on
required: true
type: number
permissions: {}
jobs:
blocked_status:
name: Check Blocked Status
runs-on: ubuntu-slim
steps:
- name: Generate token
id: generate-token
uses: actions/create-github-app-token@v3
with:
app-id: ${{ vars.PULL_REQUEST_APP_ID }}
private-key: ${{ secrets.PULL_REQUEST_APP_PRIVATE_KEY }}
- name: Setup From Dispatch Event
if: github.event_name == 'workflow_dispatch'
id: dispatch_event_setup
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
PR_NUMBER: ${{ inputs.pr_id }}
run: |
# setup env for the rest of the workflow
OWNER=$(dirname "${{ github.repository }}")
REPO=$(basename "${{ github.repository }}")
PR_JSON=$(
gh api \
-H "Accept: application/vnd.github.raw+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"/repos/$OWNER/$REPO/pulls/$PR_NUMBER"
)
echo "PR_JSON=$PR_JSON" >> "$GITHUB_ENV"
- name: Setup Environment
id: env_setup
env:
EVENT_PR_JSON: ${{ toJSON(github.event.pull_request) }}
run: |
# setup env for the rest of the workflow
PR_JSON=${PR_JSON:-"$EVENT_PR_JSON"}
{
echo "REPO=$(jq -r '.base.repo.name' <<< "$PR_JSON")"
echo "OWNER=$(jq -r '.base.repo.owner.login' <<< "$PR_JSON")"
echo "PR_NUMBER=$(jq -r '.number' <<< "$PR_JSON")"
echo "JOB_DATA=$(jq -c '
{
"repo": .base.repo.name,
"owner": .base.repo.owner.login,
"repoUrl": .base.repo.html_url,
"prNumber": .number,
"prHeadSha": .head.sha,
"prHeadLabel": .head.label,
"prBody": (.body // ""),
"prLabels": (reduce .labels[].name as $l ([]; . + [$l]))
}
' <<< "$PR_JSON")"
} >> "$GITHUB_ENV"
- name: Find Blocked/Stacked PRs in body
id: pr_ids
run: |
prs=$(
jq -c '
.prBody as $body
| (
$body |
reduce (
. | scan("[Bb]locked (?:[Bb]y|[Oo]n):? #([0-9]+)")
| map({
"type": "Blocked on",
"number": ( . | tonumber )
})
) as $i ([]; . + [$i[]])
) as $bprs
| (
$body |
reduce (
. | scan("[Ss]tacked [Oo]n:? #([0-9]+)")
| map({
"type": "Stacked on",
"number": ( . | tonumber )
})
) as $i ([]; . + [$i[]])
) as $sprs
| ($bprs + $sprs) as $prs
| {
"blocking": $prs,
"numBlocking": ( $prs | length),
}
' <<< "$JOB_DATA"
)
echo "prs=$prs" >> "$GITHUB_OUTPUT"
- name: Collect Blocked PR Data
id: blocking_data
if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
BLOCKING_PRS: ${{ steps.pr_ids.outputs.prs }}
run: |
blocked_pr_data=$(
while read -r pr_data ; do
gh api \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"/repos/$OWNER/$REPO/pulls/$(jq -r '.number' <<< "$pr_data")" \
| jq -c --arg type "$(jq -r '.type' <<< "$pr_data")" \
'
. | {
"type": $type,
"number": .number,
"merged": .merged,
"state": (if .state == "open" then "Open" elif .merged then "Merged" else "Closed" end),
"labels": (reduce .labels[].name as $l ([]; . + [$l])),
"basePrUrl": .html_url,
"baseRepoName": .head.repo.name,
"baseRepoOwner": .head.repo.owner.login,
"baseRepoUrl": .head.repo.html_url,
"baseSha": .head.sha,
"baseRefName": .head.ref,
}
'
done < <(jq -c '.blocking[]' <<< "$BLOCKING_PRS") | jq -c -s
)
{
echo "data=$blocked_pr_data";
echo "all_merged=$(jq -r 'all(.[] | (.type == "Stacked on" and .merged) or (.type == "Blocked on" and (.state != "Open")); .)' <<< "$blocked_pr_data")";
echo "current_blocking=$(jq -c 'map(
select(
(.type == "Stacked on" and (.merged | not)) or
(.type == "Blocked on" and (.state == "Open"))
) | .number
)' <<< "$blocked_pr_data" )";
} >> "$GITHUB_OUTPUT"
- name: Add 'blocked' Label if Missing
id: label_blocked
if: "(fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0) && !contains(fromJSON(env.JOB_DATA).prLabels, 'status: blocked') && !fromJSON(steps.blocking_data.outputs.all_merged)"
continue-on-error: true
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
run: |
gh -R ${{ github.repository }} issue edit --add-label 'status: blocked' "$PR_NUMBER"
- name: Remove 'blocked' Label if All Dependencies Are Merged
id: unlabel_blocked
if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0 && fromJSON(steps.blocking_data.outputs.all_merged)
continue-on-error: true
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
run: |
gh -R ${{ github.repository }} issue edit --remove-label 'status: blocked' "$PR_NUMBER"
- name: Apply 'blocking' Label to Unmerged Dependencies
id: label_blocking
if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0
continue-on-error: true
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
BLOCKING_ISSUES: ${{ steps.blocking_data.outputs.current_blocking }}
run: |
while read -r pr ; do
gh -R ${{ github.repository }} issue edit --add-label 'status: blocking' "$pr" || true
done < <(jq -c '.[]' <<< "$BLOCKING_ISSUES")
- name: Apply Blocking PR Status Check
id: blocked_check
if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0
continue-on-error: true
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
BLOCKING_DATA: ${{ steps.blocking_data.outputs.data }}
run: |
pr_head_sha=$(jq -r '.prHeadSha' <<< "$JOB_DATA")
# create commit Status, overwrites previous identical context
while read -r pr_data ; do
DESC=$(
jq -r 'if .type == "Stacked on" then
"Stacked PR #" + (.number | tostring) + " is " + (if .merged then "" else "not yet " end) + "merged"
else
"Blocking PR #" + (.number | tostring) + " is " + (if .state == "Open" then "" else "not yet " end) + "merged or closed"
end ' <<< "$pr_data"
)
gh api \
--method POST \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"/repos/${OWNER}/${REPO}/statuses/${pr_head_sha}" \
-f "state=$(jq -r 'if (.type == "Stacked on" and .merged) or (.type == "Blocked on" and (.state != "Open")) then "success" else "failure" end' <<< "$pr_data")" \
-f "target_url=$(jq -r '.basePrUrl' <<< "$pr_data" )" \
-f "description=$DESC" \
-f "context=ci/blocking-pr-check:$(jq '.number' <<< "$pr_data")"
done < <(jq -c '.[]' <<< "$BLOCKING_DATA")
- name: Context Comment
id: generate-comment
if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0
continue-on-error: true
env:
BLOCKING_DATA: ${{ steps.blocking_data.outputs.data }}
run: |
COMMENT_PATH="$(pwd)/temp_comment_file.txt"
echo '<h3>PR Dependencies :pushpin:</h3>' > "$COMMENT_PATH"
echo >> "$COMMENT_PATH"
pr_head_label=$(jq -r '.prHeadLabel' <<< "$JOB_DATA")
while read -r pr_data ; do
base_pr=$(jq -r '.number' <<< "$pr_data")
base_ref_name=$(jq -r '.baseRefName' <<< "$pr_data")
base_repo_owner=$(jq -r '.baseRepoOwner' <<< "$pr_data")
base_repo_name=$(jq -r '.baseRepoName' <<< "$pr_data")
compare_url="https://github.com/$base_repo_owner/$base_repo_name/compare/$base_ref_name...$pr_head_label"
status=$(jq -r '
if .type == "Stacked on" then
if .merged then ":heavy_check_mark: Merged" else ":x: Not Merged (" + .state + ")" end
else
if .state != "Open" then ":white_check_mark: " + .state else ":x: Open" end
end
' <<< "$pr_data")
type=$(jq -r '.type' <<< "$pr_data")
echo " - $type #$base_pr $status [(compare)]($compare_url)" >> "$COMMENT_PATH"
done < <(jq -c '.[]' <<< "$BLOCKING_DATA")
{
echo 'body<<EOF';
cat "${COMMENT_PATH}";
echo 'EOF';
} >> "$GITHUB_OUTPUT"
- name: 💬 PR Comment
if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0
continue-on-error: true
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
COMMENT_BODY: ${{ steps.generate-comment.outputs.body }}
run: |
gh -R ${{ github.repository }} issue comment "$PR_NUMBER" \
--body "$COMMENT_BODY" \
--create-if-none \
--edit-last

View file

@ -1,188 +1,704 @@
name: Build
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
merge_group:
types: [checks_requested]
pull_request:
workflow_call:
inputs:
build-type:
description: Type of build (Debug or Release)
build_type:
description: Type of build (Debug, Release, RelWithDebInfo, MinSizeRel)
type: string
default: Debug
environment:
description: Deployment environment to run under
is_qt_cached:
description: Enable Qt caching or not
type: string
workflow_dispatch:
inputs:
build-type:
description: Type of build (Debug or Release)
type: string
default: Debug
permissions: {}
default: true
secrets:
SPARKLE_ED25519_KEY:
description: Private key for signing Sparkle updates
required: false
WINDOWS_CODESIGN_CERT:
description: Certificate for signing Windows builds
required: false
WINDOWS_CODESIGN_PASSWORD:
description: Password for signing Windows builds
required: false
APPLE_CODESIGN_CERT:
description: Certificate for signing macOS builds
required: false
APPLE_CODESIGN_PASSWORD:
description: Password for signing macOS builds
required: false
APPLE_CODESIGN_ID:
description: Certificate ID for signing macOS builds
required: false
APPLE_NOTARIZE_APPLE_ID:
description: Apple ID used for notarizing macOS builds
required: false
APPLE_NOTARIZE_TEAM_ID:
description: Team ID used for notarizing macOS builds
required: false
APPLE_NOTARIZE_PASSWORD:
description: Password used for notarizing macOS builds
required: false
CACHIX_AUTH_TOKEN:
description: Private token for authenticating against Cachix cache
required: false
GPG_PRIVATE_KEY:
description: Private key for AppImage signing
required: false
GPG_PRIVATE_KEY_ID:
description: ID for the GPG_PRIVATE_KEY, to select the signing key
required: false
jobs:
build:
name: Build (${{ matrix.artifact-name }})
environment: ${{ inputs.environment || '' }}
permissions:
contents: read
# Required for Azure Trusted Signing
id-token: write
# Required for vcpkg binary cache
packages: write
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-24.04
artifact-name: Linux
cmake-preset: linux
qt-version: 6.10.2
- os: ubuntu-20.04
qt_ver: 5
qt_host: linux
qt_arch: ""
qt_version: "5.15.2"
qt_modules: "qtnetworkauth"
- os: ubuntu-24.04-arm
artifact-name: Linux-aarch64
cmake-preset: linux
qt-version: 6.10.2
- os: ubuntu-20.04
qt_ver: 6
qt_host: linux
qt_arch: ""
qt_version: "6.5.3"
qt_modules: "qt5compat qtimageformats qtnetworkauth"
- os: windows-2022
artifact-name: Windows-MinGW-w64
cmake-preset: windows_mingw
msystem: CLANG64
vcvars-arch: amd64_x86
- os: windows-11-arm
artifact-name: Windows-MinGW-arm64
cmake-preset: windows_mingw
msystem: CLANGARM64
vcvars-arch: arm64
name: "Windows-MinGW-w64"
msystem: clang64
vcvars_arch: "amd64_x86"
- os: windows-2022
artifact-name: Windows-MSVC
cmake-preset: windows_msvc
# TODO(@getchoo): This is the default in setup-dependencies/windows. Why isn't it working?!?!
vcvars-arch: amd64
qt-version: 6.10.2
name: "Windows-MSVC"
msystem: ""
architecture: "x64"
vcvars_arch: "amd64"
qt_ver: 6
qt_host: windows
qt_arch: ""
qt_version: "6.7.3"
qt_modules: "qt5compat qtimageformats qtnetworkauth"
nscurl_tag: "v24.9.26.122"
nscurl_sha256: "AEE6C4BE3CB6455858E9C1EE4B3AFE0DB9960FA03FE99CCDEDC28390D57CCBB0"
- os: windows-11-arm
artifact-name: Windows-MSVC-arm64
cmake-preset: windows_msvc
vcvars-arch: arm64
qt-version: 6.10.2
- os: windows-2022
name: "Windows-MSVC-arm64"
msystem: ""
architecture: "arm64"
vcvars_arch: "amd64_arm64"
qt_ver: 6
qt_host: windows
qt_arch: "win64_msvc2019_arm64"
qt_version: "6.7.3"
qt_modules: "qt5compat qtimageformats qtnetworkauth"
nscurl_tag: "v24.9.26.122"
nscurl_sha256: "AEE6C4BE3CB6455858E9C1EE4B3AFE0DB9960FA03FE99CCDEDC28390D57CCBB0"
- os: macos-26
artifact-name: macOS
cmake-preset: macos_universal
macosx-deployment-target: 12.0
qt-version: 6.9.3
- os: macos-14
name: macOS
macosx_deployment_target: 11.0
qt_ver: 6
qt_host: mac
qt_arch: ""
qt_version: "6.7.3"
qt_modules: "qt5compat qtimageformats qtnetworkauth"
- os: macos-14
name: macOS-Legacy
macosx_deployment_target: 10.13
qt_ver: 5
qt_host: mac
qt_version: "5.15.2"
qt_modules: "qtnetworkauth"
runs-on: ${{ matrix.os }}
defaults:
run:
shell: ${{ matrix.msystem != '' && 'msys2 {0}' || 'bash' }}
env:
ARTIFACT_NAME: ${{ matrix.artifact-name }}-Qt6
BUILD_PLATFORM: official
BUILD_TYPE: ${{ inputs.build-type || 'Debug' }}
CMAKE_PRESET: ${{ matrix.cmake-preset }}
MACOSX_DEPLOYMENT_TARGET: ${{ matrix.macosx-deployment-target }}
MACOSX_DEPLOYMENT_TARGET: ${{ matrix.macosx_deployment_target }}
INSTALL_DIR: "install"
INSTALL_PORTABLE_DIR: "install-portable"
INSTALL_APPIMAGE_DIR: "install-appdir"
BUILD_DIR: "build"
CCACHE_VAR: ""
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
steps:
##
# SETUP
# PREPARE
##
- name: Checkout
uses: actions/checkout@v4
with:
submodules: "true"
- name: "Setup MSYS2"
if: runner.os == 'Windows' && matrix.msystem != ''
uses: msys2/setup-msys2@v2
with:
msystem: ${{ matrix.msystem }}
update: true
install: >-
git
mingw-w64-x86_64-binutils
pacboy: >-
toolchain:p
cmake:p
extra-cmake-modules:p
ninja:p
qt6-base:p
qt6-svg:p
qt6-imageformats:p
quazip-qt6:p
ccache:p
qt6-5compat:p
qt6-networkauth:p
cmark:p
- name: Force newer ccache
if: runner.os == 'Windows' && matrix.msystem == '' && inputs.build_type == 'Debug'
run: |
choco install ccache --version 4.7.1
- name: Setup ccache
if: (runner.os != 'Windows' || matrix.msystem == '') && inputs.build_type == 'Debug'
uses: hendrikmuhs/ccache-action@v1.2.14
with:
key: ${{ matrix.os }}-qt${{ matrix.qt_ver }}-${{ matrix.architecture }}
- name: Retrieve ccache cache (Windows MinGW-w64)
if: runner.os == 'Windows' && matrix.msystem != '' && inputs.build_type == 'Debug'
uses: actions/cache@v4.2.0
with:
path: '${{ github.workspace }}\.ccache'
key: ${{ matrix.os }}-mingw-w64-ccache-${{ github.run_id }}
restore-keys: |
${{ matrix.os }}-mingw-w64-ccache
- name: Setup ccache (Windows MinGW-w64)
if: runner.os == 'Windows' && matrix.msystem != '' && inputs.build_type == 'Debug'
shell: msys2 {0}
run: |
ccache --set-config=cache_dir='${{ github.workspace }}\.ccache'
ccache --set-config=max_size='500M'
ccache --set-config=compression=true
ccache -p # Show config
ccache -z # Zero stats
- name: Use ccache on Debug builds only
if: inputs.build_type == 'Debug'
shell: bash
run: |
echo "CCACHE_VAR=ccache" >> $GITHUB_ENV
- name: Set short version
shell: bash
run: |
ver_short=`git rev-parse --short HEAD`
echo "VERSION=$ver_short" >> $GITHUB_ENV
- name: Install Dependencies (Linux)
if: runner.os == 'Linux'
run: |
sudo apt-get -y update
sudo apt-get -y install ninja-build extra-cmake-modules scdoc appstream libxcb-cursor-dev
- name: Install Dependencies (macOS)
if: runner.os == 'macOS'
run: |
brew update
brew install ninja extra-cmake-modules
- name: Install host Qt (Windows MSVC arm64)
if: runner.os == 'Windows' && matrix.architecture == 'arm64'
uses: jurplel/install-qt-action@v3
with:
aqtversion: "==3.1.*"
py7zrversion: ">=0.20.2"
version: ${{ matrix.qt_version }}
host: "windows"
target: "desktop"
arch: ""
modules: ${{ matrix.qt_modules }}
cache: ${{ inputs.is_qt_cached }}
cache-key-prefix: host-qt-arm64-windows
dir: ${{ github.workspace }}\HostQt
set-env: false
- name: Install Qt (macOS, Linux & Windows MSVC)
if: matrix.msystem == ''
uses: jurplel/install-qt-action@v3
with:
aqtversion: "==3.1.*"
py7zrversion: ">=0.20.2"
version: ${{ matrix.qt_version }}
target: "desktop"
arch: ${{ matrix.qt_arch }}
modules: ${{ matrix.qt_modules }}
tools: ${{ matrix.qt_tools }}
cache: ${{ inputs.is_qt_cached }}
- name: Install MSVC (Windows MSVC)
if: runner.os == 'Windows' # We want this for MinGW builds as well, as we need SignTool
uses: ilammy/msvc-dev-cmd@v1
with:
vsversion: 2022
arch: ${{ matrix.vcvars_arch }}
- name: Prepare AppImage (Linux)
if: runner.os == 'Linux' && matrix.qt_ver != 5
run: |
wget "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage"
wget "https://github.com/linuxdeploy/linuxdeploy-plugin-appimage/releases/download/continuous/linuxdeploy-plugin-appimage-x86_64.AppImage"
wget "https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage"
wget "https://github.com/AppImageCommunity/AppImageUpdate/releases/download/continuous/AppImageUpdate-x86_64.AppImage"
sudo apt install libopengl0
- name: Add QT_HOST_PATH var (Windows MSVC arm64)
if: runner.os == 'Windows' && matrix.architecture == 'arm64'
run: |
echo "QT_HOST_PATH=${{ github.workspace }}\HostQt\Qt\${{ matrix.qt_version }}\msvc2019_64" >> $env:GITHUB_ENV
- name: Setup java (macOS)
if: runner.os == 'macOS'
uses: actions/setup-java@v4
with:
distribution: "temurin"
java-version: "17"
##
# CONFIGURE
##
- name: Checkout
uses: actions/checkout@v6
with:
submodules: true
- name: Configure CMake (macOS)
if: runner.os == 'macOS' && matrix.qt_ver == 6
run: |
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_ENABLE_JAVA_DOWNLOADER=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -G Ninja
- name: Setup dependencies
id: setup-dependencies
uses: ./.github/actions/setup-dependencies
with:
build-type: ${{ env.BUILD_TYPE }}
artifact-name: ${{ matrix.artifact-name }}
msystem: ${{ matrix.msystem }}
vcvars-arch: ${{ matrix.vcvars-arch }}
qt-version: ${{ matrix.qt-version }}
- name: Configure CMake (macOS-Legacy)
if: runner.os == 'macOS' && matrix.qt_ver == 5
run: |
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_ENABLE_JAVA_DOWNLOADER=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DMACOSX_SPARKLE_UPDATE_PUBLIC_KEY="" -DMACOSX_SPARKLE_UPDATE_FEED_URL="" -DCMAKE_OSX_ARCHITECTURES="x86_64" -G Ninja
- name: Configure CMake (Windows MinGW-w64)
if: runner.os == 'Windows' && matrix.msystem != ''
shell: msys2 {0}
run: |
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_ENABLE_JAVA_DOWNLOADER=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=6 -DCMAKE_OBJDUMP=/mingw64/bin/objdump.exe -DLauncher_BUILD_ARTIFACT=${{ matrix.name }}-Qt${{ matrix.qt_ver }} -G Ninja
- name: Configure CMake (Windows MSVC)
if: runner.os == 'Windows' && matrix.msystem == ''
run: |
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_ENABLE_JAVA_DOWNLOADER=ON -DLauncher_BUILD_PLATFORM=official -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_MSVC_RUNTIME_LIBRARY="MultiThreadedDLL" -A${{ matrix.architecture}} -DLauncher_FORCE_BUNDLED_LIBS=ON -DLauncher_BUILD_ARTIFACT=${{ matrix.name }}-Qt${{ matrix.qt_ver }}
# https://github.com/ccache/ccache/wiki/MS-Visual-Studio (I coudn't figure out the compiler prefix)
if ("${{ env.CCACHE_VAR }}")
{
Copy-Item C:/ProgramData/chocolatey/lib/ccache/tools/ccache-4.7.1-windows-x86_64/ccache.exe -Destination C:/ProgramData/chocolatey/lib/ccache/tools/ccache-4.7.1-windows-x86_64/cl.exe
echo "CLToolExe=cl.exe" >> $env:GITHUB_ENV
echo "CLToolPath=C:/ProgramData/chocolatey/lib/ccache/tools/ccache-4.7.1-windows-x86_64/" >> $env:GITHUB_ENV
echo "TrackFileAccess=false" >> $env:GITHUB_ENV
}
# Needed for ccache, but also speeds up compile
echo "UseMultiToolTask=true" >> $env:GITHUB_ENV
- name: Configure CMake (Linux)
if: runner.os == 'Linux'
run: |
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_ENABLE_JAVA_DOWNLOADER=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DLauncher_BUILD_ARTIFACT=Linux-Qt${{ matrix.qt_ver }} -G Ninja
##
# BUILD
##
- name: Configure project
- name: Build
if: runner.os != 'Windows'
run: |
cmake --preset "$CMAKE_PRESET"
cmake --build ${{ env.BUILD_DIR }}
- name: Run build
- name: Build (Windows MinGW-w64)
if: runner.os == 'Windows' && matrix.msystem != ''
shell: msys2 {0}
run: |
cmake --build --preset "$CMAKE_PRESET" --config "$BUILD_TYPE"
cmake --build ${{ env.BUILD_DIR }}
- name: Run tests
- name: Build (Windows MSVC)
if: runner.os == 'Windows' && matrix.msystem == ''
run: |
ctest --preset "$CMAKE_PRESET" --build-config "$BUILD_TYPE"
cmake --build ${{ env.BUILD_DIR }} --config ${{ inputs.build_type }}
##
# PACKAGE
# TEST
##
- name: Get short version
id: short-version
shell: bash
- name: Test
if: runner.os != 'Windows'
run: |
echo "version=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"
ctest -E "^example64|example$" --test-dir build --output-on-failure
- name: Package (Linux)
if: ${{ runner.os == 'Linux' }}
uses: ./.github/actions/package/linux
with:
version: ${{ steps.short-version.outputs.version }}
build-type: ${{ steps.setup-dependencies.outputs.build-type }}
artifact-name: ${{ matrix.artifact-name }}
qt-version: ${{ steps.setup-dependencies.outputs.qt-version }}
- name: Test (Windows MinGW-w64)
if: runner.os == 'Windows' && matrix.msystem != ''
shell: msys2 {0}
run: |
ctest -E "^example64|example$" --test-dir build --output-on-failure
gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
gpg-private-key-id: ${{ secrets.GPG_PRIVATE_KEY_ID }}
- name: Test (Windows MSVC)
if: runner.os == 'Windows' && matrix.msystem == '' && matrix.architecture != 'arm64'
run: |
ctest -E "^example64|example$" --test-dir build --output-on-failure -C ${{ inputs.build_type }}
##
# PACKAGE BUILDS
##
- name: Fetch codesign certificate (macOS)
if: runner.os == 'macOS'
run: |
echo '${{ secrets.APPLE_CODESIGN_CERT }}' | base64 --decode > codesign.p12
if [ -n '${{ secrets.APPLE_CODESIGN_ID }}' ]; then
security create-keychain -p '${{ secrets.APPLE_CODESIGN_PASSWORD }}' build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p '${{ secrets.APPLE_CODESIGN_PASSWORD }}' build.keychain
security import codesign.p12 -k build.keychain -P '${{ secrets.APPLE_CODESIGN_PASSWORD }}' -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k '${{ secrets.APPLE_CODESIGN_PASSWORD }}' build.keychain
else
echo ":warning: Using ad-hoc code signing for macOS, as certificate was not present." >> $GITHUB_STEP_SUMMARY
fi
- name: Package (macOS)
if: ${{ runner.os == 'macOS' }}
uses: ./.github/actions/package/macos
with:
version: ${{ steps.short-version.outputs.version }}
build-type: ${{ steps.setup-dependencies.outputs.build-type }}
artifact-name: ${{ matrix.artifact-name }}
if: runner.os == 'macOS'
run: |
cmake --install ${{ env.BUILD_DIR }}
apple-codesign-cert: ${{ secrets.APPLE_CODESIGN_CERT }}
apple-codesign-password: ${{ secrets.APPLE_CODESIGN_PASSWORD }}
apple-codesign-id: ${{ secrets.APPLE_CODESIGN_ID }}
apple-notarize-apple-id: ${{ secrets.APPLE_NOTARIZE_APPLE_ID }}
apple-notarize-team-id: ${{ secrets.APPLE_NOTARIZE_TEAM_ID }}
apple-notarize-password: ${{ secrets.APPLE_NOTARIZE_PASSWORD }}
sparkle-ed25519-key: ${{ secrets.SPARKLE_ED25519_KEY }}
cd ${{ env.INSTALL_DIR }}
chmod +x "PrismLauncher.app/Contents/MacOS/prismlauncher"
- name: Package (Windows)
if: ${{ runner.os == 'Windows' }}
uses: ./.github/actions/package/windows
if [ -n '${{ secrets.APPLE_CODESIGN_ID }}' ]; then
APPLE_CODESIGN_ID='${{ secrets.APPLE_CODESIGN_ID }}'
else
APPLE_CODESIGN_ID='-'
fi
sudo codesign --sign "$APPLE_CODESIGN_ID" --deep --force --entitlements "../program_info/App.entitlements" --options runtime "PrismLauncher.app/Contents/MacOS/prismlauncher"
mv "PrismLauncher.app" "Prism Launcher.app"
- name: Notarize (macOS)
if: runner.os == 'macOS'
run: |
cd ${{ env.INSTALL_DIR }}
if [ -n '${{ secrets.APPLE_NOTARIZE_PASSWORD }}' ]; then
ditto -c -k --sequesterRsrc --keepParent "Prism Launcher.app" ../PrismLauncher.zip
xcrun notarytool submit ../PrismLauncher.zip \
--wait --progress \
--apple-id '${{ secrets.APPLE_NOTARIZE_APPLE_ID }}' \
--team-id '${{ secrets.APPLE_NOTARIZE_TEAM_ID }}' \
--password '${{ secrets.APPLE_NOTARIZE_PASSWORD }}'
xcrun stapler staple "Prism Launcher.app"
else
echo ":warning: Skipping notarization as credentials are not present." >> $GITHUB_STEP_SUMMARY
fi
ditto -c -k --sequesterRsrc --keepParent "Prism Launcher.app" ../PrismLauncher.zip
- name: Make Sparkle signature (macOS)
if: matrix.name == 'macOS'
run: |
if [ '${{ secrets.SPARKLE_ED25519_KEY }}' != '' ]; then
echo '${{ secrets.SPARKLE_ED25519_KEY }}' > ed25519-priv.pem
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
cat >> $GITHUB_STEP_SUMMARY << EOF
### Artifact Information :information_source:
- :memo: Sparkle Signature (ed25519): \`$signature\`
EOF
else
cat >> $GITHUB_STEP_SUMMARY << EOF
### Artifact Information :information_source:
- :warning: Sparkle Signature (ed25519): No private key available (likely a pull request or fork)
EOF
fi
- name: Package (Windows MinGW-w64)
if: runner.os == 'Windows' && matrix.msystem != ''
shell: msys2 {0}
run: |
cmake --install ${{ env.BUILD_DIR }}
touch ${{ env.INSTALL_DIR }}/manifest.txt
for l in $(find ${{ env.INSTALL_DIR }} -type f); do l=$(cygpath -u $l); l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_DIR }}/}; l=${l#./}; echo $l; done >> ${{ env.INSTALL_DIR }}/manifest.txt
- name: Package (Windows MSVC)
if: runner.os == 'Windows' && matrix.msystem == ''
run: |
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build_type }}
cd ${{ github.workspace }}
Get-ChildItem ${{ env.INSTALL_DIR }} -Recurse | ForEach FullName | Resolve-Path -Relative | %{ $_.TrimStart('.\') } | %{ $_.TrimStart('${{ env.INSTALL_DIR }}') } | %{ $_.TrimStart('\') } | Out-File -FilePath ${{ env.INSTALL_DIR }}/manifest.txt
- name: Fetch codesign certificate (Windows)
if: runner.os == 'Windows'
shell: bash # yes, we are not using MSYS2 or PowerShell here
run: |
echo '${{ secrets.WINDOWS_CODESIGN_CERT }}' | base64 --decode > codesign.pfx
- name: Sign executable (Windows)
if: runner.os == 'Windows'
run: |
if (Get-Content ./codesign.pfx){
cd ${{ env.INSTALL_DIR }}
# We ship the exact same executable for portable and non-portable editions, so signing just once is fine
SignTool sign /fd sha256 /td sha256 /f ../codesign.pfx /p '${{ secrets.WINDOWS_CODESIGN_PASSWORD }}' /tr http://timestamp.digicert.com prismlauncher.exe prismlauncher_updater.exe prismlauncher_filelink.exe
} else {
":warning: Skipped code signing for Windows, as certificate was not present." >> $env:GITHUB_STEP_SUMMARY
}
- name: Package (Windows MinGW-w64, portable)
if: runner.os == 'Windows' && matrix.msystem != ''
shell: msys2 {0}
run: |
cp -r ${{ env.INSTALL_DIR }} ${{ env.INSTALL_PORTABLE_DIR }} # cmake install on Windows is slow, let's just copy instead
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable
for l in $(find ${{ env.INSTALL_PORTABLE_DIR }} -type f); do l=$(cygpath -u $l); l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_PORTABLE_DIR }}/}; l=${l#./}; echo $l; done >> ${{ env.INSTALL_PORTABLE_DIR }}/manifest.txt
- name: Package (Windows MSVC, portable)
if: runner.os == 'Windows' && matrix.msystem == ''
run: |
cp -r ${{ env.INSTALL_DIR }} ${{ env.INSTALL_PORTABLE_DIR }} # cmake install on Windows is slow, let's just copy instead
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable
Get-ChildItem ${{ env.INSTALL_PORTABLE_DIR }} -Recurse | ForEach FullName | Resolve-Path -Relative | %{ $_.TrimStart('.\') } | %{ $_.TrimStart('${{ env.INSTALL_PORTABLE_DIR }}') } | %{ $_.TrimStart('\') } | Out-File -FilePath ${{ env.INSTALL_DIR }}/manifest.txt
- name: Package (Windows, installer)
if: runner.os == 'Windows'
run: |
if ('${{ matrix.nscurl_tag }}') {
New-Item -Name NSISPlugins -ItemType Directory
Invoke-Webrequest https://github.com/negrutiu/nsis-nscurl/releases/download/${{ matrix.nscurl_tag }}/NScurl.zip -OutFile NSISPlugins\NScurl.zip
$nscurl_hash = Get-FileHash NSISPlugins\NScurl.zip -Algorithm Sha256 | Select-Object -ExpandProperty Hash
if ( $nscurl_hash -ne "${{ matrix.nscurl_sha256 }}") {
echo "::error:: NSCurl.zip sha256 mismatch"
exit 1
}
Expand-Archive -Path NSISPlugins\NScurl.zip -DestinationPath NSISPlugins\NScurl
}
cd ${{ env.INSTALL_DIR }}
makensis -NOCD "${{ github.workspace }}/${{ env.BUILD_DIR }}/program_info/win_install.nsi"
- name: Sign installer (Windows)
if: runner.os == 'Windows'
run: |
if (Get-Content ./codesign.pfx){
SignTool sign /fd sha256 /td sha256 /f codesign.pfx /p '${{ secrets.WINDOWS_CODESIGN_PASSWORD }}' /tr http://timestamp.digicert.com PrismLauncher-Setup.exe
} else {
":warning: Skipped code signing for Windows, as certificate was not present." >> $env:GITHUB_STEP_SUMMARY
}
- name: Package AppImage (Linux)
if: runner.os == 'Linux' && matrix.qt_ver != 5
shell: bash
env:
CI_HAS_ACCESS_TO_AZURE: ${{ vars.CI_HAS_ACCESS_TO_AZURE || '' }}
with:
version: ${{ steps.short-version.outputs.version }}
build-type: ${{ steps.setup-dependencies.outputs.build-type }}
artifact-name: ${{ matrix.artifact-name }}
msystem: ${{ matrix.msystem }}
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
run: |
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_APPIMAGE_DIR }}/usr
azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}
azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}
azure-subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
mv ${{ env.INSTALL_APPIMAGE_DIR }}/usr/share/metainfo/org.prismlauncher.PrismLauncher.metainfo.xml ${{ env.INSTALL_APPIMAGE_DIR }}/usr/share/metainfo/org.prismlauncher.PrismLauncher.appdata.xml
export "NO_APPSTREAM=1" # we have to skip appstream checking because appstream on ubuntu 20.04 is outdated
export OUTPUT="PrismLauncher-Linux-x86_64.AppImage"
chmod +x linuxdeploy-*.AppImage
mkdir -p ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib
mkdir -p ${{ env.INSTALL_APPIMAGE_DIR }}/usr/plugins/iconengines
cp -r ${{ runner.workspace }}/Qt/${{ matrix.qt_version }}/gcc_64/plugins/iconengines/* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/plugins/iconengines
cp /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/
cp /usr/lib/x86_64-linux-gnu/libssl.so.1.1 ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/
cp /usr/lib/x86_64-linux-gnu/libOpenGL.so.0* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib"
export LD_LIBRARY_PATH
chmod +x AppImageUpdate-x86_64.AppImage
cp AppImageUpdate-x86_64.AppImage ${{ env.INSTALL_APPIMAGE_DIR }}/usr/bin
export UPDATE_INFORMATION="gh-releases-zsync|${{ github.repository_owner }}|${{ github.event.repository.name }}|latest|PrismLauncher-Linux-x86_64.AppImage.zsync"
if [ '${{ secrets.GPG_PRIVATE_KEY_ID }}' != '' ]; then
export SIGN=1
export SIGN_KEY=${{ secrets.GPG_PRIVATE_KEY_ID }}
mkdir -p ~/.gnupg/
echo "$GPG_PRIVATE_KEY" > ~/.gnupg/private.key
gpg --import ~/.gnupg/private.key
else
echo ":warning: Skipped code signing for Linux AppImage, as gpg key was not present." >> $GITHUB_STEP_SUMMARY
fi
./linuxdeploy-x86_64.AppImage --appdir ${{ env.INSTALL_APPIMAGE_DIR }} --output appimage --plugin qt -i ${{ env.INSTALL_APPIMAGE_DIR }}/usr/share/icons/hicolor/scalable/apps/org.prismlauncher.PrismLauncher.svg
mv "PrismLauncher-Linux-x86_64.AppImage" "PrismLauncher-Linux-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage"
- name: Package (Linux, portable)
if: runner.os == 'Linux'
run: |
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_PORTABLE_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DLauncher_BUILD_ARTIFACT=Linux-Qt${{ matrix.qt_ver }} -DINSTALL_BUNDLE=full -G Ninja
cmake --install ${{ env.BUILD_DIR }}
cmake --install ${{ env.BUILD_DIR }} --component portable
mkdir ${{ env.INSTALL_PORTABLE_DIR }}/lib
cp /lib/x86_64-linux-gnu/libbz2.so.1.0 ${{ env.INSTALL_PORTABLE_DIR }}/lib
cp /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0 ${{ env.INSTALL_PORTABLE_DIR }}/lib
cp /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 ${{ env.INSTALL_PORTABLE_DIR }}/lib
cp /usr/lib/x86_64-linux-gnu/libssl.so.1.1 ${{ env.INSTALL_PORTABLE_DIR }}/lib
cp /usr/lib/x86_64-linux-gnu/libffi.so.7 ${{ env.INSTALL_PORTABLE_DIR }}/lib
mv ${{ env.INSTALL_PORTABLE_DIR }}/bin/*.so* ${{ env.INSTALL_PORTABLE_DIR }}/lib
for l in $(find ${{ env.INSTALL_PORTABLE_DIR }} -type f); do l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_PORTABLE_DIR }}/}; l=${l#./}; echo $l; done > ${{ env.INSTALL_PORTABLE_DIR }}/manifest.txt
cd ${{ env.INSTALL_PORTABLE_DIR }}
tar -czf ../PrismLauncher-portable.tar.gz *
##
# UPLOAD BUILDS
##
- name: Upload binary tarball (macOS)
if: runner.os == 'macOS'
uses: actions/upload-artifact@v4
with:
name: PrismLauncher-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
path: PrismLauncher.zip
- name: Upload binary zip (Windows)
if: runner.os == 'Windows'
uses: actions/upload-artifact@v4
with:
name: PrismLauncher-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
path: ${{ env.INSTALL_DIR }}/**
- name: Upload binary zip (Windows, portable)
if: runner.os == 'Windows'
uses: actions/upload-artifact@v4
with:
name: PrismLauncher-${{ matrix.name }}-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
path: ${{ env.INSTALL_PORTABLE_DIR }}/**
- name: Upload installer (Windows)
if: runner.os == 'Windows'
uses: actions/upload-artifact@v4
with:
name: PrismLauncher-${{ matrix.name }}-Setup-${{ env.VERSION }}-${{ inputs.build_type }}
path: PrismLauncher-Setup.exe
- name: Upload binary tarball (Linux, portable, Qt 5)
if: runner.os == 'Linux' && matrix.qt_ver != 6
uses: actions/upload-artifact@v4
with:
name: PrismLauncher-${{ runner.os }}-Qt5-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
path: PrismLauncher-portable.tar.gz
- name: Upload binary tarball (Linux, portable, Qt 6)
if: runner.os == 'Linux' && matrix.qt_ver != 5
uses: actions/upload-artifact@v4
with:
name: PrismLauncher-${{ runner.os }}-Qt6-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
path: PrismLauncher-portable.tar.gz
- name: Upload AppImage (Linux)
if: runner.os == 'Linux' && matrix.qt_ver != 5
uses: actions/upload-artifact@v4
with:
name: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
path: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
- name: Upload AppImage Zsync (Linux)
if: runner.os == 'Linux' && matrix.qt_ver != 5
uses: actions/upload-artifact@v4
with:
name: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage.zsync
path: PrismLauncher-Linux-x86_64.AppImage.zsync
- name: ccache stats (Windows MinGW-w64)
if: runner.os == 'Windows' && matrix.msystem != ''
shell: msys2 {0}
run: |
ccache -s
flatpak:
runs-on: ubuntu-latest
container:
image: ghcr.io/flathub-infra/flatpak-github-actions:kde-6.8
options: --privileged
steps:
- name: Checkout
uses: actions/checkout@v4
if: inputs.build_type == 'Debug'
with:
submodules: true
- name: Set short version
shell: bash
run: echo "VERSION=${GITHUB_SHA::7}" >> $GITHUB_ENV
- name: Build Flatpak (Linux)
if: inputs.build_type == 'Debug'
uses: flatpak/flatpak-github-actions/flatpak-builder@v6
with:
bundle: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-Flatpak.flatpak
manifest-path: flatpak/org.prismlauncher.PrismLauncher.yml
nix:
name: Nix (${{ matrix.system }})
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-22.04
system: x86_64-linux
- os: macos-13
system: x86_64-darwin
- os: macos-14
system: aarch64-darwin
runs-on: ${{ matrix.os }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Nix
uses: cachix/install-nix-action@v30
# For PRs
- name: Setup Nix Magic Cache
uses: DeterminateSystems/magic-nix-cache-action@v8
# For in-tree builds
- name: Setup Cachix
uses: cachix/cachix-action@v15
with:
name: prismlauncher
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
- name: Run flake checks
run: |
nix flake check --print-build-logs --show-trace
- name: Build debug package
if: ${{ inputs.build_type == 'Debug' }}
run: |
nix build --print-build-logs .#prismlauncher-debug
- name: Build release package
if: ${{ inputs.build_type != 'Debug' }}
run: |
nix build --print-build-logs .#prismlauncher

View file

@ -1,48 +0,0 @@
name: Clang-Tidy Code Scanning
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
merge_group:
types: [checks_requested]
pull_request:
permissions: {}
jobs:
clang-tidy:
name: Run Clang-Tidy
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 0 # Required for diffing later on
submodules: "true"
- name: Install Nix
uses: cachix/install-nix-action@v31
- name: Run source generators
# TODO(@getchoo): Figure out how to make this work with PCH
run: |
nix develop --command bash -c '
cmake -B build -D Launcher_USE_PCH=OFF && cmake --build build --target autogen autorcc
'
# TODO: Use SARIF after https://github.com/psastras/sarif-rs/issues/638 is fixed
- name: Run clang-tidy-diff
env:
BASE_REF: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha }}
run: |
nix develop --command bash -c '
clang-tidy -verify-config && git diff -U0 --no-color "$BASE_REF" | clang-tidy-diff.py -p1 -quiet -only-check-in-db
'

View file

@ -1,52 +1,35 @@
name: "CodeQL Code Scanning"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
merge_group:
types: [checks_requested]
pull_request:
workflow_dispatch:
permissions: {}
on: [ push, pull_request, workflow_dispatch ]
jobs:
CodeQL:
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
submodules: "true"
submodules: 'true'
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
uses: github/codeql-action/init@v3
with:
config-file: ./.github/codeql/codeql-config.yml
queries: security-and-quality
languages: cpp, java
- name: Setup dependencies
uses: ./.github/actions/setup-dependencies
with:
build-type: Debug
qt-version: 6.4.3
- name: Install Dependencies
run:
sudo apt-get -y update
sudo apt-get -y install ninja-build extra-cmake-modules scdoc qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5 libqt5networkauth5 libqt5networkauth5-dev
- name: Configure and Build
run: |
cmake --preset linux -DLauncher_USE_PCH=OFF
cmake --build --preset linux --config Debug
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=/usr -DLauncher_QT_VERSION_MAJOR=5 -G Ninja
- name: Run tests
run: |
ctest --preset linux --build-config Debug --extra-verbose --output-on-failure
cmake --build build
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4
uses: github/codeql-action/analyze@v3

View file

@ -1,174 +0,0 @@
name: Development Container
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
merge_group:
types: [checks_requested]
pull_request:
workflow_dispatch:
permissions: {}
env:
REGISTRY: ghcr.io
jobs:
build:
name: Build (${{ matrix.arch }})
permissions:
contents: read
packages: write
outputs:
image-name: ${{ steps.image-name.outputs.image-name }}
strategy:
fail-fast: false
matrix:
include:
- arch: arm64
os: ubuntu-24.04-arm
- arch: amd64
os: ubuntu-24.04
runs-on: ${{ matrix.os }}
steps:
- name: Set image name
id: image-name
run: |
echo "image-name=${REGISTRY}/${GITHUB_REPOSITORY_OWNER,,}/devcontainer" >> "$GITHUB_OUTPUT"
- name: Install Podman
uses: redhat-actions/podman-install@main
# TODO(@getchoo): Always use this when the action properly supports ARM
if: ${{ runner.arch == 'X64' || runner.arch == 'X86' }}
with:
github-token: ${{ github.token }}
- name: Checkout repository
uses: actions/checkout@v6
- name: Determine metadata for image
id: image-metadata
uses: docker/metadata-action@v6
with:
images: |
${{ steps.image-name.outputs.image-name }}
flavor: |
latest=false
tags: |
type=raw,value=latest,enable=${{ github.event.merge_group.base_ref == 'refs/heads/develop' }}
type=sha
type=sha,format=long
type=ref,event=branch
type=ref,event=tag
- name: Build image
id: build-image
uses: redhat-actions/buildah-build@v2
with:
containerfiles: |
./Containerfile
tags: ${{ steps.image-metadata.outputs.tags }}
labels: ${{ steps.image-metadata.outputs.labels }}
- name: Push image
id: push-image
if: ${{ github.event_name != 'pull_request' }}
uses: redhat-actions/push-to-registry@v2
with:
tags: ${{ steps.build-image.outputs.tags }}
username: ${{ github.repository_owner }}
password: ${{ github.token }}
tls-verify: true
- name: Export image digest
if: ${{ github.event_name != 'pull_request' }}
env:
DIGEST: ${{ steps.push-image.outputs.digest }}
run: |
mkdir -p "$RUNNER_TEMP"/digests
touch "$RUNNER_TEMP"/digests/"${DIGEST#sha256:}"
- name: Upload digest artifact
if: ${{ github.event_name != 'pull_request' }}
uses: actions/upload-artifact@v7
with:
name: digests-${{ matrix.arch }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1
manifest:
name: Create manifest
needs: [ build ]
if: ${{ github.event_name != 'pull_request' }}
permissions:
contents: read
packages: write
runs-on: ubuntu-24.04
steps:
- name: Download digests
uses: actions/download-artifact@v8
with:
path: ${{ runner.temp }}/digests
pattern: digests-*
merge-multiple: true
- name: Install Podman
# TODO(@getchoo): Always use this when the action properly supports ARM
if: ${{ runner.arch == 'X64' || runner.arch == 'X86' }}
uses: redhat-actions/podman-install@main
with:
github-token: ${{ github.token }}
- name: Login to registry
uses: redhat-actions/podman-login@v1
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.repository_owner }}
password: ${{ github.token }}
- name: Determine metadata for manifest
id: manifest-metadata
uses: docker/metadata-action@v6
with:
images: |
${{ needs.build.outputs.image-name }}
flavor: |
latest=false
tags: |
type=raw,value=latest,enable=${{ github.event.merge_group.base_ref == 'refs/heads/develop' }}
type=sha
type=sha,format=long
type=ref,event=branch
type=ref,event=tag
- name: Create manifest list
working-directory: ${{ runner.temp }}/digests
env:
IMAGE_NAME: ${{ needs.build.outputs.image-name }}
run: |
while read -r tag; do
podman manifest create "$tag" \
$(printf "$IMAGE_NAME@sha256:%s " *)
done <<< "$DOCKER_METADATA_OUTPUT_TAGS"
- name: Push manifest
uses: redhat-actions/push-to-registry@v2
with:
tags: ${{ steps.manifest-metadata.outputs.tags }}
username: ${{ github.repository_owner }}
password: ${{ github.token }}
tls-verify: true

View file

@ -1,64 +0,0 @@
name: Merged Blocking Pull Request Automation
on:
pull_request_target:
types:
- closed
workflow_dispatch:
inputs:
pr_id:
description: Local Pull Request number to work on
required: true
type: number
permissions: {}
jobs:
update-blocked-status:
name: Update Blocked Status
runs-on: ubuntu-slim
# a pr that was a `blocking:<id>` label was merged.
# find the open pr's it was blocked by and trigger a refresh of their state
if: "${{ github.event_name == 'workflow_dispatch' || github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'status: blocking') }}"
steps:
- name: Generate token
id: generate-token
uses: actions/create-github-app-token@v3
with:
app-id: ${{ vars.PULL_REQUEST_APP_ID }}
private-key: ${{ secrets.PULL_REQUEST_APP_PRIVATE_KEY }}
- name: Gather Dependent PRs
id: gather_deps
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
PR_NUMBER: ${{ inputs.pr_id || github.event.pull_request.number }}
run: |
blocked_prs=$(
gh -R ${{ github.repository }} pr list --label 'status: blocked' --json 'number,body' \
| jq -c --argjson pr "$PR_NUMBER" '
reduce ( .[] | select(
.body |
scan("(?:blocked (?:by|on)|stacked on):? #([0-9]+)") |
map(tonumber) |
any(.[]; . == $pr)
)) as $i ([]; . + [$i])
'
)
{
echo "deps=$blocked_prs"
echo "numdeps=$(jq -r '. | length' <<< "$blocked_prs")"
} >> "$GITHUB_OUTPUT"
- name: Trigger Blocked PR Workflows for Dependants
if: fromJSON(steps.gather_deps.outputs.numdeps) > 0
env:
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
DEPS: ${{ steps.gather_deps.outputs.deps }}
run: |
while read -r pr ; do
gh -R ${{ github.repository }} workflow run 'blocked-prs.yml' -r "${{ github.ref_name }}" -f pr_id="$pr"
done < <(jq -c '.[].number' <<< "$DEPS")

View file

@ -1,138 +0,0 @@
name: Nix
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
push:
branches:
- "develop"
- "release-*"
tags:
- "*"
paths:
# File types
- "**.cpp"
- "**.h"
- "**.java"
- "**.ui"
- "**.md"
# Build files
- "**.nix"
- "nix/**"
- "flake.lock"
# Directories
- "buildconfig/**"
- "cmake/**"
- "launcher/**"
- "libraries/**"
- "program_info/**"
- "tests/**"
# Files
- "CMakeLists.txt"
# Workflows
- ".github/workflows/nix.yml"
pull_request:
paths:
# File types
- "**.cpp"
- "**.h"
- "**.java"
- "**.ui"
- "**.md"
# Build files
- "**.nix"
- "nix/**"
- "flake.lock"
# Directories
- "buildconfig/**"
- "cmake/**"
- "launcher/**"
- "libraries/**"
- "program_info/**"
- "tests/**"
# Files
- "CMakeLists.txt"
# Workflows
- ".github/workflows/nix.yml"
workflow_dispatch:
permissions: {}
env:
DEBUG: ${{ github.ref_type != 'tag' }}
jobs:
build:
name: Build (${{ matrix.system }})
permissions:
contents: read
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-22.04
system: x86_64-linux
- os: ubuntu-22.04-arm
system: aarch64-linux
- os: macos-26
system: aarch64-darwin
runs-on: ${{ matrix.os }}
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Install Nix
uses: cachix/install-nix-action@v31
# For PRs
- name: Setup Nix Magic Cache
if: ${{ github.event_name == 'pull_request' }}
uses: DeterminateSystems/magic-nix-cache-action@v14
with:
diagnostic-endpoint: ""
use-flakehub: false
# For in-tree builds
- name: Setup Cachix
if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }}
uses: cachix/cachix-action@v17
with:
name: prismlauncher
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
- name: Run Flake checks
run: |
nix flake check --print-build-logs --show-trace
- name: Build debug package
if: ${{ env.DEBUG == 'true' }}
run: |
nix build \
--no-link --print-build-logs --print-out-paths \
.#prismlauncher-debug >> "$GITHUB_STEP_SUMMARY"
- name: Build release package
if: ${{ env.DEBUG == 'false' }}
env:
TAG: ${{ github.ref_name }}
SYSTEM: ${{ matrix.system }}
run: |
nix build --no-link --print-out-paths .#prismlauncher \
| tee -a "$GITHUB_STEP_SUMMARY" \
| xargs cachix pin prismlauncher "$TAG"-"$SYSTEM"

43
.github/workflows/trigger_builds.yml vendored Normal file
View file

@ -0,0 +1,43 @@
name: Build Application
on:
push:
branches-ignore:
- "renovate/**"
paths-ignore:
- "**.md"
- "**/LICENSE"
- "flake.lock"
- "packages/**"
- ".github/ISSUE_TEMPLATE/**"
- ".markdownlint**"
pull_request:
paths-ignore:
- "**.md"
- "**/LICENSE"
- "flake.lock"
- "packages/**"
- ".github/ISSUE_TEMPLATE/**"
- ".markdownlint**"
workflow_dispatch:
jobs:
build_debug:
name: Build Debug
uses: ./.github/workflows/build.yml
with:
build_type: Debug
is_qt_cached: true
secrets:
SPARKLE_ED25519_KEY: ${{ secrets.SPARKLE_ED25519_KEY }}
WINDOWS_CODESIGN_CERT: ${{ secrets.WINDOWS_CODESIGN_CERT }}
WINDOWS_CODESIGN_PASSWORD: ${{ secrets.WINDOWS_CODESIGN_PASSWORD }}
APPLE_CODESIGN_CERT: ${{ secrets.APPLE_CODESIGN_CERT }}
APPLE_CODESIGN_PASSWORD: ${{ secrets.APPLE_CODESIGN_PASSWORD }}
APPLE_CODESIGN_ID: ${{ secrets.APPLE_CODESIGN_ID }}
APPLE_NOTARIZE_APPLE_ID: ${{ secrets.APPLE_NOTARIZE_APPLE_ID }}
APPLE_NOTARIZE_TEAM_ID: ${{ secrets.APPLE_NOTARIZE_TEAM_ID }}
APPLE_NOTARIZE_PASSWORD: ${{ secrets.APPLE_NOTARIZE_PASSWORD }}
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
GPG_PRIVATE_KEY_ID: ${{ secrets.GPG_PRIVATE_KEY_ID }}

View file

@ -5,38 +5,40 @@ on:
tags:
- "*"
permissions: {}
jobs:
build_release:
name: Build Release
uses: ./.github/workflows/build.yml
permissions:
contents: read
# Required for Azure Trusted Signing
id-token: write
# Required for vcpkg binary cache
packages: write
with:
build-type: Release
environment: Release
secrets: inherit
build_type: Release
is_qt_cached: false
secrets:
SPARKLE_ED25519_KEY: ${{ secrets.SPARKLE_ED25519_KEY }}
WINDOWS_CODESIGN_CERT: ${{ secrets.WINDOWS_CODESIGN_CERT }}
WINDOWS_CODESIGN_PASSWORD: ${{ secrets.WINDOWS_CODESIGN_PASSWORD }}
APPLE_CODESIGN_CERT: ${{ secrets.APPLE_CODESIGN_CERT }}
APPLE_CODESIGN_PASSWORD: ${{ secrets.APPLE_CODESIGN_PASSWORD }}
APPLE_CODESIGN_ID: ${{ secrets.APPLE_CODESIGN_ID }}
APPLE_NOTARIZE_APPLE_ID: ${{ secrets.APPLE_NOTARIZE_APPLE_ID }}
APPLE_NOTARIZE_TEAM_ID: ${{ secrets.APPLE_NOTARIZE_TEAM_ID }}
APPLE_NOTARIZE_PASSWORD: ${{ secrets.APPLE_NOTARIZE_PASSWORD }}
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
GPG_PRIVATE_KEY_ID: ${{ secrets.GPG_PRIVATE_KEY_ID }}
create_release:
needs: build_release
permissions:
contents: write
runs-on: ubuntu-slim
runs-on: ubuntu-latest
outputs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v4
with:
submodules: "true"
path: "PrismLauncher-source"
- name: Download artifacts
uses: actions/download-artifact@v8
uses: actions/download-artifact@v4
- name: Grab and store version
run: |
tag_name=$(echo ${{ github.ref }} | grep -oE "[^/]+$")
@ -45,13 +47,11 @@ jobs:
run: |
mv ${{ github.workspace }}/PrismLauncher-source PrismLauncher-${{ env.VERSION }}
mv PrismLauncher-Linux-Qt6-Portable*/PrismLauncher-portable.tar.gz PrismLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz
mv PrismLauncher-Linux-aarch64-Qt6-Portable*/PrismLauncher-portable.tar.gz PrismLauncher-Linux-aarch64-Qt6-Portable-${{ env.VERSION }}.tar.gz
mv PrismLauncher-*.AppImage/PrismLauncher-*-x86_64.AppImage PrismLauncher-Linux-x86_64.AppImage
mv PrismLauncher-*.AppImage.zsync/PrismLauncher-*-x86_64.AppImage.zsync PrismLauncher-Linux-x86_64.AppImage.zsync
mv PrismLauncher-*.AppImage/PrismLauncher-*-aarch64.AppImage PrismLauncher-Linux-aarch64.AppImage
mv PrismLauncher-*.AppImage.zsync/PrismLauncher-*-aarch64.AppImage.zsync PrismLauncher-Linux-aarch64.AppImage.zsync
mv PrismLauncher-Linux-Qt5-Portable*/PrismLauncher-portable.tar.gz PrismLauncher-Linux-Qt5-Portable-${{ env.VERSION }}.tar.gz
mv PrismLauncher-*.AppImage/PrismLauncher-*.AppImage PrismLauncher-Linux-x86_64.AppImage
mv PrismLauncher-*.AppImage.zsync/PrismLauncher-*.AppImage.zsync PrismLauncher-Linux-x86_64.AppImage.zsync
mv PrismLauncher-macOS-Legacy*/PrismLauncher.zip PrismLauncher-macOS-Legacy-${{ env.VERSION }}.zip
mv PrismLauncher-macOS*/PrismLauncher.zip PrismLauncher-macOS-${{ env.VERSION }}.zip
mv PrismLauncher-macOS*/PrismLauncher.dmg PrismLauncher-macOS-${{ env.VERSION }}.dmg
tar --exclude='.git' -czf PrismLauncher-${{ env.VERSION }}.tar.gz PrismLauncher-${{ env.VERSION }}
@ -81,40 +81,23 @@ jobs:
cd ..
done
for d in PrismLauncher-Windows-MinGW-arm64*; do
cd "${d}" || continue
INST="$(echo -n ${d} | grep -o Setup || true)"
PORT="$(echo -n ${d} | grep -o Portable || true)"
NAME="PrismLauncher-Windows-MinGW-arm64"
test -z "${PORT}" || NAME="${NAME}-Portable"
test -z "${INST}" || mv PrismLauncher-*.exe ../${NAME}-Setup-${{ env.VERSION }}.exe
test -n "${INST}" || zip -r -9 "../${NAME}-${{ env.VERSION }}.zip" *
cd ..
done
- name: Create release
id: create_release
uses: softprops/action-gh-release@v3
uses: softprops/action-gh-release@v2
with:
token: ${{ secrets.GITHUB_TOKEN }}
tag_name: ${{ github.ref }}
name: Prism Launcher ${{ env.VERSION }}
draft: true
prerelease: false
fail_on_unmatched_files: true
files: |
PrismLauncher-Linux-Qt5-Portable-${{ env.VERSION }}.tar.gz
PrismLauncher-Linux-x86_64.AppImage
PrismLauncher-Linux-x86_64.AppImage.zsync
PrismLauncher-Linux-aarch64.AppImage
PrismLauncher-Linux-aarch64.AppImage.zsync
PrismLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz
PrismLauncher-Linux-aarch64-Qt6-Portable-${{ env.VERSION }}.tar.gz
PrismLauncher-Windows-MinGW-w64-${{ env.VERSION }}.zip
PrismLauncher-Windows-MinGW-w64-Portable-${{ env.VERSION }}.zip
PrismLauncher-Windows-MinGW-w64-Setup-${{ env.VERSION }}.exe
PrismLauncher-Windows-MinGW-arm64-${{ env.VERSION }}.zip
PrismLauncher-Windows-MinGW-arm64-Portable-${{ env.VERSION }}.zip
PrismLauncher-Windows-MinGW-arm64-Setup-${{ env.VERSION }}.exe
PrismLauncher-Windows-MSVC-arm64-${{ env.VERSION }}.zip
PrismLauncher-Windows-MSVC-arm64-Portable-${{ env.VERSION }}.zip
PrismLauncher-Windows-MSVC-arm64-Setup-${{ env.VERSION }}.exe
@ -122,5 +105,5 @@ jobs:
PrismLauncher-Windows-MSVC-Portable-${{ env.VERSION }}.zip
PrismLauncher-Windows-MSVC-Setup-${{ env.VERSION }}.exe
PrismLauncher-macOS-${{ env.VERSION }}.zip
PrismLauncher-macOS-${{ env.VERSION }}.dmg
PrismLauncher-macOS-Legacy-${{ env.VERSION }}.zip
PrismLauncher-${{ env.VERSION }}.tar.gz

View file

@ -6,30 +6,25 @@ on:
- cron: "0 0 * * 0"
workflow_dispatch:
permissions: {}
permissions:
contents: write
pull-requests: write
jobs:
update-flake:
if: github.repository == 'PrismLauncher/PrismLauncher'
permissions:
contents: write
pull-requests: write
runs-on: ubuntu-slim
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: cachix/install-nix-action@8aa03977d8d733052d78f4e008a241fd1dbf36b3 # v31
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@08dcb3a5e62fa31e2da3d490afc4176ef55ecd72 # v30
- uses: DeterminateSystems/update-flake-lock@v28
- uses: DeterminateSystems/update-flake-lock@v24
with:
commit-msg: "chore(nix): update lockfile"
pr-title: "chore(nix): update lockfile"
pr-labels: |
platform: Linux
area: packaging
complexity: low
priority: low
type: robot
Linux
packaging
simple change
changelog:omit

View file

@ -1,23 +1,13 @@
name: Publish
name: Publish to WinGet
on:
release:
types: [ released ]
permissions: {}
types: [released]
jobs:
winget:
name: Winget
permissions:
contents: read
runs-on: ubuntu-slim
publish:
runs-on: windows-latest
steps:
- name: Publish on Winget
uses: vedantmgoyal2009/winget-releaser@v2
- uses: vedantmgoyal2009/winget-releaser@v2
with:
identifier: PrismLauncher.PrismLauncher
version: ${{ github.event.release.tag_name }}

8
.gitignore vendored
View file

@ -14,7 +14,6 @@ CMakeLists.txt.user.*
CMakeSettings.json
/CMakeFiles
CMakeCache.txt
CMakeUserPresets.json
/.project
/.settings
/.idea
@ -22,7 +21,6 @@ CMakeUserPresets.json
/.vs
cmake-build-*/
Debug
compile_commands.json
# Build dirs
build
@ -49,12 +47,8 @@ run/
# Nix/NixOS
.direnv/
## Used when manually invoking stdenv phases
outputs/
## Regular artifacts
.pre-commit-config.yaml
result
result-*
repl-result-*
# Flatpak
.flatpak-builder

21
.gitmodules vendored
View file

@ -1,3 +1,24 @@
[submodule "libraries/quazip"]
path = libraries/quazip
url = https://github.com/stachenov/quazip.git
[submodule "libraries/tomlplusplus"]
path = libraries/tomlplusplus
url = https://github.com/marzer/tomlplusplus.git
[submodule "libraries/filesystem"]
path = libraries/filesystem
url = https://github.com/gulrak/filesystem
[submodule "libraries/libnbtplusplus"]
path = libraries/libnbtplusplus
url = https://github.com/PrismLauncher/libnbtplusplus.git
[submodule "libraries/zlib"]
path = libraries/zlib
url = https://github.com/madler/zlib.git
[submodule "libraries/extra-cmake-modules"]
path = libraries/extra-cmake-modules
url = https://github.com/KDE/extra-cmake-modules
[submodule "libraries/cmark"]
path = libraries/cmark
url = https://github.com/commonmark/cmark.git
[submodule "flatpak/shared-modules"]
path = flatpak/shared-modules
url = https://github.com/flathub/shared-modules.git

View file

@ -1 +1,2 @@
libraries/nbtplusplus
libraries/quazip

View file

@ -1,9 +1,6 @@
cmake_minimum_required(VERSION 3.25) # Required for features like `CMAKE_MSVC_DEBUG_INFORMATION_FORMAT`
cmake_minimum_required(VERSION 3.15) # minimum version required by QuaZip
project(Launcher LANGUAGES C CXX)
if(APPLE)
enable_language(OBJC OBJCXX)
endif()
project(Launcher)
string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BUILD_DIR}" IS_IN_SOURCE_BUILD)
if(IS_IN_SOURCE_BUILD)
@ -13,10 +10,6 @@ endif()
##################################### Set CMake options #####################################
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOGEN_ORIGIN_DEPENDS OFF)
set(CMAKE_GLOBAL_AUTOGEN_TARGET ON)
set(CMAKE_GLOBAL_AUTORCC_TARGET ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/")
@ -31,106 +24,101 @@ set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${PROJECT_BINARY_DIR}/jars)
######## Set compiler flags ########
set(CMAKE_CXX_STANDARD_REQUIRED true)
set(CMAKE_C_STANDARD_REQUIRED true)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_C_STANDARD 11)
include(GenerateExportHeader)
if(MSVC)
# /GS Adds buffer security checks, default on but incuded anyway to mirror gcc's fstack-protector flag
# /permissive- specify standards-conforming compiler behavior, also enabled by Qt6, default on with std:c++20
# Use /W4 as /Wall includes unnesserey warnings such as added padding to structs
set(CMAKE_CXX_FLAGS "/GS /permissive- /W4 ${CMAKE_CXX_FLAGS}")
add_compile_definitions($<$<NOT:$<CONFIG:Debug>>:QT_NO_DEBUG>)
add_compile_definitions(QT_WARN_DEPRECATED_UP_TO=0x060400)
add_compile_definitions(QT_DISABLE_DEPRECATED_UP_TO=0x060400)
# /EHs Enables stack unwind semantics for standard C++ exceptions to ensure stackframes are unwound
# and object deconstructors are called when an exception is caught.
# without it memory leaks and a warning is printed
# /EHc tells the compiler to assume that functions declared as extern "C" never throw a C++ exception
# This appears to not always be a defualt compiler option in CMAKE
set(CMAKE_CXX_FLAGS "/EHsc ${CMAKE_CXX_FLAGS}")
if(CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
add_compile_options(
# /GS Adds buffer security checks, default on but included anyway to mirror gcc's fstack-protector flag
"$<$<COMPILE_LANGUAGE:C,CXX>:/GS>"
# /Gw helps reduce binary size
# /Gy allows the compiler to package individual functions
# /guard:cf enables control flow guard
"$<$<AND:$<CONFIG:Release,RelWithDebInfo>,$<COMPILE_LANGUAGE:C,CXX>>:/Gw;/Gy;/guard:cf>"
)
add_link_options(
# /LTCG allows for linking wholy optimizated programs
# /MANIFEST:NO disables generating a manifest file, we instead provide our own
# /STACK sets the stack reserve size, ATL's pack list needs 3-4 MiB as of November 2022, provide 8 MiB
"$<$<COMPILE_LANGUAGE:C,CXX>:/LTCG;/MANIFEST:NO;/STACK:8388608>"
)
# LINK accepts /SUBSYSTEM whics sets if we are a WINDOWS (gui) or a CONSOLE programs
# This implicitly selects an entrypoint specific to the subsystem selected
# qtmain/QtEntryPointLib provides the correct entrypoint (wWinMain) for gui programs
# Additinaly LINK autodetects we use a GUI so we can omit /SUBSYSTEM
# This allows tests to still use have console without using seperate linker flags
# /LTCG allows for linking wholy optimizated programs
# /MANIFEST:NO disables generating a manifest file, we instead provide our own
# /STACK sets the stack reserve size, ATL's pack list needs 3-4 MiB as of November 2022, provide 8 MiB
set(CMAKE_EXE_LINKER_FLAGS "/LTCG /MANIFEST:NO /STACK:8388608 ${CMAKE_EXE_LINKER_FLAGS}")
# /GL enables whole program optimizations
# NOTE: With Clang, this is implemented as regular LTO and only used during linking
if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
add_compile_options("$<$<AND:$<CONFIG:Release,RelWithDebInfo>,$<COMPILE_LANGUAGE:C,CXX>>:/GL>")
endif()
# /Gw helps reduce binary size
# /Gy allows the compiler to package individual functions
# /guard:cf enables control flow guard
foreach(lang C CXX)
set("CMAKE_${lang}_FLAGS_RELEASE" "/GL /Gw /Gy /guard:cf")
endforeach()
# See https://github.com/ccache/ccache/issues/1040
# TODO(@getchoo): Is sccache affected by this? Would be nice to use `ProgramDatabase`....
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<$<CONFIG:Debug,RelWithDebInfo>:Embedded>")
# Note, CMake 3.25 replaces this with CMAKE_MSVC_DEBUG_INFORMATION_FORMAT
# See https://cmake.org/cmake/help/v3.25/variable/CMAKE_MSVC_DEBUG_INFORMATION_FORMAT.html
foreach(config DEBUG RELWITHDEBINFO)
foreach(lang C CXX)
set(flags_var "CMAKE_${lang}_FLAGS_${config}")
string(REGEX REPLACE "/Z[Ii]" "/Z7" ${flags_var} "${${flags_var}}")
endforeach()
endforeach()
if(CMAKE_MSVC_RUNTIME_LIBRARY STREQUAL "MultiThreadedDLL")
set(CMAKE_MAP_IMPORTED_CONFIG_DEBUG Release "")
set(CMAKE_MAP_IMPORTED_CONFIG_RELWITHDEBINFO Release "")
endif()
else()
add_compile_options("$<$<COMPILE_LANGUAGE:C,CXX>:-fstack-protector-strong;--param=ssp-buffer-size=4>")
# Avoid re-defining _FORTIFY_SOURCE, as it can cause redefinition errors in setups that use it by default (i.e., package builds)
if(NOT (CMAKE_C_FLAGS MATCHES "-D_FORTIFY_SOURCE" OR CMAKE_CXX_FLAGS MATCHES "-D_FORTIFY_SOURCE"))
# NOTE: _FORTIFY_SOURCE requires optimizations in most newer versions of glibc
add_compile_options("$<$<AND:$<COMPILE_LANGUAGE:C,CXX>,$<CONFIG:Release,RelWithDebInfo>>:-D_FORTIFY_SOURCE=2>")
endif()
set(CMAKE_CXX_FLAGS "-Wall -pedantic -fstack-protector-strong --param=ssp-buffer-size=4 ${CMAKE_CXX_FLAGS}")
# ATL's pack list needs more than the default 1 Mib stack on windows
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
add_link_options("$<$<COMPILE_LANGUAGE:C,CXX>:-Wl,--stack,8388608>")
# -ffunction-sections and -fdata-sections help reduce binary size
# -mguard=cf enables Control Flow Guard
# TODO: Look into -gc-sections to further reduce binary size
add_compile_options("$<$<AND:$<CONFIG:Release,RelWithDebInfo>,$<COMPILE_LANGUAGE:C,CXX>>:-ffunction-sections;-fdata-sections;-mguard=cf>")
if(WIN32)
set(CMAKE_EXE_LINKER_FLAGS "-Wl,--stack,8388608 ${CMAKE_EXE_LINKER_FLAGS}")
endif()
endif()
# Export compile commands for debug builds if we can (useful in LSPs like clangd)
# https://cmake.org/cmake/help/v3.31/variable/CMAKE_EXPORT_COMPILE_COMMANDS.html
if(CMAKE_GENERATOR STREQUAL "Unix Makefiles" OR CMAKE_GENERATOR MATCHES "^Ninja")
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
endif()
# Fix build with Qt 5.13
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_NO_DEPRECATED_WARNINGS=Y")
option(USE_CLANG_TIDY "Enable the use of clang-tidy during compilation" OFF)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_DISABLE_DEPRECATED_BEFORE=0x050C00")
if(USE_CLANG_TIDY)
find_program(CLANG_TIDY clang-tidy OPTIONAL)
if(CLANG_TIDY)
message(STATUS "Using clang-tidy during compilation")
set(CLANG_TIDY_COMMAND "${CLANG_TIDY}" "--config-file=${CMAKE_SOURCE_DIR}/.clang-tidy")
set(CMAKE_CXX_CLANG_TIDY ${CLANG_TIDY_COMMAND})
else()
message(WARNING "Unable to find `clang-tidy`. Not using during compilation")
endif()
endif()
# Fix aarch64 build for toml++
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DTOML_ENABLE_FLOAT16=0")
# set CXXFLAGS for build targets
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -D_FORTIFY_SOURCE=2 ${CMAKE_CXX_FLAGS_RELEASE}")
option(DEBUG_ADDRESS_SANITIZER "Enable Address Sanitizer in Debug builds" OFF)
# If this is a Debug build turn on address sanitiser
if (DEBUG_ADDRESS_SANITIZER)
if ((CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") AND DEBUG_ADDRESS_SANITIZER)
message(STATUS "Address Sanitizer enabled for Debug builds, Turn it off with -DDEBUG_ADDRESS_SANITIZER=off")
set(USE_ASAN_COMPILE_OPTIONS $<AND:$<CONFIG:Debug,RelWithDebInfo>,$<COMPILE_LANGUAGE:C,CXX>>)
if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
message(STATUS "Using Address Sanitizer compile options for MSVC frontend")
add_compile_options(
$<${USE_ASAN_COMPILE_OPTIONS}:/fsanitize=address>
$<${USE_ASAN_COMPILE_OPTIONS}:/Oy->
)
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
message(STATUS "Using Address Sanitizer compile options for GCC/Clang")
add_compile_options(
$<${USE_ASAN_COMPILE_OPTIONS}:-fsanitize=address,undefined>
$<${USE_ASAN_COMPILE_OPTIONS}:-fno-omit-frame-pointer>
$<${USE_ASAN_COMPILE_OPTIONS}:-fno-sanitize-recover=null>
)
link_libraries("asan" "ubsan")
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
# using clang with clang-cl front end
message(STATUS "Address Sanitizer available on Clang MSVC frontend")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fsanitize=address /Oy-")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fsanitize=address /Oy-")
else()
# AppleClang and Clang
message(STATUS "Address Sanitizer available on Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
endif()
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
# GCC
message(STATUS "Address Sanitizer available on GCC")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
link_libraries("asan")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
message(STATUS "Address Sanitizer available on MSVC")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fsanitize=address /Oy-")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fsanitize=address /Oy-")
else()
message(STATUS "Address Sanitizer not available on compiler ${CMAKE_CXX_COMPILER_ID}")
endif()
@ -146,9 +134,8 @@ if(ENABLE_LTO)
if(ipo_supported)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_MINSIZEREL TRUE)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE)
if(CMAKE_BUILD_TYPE)
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
if(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
message(STATUS "IPO / LTO enabled")
else()
message(STATUS "Not enabling IPO / LTO on debug builds")
@ -163,9 +150,20 @@ endif()
option(BUILD_TESTING "Build the testing tree." ON)
find_package(ECM NO_MODULE REQUIRED)
set(CMAKE_MODULE_PATH "${ECM_MODULE_PATH};${CMAKE_MODULE_PATH}")
find_package(ECM QUIET NO_MODULE)
if(NOT ECM_FOUND)
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/libraries/extra-cmake-modules/CMakeLists.txt")
message(STATUS "Using bundled ECM")
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/libraries/extra-cmake-modules/modules;${CMAKE_MODULE_PATH}")
else()
message(FATAL_ERROR
" Could not find ECM\n \n"
" Either install ECM using the system package manager or clone submodules\n"
" Submodules can be cloned with 'git submodule update --init --recursive'")
endif()
else()
set(CMAKE_MODULE_PATH "${ECM_MODULE_PATH};${CMAKE_MODULE_PATH}")
endif()
include(CTest)
include(ECMAddTests)
if(BUILD_TESTING)
@ -177,19 +175,17 @@ endif()
######## Set URLs ########
set(Launcher_NEWS_RSS_URL "https://prismlauncher.org/feed/feed.xml" CACHE STRING "URL to fetch Prism Launcher's news RSS feed from.")
set(Launcher_NEWS_OPEN_URL "https://prismlauncher.org/news" CACHE STRING "URL that gets opened when the user clicks 'More News'")
set(Launcher_WIKI_URL "https://prismlauncher.org/wiki/" CACHE STRING "URL that gets opened when the user clicks 'Launcher Help'")
set(Launcher_HELP_URL "https://prismlauncher.org/wiki/help-pages/%1" CACHE STRING "URL (with arg %1 to be substituted with page-id) that gets opened when the user requests help in a dialog window")
set(Launcher_HELP_URL "https://prismlauncher.org/wiki/help-pages/%1" CACHE STRING "URL (with arg %1 to be substituted with page-id) that gets opened when the user requests help")
set(Launcher_LOGIN_CALLBACK_URL "https://prismlauncher.org/successful-login" CACHE STRING "URL that gets opened when the user successfully logins.")
set(Launcher_LEGACY_FMLLIBS_BASE_URL "https://files.prismlauncher.org/fmllibs/" CACHE STRING "URL for legacy (<=1.5.2) FML Libraries.")
set(Launcher_FMLLIBS_BASE_URL "https://files.prismlauncher.org/fmllibs/" CACHE STRING "URL for FML Libraries.")
######## Set version numbers ########
set(Launcher_VERSION_MAJOR 12)
set(Launcher_VERSION_MINOR 0)
set(Launcher_VERSION_PATCH 0)
set(Launcher_VERSION_MAJOR 9)
set(Launcher_VERSION_MINOR 2)
set(Launcher_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_PATCH}")
set(Launcher_VERSION_NAME4 "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_PATCH}.0")
set(Launcher_VERSION_NAME4_COMMA "${Launcher_VERSION_MAJOR},${Launcher_VERSION_MINOR},${Launcher_VERSION_PATCH},0")
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_COMMA "${Launcher_VERSION_MAJOR},${Launcher_VERSION_MINOR},0,0")
# Build platform.
set(Launcher_BUILD_PLATFORM "unknown" CACHE STRING "A short string identifying the platform that this build was built for. Only used to display in the about dialog.")
@ -223,10 +219,9 @@ set(Launcher_DISCORD_URL "https://prismlauncher.org/discord" CACHE STRING "URL f
set(Launcher_SUBREDDIT_URL "https://prismlauncher.org/reddit" CACHE STRING "URL for the subreddit.")
# Builds
set(Launcher_FORCE_BUNDLED_LIBS OFF CACHE BOOL "Prevent using system libraries, if they are available as submodules")
set(Launcher_QT_VERSION_MAJOR "6" CACHE STRING "Major Qt version to build against")
option(Launcher_USE_PCH "Use precompiled headers where possible" ON)
# Java downloader
set(Launcher_ENABLE_JAVA_DOWNLOADER_DEFAULT ON)
@ -234,7 +229,7 @@ set(Launcher_ENABLE_JAVA_DOWNLOADER_DEFAULT ON)
# differing Linux/BSD/etc distributions. Downstream packagers should be explicitly opt-ing into this
# feature if they know it will work with their distribution.
if(UNIX AND NOT APPLE)
set(Launcher_ENABLE_JAVA_DOWNLOADER_DEFAULT OFF)
set(Launcher_ENABLE_JAVA_DOWNLOADER_DEFAULT OFF)
endif()
# Java downloader
@ -289,59 +284,75 @@ set(Launcher_BUILD_TIMESTAMP "${TODAY}")
################################ 3rd Party Libs ################################
# Successive configurations of cmake without cleaning the build dir will cause zlib fallback to fail due to cached values
# Record when fallback triggered and skip this find_package
if(NOT Launcher_FORCE_BUNDLED_LIBS AND NOT FORCE_BUNDLED_ZLIB)
find_package(ZLIB QUIET)
endif()
if(NOT ZLIB_FOUND)
set(FORCE_BUNDLED_ZLIB TRUE CACHE BOOL "")
mark_as_advanced(FORCE_BUNDLED_ZLIB)
endif()
# Find the required Qt parts
if(Launcher_QT_VERSION_MAJOR EQUAL 6)
include(QtVersionlessBackport)
if(Launcher_QT_VERSION_MAJOR EQUAL 5)
set(QT_VERSION_MAJOR 5)
find_package(Qt5 REQUIRED COMPONENTS Core Widgets Concurrent Network Test Xml NetworkAuth)
if(NOT Launcher_FORCE_BUNDLED_LIBS)
find_package(QuaZip-Qt5 1.3 QUIET)
endif()
if (NOT QuaZip-Qt5_FOUND)
set(QUAZIP_QT_MAJOR_VERSION ${QT_VERSION_MAJOR} CACHE STRING "Qt version to use (4, 5 or 6), defaults to ${QT_VERSION_MAJOR}" FORCE)
set(FORCE_BUNDLED_QUAZIP 1)
endif()
# Qt 6 sets these by default. Notably causes Windows APIs to use UNICODE strings.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUNICODE -D_UNICODE")
elseif(Launcher_QT_VERSION_MAJOR EQUAL 6)
set(QT_VERSION_MAJOR 6)
find_package(Qt6 6.4 REQUIRED COMPONENTS Core CoreTools Widgets Concurrent Network Test Xml NetworkAuth OpenGL)
find_package(Qt6 COMPONENTS DBus)
list(APPEND Launcher_QT_DBUS Qt6::DBus)
find_package(Qt6 REQUIRED COMPONENTS Core CoreTools Widgets Concurrent Network Test Xml Core5Compat NetworkAuth)
list(APPEND Launcher_QT_LIBS Qt6::Core5Compat)
if(NOT Launcher_FORCE_BUNDLED_LIBS)
find_package(QuaZip-Qt6 1.3 QUIET)
endif()
if (NOT QuaZip-Qt6_FOUND)
set(QUAZIP_QT_MAJOR_VERSION ${QT_VERSION_MAJOR} CACHE STRING "Qt version to use (4, 5 or 6), defaults to ${QT_VERSION_MAJOR}" FORCE)
set(FORCE_BUNDLED_QUAZIP 1)
endif()
else()
message(FATAL_ERROR "Qt version ${Launcher_QT_VERSION_MAJOR} is not supported")
endif()
if(Launcher_QT_VERSION_MAJOR EQUAL 6)
if(Launcher_QT_VERSION_MAJOR EQUAL 5)
include(ECMQueryQt)
ecm_query_qt(QT_PLUGINS_DIR QT_INSTALL_PLUGINS)
ecm_query_qt(QT_LIBS_DIR QT_INSTALL_LIBS)
ecm_query_qt(QT_LIBEXECS_DIR QT_INSTALL_LIBEXECS)
else()
set(QT_PLUGINS_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_PLUGINS})
set(QT_LIBS_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_LIBS})
set(QT_LIBEXECS_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_LIBEXECS})
endif()
find_package(cmark REQUIRED)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
find_package(PkgConfig REQUIRED)
pkg_check_modules(gamemode REQUIRED IMPORTED_TARGET gamemode)
# NOTE: Qt 6 already sets this by default
if (Qt5_POSITION_INDEPENDENT_CODE)
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
# Find libqrencode
## NOTE(@getchoo): Never use pkg-config with MSVC since the vcpkg port makes our install bundle fail to find the dll
if(MSVC)
find_path(LIBQRENCODE_INCLUDE_DIR qrencode.h REQUIRED)
find_library(LIBQRENCODE_LIBRARY_RELEASE qrencode REQUIRED)
find_library(LIBQRENCODE_LIBRARY_DEBUG qrencoded)
set(LIBQRENCODE_LIBRARIES optimized ${LIBQRENCODE_LIBRARY_RELEASE} debug ${LIBQRENCODE_LIBRARY_DEBUG})
else()
find_package(PkgConfig REQUIRED)
pkg_check_modules(libqrencode REQUIRED IMPORTED_TARGET libqrencode)
if(NOT Launcher_FORCE_BUNDLED_LIBS)
# Find toml++
find_package(tomlplusplus 3.2.0 QUIET)
# Find ghc_filesystem
find_package(ghc_filesystem QUIET)
# Find cmark
find_package(cmark QUIET)
endif()
# Find libarchive through CMake packages, mainly for vcpkg
find_package(LibArchive)
# CMake packages aren't available in most distributions of libarchive, so fallback to pkg-config
if(NOT LibArchive_FOUND)
find_package(PkgConfig REQUIRED)
pkg_check_modules(libarchive REQUIRED IMPORTED_TARGET libarchive)
endif()
find_package(tomlplusplus 3.2.0)
# fallback to pkgconfig, important especially as many distros package toml++ built with meson
if(NOT tomlplusplus_FOUND)
find_package(PkgConfig REQUIRED)
pkg_check_modules(tomlplusplus REQUIRED IMPORTED_TARGET tomlplusplus>=3.2.0)
endif()
find_package(ZLIB REQUIRED)
include(ECMQtDeclareLoggingCategory)
####################################### Program Info #######################################
@ -355,7 +366,7 @@ set(Launcher_ENABLE_UPDATER NO)
set(Launcher_BUILD_UPDATER NO)
if (NOT APPLE AND (NOT Launcher_UPDATER_GITHUB_REPO STREQUAL "" AND NOT Launcher_BUILD_ARTIFACT STREQUAL ""))
set(Launcher_BUILD_UPDATER YES)
set(Launcher_BUILD_UPDATER YES)
endif()
if(NOT (UNIX AND APPLE))
@ -371,10 +382,13 @@ if(UNIX AND APPLE)
set(RESOURCES_DEST_DIR "${Launcher_Name}.app/Contents/Resources")
set(JARS_DEST_DIR "${Launcher_Name}.app/Contents/MacOS/jars")
# Apps to bundle
set(APPS "\${CMAKE_INSTALL_PREFIX}/${Launcher_Name}.app")
# Mac bundle settings
set(MACOSX_BUNDLE_BUNDLE_NAME "${Launcher_DisplayName}")
set(MACOSX_BUNDLE_INFO_STRING "${Launcher_DisplayName}: A custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once.")
set(MACOSX_BUNDLE_GUI_IDENTIFIER "${Launcher_AppID}")
set(MACOSX_BUNDLE_GUI_IDENTIFIER "org.prismlauncher.${Launcher_Name}")
set(MACOSX_BUNDLE_BUNDLE_VERSION "${Launcher_VERSION_NAME}")
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${Launcher_VERSION_NAME}")
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${Launcher_VERSION_NAME}")
@ -383,63 +397,23 @@ if(UNIX AND APPLE)
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_DOWNLOAD_URL "https://github.com/sparkle-project/Sparkle/releases/download/2.8.0/Sparkle-2.8.0.tar.xz" CACHE STRING "URL to Sparkle release archive")
set(MACOSX_SPARKLE_SHA256 "fd5681ee92bf238aaac2d08214ceaf0cc8976e452d7f882d80bac1e61581f3b1" CACHE STRING "SHA256 checksum for 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 "50612a06038abc931f16011d7903b8326a362c1074dabccb718404ce8e585f0b" CACHE STRING "SHA256 checksum for Sparkle release archive")
set(MACOSX_SPARKLE_DIR "${CMAKE_BINARY_DIR}/frameworks/Sparkle")
# directories to look for dependencies
set(DIRS ${QT_LIBS_DIR} ${QT_LIBEXECS_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} ${MACOSX_SPARKLE_DIR})
if(NOT MACOSX_SPARKLE_UPDATE_PUBLIC_KEY STREQUAL "" AND NOT MACOSX_SPARKLE_UPDATE_FEED_URL STREQUAL "")
set(Launcher_ENABLE_UPDATER YES)
endif()
# install as bundle
set(INSTALL_BUNDLE "full" CACHE STRING "Use fixup_bundle to bundle dependencies")
# Add the icon
install(FILES ${Launcher_Branding_ICNS} DESTINATION ${RESOURCES_DEST_DIR} RENAME ${Launcher_Name}.icns)
find_program(ACTOOL_EXE actool DOC "Path to the apple asset catalog compiler")
if(ACTOOL_EXE)
execute_process(
COMMAND xcodebuild -version
OUTPUT_VARIABLE XCODE_VERSION_OUTPUT
OUTPUT_STRIP_TRAILING_WHITESPACE
)
string(REGEX MATCH "Xcode ([0-9]+\.[0-9]+)" XCODE_VERSION_MATCH "${XCODE_VERSION_OUTPUT}")
if(XCODE_VERSION_MATCH)
set(XCODE_VERSION ${CMAKE_MATCH_1})
else()
set(XCODE_VERSION 0.0)
endif()
if(XCODE_VERSION VERSION_GREATER_EQUAL 26.0)
set(ASSETS_OUT_DIR "${CMAKE_BINARY_DIR}/program_info")
set(GENERATED_ASSETS_CAR "${ASSETS_OUT_DIR}/Assets.car")
set(ICON_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_Branding_MAC_ICON}")
add_custom_command(
OUTPUT "${GENERATED_ASSETS_CAR}"
COMMAND ${ACTOOL_EXE} "${ICON_SOURCE}"
--compile "${ASSETS_OUT_DIR}"
--output-partial-info-plist /dev/null
--app-icon ${Launcher_Name}
--enable-on-demand-resources NO
--target-device mac
--minimum-deployment-target ${CMAKE_OSX_DEPLOYMENT_TARGET}
--platform macosx
DEPENDS "${ICON_SOURCE}"
COMMENT "Compiling asset catalog (${ICON_SOURCE})"
VERBATIM
)
add_custom_target(compile_assets ALL DEPENDS "${GENERATED_ASSETS_CAR}")
install(FILES "${GENERATED_ASSETS_CAR}" DESTINATION "${RESOURCES_DEST_DIR}")
else()
message(WARNING "Xcode ${XCODE_VERSION} is too old. Minimum required version is 26.0. Not compiling liquid glass icons.")
endif()
else()
message(WARNING "actool not found. Cannot compile macOS app icons.\n"
"Install Xcode command line tools: 'xcode-select --install'")
endif()
elseif(UNIX)
include(KDEInstallDirs)
@ -447,20 +421,30 @@ elseif(UNIX)
set(LIBRARY_DEST_DIR "lib${LIB_SUFFIX}")
set(JARS_DEST_DIR "share/${Launcher_Name}")
# install as bundle with no dependencies included
set(INSTALL_BUNDLE "nodeps" CACHE STRING "Use fixup_bundle to bundle dependencies")
# Set RPATH
SET(Launcher_BINARY_RPATH "$ORIGIN/")
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_Desktop} DESTINATION ${KDE_INSTALL_APPDIR})
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_MetaInfo} DESTINATION ${KDE_INSTALL_METAINFODIR})
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_SVG} DESTINATION "${KDE_INSTALL_ICONDIR}/hicolor/scalable/apps")
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_PNG_256} DESTINATION "${KDE_INSTALL_ICONDIR}/hicolor/256x256/apps" RENAME "${Launcher_AppID}.png")
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_MIMEInfo} DESTINATION ${KDE_INSTALL_MIMEDIR})
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_mrpack_MIMEInfo} DESTINATION ${KDE_INSTALL_MIMEDIR})
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/launcher/qtlogging.ini" DESTINATION "share/${Launcher_Name}")
set(PLUGIN_DEST_DIR "plugins")
set(BUNDLE_DEST_DIR ".")
set(RESOURCES_DEST_DIR ".")
if (INSTALL_BUNDLE STREQUAL full)
set(PLUGIN_DEST_DIR "plugins")
set(BUNDLE_DEST_DIR ".")
set(RESOURCES_DEST_DIR ".")
# Apps to bundle
set(APPS "\${CMAKE_INSTALL_PREFIX}/bin/${Launcher_APP_BINARY_NAME}")
# directories to look for dependencies
set(DIRS ${QT_LIBS_DIR} ${QT_LIBEXECS_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
endif()
if(Launcher_ManPage)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_ManPage} DESTINATION "${KDE_INSTALL_MANDIR}/man6")
@ -476,6 +460,15 @@ elseif(WIN32)
set(PLUGIN_DEST_DIR ".")
set(RESOURCES_DEST_DIR ".")
set(JARS_DEST_DIR "jars")
# Apps to bundle
set(APPS "\${CMAKE_INSTALL_PREFIX}/${Launcher_Name}.exe")
# directories to look for dependencies
set(DIRS ${QT_LIBS_DIR} ${QT_LIBEXECS_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
# install as bundle
set(INSTALL_BUNDLE "full" CACHE STRING "Use fixup_bundle to bundle dependencies")
else()
message(FATAL_ERROR "Platform not supported")
endif()
@ -492,12 +485,70 @@ option(NBT_USE_ZLIB "Build NBT library with zlib support" OFF)
option(NBT_BUILD_TESTS "Build NBT library tests" OFF) #FIXME: fix unit tests.
add_subdirectory(libraries/libnbtplusplus)
add_subdirectory(libraries/systeminfo) # system information library
add_subdirectory(libraries/launcher) # java based launcher part for Minecraft
add_subdirectory(libraries/javacheck) # java compatibility checker
if(FORCE_BUNDLED_ZLIB)
message(STATUS "Using bundled zlib")
set(CMAKE_POLICY_DEFAULT_CMP0069 NEW) # Suppress cmake warnings and allow INTERPROCEDURAL_OPTIMIZATION for zlib
set(SKIP_INSTALL_ALL ON)
add_subdirectory(libraries/zlib EXCLUDE_FROM_ALL)
# On OS where unistd.h exists, zlib's generated header defines `Z_HAVE_UNISTD_H`, while the included header does not.
# We cannot safely undo the rename on those systems, and they generally have packages for zlib anyway.
check_include_file(unistd.h NEED_GENERATED_ZCONF)
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/libraries/zlib/zconf.h.included" AND NOT NEED_GENERATED_ZCONF)
# zlib's cmake script renames a file, dirtying the submodule, see https://github.com/madler/zlib/issues/162
message(STATUS "Undoing Rename")
message(STATUS " ${CMAKE_CURRENT_SOURCE_DIR}/libraries/zlib/zconf.h")
file(RENAME "${CMAKE_CURRENT_SOURCE_DIR}/libraries/zlib/zconf.h.included" "${CMAKE_CURRENT_SOURCE_DIR}/libraries/zlib/zconf.h")
endif()
set(ZLIB_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/libraries/zlib" "${CMAKE_CURRENT_SOURCE_DIR}/libraries/zlib" CACHE STRING "" FORCE)
set_target_properties(zlibstatic PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${ZLIB_INCLUDE_DIR}")
add_library(ZLIB::ZLIB ALIAS zlibstatic)
set(ZLIB_LIBRARY ZLIB::ZLIB CACHE STRING "zlib library name")
find_package(ZLIB REQUIRED)
else()
message(STATUS "Using system zlib")
endif()
if (FORCE_BUNDLED_QUAZIP)
message(STATUS "Using bundled QuaZip")
set(BUILD_SHARED_LIBS 0) # link statically to avoid conflicts.
set(QUAZIP_INSTALL 0)
add_subdirectory(libraries/quazip) # zip manipulation library
else()
message(STATUS "Using system QuaZip")
endif()
add_subdirectory(libraries/rainbow) # Qt extension for colors
add_subdirectory(libraries/LocalPeer) # fork of a library from Qt solutions
if(NOT tomlplusplus_FOUND)
message(STATUS "Using bundled tomlplusplus")
add_subdirectory(libraries/tomlplusplus) # toml parser
else()
message(STATUS "Using system tomlplusplus")
endif()
if(NOT cmark_FOUND)
message(STATUS "Using bundled cmark")
set(ORIGINAL_BUILD_TESTING ${BUILD_TESTING})
set(BUILD_TESTING 0)
set(BUILD_SHARED_LIBS 0)
add_subdirectory(libraries/cmark EXCLUDE_FROM_ALL) # Markdown parser
add_library(cmark::cmark ALIAS cmark)
set(BUILD_TESTING ${ORIGINAL_BUILD_TESTING})
else()
message(STATUS "Using system cmark")
endif()
add_subdirectory(libraries/gamemode)
add_subdirectory(libraries/murmur2) # Hash for usage with the CurseForge API
if (NOT ghc_filesystem_FOUND)
message(STATUS "Using bundled ghc_filesystem")
add_subdirectory(libraries/filesystem) # Implementation of std::filesystem for old C++, for usage in old macOS
else()
message(STATUS "Using system ghc_filesystem")
endif()
add_subdirectory(libraries/qdcss) # css parser
############################### Built Artifacts ###############################

View file

@ -1,222 +0,0 @@
{
"$schema": "https://cmake.org/cmake/help/latest/_downloads/3e2d73bff478d88a7de0de736ba5e361/schema.json",
"version": 8,
"cmakeMinimumRequired": {
"major": 3,
"minor": 28
},
"configurePresets": [
{
"name": "base",
"hidden": true,
"binaryDir": "build",
"installDir": "install",
"generator": "Ninja Multi-Config",
"cacheVariables": {
"Launcher_BUILD_ARTIFACT": "$penv{ARTIFACT_NAME}",
"Launcher_BUILD_PLATFORM": "$penv{BUILD_PLATFORM}",
"Launcher_ENABLE_JAVA_DOWNLOADER": "ON",
"ENABLE_LTO": "ON"
}
},
{
"name": "linux",
"displayName": "Linux",
"inherits": [
"base"
],
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
}
},
{
"name": "macos",
"displayName": "macOS",
"inherits": [
"base"
],
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Darwin"
},
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "$penv{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
}
},
{
"name": "macos_universal",
"displayName": "macOS (Universal Binary)",
"inherits": [
"macos"
],
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "$penv{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake",
"CMAKE_OSX_ARCHITECTURES": "x86_64;arm64",
"VCPKG_TARGET_TRIPLET": "universal-osx"
}
},
{
"name": "windows_mingw",
"displayName": "Windows (MinGW)",
"inherits": [
"base"
],
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
}
},
{
"name": "windows_msvc",
"displayName": "Windows (MSVC)",
"inherits": [
"base"
],
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
},
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "$penv{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
}
}
],
"buildPresets": [
{
"name": "linux",
"displayName": "Linux",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
},
"configurePreset": "linux"
},
{
"name": "macos",
"displayName": "macOS",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Darwin"
},
"configurePreset": "macos"
},
{
"name": "macos_universal",
"displayName": "macOS (Universal Binary)",
"inherits": [
"macos"
],
"configurePreset": "macos_universal"
},
{
"name": "windows_mingw",
"displayName": "Windows (MinGW)",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
},
"configurePreset": "windows_mingw"
},
{
"name": "windows_msvc",
"displayName": "Windows (MSVC)",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
},
"configurePreset": "windows_msvc"
}
],
"testPresets": [
{
"name": "base",
"hidden": true,
"output": {
"outputOnFailure": true,
"verbosity": "extra"
},
"execution": {
"noTestsAction": "error"
},
"filter": {
"exclude": {
"name": "^example64|example$"
}
}
},
{
"name": "linux",
"displayName": "Linux",
"inherits": [
"base"
],
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
},
"configurePreset": "linux"
},
{
"name": "macos",
"displayName": "macOS",
"inherits": [
"base"
],
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Darwin"
},
"configurePreset": "macos"
},
{
"name": "macos_universal",
"displayName": "macOS (Universal Binary)",
"inherits": [
"base"
],
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Darwin"
},
"configurePreset": "macos_universal"
},
{
"name": "windows_mingw",
"displayName": "Windows (MinGW)",
"inherits": [
"base"
],
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
},
"configurePreset": "windows_mingw"
},
{
"name": "windows_msvc",
"displayName": "Windows (MSVC)",
"inherits": [
"base"
],
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
},
"configurePreset": "windows_msvc"
}
]
}

View file

@ -1,113 +1,17 @@
# Contributions Guidelines
## Restrictions on Generative AI Usage (AI Policy)
## Code formatting
> [!NOTE]
> The following is adapted from [matplotlib's contributing guide](https://matplotlib.org/devdocs/devel/contribute.html#generative-ai) and the [Linux Kernel policy guide](https://www.kernel.org/doc./html/next/process/coding-assistants.html)
Try to follow the existing formatting.
If there is no existing formatting, you may use `clang-format` with our included `.clang-format` configuration.
We expect authentic engagement in our community.
In general, in order of importance:
- Do not post output from Large Language Models or similar generative AI as comments on GitHub or our discord server, as such comments tend to be formulaic and low-quality content.
- If you use generative AI tools as an aid in developing code or documentation changes, ensure that you fully understand the proposed changes and can explain why they are the correct approach.
Make sure you have added value based on your personal competency to your contributions.
Just taking some input, feeding it to an AI and posting the result is not of value to the project.
To preserve precious core developer capacity, we reserve the right to rigorously reject seemingly AI generated low-value contributions.
### Signed-off-by and Developer Certificate of Origin
AI agents MUST NOT add Signed-off-by tags. Only humans can legally certify the Developer Certificate of Origin (DCO). The human submitter is responsible for:
- Reviewing all AI-generated code
- Ensuring compliance with licensing requirements
- Adding their own Signed-off-by tag to certify the DCO
- Taking full responsibility for the contribution
See [Signing your work](#signing-your-work) for more information.
### Attribution
When AI tools contribute to development, proper attribution helps track the evolving role of AI in the development process. Contributions should include an Assisted-by tag in the commit message with the following format:
```text
Assisted-by: AGENT_NAME:MODEL_VERSION [TOOL1] [TOOL2]
```
Where:
- `AGENT_NAME` is the name of the AI tool or framework
- `MODEL_VERSION` is the specific model version used
- `[TOOL1] [TOOL2]` are optional specialized analysis tools used (e.g., coccinelle, sparse, smatch, clang-tidy)
Basic development tools (git, gcc, make, editors) should not be listed.
Example:
```text
Assisted-by: Claude:claude-3-opus coccinelle sparse
```
## Code style
All files are formatted with `clang-format` using the configuration in `.clang-format`. Ensure it is run on changed files before committing!
Please also follow the project's conventions for C++:
- Class and type names should be formatted as `PascalCase`: `MyClass`.
- Private or protected class data members should be formatted as `camelCase` prefixed with `m_`: `m_myCounter`.
- Private or protected `static` class data members should be formatted as `camelCase` prefixed with `s_`: `s_instance`.
- Public class data members should be formatted as `camelCase` without the prefix: `dateOfBirth`.
- Public, private or protected `static const` class data members should be formatted as `SCREAMING_SNAKE_CASE`: `MAX_VALUE`.
- Class function members should be formatted as `camelCase` without a prefix: `incrementCounter`.
- Global functions and non-`const` global variables should be formatted as `camelCase` without a prefix: `globalData`.
- `const` global variables and macros should be formatted as `SCREAMING_SNAKE_CASE`: `LIGHT_GRAY`.
- enum constants should be formatted as `PascalCase`: `CamelusBactrianus`
- Avoid inventing acronyms or abbreviations especially for a name of multiple words - like `tp` for `texturePack`.
- Avoid using `[[nodiscard]]` unless ignoring the return value is likely to cause a bug in cases such as:
- A function allocates memory or another resource and the caller needs to clean it up.
- A function has side effects and an error status is returned.
- A function is likely be mistaken for having side effects.
- A plain getter is unlikely to cause confusion and adding `[[nodiscard]]` can create clutter and inconsistency.
Most of these rules are included in the `.clang-tidy` file, so you can run `clang-tidy` to check for any violations.
Here is what these conventions with the formatting configuration look like:
```c++
#define AWESOMENESS 10
constexpr double PI = 3.14159;
enum class PizzaToppings { HamAndPineapple, OreoAndKetchup };
struct Person {
QString name;
QDateTime dateOfBirth;
long daysOld() const { return dateOfBirth.daysTo(QDateTime::currentDateTime()); }
};
class ImportantClass {
public:
void incrementCounter()
{
if (m_counter + 1 > MAX_COUNTER_VALUE)
throw std::runtime_error("Counter has reached limit!");
++m_counter;
}
int counter() const { return m_counter; }
private:
static constexpr int MAX_COUNTER_VALUE = 100;
int m_counter;
};
ImportantClass importantClassInstance;
```
If you see any names which do not follow these conventions, it is preferred that you leave them be - renames increase the number of changes therefore make reviewing harder and make your PR more prone to conflicts. However, if you're refactoring a whole class anyway, it's fine.
- Make sure your IDE is not messing up line endings or whitespace and avoid using linters.
- Prefer readability over dogma.
- Keep to the existing formatting.
- Indent with 4 space unless it's in a submodule.
- Keep lists (of arguments, parameters, initializers...) as lists, not paragraphs. It should either read from top to bottom, or left to right. Not both.
## Signing your work

View file

@ -1,7 +1,7 @@
## Prism Launcher
Prism Launcher - Minecraft Launcher
Copyright (C) 2022-2026 Prism Launcher Contributors
Copyright (C) 2022-2024 Prism Launcher Contributors
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -108,7 +108,7 @@
Information on third party licenses used in MinGW-w64 can be found in its COPYING.MinGW-w64-runtime.txt.
## Qt 6
## Qt 5/6
Copyright (C) 2022 The Qt Company Ltd and other contributors.
Contact: https://www.qt.io/licensing
@ -212,6 +212,30 @@
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
## Quazip
Copyright (C) 2005-2021 Sergey A. Tachenov
The QuaZip library is licensed under the GNU Lesser General Public
License V2.1 plus a static linking exception.
The original ZIP/UNZIP package (MiniZip) is copyrighted by Gilles
Vollant and contributors, see quazip/(un)zip.h files for details.
Basically it's the zlib license.
STATIC LINKING EXCEPTION
The copyright holders give you permission to link this library with
independent modules to produce an executable, regardless of the license
terms of these independent modules, and to copy and distribute the
resulting executable under terms of your choice, provided that you also
meet, for each linked independent module, the terms and conditions of
the license of that module. An independent module is a module which is
not derived from or based on this library. If you modify this library,
you must extend this exception to your version of the library.
See COPYING file for the full LGPL text.
## launcher (`libraries/launcher`)
PolyMC - Minecraft Launcher
@ -338,6 +362,28 @@
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
## gulrak/filesystem
Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
## Breeze icons
Copyright (C) 2014 Uri Herrera <uri_herrera@nitrux.in> and others
@ -379,44 +425,3 @@
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
## libqrencode (`fukuchi/libqrencode`)
Copyright (C) 2020 libqrencode Authors
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
## vcpkg (`cmake/vcpkg-ports`)
MIT License
Copyright (c) Microsoft Corporation
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be included in all copies
or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -1,74 +0,0 @@
ARG DEBIAN_VERSION=stable-slim
FROM docker.io/library/debian:${DEBIAN_VERSION}
ARG QT_ABI=gcc_64
ARG QT_ARCH=
ARG QT_HOST=linux
ARG QT_TARGET=desktop
ARG QT_VERSION=6.10.2
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
&& apt-get --assume-yes upgrade \
&& apt-get --assume-yes autopurge
# Use Adoptium for Java 17
RUN apt-get --assume-yes --no-install-recommends install \
apt-transport-https ca-certificates curl gpg
RUN curl -L https://packages.adoptium.net/artifactory/api/gpg/key/public | gpg --dearmor | tee /etc/apt/trusted.gpg.d/adoptium.gpg
RUN echo "deb https://packages.adoptium.net/artifactory/deb $(awk -F= '/^VERSION_CODENAME/{print$2}' /etc/os-release) main" | tee /etc/apt/sources.list.d/adoptium.list
RUN apt-get update
# Install base dependencies
RUN apt-get --assume-yes --no-install-recommends install \
# Compilers
clang lld llvm temurin-17-jdk \
# Build system
cmake ninja-build extra-cmake-modules pkg-config \
# Dependencies
cmark gamemode-dev libarchive-dev libcmark-dev libgamemode0 libgl1-mesa-dev libqrencode-dev libtomlplusplus-dev scdoc zlib1g-dev \
# Tooling
clang-format clang-tidy git
# Use LLD by default for faster linking
ENV CMAKE_LINKER_TYPE=lld
# Prepare and install Qt
## Setup UTF-8 locale (required, apparently)
RUN apt-get --assume-yes --no-install-recommends install locales
RUN echo "C.UTF-8 UTF-8" > /etc/locale.gen
RUN locale-gen
ENV LC_ALL=C.UTF-8
## Some libraries are required for the official binaries
RUN apt-get --assume-yes --no-install-recommends install \
libglib2.0-0t64 libxkbcommon0 python3-pip
RUN pip3 install --break-system-packages aqtinstall
RUN aqt install-qt \
${QT_HOST} ${QT_TARGET} ${QT_VERSION} ${QT_ARCH} \
--outputdir /opt/qt \
--modules qtimageformats qtnetworkauth
ENV PATH=/opt/qt/${QT_VERSION}/${QT_ABI}/bin:$PATH
ENV QT_PLUGIN_PATH=/opt/qt/${QT_VERSION}/${QT_ABI}/plugins/
## We don't use these. Nuke them
RUN rm -rf \
"$QT_PLUGIN_PATH"/designer \
"$QT_PLUGIN_PATH"/help \
# "$QT_PLUGIN_PATH"/platformthemes/libqgtk3.so \
"$QT_PLUGIN_PATH"/printsupport \
"$QT_PLUGIN_PATH"/qmllint \
"$QT_PLUGIN_PATH"/qmlls \
"$QT_PLUGIN_PATH"/qmltooling \
"$QT_PLUGIN_PATH"/sqldrivers
# Setup workspace
RUN mkdir /work
WORKDIR /work
ENTRYPOINT ["bash"]
CMD ["-i"]

View file

@ -26,14 +26,18 @@ Please understand that these builds are not intended for most users. There may b
There are development builds available through:
- [GitHub Actions](https://github.com/PrismLauncher/PrismLauncher/actions) (includes builds from pull requests opened by contributors)
- [nightly.link](https://prismlauncher.org/nightly) (this will always point only to the latest version of develop)
- [GitHub Actions](https://github.com/PrismLauncher/PrismLauncher/actions) (includes builds from pull requests opened by contribuitors)
- [nightly.link](https://nightly.link/PrismLauncher/PrismLauncher/workflows/trigger_builds/develop) (this will always point only to the latest version of develop)
These have debug information in the binaries, so their file sizes are relatively larger.
Prebuilt Development builds are provided for **Linux**, **Windows** and **macOS**.
On Linux, we also offer our own [Flatpak nightly repository](https://github.com/PrismLauncher/flatpak). Most software centers are able to install it by opening [this link](https://flatpak.prismlauncher.org/prismlauncher-nightly.flatpakref).
For **Arch**, **Debian**, **Fedora**, **OpenSUSE (Tumbleweed)** and **Gentoo**, respectively, you can use these packages for the latest development versions:
[![prismlauncher-git](https://img.shields.io/badge/aur-prismlauncher--git-1793D1?label=AUR&logo=archlinux&logoColor=white)](https://aur.archlinux.org/packages/prismlauncher-git) [![prismlauncher-git](https://img.shields.io/badge/aur-prismlauncher--qt5--git-1793D1?label=AUR&logo=archlinux&logoColor=white)](https://aur.archlinux.org/packages/prismlauncher-qt5-git) [![prismlauncher-git](https://img.shields.io/badge/mpr-prismlauncher--git-A80030?label=MPR&logo=debian&logoColor=white)](https://mpr.makedeb.org/packages/prismlauncher-git)<br />[![prismlauncher-nightly](https://img.shields.io/badge/copr-prismlauncher--nightly-51A2DA?label=COPR&logo=fedora&logoColor=white)](https://copr.fedorainfracloud.org/coprs/g3tchoo/prismlauncher/) [![prismlauncher-nightly](https://img.shields.io/badge/OBS-prismlauncher--nightly-3AB6A9?logo=opensuse&logoColor=white)](https://build.opensuse.org/project/show/home:getchoo) [![prismlauncher-9999](https://img.shields.io/badge/gentoo-prismlauncher--9999-4D4270?label=Gentoo&logo=gentoo&logoColor=white)](https://packages.gentoo.org/packages/games-action/prismlauncher)
These packages are also available to all the distributions based on the ones mentioned above.
## Community & Support
@ -57,7 +61,12 @@ The translation effort for Prism Launcher is hosted on [Weblate](https://hosted.
## Building
If you want to build Prism Launcher yourself, check the [build instructions](https://prismlauncher.org/wiki/development/build-instructions).
If you want to build Prism Launcher yourself, check the build instructions:
- [Windows](https://prismlauncher.org/wiki/development/build-instructions/windows/)
- [Linux](https://prismlauncher.org/wiki/development/build-instructions/linux/)
- [MacOS](https://prismlauncher.org/wiki/development/build-instructions/macos/)
- [OpenBSD](https://prismlauncher.org/wiki/development/build-instructions/openbsd/)
## Sponsors & Partners
@ -67,13 +76,7 @@ We thank all the wonderful backers over at Open Collective! Support Prism Launch
Thanks to JetBrains for providing us a few licenses for all their products, as part of their [Open Source program](https://www.jetbrains.com/opensource/).
<a href="https://jb.gg/OpenSource">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://www.jetbrains.com/company/brand/img/logo_jb_dos_4.svg">
<source media="(prefers-color-scheme: light)" srcset="https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.svg">
<img alt="JetBrains logo" src="https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.svg" width="40%">
</picture>
</a>
[![JetBrains](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)](https://www.jetbrains.com/opensource/)
Thanks to Weblate for hosting our translation efforts.

View file

@ -33,8 +33,9 @@
* limitations under the License.
*/
#include <QObject>
#include <qstringliteral.h>
#include "BuildConfig.h"
#include <QObject>
const Config BuildConfig;
@ -48,16 +49,15 @@ Config::Config()
LAUNCHER_DOMAIN = "@Launcher_Domain@";
LAUNCHER_CONFIGFILE = "@Launcher_ConfigFile@";
LAUNCHER_GIT = "@Launcher_Git@";
LAUNCHER_APPID = "@Launcher_AppID@";
LAUNCHER_DESKTOPFILENAME = "@Launcher_DesktopFileName@";
LAUNCHER_SVGFILENAME = "@Launcher_SVGFileName@";
LAUNCHER_ENVNAME = "@Launcher_ENVName@";
USER_AGENT = "@Launcher_UserAgent@";
USER_AGENT_UNCACHED = USER_AGENT + " (Uncached)";
// Version information
VERSION_MAJOR = @Launcher_VERSION_MAJOR@;
VERSION_MINOR = @Launcher_VERSION_MINOR@;
VERSION_PATCH = @Launcher_VERSION_PATCH@;
BUILD_PLATFORM = "@Launcher_BUILD_PLATFORM@";
BUILD_ARTIFACT = "@Launcher_BUILD_ARTIFACT@";
@ -74,13 +74,14 @@ Config::Config()
MAC_SPARKLE_PUB_KEY = "@MACOSX_SPARKLE_UPDATE_PUBLIC_KEY@";
MAC_SPARKLE_APPCAST_URL = "@MACOSX_SPARKLE_UPDATE_FEED_URL@";
if (!MAC_SPARKLE_PUB_KEY.isEmpty() && !MAC_SPARKLE_APPCAST_URL.isEmpty()) {
if (!MAC_SPARKLE_PUB_KEY.isEmpty() && !MAC_SPARKLE_APPCAST_URL.isEmpty())
{
UPDATER_ENABLED = true;
} else if (!UPDATER_GITHUB_REPO.isEmpty() && !BUILD_ARTIFACT.isEmpty()) {
} else if(!UPDATER_GITHUB_REPO.isEmpty() && !BUILD_ARTIFACT.isEmpty()) {
UPDATER_ENABLED = true;
}
#cmakedefine01 Launcher_ENABLE_JAVA_DOWNLOADER
#cmakedefine01 Launcher_ENABLE_JAVA_DOWNLOADER
JAVA_DOWNLOADER_ENABLED = Launcher_ENABLE_JAVA_DOWNLOADER;
GIT_COMMIT = "@Launcher_GIT_COMMIT@";
@ -88,32 +89,39 @@ Config::Config()
GIT_REFSPEC = "@Launcher_GIT_REFSPEC@";
// Assume that builds outside of Git repos are "stable"
if (GIT_REFSPEC == QStringLiteral("GITDIR-NOTFOUND") || GIT_TAG == QStringLiteral("GITDIR-NOTFOUND") ||
GIT_REFSPEC == QStringLiteral("") || GIT_TAG == QStringLiteral("GIT-NOTFOUND")) {
if (GIT_REFSPEC == QStringLiteral("GITDIR-NOTFOUND")
|| GIT_TAG == QStringLiteral("GITDIR-NOTFOUND")
|| GIT_REFSPEC == QStringLiteral("")
|| GIT_TAG == QStringLiteral("GIT-NOTFOUND"))
{
GIT_REFSPEC = "refs/heads/stable";
GIT_TAG = versionString();
GIT_COMMIT = "";
}
if (GIT_REFSPEC.startsWith("refs/heads/")) {
if (GIT_REFSPEC.startsWith("refs/heads/"))
{
VERSION_CHANNEL = GIT_REFSPEC;
VERSION_CHANNEL.remove("refs/heads/");
} else if (!GIT_COMMIT.isEmpty()) {
VERSION_CHANNEL.remove("refs/heads/");
}
else if (!GIT_COMMIT.isEmpty())
{
VERSION_CHANNEL = GIT_COMMIT.mid(0, 8);
} else {
}
else
{
VERSION_CHANNEL = "unknown";
}
NEWS_RSS_URL = "@Launcher_NEWS_RSS_URL@";
NEWS_OPEN_URL = "@Launcher_NEWS_OPEN_URL@";
WIKI_URL = "@Launcher_WIKI_URL@";
HELP_URL = "@Launcher_HELP_URL@";
LOGIN_CALLBACK_URL = "@Launcher_LOGIN_CALLBACK_URL@";
IMGUR_CLIENT_ID = "@Launcher_IMGUR_CLIENT_ID@";
MSA_CLIENT_ID = "@Launcher_MSA_CLIENT_ID@";
FLAME_API_KEY = "@Launcher_CURSEFORGE_API_KEY@";
META_URL = "@Launcher_META_URL@";
LEGACY_FMLLIBS_BASE_URL = "@Launcher_LEGACY_FMLLIBS_BASE_URL@";
FMLLIBS_BASE_URL = "@Launcher_FMLLIBS_BASE_URL@";
GLFW_LIBRARY_NAME = "@Launcher_GLFW_LIBRARY_NAME@";
OPENAL_LIBRARY_NAME = "@Launcher_OPENAL_LIBRARY_NAME@";
@ -128,7 +136,7 @@ Config::Config()
QString Config::versionString() const
{
return QString("%1.%2.%3").arg(VERSION_MAJOR).arg(VERSION_MINOR).arg(VERSION_PATCH);
return QString("%1.%2").arg(VERSION_MAJOR).arg(VERSION_MINOR);
}
QString Config::printableVersionString() const
@ -136,7 +144,8 @@ QString Config::printableVersionString() const
QString vstr = versionString();
// If the build is not a main release, append the channel
if (VERSION_CHANNEL != "stable" && GIT_TAG != vstr) {
if(VERSION_CHANNEL != "stable" && GIT_TAG != vstr)
{
vstr += "-" + VERSION_CHANNEL;
}
return vstr;
@ -153,3 +162,4 @@ QString Config::systemID() const
{
return QStringLiteral("%1 %2 %3").arg(COMPILER_TARGET_SYSTEM, COMPILER_TARGET_SYSTEM_VERSION, COMPILER_TARGET_SYSTEM_PROCESSOR);
}

View file

@ -52,16 +52,13 @@ class Config {
QString LAUNCHER_DOMAIN;
QString LAUNCHER_CONFIGFILE;
QString LAUNCHER_GIT;
QString LAUNCHER_APPID;
QString LAUNCHER_DESKTOPFILENAME;
QString LAUNCHER_SVGFILENAME;
QString LAUNCHER_ENVNAME;
/// The major version number.
int VERSION_MAJOR;
/// The minor version number.
int VERSION_MINOR;
/// The patch version number.
int VERSION_PATCH;
/**
* The version channel
@ -108,6 +105,9 @@ class Config {
/// User-Agent to use.
QString USER_AGENT;
/// User-Agent to use for uncached requests.
QString USER_AGENT_UNCACHED;
/// The git commit hash of this build
QString GIT_COMMIT;
@ -129,12 +129,7 @@ class Config {
QString NEWS_OPEN_URL;
/**
* URL that gets opened when the user clicks 'Launcher Help'
*/
QString WIKI_URL;
/**
* URL (with arg %1 to be substituted with page-id) that gets opened when the user requests help in a dialog window
* URL (with arg %1 to be substituted with page-id) that gets opened when the user requests help
*/
QString HELP_URL;
@ -172,13 +167,13 @@ class Config {
QString DISCORD_URL;
QString SUBREDDIT_URL;
QString DEFAULT_RESOURCE_BASE = "https://resources.download.minecraft.net/";
QString RESOURCE_BASE = "https://resources.download.minecraft.net/";
QString LIBRARY_BASE = "https://libraries.minecraft.net/";
QString IMGUR_BASE_URL = "https://api.imgur.com/3/";
QString LEGACY_FMLLIBS_BASE_URL;
QString FMLLIBS_BASE_URL;
QString TRANSLATION_FILES_URL;
QString FTB_API_BASE_URL = "https://api.feed-the-beast.com/v1/modpacks/public";
QString MODPACKSCH_API_BASE_URL = "https://api.modpacks.ch/";
QString LEGACY_FTB_CDN_BASE_URL = "https://dist.creeper.host/FTB2/";
@ -194,10 +189,8 @@ class Config {
QString MODRINTH_STAGING_URL = "https://staging-api.modrinth.com/v2";
QString MODRINTH_PROD_URL = "https://api.modrinth.com/v2";
QStringList MODRINTH_MRPACK_HOSTS{ "cdn.modrinth.com", "github.com", "raw.githubusercontent.com", "gitlab.com" };
QString MODRINTH_DOWNLOAD_HOST = "cdn.modrinth.com";
QString FLAME_BASE_URL = "https://api.curseforge.com/v1";
QString FLAME_DOWNLOAD_HOST = "edge.forgecdn.net";
QString versionString() const;
/**

View file

@ -0,0 +1,163 @@
#
# Function to set compiler warnings with reasonable defaults at the project level.
# Taken from https://github.com/aminya/project_options/blob/main/src/CompilerWarnings.cmake
# under the folowing license:
#
# MIT License
#
# Copyright (c) 2022-2100 Amin Yahyaabadi
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
include_guard()
function(_set_project_warnings_add_target_link_option TARGET OPTIONS)
target_link_options(${_project_name} INTERFACE ${OPTIONS})
endfunction()
# Set the compiler warnings
#
# https://clang.llvm.org/docs/DiagnosticsReference.html
# https://github.com/lefticus/cppbestpractices/blob/master/02-Use_the_Tools_Available.md
function(
set_project_warnings
_project_name
MSVC_WARNINGS
CLANG_WARNINGS
GCC_WARNINGS
)
if("${MSVC_WARNINGS}" STREQUAL "")
set(MSVC_WARNINGS
/W4 # Baseline reasonable warnings
/w14242 # 'identifier': conversion from 'type1' to 'type1', possible loss of data
/w14254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
/w14263 # 'function': member function does not override any base class virtual member function
/w14265 # 'classname': class has virtual functions, but destructor is not virtual instances of this class may not
# be destructed correctly
/w14287 # 'operator': unsigned/negative constant mismatch
/we4289 # nonstandard extension used: 'variable': loop control variable declared in the for-loop is used outside
# the for-loop scope
/w14296 # 'operator': expression is always 'boolean_value'
/w14311 # 'variable': pointer truncation from 'type1' to 'type2'
/w14545 # expression before comma evaluates to a function which is missing an argument list
/w14546 # function call before comma missing argument list
/w14547 # 'operator': operator before comma has no effect; expected operator with side-effect
/w14549 # 'operator': operator before comma has no effect; did you intend 'operator'?
/w14555 # expression has no effect; expected expression with side- effect
/w14619 # pragma warning: there is no warning number 'number'
/w14640 # Enable warning on thread un-safe static member initialization
/w14826 # Conversion from 'type1' to 'type_2' is sign-extended. This may cause unexpected runtime behavior.
/w14905 # wide string literal cast to 'LPSTR'
/w14906 # string literal cast to 'LPWSTR'
/w14928 # illegal copy-initialization; more than one user-defined conversion has been implicitly applied
/permissive- # standards conformance mode for MSVC compiler.
/we4062 # forbid omitting a possible value of an enum in a switch statement
)
endif()
if("${CLANG_WARNINGS}" STREQUAL "")
set(CLANG_WARNINGS
-Wall
-Wextra # reasonable and standard
-Wshadow # warn the user if a variable declaration shadows one from a parent context
-Wnon-virtual-dtor # warn the user if a class with virtual functions has a non-virtual destructor. This helps
# catch hard to track down memory errors
-Wold-style-cast # warn for c-style casts
-Wcast-align # warn for potential performance problem casts
-Wunused # warn on anything being unused
-Woverloaded-virtual # warn if you overload (not override) a virtual function
-Wpedantic # warn if non-standard C++ is used
-Wconversion # warn on type conversions that may lose data
-Wsign-conversion # warn on sign conversions
-Wnull-dereference # warn if a null dereference is detected
-Wdouble-promotion # warn if float is implicit promoted to double
-Wformat=2 # warn on security issues around functions that format output (ie printf)
-Wimplicit-fallthrough # warn on statements that fallthrough without an explicit annotation
# -Wgnu-zero-variadic-macro-arguments (part of -pedantic) is triggered by every qCDebug() call and therefore results
# in a lot of noise. This warning is only notifying us that clang is emulating the GCC behaviour
# instead of the exact standard wording so we can safely ignore it
-Wno-gnu-zero-variadic-macro-arguments
-Werror=switch # forbid omitting a possible value of an enum in a switch statement
)
endif()
if("${GCC_WARNINGS}" STREQUAL "")
set(GCC_WARNINGS
${CLANG_WARNINGS}
-Wmisleading-indentation # warn if indentation implies blocks where blocks do not exist
-Wduplicated-cond # warn if if / else chain has duplicated conditions
-Wduplicated-branches # warn if if / else branches have duplicated code
-Wlogical-op # warn about logical operations being used where bitwise were probably wanted
-Wuseless-cast # warn if you perform a cast to the same type
-Werror=switch # forbid omitting a possible value of an enum in a switch statement
)
endif()
if(MSVC)
set(PROJECT_WARNINGS_CXX ${MSVC_WARNINGS})
elseif(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang")
set(PROJECT_WARNINGS_CXX ${CLANG_WARNINGS})
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(PROJECT_WARNINGS_CXX ${GCC_WARNINGS})
else()
message(AUTHOR_WARNING "No compiler warnings set for CXX compiler: '${CMAKE_CXX_COMPILER_ID}'")
# TODO support Intel compiler
endif()
# Add C warnings
set(PROJECT_WARNINGS_C "${PROJECT_WARNINGS_CXX}")
list(
REMOVE_ITEM
PROJECT_WARNINGS_C
-Wnon-virtual-dtor
-Wold-style-cast
-Woverloaded-virtual
-Wuseless-cast
-Wextra-semi
-Werror=switch # forbid omitting a possible value of an enum in a switch statement
)
target_compile_options(
${_project_name}
INTERFACE # C++ warnings
$<$<COMPILE_LANGUAGE:CXX>:${PROJECT_WARNINGS_CXX}>
# C warnings
$<$<COMPILE_LANGUAGE:C>:${PROJECT_WARNINGS_C}>
)
# If we are using the compiler as a linker driver pass the warnings to it
# (most useful when using LTO or warnings as errors)
if(CMAKE_CXX_LINK_EXECUTABLE MATCHES "^<CMAKE_CXX_COMPILER>")
_set_project_warnings_add_target_link_option(
${_project_name} "$<$<COMPILE_LANGUAGE:CXX>:${PROJECT_WARNINGS_CXX}>"
)
endif()
if(CMAKE_C_LINK_EXECUTABLE MATCHES "^<CMAKE_C_COMPILER>")
_set_project_warnings_add_target_link_option(
${_project_name} "$<$<COMPILE_LANGUAGE:C>:${PROJECT_WARNINGS_C}>"
)
endif()
endfunction()

100
cmake/ECMQueryQt.cmake Normal file
View file

@ -0,0 +1,100 @@
# SPDX-FileCopyrightText: 2014 Rohan Garg <rohan16garg@gmail.com>
# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org>
# SPDX-FileCopyrightText: 2014-2016 Aleix Pol <aleixpol@kde.org>
# SPDX-FileCopyrightText: 2017 Friedrich W. H. Kossebau <kossebau@kde.org>
# SPDX-FileCopyrightText: 2022 Ahmad Samir <a.samir78@gmail.com>
#
# SPDX-License-Identifier: BSD-3-Clause
#[=======================================================================[.rst:
ECMQueryQt
---------------
This module can be used to query the installation paths used by Qt.
For Qt5 this uses ``qmake``, and for Qt6 this used ``qtpaths`` (the latter has built-in
support to query the paths of a target platform when cross-compiling).
This module defines the following function:
::
ecm_query_qt(<result_variable> <qt_variable> [TRY])
Passing ``TRY`` will result in the method not making the build fail if the executable
used for querying has not been found, but instead simply print a warning message and
return an empty string.
Example usage:
.. code-block:: cmake
include(ECMQueryQt)
ecm_query_qt(bin_dir QT_INSTALL_BINS)
If the call succeeds ``${bin_dir}`` will be set to ``<prefix>/path/to/bin/dir`` (e.g.
``/usr/lib64/qt/bin/``).
Since: 5.93
#]=======================================================================]
include(${CMAKE_CURRENT_LIST_DIR}/QtVersionOption.cmake)
include(CheckLanguage)
check_language(CXX)
if (CMAKE_CXX_COMPILER)
# Enable the CXX language to let CMake look for config files in library dirs.
# See: https://gitlab.kitware.com/cmake/cmake/-/issues/23266
enable_language(CXX)
endif()
if (QT_MAJOR_VERSION STREQUAL "5")
# QUIET to accommodate the TRY option
find_package(Qt${QT_MAJOR_VERSION}Core QUIET)
if(TARGET Qt5::qmake)
get_target_property(_qmake_executable_default Qt5::qmake LOCATION)
set(QUERY_EXECUTABLE ${_qmake_executable_default}
CACHE FILEPATH "Location of the Qt5 qmake executable")
set(_exec_name_text "Qt5 qmake")
set(_cli_option "-query")
endif()
elseif(QT_MAJOR_VERSION STREQUAL "6")
# QUIET to accommodate the TRY option
find_package(Qt6 COMPONENTS CoreTools QUIET CONFIG)
if (TARGET Qt6::qtpaths)
get_target_property(_qtpaths_executable Qt6::qtpaths LOCATION)
set(QUERY_EXECUTABLE ${_qtpaths_executable}
CACHE FILEPATH "Location of the Qt6 qtpaths executable")
set(_exec_name_text "Qt6 qtpaths")
set(_cli_option "--query")
endif()
endif()
function(ecm_query_qt result_variable qt_variable)
set(options TRY)
set(oneValueArgs)
set(multiValueArgs)
cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT QUERY_EXECUTABLE)
if(ARGS_TRY)
set(${result_variable} "" PARENT_SCOPE)
message(STATUS "No ${_exec_name_text} executable found. Can't check ${qt_variable}")
return()
else()
message(FATAL_ERROR "No ${_exec_name_text} executable found. Can't check ${qt_variable} as required")
endif()
endif()
execute_process(
COMMAND ${QUERY_EXECUTABLE} ${_cli_option} "${qt_variable}"
RESULT_VARIABLE return_code
OUTPUT_VARIABLE output
)
if(return_code EQUAL 0)
string(STRIP "${output}" output)
file(TO_CMAKE_PATH "${output}" output_path)
set(${result_variable} "${output_path}" PARENT_SCOPE)
else()
message(WARNING "Failed call: ${_command} \"${qt_variable}\"")
message(FATAL_ERROR "${_exec_name_text} call failed: ${return_code}")
endif()
endfunction()

View file

@ -7,7 +7,7 @@
<key>NSMicrophoneUsageDescription</key>
<string>A Minecraft mod wants to access your microphone.</string>
<key>NSDownloadsFolderUsageDescription</key>
<string>${Launcher_DisplayName} 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 ${Launcher_DisplayName} 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>
@ -21,9 +21,7 @@
<key>CFBundleGetInfoString</key>
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
<key>CFBundleIconFile</key>
<string>${Launcher_Name}</string>
<key>CFBundleIconName</key>
<string>${Launcher_Name}</string>
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
@ -44,8 +42,6 @@
<true/>
<key>LSRequiresCarbon</key>
<true/>
<key>LSApplicationCategoryType</key>
<string>public.app-category.games</string>
<key>NSHumanReadableCopyright</key>
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
<key>SUPublicEDKey</key>
@ -61,7 +57,7 @@
<string>mrpack</string>
</array>
<key>CFBundleTypeName</key>
<string>${Launcher_DisplayName} instance</string>
<string>Prism Launcher instance</string>
<key>CFBundleTypeOSTypes</key>
<array>
<string>TEXT</string>
@ -87,11 +83,10 @@
</dict>
<dict>
<key>CFBundleURLName</key>
<string>${Launcher_Name}</string>
<string>Prismlauncher</string>
<key>CFBundleURLSchemes</key>
<array>
<string>prismlauncher</string>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
</array>
</dict>
</array>

View file

@ -0,0 +1,38 @@
#.rst:
# QtVersionOption
# ---------------
#
# Adds a build option to select the major Qt version if necessary,
# that is, if the major Qt version has not yet been determined otherwise
# (e.g. by a corresponding find_package() call).
#
# This module is typically included by other modules requiring knowledge
# about the major Qt version.
#
# ``QT_MAJOR_VERSION`` is defined to either be "5" or "6".
#
#
# Since 5.82.0.
#=============================================================================
# SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause
if (DEFINED QT_MAJOR_VERSION)
return()
endif()
if (TARGET Qt5::Core)
set(QT_MAJOR_VERSION 5)
elseif (TARGET Qt6::Core)
set(QT_MAJOR_VERSION 6)
else()
option(BUILD_WITH_QT6 "Build against Qt 6" OFF)
if (BUILD_WITH_QT6)
set(QT_MAJOR_VERSION 6)
else()
set(QT_MAJOR_VERSION 5)
endif()
endif()

View file

@ -0,0 +1,97 @@
#=============================================================================
# Copyright 2005-2011 Kitware, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# * Neither the name of Kitware, Inc. nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#=============================================================================
# From Qt5CoreMacros.cmake
function(qt_generate_moc)
if(QT_VERSION_MAJOR EQUAL 5)
qt5_generate_moc(${ARGV})
elseif(QT_VERSION_MAJOR EQUAL 6)
qt6_generate_moc(${ARGV})
endif()
endfunction()
function(qt_wrap_cpp outfiles)
if(QT_VERSION_MAJOR EQUAL 5)
qt5_wrap_cpp("${outfiles}" ${ARGN})
elseif(QT_VERSION_MAJOR EQUAL 6)
qt6_wrap_cpp("${outfiles}" ${ARGN})
endif()
set("${outfiles}" "${${outfiles}}" PARENT_SCOPE)
endfunction()
function(qt_add_binary_resources)
if(QT_VERSION_MAJOR EQUAL 5)
qt5_add_binary_resources(${ARGV})
elseif(QT_VERSION_MAJOR EQUAL 6)
qt6_add_binary_resources(${ARGV})
endif()
endfunction()
function(qt_add_resources outfiles)
if(QT_VERSION_MAJOR EQUAL 5)
qt5_add_resources("${outfiles}" ${ARGN})
elseif(QT_VERSION_MAJOR EQUAL 6)
qt6_add_resources("${outfiles}" ${ARGN})
endif()
set("${outfiles}" "${${outfiles}}" PARENT_SCOPE)
endfunction()
function(qt_add_big_resources outfiles)
if(QT_VERSION_MAJOR EQUAL 5)
qt5_add_big_resources(${outfiles} ${ARGN})
elseif(QT_VERSION_MAJOR EQUAL 6)
qt6_add_big_resources(${outfiles} ${ARGN})
endif()
set("${outfiles}" "${${outfiles}}" PARENT_SCOPE)
endfunction()
function(qt_import_plugins)
if(QT_VERSION_MAJOR EQUAL 5)
qt5_import_plugins(${ARGV})
elseif(QT_VERSION_MAJOR EQUAL 6)
qt6_import_plugins(${ARGV})
endif()
endfunction()
# From Qt5WidgetsMacros.cmake
function(qt_wrap_ui outfiles)
if(QT_VERSION_MAJOR EQUAL 5)
qt5_wrap_ui("${outfiles}" ${ARGN})
elseif(QT_VERSION_MAJOR EQUAL 6)
qt6_wrap_ui("${outfiles}" ${ARGN})
endif()
set("${outfiles}" "${${outfiles}}" PARENT_SCOPE)
endfunction()

View file

@ -1,3 +0,0 @@
The only difference between this and the upstream vcpkg port is the addition of `universal-osx.patch`. It's very annoying we need to bundle this entire tree to do that.
-@getchoo

View file

@ -1,13 +0,0 @@
diff --git a/mesonbuild/cmake/toolchain.py b/mesonbuild/cmake/toolchain.py
index 11a00be5d..89ae490ff 100644
--- a/mesonbuild/cmake/toolchain.py
+++ b/mesonbuild/cmake/toolchain.py
@@ -202,7 +202,7 @@ class CMakeToolchain:
@staticmethod
def is_cmdline_option(compiler: 'Compiler', arg: str) -> bool:
if compiler.get_argument_syntax() == 'msvc':
- return arg.startswith('/')
+ return arg.startswith(('/','-'))
else:
if os.path.basename(compiler.get_exe()) == 'zig' and arg in {'ar', 'cc', 'c++', 'dlltool', 'lib', 'ranlib', 'objcopy', 'rc'}:
return True

View file

@ -1,45 +0,0 @@
diff --git a/mesonbuild/dependencies/python.py b/mesonbuild/dependencies/python.py
index 883a29a..d9a82af 100644
--- a/mesonbuild/dependencies/python.py
+++ b/mesonbuild/dependencies/python.py
@@ -232,8 +232,10 @@ class _PythonDependencyBase(_Base):
else:
if self.is_freethreaded:
libpath = Path('libs') / f'python{vernum}t.lib'
+ libpath = Path('libs') / f'..' / f'..' / f'..' / f'lib' / f'python{vernum}t.lib'
else:
libpath = Path('libs') / f'python{vernum}.lib'
+ libpath = Path('libs') / f'..' / f'..' / f'..' / f'lib' / f'python{vernum}.lib'
# For a debug build, pyconfig.h may force linking with
# pythonX_d.lib (see meson#10776). This cannot be avoided
# and won't work unless we also have a debug build of
@@ -250,6 +252,8 @@ class _PythonDependencyBase(_Base):
vscrt = self.env.coredata.optstore.get_value('b_vscrt')
if vscrt in {'mdd', 'mtd', 'from_buildtype', 'static_from_buildtype'}:
vscrt_debug = True
+ if is_debug_build:
+ libpath = Path('libs') / f'..' / f'..' / f'..' / f'debug/lib' / f'python{vernum}_d.lib'
if is_debug_build and vscrt_debug and not self.variables.get('Py_DEBUG'):
mlog.warning(textwrap.dedent('''\
Using a debug build type with MSVC or an MSVC-compatible compiler
@@ -350,9 +354,10 @@ class PythonSystemDependency(SystemDependency, _PythonDependencyBase):
self.is_found = True
# compile args
+ verdot = self.variables.get('py_version_short')
inc_paths = mesonlib.OrderedSet([
self.variables.get('INCLUDEPY'),
- self.paths.get('include'),
+ self.paths.get('include') + f'/../../../include/python${verdot}',
self.paths.get('platinclude')])
self.compile_args += ['-I' + path for path in inc_paths if path]
@@ -416,7 +421,7 @@ def python_factory(env: 'Environment', for_machine: 'MachineChoice',
candidates.append(functools.partial(wrap_in_pythons_pc_dir, pkg_name, env, kwargs, installation))
# We only need to check both, if a python install has a LIBPC. It might point to the wrong location,
# e.g. relocated / cross compilation, but the presence of LIBPC indicates we should definitely look for something.
- if pkg_libdir is not None:
+ if True or pkg_libdir is not None:
candidates.append(functools.partial(PythonPkgConfigDependency, pkg_name, env, kwargs, installation))
else:
candidates.append(functools.partial(PkgConfigDependency, 'python3', env, kwargs))

View file

@ -1,52 +0,0 @@
From a16ec8b0fb6d7035b669a13edd4d97ff0c307a0b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20D=C3=B8rum?= <martid0311@gmail.com>
Date: Fri, 2 May 2025 10:56:28 +0200
Subject: [PATCH] cpp: fix _LIBCPP_ENABLE_ASSERTIONS warning
libc++ deprecated _LIBCPP_ENABLE_ASSERTIONS from version 18.
However, the libc++ shipped with Apple Clang backported that
deprecation in version 17 already,
which is the version which Apple currently ships for macOS.
This PR changes the _LIBCPP_ENABLE_ASSERTIONS deprecation check
to use version ">=17" on Apple Clang.
---
mesonbuild/compilers/cpp.py | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py
index 01b9bb9fa34f..f7dc150e8608 100644
--- a/mesonbuild/compilers/cpp.py
+++ b/mesonbuild/compilers/cpp.py
@@ -311,6 +311,9 @@ def get_option_link_args(self, target: 'BuildTarget', env: 'Environment', subpro
return libs
return []
+ def is_libcpp_enable_assertions_deprecated(self) -> bool:
+ return version_compare(self.version, ">=18")
+
def get_assert_args(self, disable: bool, env: 'Environment') -> T.List[str]:
if disable:
return ['-DNDEBUG']
@@ -323,7 +326,7 @@ def get_assert_args(self, disable: bool, env: 'Environment') -> T.List[str]:
if self.language_stdlib_provider(env) == 'stdc++':
return ['-D_GLIBCXX_ASSERTIONS=1']
else:
- if version_compare(self.version, '>=18'):
+ if self.is_libcpp_enable_assertions_deprecated():
return ['-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST']
elif version_compare(self.version, '>=15'):
return ['-D_LIBCPP_ENABLE_ASSERTIONS=1']
@@ -343,7 +346,12 @@ class ArmLtdClangCPPCompiler(ClangCPPCompiler):
class AppleClangCPPCompiler(AppleCompilerMixin, AppleCPPStdsMixin, ClangCPPCompiler):
- pass
+ def is_libcpp_enable_assertions_deprecated(self) -> bool:
+ # Upstream libc++ deprecated _LIBCPP_ENABLE_ASSERTIONS
+ # in favor of _LIBCPP_HARDENING_MODE from version 18 onwards,
+ # but Apple Clang 17's libc++ has back-ported that change.
+ # See: https://github.com/mesonbuild/meson/issues/14440
+ return version_compare(self.version, ">=17")
class EmscriptenCPPCompiler(EmscriptenMixin, ClangCPPCompiler):

View file

@ -1,5 +0,0 @@
file(MAKE_DIRECTORY "${CURRENT_PACKAGES_DIR}/tools/meson")
file(INSTALL "${SOURCE_PATH}/meson.py"
"${SOURCE_PATH}/mesonbuild"
DESTINATION "${CURRENT_PACKAGES_DIR}/tools/meson"
)

View file

@ -1,13 +0,0 @@
diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py
--- a/mesonbuild/dependencies/misc.py
+++ b/mesonbuild/dependencies/misc.py
@@ -593,7 +593,8 @@ iconv_factory = DependencyFactory(
packages['intl'] = intl_factory = DependencyFactory(
'intl',
+ [DependencyMethods.BUILTIN, DependencyMethods.SYSTEM, DependencyMethods.CMAKE],
+ cmake_name='Intl',
- [DependencyMethods.BUILTIN, DependencyMethods.SYSTEM],
builtin_class=IntlBuiltinDependency,
system_class=IntlSystemDependency,
)

View file

@ -1,43 +0,0 @@
[binaries]
cmake = ['@CMAKE_COMMAND@']
ninja = ['@NINJA@']
pkg-config = ['@PKGCONFIG@']
@MESON_MT@
@MESON_AR@
@MESON_RC@
@MESON_C@
@MESON_C_LD@
@MESON_CXX@
@MESON_CXX_LD@
@MESON_OBJC@
@MESON_OBJC_LD@
@MESON_OBJCPP@
@MESON_OBJCPP_LD@
@MESON_FC@
@MESON_FC_LD@
@MESON_WINDRES@
@MESON_ADDITIONAL_BINARIES@
[properties]
cmake_toolchain_file = '@SCRIPTS@/buildsystems/vcpkg.cmake'
@MESON_ADDITIONAL_PROPERTIES@
[cmake]
CMAKE_BUILD_TYPE = '@MESON_CMAKE_BUILD_TYPE@'
VCPKG_TARGET_TRIPLET = '@TARGET_TRIPLET@'
VCPKG_HOST_TRIPLET = '@_HOST_TRIPLET@'
VCPKG_CHAINLOAD_TOOLCHAIN_FILE = '@VCPKG_CHAINLOAD_TOOLCHAIN_FILE@'
VCPKG_CRT_LINKAGE = '@VCPKG_CRT_LINKAGE@'
_VCPKG_INSTALLED_DIR = '@_VCPKG_INSTALLED_DIR@'
@MESON_HOST_MACHINE@
@MESON_BUILD_MACHINE@
[built-in options]
default_library = '@MESON_DEFAULT_LIBRARY@'
werror = false
@MESON_CFLAGS@
@MESON_CXXFLAGS@
@MESON_FCFLAGS@
@MESON_OBJCFLAGS@
@MESON_OBJCPPFLAGS@
# b_vscrt
@MESON_VSCRT_LINKAGE@
# c_winlibs/cpp_winlibs
@MESON_WINLIBS@

View file

@ -1,45 +0,0 @@
# This port represents a dependency on the Meson build system.
# In the future, it is expected that this port acquires and installs Meson.
# Currently is used in ports that call vcpkg_find_acquire_program(MESON) in order to force rebuilds.
set(VCPKG_POLICY_CMAKE_HELPER_PORT enabled)
set(patches
meson-intl.patch
adjust-python-dep.patch
adjust-args.patch
remove-freebsd-pcfile-specialization.patch
fix-libcpp-enable-assertions.patch # https://github.com/mesonbuild/meson/pull/14548, Remove in 1.8.3
universal-osx.patch # NOTE(@getchoo): THIS IS THE ONLY CHANGE NEEDED FOR PRISM
)
set(scripts
vcpkg-port-config.cmake
vcpkg_configure_meson.cmake
vcpkg_install_meson.cmake
meson.template.in
)
set(to_hash
"${CMAKE_CURRENT_LIST_DIR}/vcpkg.json"
"${CMAKE_CURRENT_LIST_DIR}/portfile.cmake"
)
foreach(file IN LISTS patches scripts)
set(filepath "${CMAKE_CURRENT_LIST_DIR}/${file}")
list(APPEND to_hash "${filepath}")
file(COPY "${filepath}" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}")
endforeach()
set(meson_path_hash "")
foreach(filepath IN LISTS to_hash)
file(SHA1 "${filepath}" to_append)
string(APPEND meson_path_hash "${to_append}")
endforeach()
string(SHA512 meson_path_hash "${meson_path_hash}")
string(SUBSTRING "${meson_path_hash}" 0 6 MESON_SHORT_HASH)
list(TRANSFORM patches REPLACE [[^(..*)$]] [["${CMAKE_CURRENT_LIST_DIR}/\0"]])
list(JOIN patches "\n " PATCHES)
configure_file("${CMAKE_CURRENT_LIST_DIR}/vcpkg-port-config.cmake" "${CURRENT_PACKAGES_DIR}/share/${PORT}/vcpkg-port-config.cmake" @ONLY)
vcpkg_install_copyright(FILE_LIST "${VCPKG_ROOT_DIR}/LICENSE.txt")
include("${CURRENT_PACKAGES_DIR}/share/${PORT}/vcpkg-port-config.cmake")

View file

@ -1,23 +0,0 @@
diff --git a/mesonbuild/modules/pkgconfig.py b/mesonbuild/modules/pkgconfig.py
index cc0450a52..13501466d 100644
--- a/mesonbuild/modules/pkgconfig.py
+++ b/mesonbuild/modules/pkgconfig.py
@@ -701,16 +701,8 @@ class PkgConfigModule(NewExtensionModule):
pcfile = filebase + '.pc'
pkgroot = pkgroot_name = kwargs['install_dir'] or default_install_dir
if pkgroot is None:
- m = state.environment.machines.host
- if m.is_freebsd():
- pkgroot = os.path.join(_as_str(state.environment.coredata.optstore.get_value_for(OptionKey('prefix'))), 'libdata', 'pkgconfig')
- pkgroot_name = os.path.join('{prefix}', 'libdata', 'pkgconfig')
- elif m.is_haiku():
- pkgroot = os.path.join(_as_str(state.environment.coredata.optstore.get_value_for(OptionKey('prefix'))), 'develop', 'lib', 'pkgconfig')
- pkgroot_name = os.path.join('{prefix}', 'develop', 'lib', 'pkgconfig')
- else:
- pkgroot = os.path.join(_as_str(state.environment.coredata.optstore.get_value_for(OptionKey('libdir'))), 'pkgconfig')
- pkgroot_name = os.path.join('{libdir}', 'pkgconfig')
+ pkgroot = os.path.join(_as_str(state.environment.coredata.optstore.get_value_for(OptionKey('libdir'))), 'pkgconfig')
+ pkgroot_name = os.path.join('{libdir}', 'pkgconfig')
relocatable = state.get_option('pkgconfig.relocatable')
self._generate_pkgconfig_file(state, deps, subdirs, name, description, url,
version, pcfile, conflicts, variables,

View file

@ -1,16 +0,0 @@
diff --git a/mesonbuild/compilers/detect.py b/mesonbuild/compilers/detect.py
index f57957f0b..a72e72a0b 100644
--- a/mesonbuild/compilers/detect.py
+++ b/mesonbuild/compilers/detect.py
@@ -1472,6 +1472,11 @@ def _get_clang_compiler_defines(compiler: T.List[str], lang: str) -> T.Dict[str,
"""
from .mixins.clang import clang_lang_map
+ # Filter out `-arch` flags passed to the compiler for Universal Binaries
+ # https://github.com/mesonbuild/meson/issues/5290
+ # https://github.com/mesonbuild/meson/issues/8206
+ compiler = [arg for i, arg in enumerate(compiler) if not (i > 0 and compiler[i - 1] == "-arch") and not arg == "-arch"]
+
def _try_obtain_compiler_defines(args: T.List[str]) -> str:
mlog.debug(f'Running command: {join_args(args)}')
p, output, error = Popen_safe(compiler + args, write='', stdin=subprocess.PIPE)

View file

@ -1,62 +0,0 @@
include("${CURRENT_HOST_INSTALLED_DIR}/share/vcpkg-cmake-get-vars/vcpkg-port-config.cmake")
# Overwrite builtin scripts
include("${CMAKE_CURRENT_LIST_DIR}/vcpkg_configure_meson.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/vcpkg_install_meson.cmake")
set(meson_short_hash @MESON_SHORT_HASH@)
# Setup meson:
set(program MESON)
set(program_version @VERSION@)
set(program_name meson)
set(search_names meson meson.py)
set(ref "${program_version}")
set(path_to_search "${DOWNLOADS}/tools/meson-${program_version}-${meson_short_hash}")
set(download_urls "https://github.com/mesonbuild/meson/archive/${ref}.tar.gz")
set(download_filename "meson-${ref}.tar.gz")
set(download_sha512 bd2e65f0863d9cb974e659ff502d773e937b8a60aaddfd7d81e34cd2c296c8e82bf214d790ac089ba441543059dfc2677ba95ed51f676df9da420859f404a907)
find_program(SCRIPT_MESON NAMES ${search_names} PATHS "${path_to_search}" NO_DEFAULT_PATH) # NO_DEFAULT_PATH due top patching
if(NOT SCRIPT_MESON)
vcpkg_download_distfile(archive_path
URLS ${download_urls}
SHA512 "${download_sha512}"
FILENAME "${download_filename}"
)
file(REMOVE_RECURSE "${path_to_search}")
file(REMOVE_RECURSE "${path_to_search}-tmp")
file(MAKE_DIRECTORY "${path_to_search}-tmp")
file(ARCHIVE_EXTRACT INPUT "${archive_path}"
DESTINATION "${path_to_search}-tmp"
#PATTERNS "**/mesonbuild/*" "**/*.py"
)
z_vcpkg_apply_patches(
SOURCE_PATH "${path_to_search}-tmp/meson-${ref}"
PATCHES
@PATCHES@
)
file(MAKE_DIRECTORY "${path_to_search}")
file(RENAME "${path_to_search}-tmp/meson-${ref}/meson.py" "${path_to_search}/meson.py")
file(RENAME "${path_to_search}-tmp/meson-${ref}/mesonbuild" "${path_to_search}/mesonbuild")
file(REMOVE_RECURSE "${path_to_search}-tmp")
set(SCRIPT_MESON "${path_to_search}/meson.py")
endif()
# Check required python version
vcpkg_find_acquire_program(PYTHON3)
vcpkg_execute_in_download_mode(
COMMAND "${PYTHON3}" --version
OUTPUT_VARIABLE version_contents
WORKING_DIRECTORY "${CURRENT_BUILDTREES_DIR}"
)
string(REGEX MATCH [[[0-9]+\.[0-9]+\.[0-9]+]] python_ver "${version_contents}")
set(min_required 3.7)
if(python_ver VERSION_LESS "${min_required}")
message(FATAL_ERROR "Found Python version '${python_ver} at ${PYTHON3}' is insufficient for meson. meson requires at least version '${min_required}'")
else()
message(STATUS "Found Python version '${python_ver} at ${PYTHON3}'")
endif()
message(STATUS "Using meson: ${SCRIPT_MESON}")

View file

@ -1,11 +0,0 @@
{
"name": "vcpkg-tool-meson",
"version": "1.8.2",
"description": "Meson build system",
"homepage": "https://github.com/mesonbuild/meson",
"license": "Apache-2.0",
"supports": "native",
"dependencies": [
"vcpkg-cmake-get-vars"
]
}

View file

@ -1,480 +0,0 @@
function(z_vcpkg_meson_set_proglist_variables config_type)
if(VCPKG_TARGET_IS_WINDOWS)
set(proglist MT AR)
else()
set(proglist AR RANLIB STRIP NM OBJDUMP DLLTOOL MT)
endif()
foreach(prog IN LISTS proglist)
if(VCPKG_DETECTED_CMAKE_${prog})
if(meson_${prog})
string(TOUPPER "MESON_${meson_${prog}}" var_to_set)
set("${var_to_set}" "${meson_${prog}} = ['${VCPKG_DETECTED_CMAKE_${prog}}']" PARENT_SCOPE)
elseif(${prog} STREQUAL AR AND VCPKG_COMBINED_STATIC_LINKER_FLAGS_${config_type})
# Probably need to move AR somewhere else
string(TOLOWER "${prog}" proglower)
z_vcpkg_meson_convert_compiler_flags_to_list(ar_flags "${VCPKG_COMBINED_STATIC_LINKER_FLAGS_${config_type}}")
list(PREPEND ar_flags "${VCPKG_DETECTED_CMAKE_${prog}}")
z_vcpkg_meson_convert_list_to_python_array(ar_flags ${ar_flags})
set("MESON_AR" "${proglower} = ${ar_flags}" PARENT_SCOPE)
else()
string(TOUPPER "MESON_${prog}" var_to_set)
string(TOLOWER "${prog}" proglower)
set("${var_to_set}" "${proglower} = ['${VCPKG_DETECTED_CMAKE_${prog}}']" PARENT_SCOPE)
endif()
endif()
endforeach()
set(compilers "${arg_LANGUAGES}")
if(VCPKG_TARGET_IS_WINDOWS)
list(APPEND compilers RC)
endif()
set(meson_RC windres)
set(meson_Fortran fortran)
set(meson_CXX cpp)
foreach(prog IN LISTS compilers)
if(VCPKG_DETECTED_CMAKE_${prog}_COMPILER)
string(TOUPPER "MESON_${prog}" var_to_set)
if(meson_${prog})
if(VCPKG_COMBINED_${prog}_FLAGS_${config_type})
# Need compiler flags in prog vars for sanity check.
z_vcpkg_meson_convert_compiler_flags_to_list(${prog}flags "${VCPKG_COMBINED_${prog}_FLAGS_${config_type}}")
endif()
list(PREPEND ${prog}flags "${VCPKG_DETECTED_CMAKE_${prog}_COMPILER}")
list(FILTER ${prog}flags EXCLUDE REGEX "(-|/)nologo") # Breaks compiler detection otherwise
z_vcpkg_meson_convert_list_to_python_array(${prog}flags ${${prog}flags})
set("${var_to_set}" "${meson_${prog}} = ${${prog}flags}" PARENT_SCOPE)
if (DEFINED VCPKG_DETECTED_CMAKE_${prog}_COMPILER_ID
AND NOT VCPKG_DETECTED_CMAKE_${prog}_COMPILER_ID MATCHES "^(GNU|Intel)$"
AND VCPKG_DETECTED_CMAKE_LINKER)
string(TOUPPER "MESON_${prog}_LD" var_to_set)
set(${var_to_set} "${meson_${prog}}_ld = ['${VCPKG_DETECTED_CMAKE_LINKER}']" PARENT_SCOPE)
endif()
else()
if(VCPKG_COMBINED_${prog}_FLAGS_${config_type})
# Need compiler flags in prog vars for sanity check.
z_vcpkg_meson_convert_compiler_flags_to_list(${prog}flags "${VCPKG_COMBINED_${prog}_FLAGS_${config_type}}")
endif()
list(PREPEND ${prog}flags "${VCPKG_DETECTED_CMAKE_${prog}_COMPILER}")
list(FILTER ${prog}flags EXCLUDE REGEX "(-|/)nologo") # Breaks compiler detection otherwise
z_vcpkg_meson_convert_list_to_python_array(${prog}flags ${${prog}flags})
string(TOLOWER "${prog}" proglower)
set("${var_to_set}" "${proglower} = ${${prog}flags}" PARENT_SCOPE)
if (DEFINED VCPKG_DETECTED_CMAKE_${prog}_COMPILER_ID
AND NOT VCPKG_DETECTED_CMAKE_${prog}_COMPILER_ID MATCHES "^(GNU|Intel)$"
AND VCPKG_DETECTED_CMAKE_LINKER)
string(TOUPPER "MESON_${prog}_LD" var_to_set)
set(${var_to_set} "${proglower}_ld = ['${VCPKG_DETECTED_CMAKE_LINKER}']" PARENT_SCOPE)
endif()
endif()
endif()
endforeach()
endfunction()
function(z_vcpkg_meson_convert_compiler_flags_to_list out_var compiler_flags)
separate_arguments(cmake_list NATIVE_COMMAND "${compiler_flags}")
list(TRANSFORM cmake_list REPLACE ";" [[\\;]])
set("${out_var}" "${cmake_list}" PARENT_SCOPE)
endfunction()
function(z_vcpkg_meson_convert_list_to_python_array out_var)
z_vcpkg_function_arguments(flag_list 1)
vcpkg_list(REMOVE_ITEM flag_list "") # remove empty elements if any
vcpkg_list(JOIN flag_list "', '" flag_list)
set("${out_var}" "['${flag_list}']" PARENT_SCOPE)
endfunction()
# Generates the required compiler properties for meson
function(z_vcpkg_meson_set_flags_variables config_type)
if(VCPKG_TARGET_IS_WINDOWS AND NOT VCPKG_TARGET_IS_MINGW)
set(libpath_flag /LIBPATH:)
else()
set(libpath_flag -L)
endif()
if(config_type STREQUAL "DEBUG")
set(path_suffix "/debug")
else()
set(path_suffix "")
endif()
set(includepath "-I${CURRENT_INSTALLED_DIR}/include")
set(libpath "${libpath_flag}${CURRENT_INSTALLED_DIR}${path_suffix}/lib")
foreach(lang IN LISTS arg_LANGUAGES)
z_vcpkg_meson_convert_compiler_flags_to_list(${lang}flags "${VCPKG_COMBINED_${lang}_FLAGS_${config_type}}")
if(lang MATCHES "^(C|CXX)$")
vcpkg_list(APPEND ${lang}flags "${includepath}")
endif()
z_vcpkg_meson_convert_list_to_python_array(${lang}flags ${${lang}flags})
set(lang_mapping "${lang}")
if(lang STREQUAL "Fortran")
set(lang_mapping "FC")
endif()
string(TOLOWER "${lang_mapping}" langlower)
if(lang STREQUAL "CXX")
set(langlower cpp)
endif()
set(MESON_${lang_mapping}FLAGS "${langlower}_args = ${${lang}flags}\n")
set(linker_flags "${VCPKG_COMBINED_SHARED_LINKER_FLAGS_${config_type}}")
z_vcpkg_meson_convert_compiler_flags_to_list(linker_flags "${linker_flags}")
vcpkg_list(APPEND linker_flags "${libpath}")
z_vcpkg_meson_convert_list_to_python_array(linker_flags ${linker_flags})
string(APPEND MESON_${lang_mapping}FLAGS "${langlower}_link_args = ${linker_flags}\n")
set(MESON_${lang_mapping}FLAGS "${MESON_${lang_mapping}FLAGS}" PARENT_SCOPE)
endforeach()
endfunction()
function(z_vcpkg_get_build_and_host_system build_system host_system is_cross) #https://mesonbuild.com/Cross-compilation.html
set(build_unknown FALSE)
if(CMAKE_HOST_WIN32)
if(DEFINED ENV{PROCESSOR_ARCHITEW6432})
set(build_arch $ENV{PROCESSOR_ARCHITEW6432})
else()
set(build_arch $ENV{PROCESSOR_ARCHITECTURE})
endif()
if(build_arch MATCHES "(amd|AMD)64")
set(build_cpu_fam x86_64)
set(build_cpu x86_64)
elseif(build_arch MATCHES "(x|X)86")
set(build_cpu_fam x86)
set(build_cpu i686)
elseif(build_arch MATCHES "^(ARM|arm)64$")
set(build_cpu_fam aarch64)
set(build_cpu armv8)
elseif(build_arch MATCHES "^(ARM|arm)$")
set(build_cpu_fam arm)
set(build_cpu armv7hl)
else()
if(NOT DEFINED VCPKG_MESON_CROSS_FILE OR NOT DEFINED VCPKG_MESON_NATIVE_FILE)
message(WARNING "Unsupported build architecture ${build_arch}! Please set VCPKG_MESON_(CROSS|NATIVE)_FILE to a meson file containing the build_machine entry!")
endif()
set(build_unknown TRUE)
endif()
elseif(CMAKE_HOST_UNIX)
# at this stage, CMAKE_HOST_SYSTEM_PROCESSOR is not defined
execute_process(
COMMAND uname -m
OUTPUT_VARIABLE MACHINE
OUTPUT_STRIP_TRAILING_WHITESPACE
COMMAND_ERROR_IS_FATAL ANY)
# Show real machine architecture to visually understand whether we are in a native Apple Silicon terminal or running under Rosetta emulation
debug_message("Machine: ${MACHINE}")
if(MACHINE MATCHES "arm64|aarch64")
set(build_cpu_fam aarch64)
set(build_cpu armv8)
elseif(MACHINE MATCHES "armv7h?l")
set(build_cpu_fam arm)
set(build_cpu ${MACHINE})
elseif(MACHINE MATCHES "x86_64|amd64")
set(build_cpu_fam x86_64)
set(build_cpu x86_64)
elseif(MACHINE MATCHES "x86|i686")
set(build_cpu_fam x86)
set(build_cpu i686)
elseif(MACHINE MATCHES "i386")
set(build_cpu_fam x86)
set(build_cpu i386)
elseif(MACHINE MATCHES "loongarch64")
set(build_cpu_fam loongarch64)
set(build_cpu loongarch64)
else()
# https://github.com/mesonbuild/meson/blob/master/docs/markdown/Reference-tables.md#cpu-families
if(NOT DEFINED VCPKG_MESON_CROSS_FILE OR NOT DEFINED VCPKG_MESON_NATIVE_FILE)
message(WARNING "Unhandled machine: ${MACHINE}! Please set VCPKG_MESON_(CROSS|NATIVE)_FILE to a meson file containing the build_machine entry!")
endif()
set(build_unknown TRUE)
endif()
else()
if(NOT DEFINED VCPKG_MESON_CROSS_FILE OR NOT DEFINED VCPKG_MESON_NATIVE_FILE)
message(WARNING "Failed to detect the build architecture! Please set VCPKG_MESON_(CROSS|NATIVE)_FILE to a meson file containing the build_machine entry!")
endif()
set(build_unknown TRUE)
endif()
set(build "[build_machine]\n") # Machine the build is performed on
string(APPEND build "endian = 'little'\n")
if(CMAKE_HOST_WIN32)
string(APPEND build "system = 'windows'\n")
elseif(CMAKE_HOST_APPLE)
string(APPEND build "system = 'darwin'\n")
elseif(CYGWIN)
string(APPEND build "system = 'cygwin'\n")
elseif(CMAKE_HOST_UNIX)
string(APPEND build "system = 'linux'\n")
else()
set(build_unknown TRUE)
endif()
if(DEFINED build_cpu_fam)
string(APPEND build "cpu_family = '${build_cpu_fam}'\n")
endif()
if(DEFINED build_cpu)
string(APPEND build "cpu = '${build_cpu}'")
endif()
if(NOT build_unknown)
set(${build_system} "${build}" PARENT_SCOPE)
endif()
set(host_unkown FALSE)
if(VCPKG_TARGET_ARCHITECTURE MATCHES "(amd|AMD|x|X)64")
set(host_cpu_fam x86_64)
set(host_cpu x86_64)
elseif(VCPKG_TARGET_ARCHITECTURE MATCHES "(x|X)86")
set(host_cpu_fam x86)
set(host_cpu i686)
elseif(VCPKG_TARGET_ARCHITECTURE MATCHES "^(ARM|arm)64$")
set(host_cpu_fam aarch64)
set(host_cpu armv8)
elseif(VCPKG_TARGET_ARCHITECTURE MATCHES "^(ARM|arm)$")
set(host_cpu_fam arm)
set(host_cpu armv7hl)
elseif(VCPKG_TARGET_ARCHITECTURE MATCHES "loongarch64")
set(host_cpu_fam loongarch64)
set(host_cpu loongarch64)
elseif(VCPKG_TARGET_ARCHITECTURE MATCHES "wasm32")
set(host_cpu_fam wasm32)
set(host_cpu wasm32)
else()
if(NOT DEFINED VCPKG_MESON_CROSS_FILE OR NOT DEFINED VCPKG_MESON_NATIVE_FILE)
message(WARNING "Unsupported target architecture ${VCPKG_TARGET_ARCHITECTURE}! Please set VCPKG_MESON_(CROSS|NATIVE)_FILE to a meson file containing the host_machine entry!" )
endif()
set(host_unkown TRUE)
endif()
set(host "[host_machine]\n") # host=target in vcpkg.
string(APPEND host "endian = 'little'\n")
if(NOT VCPKG_CMAKE_SYSTEM_NAME OR VCPKG_TARGET_IS_MINGW OR VCPKG_TARGET_IS_UWP)
set(meson_system_name "windows")
else()
string(TOLOWER "${VCPKG_CMAKE_SYSTEM_NAME}" meson_system_name)
endif()
string(APPEND host "system = '${meson_system_name}'\n")
string(APPEND host "cpu_family = '${host_cpu_fam}'\n")
string(APPEND host "cpu = '${host_cpu}'")
if(NOT host_unkown)
set(${host_system} "${host}" PARENT_SCOPE)
endif()
if(NOT build_cpu_fam MATCHES "${host_cpu_fam}"
OR VCPKG_TARGET_IS_ANDROID OR VCPKG_TARGET_IS_IOS OR VCPKG_TARGET_IS_UWP
OR (VCPKG_TARGET_IS_MINGW AND NOT CMAKE_HOST_WIN32))
set(${is_cross} TRUE PARENT_SCOPE)
endif()
endfunction()
function(z_vcpkg_meson_setup_extra_windows_variables config_type)
## b_vscrt
if(VCPKG_CRT_LINKAGE STREQUAL "static")
set(crt_type "mt")
else()
set(crt_type "md")
endif()
if(config_type STREQUAL "DEBUG")
set(crt_type "${crt_type}d")
endif()
set(MESON_VSCRT_LINKAGE "b_vscrt = '${crt_type}'" PARENT_SCOPE)
## winlibs
separate_arguments(c_winlibs NATIVE_COMMAND "${VCPKG_DETECTED_CMAKE_C_STANDARD_LIBRARIES}")
separate_arguments(cpp_winlibs NATIVE_COMMAND "${VCPKG_DETECTED_CMAKE_CXX_STANDARD_LIBRARIES}")
z_vcpkg_meson_convert_list_to_python_array(c_winlibs ${c_winlibs})
z_vcpkg_meson_convert_list_to_python_array(cpp_winlibs ${cpp_winlibs})
set(MESON_WINLIBS "c_winlibs = ${c_winlibs}\n")
string(APPEND MESON_WINLIBS "cpp_winlibs = ${cpp_winlibs}")
set(MESON_WINLIBS "${MESON_WINLIBS}" PARENT_SCOPE)
endfunction()
function(z_vcpkg_meson_setup_variables config_type)
set(meson_var_list VSCRT_LINKAGE WINLIBS MT AR RC C C_LD CXX CXX_LD OBJC OBJC_LD OBJCXX OBJCXX_LD FC FC_LD WINDRES CFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS FCFLAGS SHARED_LINKER_FLAGS)
foreach(var IN LISTS meson_var_list)
set(MESON_${var} "")
endforeach()
if(VCPKG_TARGET_IS_WINDOWS)
z_vcpkg_meson_setup_extra_windows_variables("${config_type}")
endif()
z_vcpkg_meson_set_proglist_variables("${config_type}")
z_vcpkg_meson_set_flags_variables("${config_type}")
foreach(var IN LISTS meson_var_list)
set(MESON_${var} "${MESON_${var}}" PARENT_SCOPE)
endforeach()
endfunction()
function(vcpkg_generate_meson_cmd_args)
cmake_parse_arguments(PARSE_ARGV 0 arg
""
"OUTPUT;CONFIG"
"OPTIONS;LANGUAGES;ADDITIONAL_BINARIES;ADDITIONAL_PROPERTIES"
)
if(NOT arg_LANGUAGES)
set(arg_LANGUAGES C CXX)
endif()
vcpkg_list(JOIN arg_ADDITIONAL_BINARIES "\n" MESON_ADDITIONAL_BINARIES)
vcpkg_list(JOIN arg_ADDITIONAL_PROPERTIES "\n" MESON_ADDITIONAL_PROPERTIES)
set(buildtype "${arg_CONFIG}")
if(NOT VCPKG_CHAINLOAD_TOOLCHAIN_FILE)
z_vcpkg_select_default_vcpkg_chainload_toolchain()
endif()
vcpkg_list(APPEND VCPKG_CMAKE_CONFIGURE_OPTIONS "-DVCPKG_LANGUAGES=${arg_LANGUAGES}")
vcpkg_cmake_get_vars(cmake_vars_file)
debug_message("Including cmake vars from: ${cmake_vars_file}")
include("${cmake_vars_file}")
vcpkg_list(APPEND arg_OPTIONS --backend ninja --wrap-mode nodownload -Doptimization=plain)
z_vcpkg_get_build_and_host_system(MESON_HOST_MACHINE MESON_BUILD_MACHINE IS_CROSS)
if(arg_CONFIG STREQUAL "DEBUG")
set(suffix "dbg")
else()
string(SUBSTRING "${arg_CONFIG}" 0 3 suffix)
string(TOLOWER "${suffix}" suffix)
endif()
set(meson_input_file_${buildtype} "${CURRENT_BUILDTREES_DIR}/meson-${TARGET_TRIPLET}-${suffix}.log")
if(IS_CROSS)
# VCPKG_CROSSCOMPILING is not used since it regresses a lot of ports in x64-windows-x triplets
# For consistency this should proably be changed in the future?
vcpkg_list(APPEND arg_OPTIONS --native "${SCRIPTS}/buildsystems/meson/none.txt")
vcpkg_list(APPEND arg_OPTIONS --cross "${meson_input_file_${buildtype}}")
else()
vcpkg_list(APPEND arg_OPTIONS --native "${meson_input_file_${buildtype}}")
endif()
# User provided cross/native files
if(VCPKG_MESON_NATIVE_FILE)
vcpkg_list(APPEND arg_OPTIONS --native "${VCPKG_MESON_NATIVE_FILE}")
endif()
if(VCPKG_MESON_NATIVE_FILE_${buildtype})
vcpkg_list(APPEND arg_OPTIONS --native "${VCPKG_MESON_NATIVE_FILE_${buildtype}}")
endif()
if(VCPKG_MESON_CROSS_FILE)
vcpkg_list(APPEND arg_OPTIONS --cross "${VCPKG_MESON_CROSS_FILE}")
endif()
if(VCPKG_MESON_CROSS_FILE_${buildtype})
vcpkg_list(APPEND arg_OPTIONS --cross "${VCPKG_MESON_CROSS_FILE_${buildtype}}")
endif()
vcpkg_list(APPEND arg_OPTIONS --libdir lib) # else meson install into an architecture describing folder
vcpkg_list(APPEND arg_OPTIONS --pkgconfig.relocatable)
if(arg_CONFIG STREQUAL "RELEASE")
vcpkg_list(APPEND arg_OPTIONS -Ddebug=false --prefix "${CURRENT_PACKAGES_DIR}")
vcpkg_list(APPEND arg_OPTIONS "--pkg-config-path;['${CURRENT_INSTALLED_DIR}/lib/pkgconfig','${CURRENT_INSTALLED_DIR}/share/pkgconfig']")
if(VCPKG_TARGET_IS_WINDOWS)
vcpkg_list(APPEND arg_OPTIONS "-Dcmake_prefix_path=['${CURRENT_INSTALLED_DIR}','${CURRENT_INSTALLED_DIR}/debug','${CURRENT_INSTALLED_DIR}/share']")
else()
vcpkg_list(APPEND arg_OPTIONS "-Dcmake_prefix_path=['${CURRENT_INSTALLED_DIR}','${CURRENT_INSTALLED_DIR}/debug']")
endif()
elseif(arg_CONFIG STREQUAL "DEBUG")
vcpkg_list(APPEND arg_OPTIONS -Ddebug=true --prefix "${CURRENT_PACKAGES_DIR}/debug" --includedir ../include)
vcpkg_list(APPEND arg_OPTIONS "--pkg-config-path;['${CURRENT_INSTALLED_DIR}/debug/lib/pkgconfig','${CURRENT_INSTALLED_DIR}/share/pkgconfig']")
if(VCPKG_TARGET_IS_WINDOWS)
vcpkg_list(APPEND arg_OPTIONS "-Dcmake_prefix_path=['${CURRENT_INSTALLED_DIR}/debug','${CURRENT_INSTALLED_DIR}','${CURRENT_INSTALLED_DIR}/share']")
else()
vcpkg_list(APPEND arg_OPTIONS "-Dcmake_prefix_path=['${CURRENT_INSTALLED_DIR}/debug','${CURRENT_INSTALLED_DIR}']")
endif()
else()
message(FATAL_ERROR "Unknown configuration. Only DEBUG and RELEASE are valid values.")
endif()
# Allow overrides / additional configuration variables from triplets
if(DEFINED VCPKG_MESON_CONFIGURE_OPTIONS)
vcpkg_list(APPEND arg_OPTIONS ${VCPKG_MESON_CONFIGURE_OPTIONS})
endif()
if(DEFINED VCPKG_MESON_CONFIGURE_OPTIONS_${buildtype})
vcpkg_list(APPEND arg_OPTIONS ${VCPKG_MESON_CONFIGURE_OPTIONS_${buildtype}})
endif()
if(VCPKG_LIBRARY_LINKAGE STREQUAL "dynamic")
set(MESON_DEFAULT_LIBRARY shared)
else()
set(MESON_DEFAULT_LIBRARY static)
endif()
set(MESON_CMAKE_BUILD_TYPE "${cmake_build_type_${buildtype}}")
z_vcpkg_meson_setup_variables(${buildtype})
configure_file("${CMAKE_CURRENT_FUNCTION_LIST_DIR}/meson.template.in" "${meson_input_file_${buildtype}}" @ONLY)
set("${arg_OUTPUT}" ${arg_OPTIONS} PARENT_SCOPE)
endfunction()
function(vcpkg_configure_meson)
# parse parameters such that semicolons in options arguments to COMMAND don't get erased
cmake_parse_arguments(PARSE_ARGV 0 arg
"NO_PKG_CONFIG"
"SOURCE_PATH"
"OPTIONS;OPTIONS_DEBUG;OPTIONS_RELEASE;LANGUAGES;ADDITIONAL_BINARIES;ADDITIONAL_NATIVE_BINARIES;ADDITIONAL_CROSS_BINARIES;ADDITIONAL_PROPERTIES"
)
if(DEFINED arg_ADDITIONAL_NATIVE_BINARIES OR DEFINED arg_ADDITIONAL_CROSS_BINARIES)
message(WARNING "Options ADDITIONAL_(NATIVE|CROSS)_BINARIES have been deprecated. Only use ADDITIONAL_BINARIES!")
endif()
vcpkg_list(APPEND arg_ADDITIONAL_BINARIES ${arg_ADDITIONAL_NATIVE_BINARIES} ${arg_ADDITIONAL_CROSS_BINARIES})
vcpkg_list(REMOVE_DUPLICATES arg_ADDITIONAL_BINARIES)
file(REMOVE_RECURSE "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-rel")
file(REMOVE_RECURSE "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-dbg")
vcpkg_find_acquire_program(MESON)
get_filename_component(CMAKE_PATH "${CMAKE_COMMAND}" DIRECTORY)
vcpkg_add_to_path("${CMAKE_PATH}") # Make CMake invokeable for Meson
vcpkg_find_acquire_program(NINJA)
if(NOT arg_NO_PKG_CONFIG)
vcpkg_find_acquire_program(PKGCONFIG)
set(ENV{PKG_CONFIG} "${PKGCONFIG}")
endif()
vcpkg_find_acquire_program(PYTHON3)
get_filename_component(PYTHON3_DIR "${PYTHON3}" DIRECTORY)
vcpkg_add_to_path(PREPEND "${PYTHON3_DIR}")
set(buildtypes "")
if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "debug")
set(buildname "DEBUG")
set(cmake_build_type_${buildname} "Debug")
vcpkg_list(APPEND buildtypes "${buildname}")
set(path_suffix_${buildname} "debug/")
set(suffix_${buildname} "dbg")
endif()
if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "release")
set(buildname "RELEASE")
set(cmake_build_type_${buildname} "Release")
vcpkg_list(APPEND buildtypes "${buildname}")
set(path_suffix_${buildname} "")
set(suffix_${buildname} "rel")
endif()
# configure build
foreach(buildtype IN LISTS buildtypes)
message(STATUS "Configuring ${TARGET_TRIPLET}-${suffix_${buildtype}}")
file(MAKE_DIRECTORY "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-${suffix_${buildtype}}")
vcpkg_generate_meson_cmd_args(
OUTPUT cmd_args
CONFIG ${buildtype}
LANGUAGES ${arg_LANGUAGES}
OPTIONS ${arg_OPTIONS} ${arg_OPTIONS_${buildtype}}
ADDITIONAL_BINARIES ${arg_ADDITIONAL_BINARIES}
ADDITIONAL_PROPERTIES ${arg_ADDITIONAL_PROPERTIES}
)
vcpkg_execute_required_process(
COMMAND ${MESON} setup ${cmd_args} ${arg_SOURCE_PATH}
WORKING_DIRECTORY "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-${suffix_${buildtype}}"
LOGNAME config-${TARGET_TRIPLET}-${suffix_${buildtype}}
SAVE_LOG_FILES
meson-logs/meson-log.txt
meson-info/intro-dependencies.json
meson-logs/install-log.txt
)
message(STATUS "Configuring ${TARGET_TRIPLET}-${suffix_${buildtype}} done")
endforeach()
endfunction()

View file

@ -1,71 +0,0 @@
function(vcpkg_install_meson)
cmake_parse_arguments(PARSE_ARGV 0 arg "ADD_BIN_TO_PATH" "" "")
vcpkg_find_acquire_program(NINJA)
unset(ENV{DESTDIR}) # installation directory was already specified with '--prefix' option
if(VCPKG_TARGET_IS_OSX)
vcpkg_backup_env_variables(VARS SDKROOT MACOSX_DEPLOYMENT_TARGET)
set(ENV{SDKROOT} "${VCPKG_DETECTED_CMAKE_OSX_SYSROOT}")
set(ENV{MACOSX_DEPLOYMENT_TARGET} "${VCPKG_DETECTED_CMAKE_OSX_DEPLOYMENT_TARGET}")
endif()
foreach(buildtype IN ITEMS "debug" "release")
if(DEFINED VCPKG_BUILD_TYPE AND NOT VCPKG_BUILD_TYPE STREQUAL buildtype)
continue()
endif()
if(buildtype STREQUAL "debug")
set(short_buildtype "dbg")
else()
set(short_buildtype "rel")
endif()
message(STATUS "Package ${TARGET_TRIPLET}-${short_buildtype}")
if(arg_ADD_BIN_TO_PATH)
vcpkg_backup_env_variables(VARS PATH)
if(buildtype STREQUAL "debug")
vcpkg_add_to_path(PREPEND "${CURRENT_INSTALLED_DIR}/debug/bin")
else()
vcpkg_add_to_path(PREPEND "${CURRENT_INSTALLED_DIR}/bin")
endif()
endif()
vcpkg_execute_required_process(
COMMAND "${NINJA}" install -v
WORKING_DIRECTORY "${CURRENT_BUILDTREES_DIR}/${TARGET_TRIPLET}-${short_buildtype}"
LOGNAME package-${TARGET_TRIPLET}-${short_buildtype}
)
if(arg_ADD_BIN_TO_PATH)
vcpkg_restore_env_variables(VARS PATH)
endif()
endforeach()
vcpkg_list(SET renamed_libs)
if(VCPKG_TARGET_IS_WINDOWS AND VCPKG_LIBRARY_LINKAGE STREQUAL static AND NOT VCPKG_TARGET_IS_MINGW)
# Meson names all static libraries lib<name>.a which basically breaks the world
file(GLOB_RECURSE gen_libraries "${CURRENT_PACKAGES_DIR}*/**/lib*.a")
foreach(gen_library IN LISTS gen_libraries)
get_filename_component(libdir "${gen_library}" DIRECTORY)
get_filename_component(libname "${gen_library}" NAME)
string(REGEX REPLACE ".a$" ".lib" fixed_librawname "${libname}")
string(REGEX REPLACE "^lib" "" fixed_librawname "${fixed_librawname}")
file(RENAME "${gen_library}" "${libdir}/${fixed_librawname}")
# For cmake fixes.
string(REGEX REPLACE ".a$" "" origin_librawname "${libname}")
string(REGEX REPLACE ".lib$" "" fixed_librawname "${fixed_librawname}")
vcpkg_list(APPEND renamed_libs ${fixed_librawname})
set(${librawname}_old ${origin_librawname})
set(${librawname}_new ${fixed_librawname})
endforeach()
file(GLOB_RECURSE cmake_files "${CURRENT_PACKAGES_DIR}*/*.cmake")
foreach(cmake_file IN LISTS cmake_files)
foreach(current_lib IN LISTS renamed_libs)
vcpkg_replace_string("${cmake_file}" "${${current_lib}_old}" "${${current_lib}_new}" IGNORE_UNCHANGED)
endforeach()
endforeach()
endif()
if(VCPKG_TARGET_IS_OSX)
vcpkg_restore_env_variables(VARS SDKROOT MACOSX_DEPLOYMENT_TARGET)
endif()
endfunction()

View file

@ -1,8 +0,0 @@
# See https://github.com/microsoft/vcpkg/discussions/19454
# NOTE: Try to keep in sync with default arm64-osx definition
set(VCPKG_TARGET_ARCHITECTURE x64)
set(VCPKG_CRT_LINKAGE dynamic)
set(VCPKG_LIBRARY_LINKAGE static)
set(VCPKG_CMAKE_SYSTEM_NAME Darwin)
set(VCPKG_OSX_ARCHITECTURES "arm64;x86_64")

View file

@ -1,4 +1,9 @@
(import (fetchTarball {
url = "https://github.com/edolstra/flake-compat/archive/ff81ac966bb2cae68946d5ed5fc4994f96d0ffec.tar.gz";
sha256 = "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=";
}) { src = ./.; }).defaultNix
(import (
let
lock = builtins.fromJSON (builtins.readFile ./flake.lock);
in
fetchTarball {
url = "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
sha256 = lock.nodes.flake-compat.locked.narHash;
}
) { src = ./.; }).defaultNix

56
flake.lock generated
View file

@ -1,13 +1,29 @@
{
"nodes": {
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1696426674,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"libnbtplusplus": {
"flake": false,
"locked": {
"lastModified": 1772016279,
"narHash": "sha256-7itkptyjoRcXfGLwg1/jxajetZ3a4mDc66+w4X6yW8s=",
"lastModified": 1699286814,
"narHash": "sha256-yy0q+bky80LtK1GWzz7qpM+aAGrOqLuewbid8WT1ilk=",
"owner": "PrismLauncher",
"repo": "libnbtplusplus",
"rev": "687e43031df0dc641984b4256bcca50d5b3f7de3",
"rev": "23b955121b8217c1c348a9ed2483167a6f3ff4ad",
"type": "github"
},
"original": {
@ -16,22 +32,42 @@
"type": "github"
}
},
"nix-filter": {
"locked": {
"lastModified": 1710156097,
"narHash": "sha256-1Wvk8UP7PXdf8bCCaEoMnOT1qe5/Duqgj+rL8sRQsSM=",
"owner": "numtide",
"repo": "nix-filter",
"rev": "3342559a24e85fc164b295c3444e8a139924675b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "nix-filter",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1778443072,
"narHash": "sha256-rNDJzV2JTV5SUTwv1cgKZYMdyoUYU9/YfegSaUf3QfY=",
"rev": "da5ad661ba4e5ef59ba743f0d112cbc30e474f32",
"type": "tarball",
"url": "https://releases.nixos.org/nixos/unstable/nixos-26.05pre995699.da5ad661ba4e/nixexprs.tar.xz"
"lastModified": 1729256560,
"narHash": "sha256-/uilDXvCIEs3C9l73JTACm4quuHUsIHcns1c+cHUJwA=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "4c2fcb090b1f3e5b47eaa7bd33913b574a11e0a0",
"type": "github"
},
"original": {
"type": "tarball",
"url": "https://channels.nixos.org/nixos-unstable/nixexprs.tar.xz"
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-compat": "flake-compat",
"libnbtplusplus": "libnbtplusplus",
"nix-filter": "nix-filter",
"nixpkgs": "nixpkgs"
}
}

205
flake.nix
View file

@ -9,12 +9,34 @@
};
inputs = {
nixpkgs.url = "https://channels.nixos.org/nixos-unstable/nixexprs.tar.xz";
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
libnbtplusplus = {
url = "github:PrismLauncher/libnbtplusplus";
flake = false;
};
nix-filter.url = "github:numtide/nix-filter";
/*
Inputs below this are optional and can be removed
```
{
inputs.prismlauncher = {
url = "github:PrismLauncher/PrismLauncher";
inputs = {
flake-compat.follows = "";
};
};
}
```
*/
flake-compat = {
url = "github:edolstra/flake-compat";
flake = false;
};
};
outputs =
@ -22,8 +44,9 @@
self,
nixpkgs,
libnbtplusplus,
nix-filter,
...
}:
let
inherit (nixpkgs) lib;
@ -35,178 +58,47 @@
forAllSystems = lib.genAttrs systems;
nixpkgsFor = forAllSystems (system: nixpkgs.legacyPackages.${system});
in
{
checks = forAllSystems (
system:
let
pkgs = nixpkgsFor.${system};
llvm = pkgs.llvmPackages_22;
checks' = nixpkgsFor.${system}.callPackage ./nix/checks.nix { inherit self; };
in
{
formatting =
pkgs.runCommand "check-formatting"
{
nativeBuildInputs = with pkgs; [
deadnix
llvm.clang-tools
markdownlint-cli
nixfmt-rfc-style
statix
];
}
''
cd ${self}
echo "Running clang-format...."
clang-format --dry-run --style='file' --Werror */**.{c,cc,cpp,h,hh,hpp}
echo "Running deadnix..."
deadnix --fail
echo "Running markdownlint..."
markdownlint --dot .
echo "Running nixfmt..."
find -type f -name '*.nix' -exec nixfmt --check {} +
echo "Running statix"
statix check .
touch $out
'';
}
lib.filterAttrs (_: lib.isDerivation) checks'
);
devShells = forAllSystems (
system:
let
pkgs = nixpkgsFor.${system};
llvm = pkgs.llvmPackages_22;
python = pkgs.python3;
mkShell = pkgs.mkShell.override { inherit (llvm) stdenv; };
packages' = self.packages.${system};
welcomeMessage = ''
Welcome to the Prism Launcher repository! 🌈
We just set some things up for you. To get building, you can run:
```
$ cd "$cmakeBuildDir"
$ ninjaBuildPhase
$ ninjaInstallPhase
```
Feel free to ask any questions in our Discord server or Matrix space:
- https://prismlauncher.org/discord
- https://matrix.to/#/#prismlauncher:matrix.org
And thanks for helping out :)
'';
# Re-use our package wrapper to wrap our development environment
qt-wrapper-env = packages'.prismlauncher.overrideAttrs (old: {
name = "qt-wrapper-env";
# Required to use script-based makeWrapper below
strictDeps = true;
# We don't need/want the unwrapped Prism package
paths = [ ];
nativeBuildInputs = old.nativeBuildInputs or [ ] ++ [
# Ensure the wrapper is script based so it can be sourced
pkgs.makeWrapper
];
# Inspired by https://discourse.nixos.org/t/python-qt-woes/11808/10
buildCommand = ''
makeQtWrapper ${lib.getExe pkgs.runtimeShellPackage} "$out"
sed -i '/^exec/d' "$out"
'';
});
in
{
default = mkShell {
name = "prism-launcher";
inputsFrom = [ packages'.prismlauncher-unwrapped ];
packages = [
pkgs.ccache
llvm.clang-tools
python # NOTE(@getchoo): Required for run-clang-tidy, etc.
(pkgs.stdenvNoCC.mkDerivation {
pname = "clang-tidy-diff";
inherit (llvm.clang) version;
nativeBuildInputs = [
pkgs.installShellFiles
python.pkgs.wrapPython
];
dontUnpack = true;
dontConfigure = true;
dontBuild = true;
postInstall = "installBin ${llvm.libclang.python}/share/clang/clang-tidy-diff.py";
postFixup = "wrapPythonPrograms";
})
default = pkgs.mkShell {
inputsFrom = [ self.packages.${system}.prismlauncher-unwrapped ];
buildInputs = with pkgs; [
ccache
ninja
];
cmakeBuildType = "Debug";
cmakeFlags = [ "-GNinja" ] ++ packages'.prismlauncher-unwrapped.cmakeFlags;
dontFixCmake = true;
shellHook = ''
echo "Sourcing ${qt-wrapper-env}"
source ${qt-wrapper-env}
git submodule update --init --force
if [ ! -f compile_commands.json ]; then
cmakeConfigurePhase
cd ..
ln -s "$cmakeBuildDir"/compile_commands.json compile_commands.json
fi
echo ${lib.escapeShellArg welcomeMessage}
'';
};
}
);
formatter = forAllSystems (system: nixpkgsFor.${system}.nixfmt-rfc-style);
overlays.default =
final: prev:
let
llvm = final.llvmPackages_22 or prev.llvmPackages_22;
in
{
prismlauncher-unwrapped = prev.callPackage ./nix/unwrapped.nix {
inherit (llvm) stdenv;
inherit
libnbtplusplus
self
;
};
prismlauncher = final.callPackage ./nix/wrapper.nix { };
overlays.default = final: prev: {
prismlauncher-unwrapped = prev.callPackage ./nix/unwrapped.nix {
inherit
libnbtplusplus
nix-filter
self
;
};
prismlauncher = final.callPackage ./nix/wrapper.nix { };
};
packages = forAllSystems (
system:
let
pkgs = nixpkgsFor.${system};
@ -219,7 +111,6 @@
default = prismPackages.prismlauncher;
};
in
# Only output them if they're available on the current system
lib.filterAttrs (_: lib.meta.availableOn pkgs.stdenv.hostPlatform) packages
);
@ -227,18 +118,16 @@
# We put these under legacyPackages as they are meant for CI, not end user consumption
legacyPackages = forAllSystems (
system:
let
packages' = self.packages.${system};
legacyPackages' = self.legacyPackages.${system};
prismPackages = self.packages.${system};
legacyPackages = self.legacyPackages.${system};
in
{
prismlauncher-debug = packages'.prismlauncher.override {
prismlauncher-unwrapped = legacyPackages'.prismlauncher-unwrapped-debug;
prismlauncher-debug = prismPackages.prismlauncher.override {
prismlauncher-unwrapped = legacyPackages.prismlauncher-unwrapped-debug;
};
prismlauncher-unwrapped-debug = packages'.prismlauncher-unwrapped.overrideAttrs {
prismlauncher-unwrapped-debug = prismPackages.prismlauncher-unwrapped.overrideAttrs {
cmakeBuildType = "Debug";
dontStrip = true;
};

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.]+)$"
}
}
]
}

18
flatpak/libdecor.json Normal file
View file

@ -0,0 +1,18 @@
{
"name": "libdecor",
"buildsystem": "meson",
"config-opts": [
"-Ddemo=false"
],
"sources": [
{
"type": "git",
"url": "https://gitlab.freedesktop.org/libdecor/libdecor.git",
"commit": "c2bd8ad6fa42c0cb17553ce77ad8a87d1f543b1f"
}
],
"cleanup": [
"/include",
"/lib/pkgconfig"
]
}

View file

@ -0,0 +1,151 @@
id: org.prismlauncher.PrismLauncher
runtime: org.kde.Platform
runtime-version: '6.8'
sdk: org.kde.Sdk
sdk-extensions:
- org.freedesktop.Sdk.Extension.openjdk17
command: prismlauncher
finish-args:
- --share=ipc
- --socket=x11
- --socket=wayland
- --device=all
- --share=network
- --socket=pulseaudio
# for Discord RPC mods
- --filesystem=xdg-run/app/com.discordapp.Discord:create
# Mod drag&drop
- --filesystem=xdg-download:ro
# FTBApp import
- --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:
# Might be needed by some Controller mods (see https://github.com/isXander/Controlify/issues/31)
- shared-modules/libusb/libusb.json
# Needed for proper Wayland support
- libdecor.json
# Text to Speech in the game
- flite.json
- name: prismlauncher
buildsystem: cmake-ninja
builddir: true
config-opts:
- -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
build-options:
env:
JAVA_HOME: /usr/lib/sdk/openjdk17/jvm/openjdk-17
JAVA_COMPILER: /usr/lib/sdk/openjdk17/jvm/openjdk-17/bin/javac
run-tests: true
sources:
- type: dir
path: ../
- name: glfw
buildsystem: cmake-ninja
config-opts:
- -DCMAKE_BUILD_TYPE=RelWithDebInfo
- -DBUILD_SHARED_LIBS:BOOL=ON
- -DGLFW_BUILD_WAYLAND:BOOL=ON
- -DGLFW_BUILD_DOCS:BOOL=OFF
sources:
- type: git
url: https://github.com/glfw/glfw.git
commit: 7b6aead9fb88b3623e3b3725ebb42670cbe4c579 # 3.4
- type: patch
path: patches/0009-Defer-setting-cursor-position-until-the-cursor-is-lo.patch
cleanup:
- /include
- /lib/cmake
- /lib/pkgconfig
- name: xrandr
buildsystem: autotools
sources:
- type: archive
url: https://xorg.freedesktop.org/archive/individual/app/xrandr-1.5.3.tar.xz
sha256: f8dd7566adb74147fab9964680b6bbadee87cf406a7fcff51718a5e6949b841c
x-checker-data:
type: anitya
project-id: 14957
stable-only: true
url-template: https://xorg.freedesktop.org/archive/individual/app/xrandr-$version.tar.xz
cleanup:
- /share/man
- /bin/xkeystone
- name: gamemode
buildsystem: meson
config-opts:
- -Dwith-sd-bus-provider=no-daemon
- -Dwith-examples=false
post-install:
# gamemoderun is installed for users who want to use wrapper commands
# post-install is running inside the build dir, we need it from the source though
- install -Dm755 ../data/gamemoderun -t /app/bin
sources:
- type: archive
dest-filename: gamemode.tar.gz
url: https://api.github.com/repos/FeralInteractive/gamemode/tarball/1.8.2
sha256: 2886d4ce543c78bd2a364316d5e7fd59ef06b71de63f896b37c6d3dc97658f60
x-checker-data:
type: json
url: https://api.github.com/repos/FeralInteractive/gamemode/releases/latest
version-query: .tag_name
url-query: .tarball_url
timestamp-query: .published_at
cleanup:
- /include
- /lib/pkgconfig
- /lib/libgamemodeauto.a
- name: glxinfo
buildsystem: meson
config-opts:
- --bindir=/app/mesa-demos
- -Degl=disabled
- -Dglut=disabled
- -Dosmesa=disabled
- -Dvulkan=disabled
- -Dwayland=disabled
post-install:
- mv -v /app/mesa-demos/glxinfo /app/bin
sources:
- type: archive
url: https://archive.mesa3d.org/demos/mesa-demos-9.0.0.tar.xz
sha256: 3046a3d26a7b051af7ebdd257a5f23bfeb160cad6ed952329cdff1e9f1ed496b
x-checker-data:
type: anitya
project-id: 16781
stable-only: true
url-template: https://archive.mesa3d.org/demos/mesa-demos-$version.tar.xz
cleanup:
- /include
- /mesa-demos
- /share
modules:
- shared-modules/glu/glu-9.json
- name: enhance
buildsystem: simple
build-commands:
- install -Dm755 prime-run /app/bin/prime-run
- mv /app/bin/prismlauncher /app/bin/prismrun
- install -Dm755 prismlauncher /app/bin/prismlauncher
sources:
- type: file
path: prime-run
- type: file
path: prismlauncher

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

4
flatpak/prime-run Normal file
View file

@ -0,0 +1,4 @@
#!/bin/sh
export __NV_PRIME_RENDER_OFFLOAD=1 __VK_LAYER_NV_optimus=NVIDIA_only __GLX_VENDOR_LIBRARY_NAME=nvidia
exec "$@"

11
flatpak/prismlauncher Normal file
View file

@ -0,0 +1,11 @@
#!/bin/bash
# discord RPC
for i in {0..9}; do
test -S "$XDG_RUNTIME_DIR"/discord-ipc-"$i" || ln -sf {app/com.discordapp.Discord,"$XDG_RUNTIME_DIR"}/discord-ipc-"$i";
done
export PATH="${PATH}${PATH:+:}/usr/lib/extensions/vulkan/gamescope/bin:/usr/lib/extensions/vulkan/MangoHud/bin"
export VK_LAYER_PATH="/usr/lib/extensions/vulkan/share/vulkan/implicit_layer.d/"
exec /app/bin/prismrun "$@"

@ -0,0 +1 @@
Subproject commit f2b0c16a2a217a1822ce5a6538ba8f755ed1dd32

File diff suppressed because it is too large Load diff

View file

@ -37,8 +37,6 @@
#pragma once
#include <memory>
#include <QApplication>
#include <QDateTime>
#include <QDebug>
@ -46,16 +44,16 @@
#include <QIcon>
#include <QMutex>
#include <QUrl>
#include <memory>
#include "QObjectPtr.h"
#include <BaseInstance.h>
#include "minecraft/auth/MinecraftAccount.h"
#include "minecraft/launch/MinecraftTarget.h"
class LaunchController;
class LocalPeer;
class InstanceWindow;
class MainWindow;
class ViewLogWindow;
class SetupWizard;
class GenericPageProvider;
class QFile;
@ -74,12 +72,6 @@ class ITheme;
class MCEditTool;
class ThemeManager;
class IconTheme;
class BaseInstance;
class LogModel;
struct MinecraftTarget;
class MinecraftAccount;
namespace Meta {
class Index;
@ -97,6 +89,7 @@ class Index;
#define APPLICATION_DYN (dynamic_cast<Application*>(QCoreApplication::instance()))
class Application : public QApplication {
// friends for the purpose of limiting access to deprecated stuff
Q_OBJECT
public:
enum Status { StartingUp, Failed, Succeeded, Initialized };
@ -117,29 +110,29 @@ class Application : public QApplication {
bool event(QEvent* event) override;
SettingsObject* settings() const { return m_settings.get(); }
std::shared_ptr<SettingsObject> settings() const { return m_settings; }
qint64 timeSinceStart() const { return m_startTime.msecsTo(QDateTime::currentDateTime()); }
qint64 timeSinceStart() const { return startTime.msecsTo(QDateTime::currentDateTime()); }
QIcon logo();
QIcon getThemedIcon(const QString& name);
ThemeManager* themeManager() { return m_themeManager.get(); }
ExternalUpdater* updater() { return m_updater.get(); }
shared_qobject_ptr<ExternalUpdater> updater() { return m_updater; }
void triggerUpdateCheck();
TranslationsModel* translations();
std::shared_ptr<TranslationsModel> translations();
JavaInstallList* javalist();
std::shared_ptr<JavaInstallList> javalist();
InstanceList* instances() const { return m_instances.get(); }
std::shared_ptr<InstanceList> instances() const { return m_instances; }
IconList* icons() const { return m_icons.get(); }
std::shared_ptr<IconList> icons() const { return m_icons; }
MCEditTool* mcedit() const { return m_mcedit.get(); }
AccountList* accounts() const { return m_accounts.get(); }
shared_qobject_ptr<AccountList> accounts() const { return m_accounts; }
Status status() const { return m_status; }
@ -147,11 +140,11 @@ class Application : public QApplication {
void updateProxySettings(QString proxyTypeStr, QString addr, int port, QString user, QString password);
QNetworkAccessManager* network();
shared_qobject_ptr<QNetworkAccessManager> network();
HttpMetaCache* metacache();
shared_qobject_ptr<HttpMetaCache> metacache();
Meta::Index* metadataIndex();
shared_qobject_ptr<Meta::Index> metadataIndex();
void updateCapabilities();
@ -167,6 +160,7 @@ class Application : public QApplication {
QString getFlameAPIKey();
QString getModrinthAPIToken();
QString getUserAgent();
QString getUserAgentUncached();
/// this is the root of the 'installation'. Used for automatic updates
const QString& root() { return m_rootPath; }
@ -187,9 +181,8 @@ class Application : public QApplication {
*/
bool openJsonEditor(const QString& filename);
InstanceWindow* showInstanceWindow(BaseInstance* instance, QString page = QString());
InstanceWindow* showInstanceWindow(InstancePtr instance, QString page = QString());
MainWindow* showMainWindow(bool minimized = false);
ViewLogWindow* showLogWindow();
void updateIsRunning(bool running);
bool updatesAreAllowed();
@ -199,12 +192,12 @@ class Application : public QApplication {
bool updaterEnabled();
QString updaterBinaryName();
QUrl normalizeImportUrl(const QString& url);
QUrl normalizeImportUrl(QString const& url);
signals:
void updateAllowedChanged(bool status);
void globalSettingsAboutToOpen();
void globalSettingsApplied();
void globalSettingsClosed();
int currentCatChanged(int index);
void oauthReplyRecieved(QVariantMap);
@ -214,18 +207,19 @@ class Application : public QApplication {
#endif
public slots:
bool launch(BaseInstance* instance,
LaunchMode mode = LaunchMode::Normal,
std::shared_ptr<MinecraftTarget> targetToJoin = nullptr,
shared_qobject_ptr<MinecraftAccount> accountToUse = nullptr,
const QString& offlineName = QString());
bool kill(BaseInstance* instance);
bool launch(InstancePtr instance,
bool online = true,
bool demo = false,
MinecraftTarget::Ptr targetToJoin = nullptr,
MinecraftAccountPtr accountToUse = nullptr);
bool kill(InstancePtr instance);
void closeCurrentWindow();
private slots:
void on_windowClose();
void messageReceived(const QByteArray& message);
void controllerFinished();
void controllerSucceeded();
void controllerFailed(const QString& error);
void setupWizardFinished(int status);
private:
@ -242,26 +236,22 @@ class Application : public QApplication {
bool shouldExitNow() const;
private:
QHash<QString, int> m_qsaveResources;
mutable QMutex m_qsaveResourcesMutex;
QDateTime startTime;
private:
QDateTime m_startTime;
shared_qobject_ptr<QNetworkAccessManager> m_network;
std::unique_ptr<QNetworkAccessManager> m_network;
shared_qobject_ptr<ExternalUpdater> m_updater;
shared_qobject_ptr<AccountList> m_accounts;
std::unique_ptr<ExternalUpdater> m_updater;
std::unique_ptr<AccountList> m_accounts;
shared_qobject_ptr<HttpMetaCache> m_metacache;
shared_qobject_ptr<Meta::Index> m_metadataIndex;
std::unique_ptr<HttpMetaCache> m_metacache;
std::unique_ptr<Meta::Index> m_metadataIndex;
std::unique_ptr<SettingsObject> m_settings;
std::unique_ptr<InstanceList> m_instances;
std::unique_ptr<IconList> m_icons;
std::unique_ptr<JavaInstallList> m_javalist;
std::unique_ptr<TranslationsModel> m_translations;
std::unique_ptr<GenericPageProvider> m_globalSettingsProvider;
std::shared_ptr<SettingsObject> m_settings;
std::shared_ptr<InstanceList> m_instances;
std::shared_ptr<IconList> m_icons;
std::shared_ptr<JavaInstallList> m_javalist;
std::shared_ptr<TranslationsModel> m_translations;
std::shared_ptr<GenericPageProvider> m_globalSettingsProvider;
std::unique_ptr<MCEditTool> m_mcedit;
QSet<QString> m_features;
std::unique_ptr<ThemeManager> m_themeManager;
@ -278,10 +268,15 @@ class Application : public QApplication {
Qt::ApplicationState m_prevAppState = Qt::ApplicationInactive;
#endif
#if defined Q_OS_WIN32
// used on Windows to attach the standard IO streams
bool consoleAttached = false;
#endif
// FIXME: attach to instances instead.
struct InstanceXtras {
InstanceWindow* window = nullptr;
std::unique_ptr<LaunchController> controller;
shared_qobject_ptr<LaunchController> controller;
};
std::map<QString, InstanceXtras> m_instanceExtras;
mutable QMutex m_instanceExtrasMutex;
@ -294,9 +289,6 @@ class Application : public QApplication {
// main window, if any
MainWindow* m_mainWindow = nullptr;
// log window, if any
ViewLogWindow* m_viewLogWindow = nullptr;
// peer launcher instance connector - used to implement single instance launcher and signalling
LocalPeer* m_peerInstance = nullptr;
@ -309,17 +301,17 @@ class Application : public QApplication {
QString m_serverToJoin;
QString m_worldToJoin;
QString m_profileToUse;
bool m_launchOffline = false;
QString m_offlineName;
bool m_liveCheck = false;
QList<QUrl> m_urlsToImport;
QString m_instanceIdToShowWindowOf;
bool m_showMainWindow = false;
std::unique_ptr<QFile> logFile;
std::unique_ptr<LogModel> logModel;
public:
void addQSavePath(QString);
void removeQSavePath(QString);
bool checkQSavePath(QString);
private:
QHash<QString, int> m_qsaveResources;
mutable QMutex m_qsaveResourcesMutex;
};

View file

@ -1,25 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2025 Octol1ttle <l1ttleofficial@outlook.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
#if defined(ASSERT_NEVER)
#error ASSERT_NEVER already defined
#else
#define ASSERT_NEVER(cond) (Q_ASSERT((cond) == false), (cond))
#endif

View file

@ -42,10 +42,8 @@
#include <QFileInfo>
#include <QJsonDocument>
#include <QJsonObject>
#include <QRegularExpression>
#include "Application.h"
#include "Json.h"
#include "launch/LaunchTask.h"
#include "settings/INISettingsObject.h"
#include "settings/OverrideSetting.h"
#include "settings/Setting.h"
@ -54,26 +52,9 @@
#include "Commandline.h"
#include "FileSystem.h"
int getConsoleMaxLines(SettingsObject* settings)
BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString& rootDir) : QObject()
{
auto lineSetting = settings->getSetting("ConsoleMaxLines");
bool conversionOk = false;
int maxLines = lineSetting->get().toInt(&conversionOk);
if (!conversionOk) {
maxLines = lineSetting->defValue().toInt();
qWarning() << "ConsoleMaxLines has nonsensical value, defaulting to" << maxLines;
}
return maxLines;
}
bool shouldStopOnConsoleOverflow(SettingsObject* settings)
{
return settings->get("ConsoleOverflowStop").toBool();
}
BaseInstance::BaseInstance(SettingsObject* globalSettings, std::unique_ptr<SettingsObject> settings, const QString& rootDir) : QObject()
{
m_settings = std::move(settings);
m_settings = settings;
m_global_settings = globalSettings;
m_rootDir = rootDir;
@ -88,7 +69,6 @@ BaseInstance::BaseInstance(SettingsObject* globalSettings, std::unique_ptr<Setti
m_settings->registerSetting("lastTimePlayed", 0);
m_settings->registerSetting("linkedInstances", "[]");
m_settings->registerSetting("shortcuts", QString());
// Game time override
auto gameTimeOverride = m_settings->registerSetting("OverrideGameTime", false);
@ -123,13 +103,10 @@ BaseInstance::BaseInstance(SettingsObject* globalSettings, std::unique_ptr<Setti
m_settings->registerSetting("ManagedPackName", "");
m_settings->registerSetting("ManagedPackVersionID", "");
m_settings->registerSetting("ManagedPackVersionName", "");
m_settings->registerSetting("ManagedPackURL", "");
m_settings->registerSetting("Profiler", "");
}
BaseInstance::~BaseInstance() {}
QString BaseInstance::getPreLaunchCommand()
{
return settings()->get("PreLaunchCommand").toString();
@ -197,35 +174,46 @@ void BaseInstance::copyManagedPack(BaseInstance& other)
m_settings->set("ManagedPackName", other.getManagedPackName());
m_settings->set("ManagedPackVersionID", other.getManagedPackVersionID());
m_settings->set("ManagedPackVersionName", other.getManagedPackVersionName());
}
if (APPLICATION->settings()->get("AutomaticJavaSwitch").toBool() && m_settings->get("AutomaticJava").toBool() &&
m_settings->get("OverrideJavaLocation").toBool()) {
m_settings->set("OverrideJavaLocation", false);
m_settings->set("JavaPath", "");
int BaseInstance::getConsoleMaxLines() const
{
auto lineSetting = m_settings->getSetting("ConsoleMaxLines");
bool conversionOk = false;
int maxLines = lineSetting->get().toInt(&conversionOk);
if (!conversionOk) {
maxLines = lineSetting->defValue().toInt();
qWarning() << "ConsoleMaxLines has nonsensical value, defaulting to" << maxLines;
}
return maxLines;
}
bool BaseInstance::shouldStopOnConsoleOverflow() const
{
return m_settings->get("ConsoleOverflowStop").toBool();
}
QStringList BaseInstance::getLinkedInstances() const
{
auto setting = m_settings->get("linkedInstances").toString();
return Json::toStringList(setting);
return m_settings->get("linkedInstances").toStringList();
}
void BaseInstance::setLinkedInstances(const QStringList& list)
{
m_settings->set("linkedInstances", Json::fromStringList(list));
auto linkedInstances = m_settings->get("linkedInstances").toStringList();
m_settings->set("linkedInstances", list);
}
void BaseInstance::addLinkedInstanceId(const QString& id)
{
auto linkedInstances = getLinkedInstances();
auto linkedInstances = m_settings->get("linkedInstances").toStringList();
linkedInstances.append(id);
setLinkedInstances(linkedInstances);
}
bool BaseInstance::removeLinkedInstanceId(const QString& id)
{
auto linkedInstances = getLinkedInstances();
auto linkedInstances = m_settings->get("linkedInstances").toStringList();
int numRemoved = linkedInstances.removeAll(id);
setLinkedInstances(linkedInstances);
return numRemoved > 0;
@ -233,7 +221,7 @@ bool BaseInstance::removeLinkedInstanceId(const QString& id)
bool BaseInstance::isLinkedToInstanceId(const QString& id) const
{
auto linkedInstances = getLinkedInstances();
auto linkedInstances = m_settings->get("linkedInstances").toStringList();
return linkedInstances.contains(id);
}
@ -339,11 +327,11 @@ QString BaseInstance::instanceRoot() const
return m_rootDir;
}
SettingsObject* BaseInstance::settings()
SettingsObjectPtr BaseInstance::settings()
{
loadSpecificSettings();
return m_settings.get();
return m_settings;
}
bool BaseInstance::canLaunch() const
@ -398,63 +386,6 @@ void BaseInstance::setName(QString val)
emit propertiesChanged(this);
}
bool BaseInstance::syncInstanceDirName(const QString& newRoot) const
{
auto oldRoot = instanceRoot();
return oldRoot == newRoot || QFile::rename(oldRoot, newRoot);
}
void BaseInstance::registerShortcut(const ShortcutData& data)
{
auto currentShortcuts = shortcuts();
currentShortcuts.append(data);
qDebug() << "Registering shortcut for instance" << id() << "with name" << data.name << "and path" << data.filePath;
setShortcuts(currentShortcuts);
}
void BaseInstance::setShortcuts(const QList<ShortcutData>& shortcuts)
{
// FIXME: if no change, do not set. setting involves saving a file.
QJsonArray array;
for (const auto& elem : shortcuts) {
array.append(QJsonObject{ { "name", elem.name }, { "filePath", elem.filePath }, { "target", static_cast<int>(elem.target) } });
}
QJsonDocument document;
document.setArray(array);
m_settings->set("shortcuts", QString::fromUtf8(document.toJson(QJsonDocument::Compact)));
}
QList<ShortcutData> BaseInstance::shortcuts() const
{
auto data = m_settings->get("shortcuts").toString().toUtf8();
QJsonParseError parseError;
auto document = QJsonDocument::fromJson(data, &parseError);
if (parseError.error != QJsonParseError::NoError || !document.isArray())
return {};
QList<ShortcutData> results;
for (const auto& elem : document.array()) {
if (!elem.isObject())
continue;
auto dict = elem.toObject();
if (!dict.contains("name") || !dict.contains("filePath") || !dict.contains("target"))
continue;
int value = dict["target"].toInt(-1);
if (!dict["name"].isString() || !dict["filePath"].isString() || value < 0 || value >= 3)
continue;
QString shortcutName = dict["name"].toString();
QString filePath = dict["filePath"].toString();
if (!QDir(filePath).exists()) {
qWarning() << "Shortcut" << shortcutName << "for instance" << name() << "have non-existent path" << filePath;
continue;
}
results.append({ shortcutName, filePath, static_cast<ShortcutTarget>(value) });
}
return results;
}
QString BaseInstance::name() const
{
return m_settings->get("name").toString();
@ -471,17 +402,12 @@ QStringList BaseInstance::extraArguments()
return Commandline::splitArgs(settings()->get("JvmArgs").toString());
}
LaunchTask* BaseInstance::getLaunchTask()
shared_qobject_ptr<LaunchTask> BaseInstance::getLaunchTask()
{
return m_launchProcess.get();
return m_launchProcess;
}
void BaseInstance::updateRuntimeContext()
{
// NOOP
}
bool BaseInstance::isLegacy()
{
return traits().contains("legacyLaunch") || traits().contains("alphaLaunch");
}

View file

@ -38,9 +38,7 @@
#pragma once
#include <cassert>
#include <QDataStream>
#include <QDateTime>
#include <QList>
#include <QMenu>
#include <QObject>
#include <QProcess>
@ -52,6 +50,7 @@
#include "BaseVersionList.h"
#include "MessageLevel.h"
#include "minecraft/auth/MinecraftAccount.h"
#include "pathmatcher/IPathMatcher.h"
#include "settings/INIFile.h"
#include "net/Mode.h"
@ -64,19 +63,8 @@ class Task;
class LaunchTask;
class BaseInstance;
/// Shortcut saving target representations
enum class ShortcutTarget { Desktop, Applications, Other };
/// Shortcut data representation
struct ShortcutData {
QString name;
QString filePath;
ShortcutTarget target = ShortcutTarget::Other;
};
/// Console settings
int getConsoleMaxLines(SettingsObject* settings);
bool shouldStopOnConsoleOverflow(SettingsObject* settings);
// pointer for lazy people
using InstancePtr = std::shared_ptr<BaseInstance>;
/*!
* \brief Base class for instances.
@ -86,11 +74,11 @@ bool shouldStopOnConsoleOverflow(SettingsObject* settings);
* To create a new instance type, create a new class inheriting from this class
* and implement the pure virtual functions.
*/
class BaseInstance : public QObject {
class BaseInstance : public QObject, public std::enable_shared_from_this<BaseInstance> {
Q_OBJECT
protected:
/// no-touchy!
BaseInstance(SettingsObject* globalSettings, std::unique_ptr<SettingsObject> settings, const QString& rootDir);
BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString& rootDir);
public: /* types */
enum class Status {
@ -100,7 +88,7 @@ class BaseInstance : public QObject {
public:
/// virtual destructor to make sure the destruction is COMPLETE
virtual ~BaseInstance();
virtual ~BaseInstance() {}
virtual void saveNow() = 0;
@ -138,14 +126,6 @@ class BaseInstance : public QObject {
QString name() const;
void setName(QString val);
/// Sync name and rename instance dir accordingly; returns true if successful
bool syncInstanceDirName(const QString& newRoot) const;
/// Register a created shortcut
void registerShortcut(const ShortcutData& data);
QList<ShortcutData> shortcuts() const;
void setShortcuts(const QList<ShortcutData>& shortcuts);
/// Value used for instance window titles
QString windowTitle() const;
@ -168,6 +148,9 @@ class BaseInstance : public QObject {
void setManagedPack(const QString& type, const QString& id, const QString& name, const QString& versionId, const QString& version);
void copyManagedPack(BaseInstance& other);
/// guess log level from a line of game log
virtual MessageLevel::Enum guessLevel([[maybe_unused]] const QString& line, MessageLevel::Enum level) { return level; }
virtual QStringList extraArguments();
/// Traits. Normally inside the version, depends on instance implementation.
@ -190,7 +173,7 @@ class BaseInstance : public QObject {
*
* \return A pointer to this instance's settings object.
*/
virtual SettingsObject* settings();
virtual SettingsObjectPtr settings();
/*!
* \brief Loads settings specific to an instance type if they're not already loaded.
@ -201,10 +184,10 @@ class BaseInstance : public QObject {
virtual QList<Task::Ptr> createUpdateTask() = 0;
/// returns a valid launcher (task container)
virtual LaunchTask* createLaunchTask(AuthSessionPtr account, MinecraftTarget::Ptr targetToJoin) = 0;
virtual shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account, MinecraftTarget::Ptr targetToJoin) = 0;
/// returns the current launch task (if any)
LaunchTask* getLaunchTask();
shared_qobject_ptr<LaunchTask> getLaunchTask();
/*!
* Create envrironment variables for running the instance
@ -212,10 +195,15 @@ class BaseInstance : public QObject {
virtual QProcessEnvironment createEnvironment() = 0;
virtual QProcessEnvironment createLaunchEnvironment() = 0;
/*!
* Returns a matcher that can maps relative paths within the instance to whether they are 'log files'
*/
virtual IPathMatcher::Ptr getLogFileMatcher() = 0;
/*!
* Returns the root folder to use for looking up log files
*/
virtual QStringList getLogFileSearchPaths() = 0;
virtual QString getLogFileRoot() = 0;
virtual QString getStatusbarDescription() = 0;
@ -272,18 +260,19 @@ class BaseInstance : public QObject {
Status currentStatus() const;
int getConsoleMaxLines() const;
bool shouldStopOnConsoleOverflow() const;
QStringList getLinkedInstances() const;
void setLinkedInstances(const QStringList& list);
void addLinkedInstanceId(const QString& id);
bool removeLinkedInstanceId(const QString& id);
bool isLinkedToInstanceId(const QString& id) const;
bool isLegacy();
protected:
void changeStatus(Status newStatus);
SettingsObject* globalSettings() const { return m_global_settings; }
SettingsObjectPtr globalSettings() const { return m_global_settings.lock(); }
bool isSpecificSettingsLoaded() const { return m_specific_settings_loaded; }
void setSpecificSettingsLoaded(bool loaded) { m_specific_settings_loaded = loaded; }
@ -294,7 +283,7 @@ class BaseInstance : public QObject {
*/
void propertiesChanged(BaseInstance* inst);
void launchTaskChanged(LaunchTask*);
void launchTaskChanged(shared_qobject_ptr<LaunchTask>);
void runningStatusChanged(bool running);
@ -307,10 +296,10 @@ class BaseInstance : public QObject {
protected: /* data */
QString m_rootDir;
std::unique_ptr<SettingsObject> m_settings;
SettingsObjectPtr m_settings;
// InstanceFlags m_flags;
bool m_isRunning = false;
std::unique_ptr<LaunchTask> m_launchProcess;
shared_qobject_ptr<LaunchTask> m_launchProcess;
QDateTime m_timeStarted;
RuntimeContext m_runtimeContext;
@ -320,7 +309,7 @@ class BaseInstance : public QObject {
bool m_hasUpdate = false;
bool m_hasBrokenVersion = false;
SettingsObject* m_global_settings;
SettingsObjectWeakPtr m_global_settings;
bool m_specific_settings_loaded = false;
};

View file

@ -24,28 +24,27 @@
*/
class BaseVersion {
public:
// TODO: delete
using Ptr = std::shared_ptr<BaseVersion>;
virtual ~BaseVersion() {}
/*!
* A string used to identify this version in config files.
* This should be unique within the version list or shenanigans will occur.
*/
virtual QString descriptor() const = 0;
virtual QString descriptor() = 0;
/*!
* The name of this version as it is displayed to the user.
* For example: "1.5.1"
*/
virtual QString name() const = 0;
virtual QString name() = 0;
/*!
* This should return a string that describes
* the kind of version this is (Stable, Beta, Snapshot, whatever)
*/
virtual QString typeString() const = 0;
virtual bool operator<(BaseVersion& a) const { return name() < a.name(); }
virtual bool operator>(BaseVersion& a) const { return name() > a.name(); }
virtual bool operator<(BaseVersion& a) { return name() < a.name(); }
virtual bool operator>(BaseVersion& a) { return name() > a.name(); }
};
Q_DECLARE_METATYPE(BaseVersion::Ptr)

View file

@ -63,7 +63,7 @@ class BaseVersionList : public QAbstractListModel {
* The task returned by this function should reset the model when it's done.
* \return A pointer to a task that reloads the version list.
*/
virtual Task::Ptr getLoadTask(bool forceReload = false) = 0;
virtual Task::Ptr getLoadTask() = 0;
//! Checks whether or not the list is loaded. If this returns false, the list should be
// loaded.

File diff suppressed because it is too large Load diff

View file

@ -12,10 +12,10 @@
#include <QtConcurrent>
DataMigrationTask::DataMigrationTask(const QString& sourcePath, const QString& targetPath, Filter pathMatcher)
DataMigrationTask::DataMigrationTask(const QString& sourcePath, const QString& targetPath, const IPathMatcher::Ptr pathMatcher)
: Task(), m_sourcePath(sourcePath), m_targetPath(targetPath), m_pathMatcher(pathMatcher), m_copy(sourcePath, targetPath)
{
m_copy.matcher(m_pathMatcher).whitelist(true);
m_copy.matcher(m_pathMatcher.get()).whitelist(true);
}
void DataMigrationTask::executeTask()
@ -24,7 +24,7 @@ void DataMigrationTask::executeTask()
// 1. Scan
// Check how many files we gotta copy
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [this] {
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [&] {
return m_copy(true); // dry run to collect amount of files
});
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::dryRunFinished);
@ -37,7 +37,11 @@ void DataMigrationTask::dryRunFinished()
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::dryRunFinished);
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &DataMigrationTask::dryRunAborted);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
if (!m_copyFuture.isValid() || !m_copyFuture.result()) {
#else
if (!m_copyFuture.result()) {
#endif
emitFailed(tr("Failed to scan source path."));
return;
}
@ -53,7 +57,7 @@ void DataMigrationTask::dryRunFinished()
setProgress(m_copy.totalCopied(), m_toCopy);
setStatus(tr("Copying %1…").arg(shortenedName));
});
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [this] {
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [&] {
return m_copy(false); // actually copy now
});
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::copyFinished);
@ -63,7 +67,7 @@ void DataMigrationTask::dryRunFinished()
void DataMigrationTask::dryRunAborted()
{
emitAborted();
emitFailed(tr("Aborted"));
}
void DataMigrationTask::copyFinished()
@ -71,7 +75,11 @@ void DataMigrationTask::copyFinished()
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::copyFinished);
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &DataMigrationTask::copyAborted);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
if (!m_copyFuture.isValid() || !m_copyFuture.result()) {
#else
if (!m_copyFuture.result()) {
#endif
emitFailed(tr("Some paths could not be copied!"));
return;
}
@ -81,5 +89,5 @@ void DataMigrationTask::copyFinished()
void DataMigrationTask::copyAborted()
{
emitAborted();
emitFailed(tr("Aborted"));
}

View file

@ -5,7 +5,7 @@
#pragma once
#include "FileSystem.h"
#include "Filter.h"
#include "pathmatcher/IPathMatcher.h"
#include "tasks/Task.h"
#include <QFuture>
@ -18,7 +18,7 @@
class DataMigrationTask : public Task {
Q_OBJECT
public:
explicit DataMigrationTask(const QString& sourcePath, const QString& targetPath, Filter pathmatcher);
explicit DataMigrationTask(const QString& sourcePath, const QString& targetPath, IPathMatcher::Ptr pathmatcher);
~DataMigrationTask() override = default;
protected:
@ -33,7 +33,7 @@ class DataMigrationTask : public Task {
private:
const QString& m_sourcePath;
const QString& m_targetPath;
const Filter m_pathMatcher;
const IPathMatcher::Ptr m_pathMatcher;
FS::copy m_copy;
int m_toCopy = 0;

View file

@ -0,0 +1,23 @@
#pragma once
template <typename T>
class DefaultVariable {
public:
DefaultVariable(const T& value) { defaultValue = value; }
DefaultVariable<T>& operator=(const T& value)
{
currentValue = value;
is_default = currentValue == defaultValue;
is_explicit = true;
return *this;
}
operator const T&() const { return is_default ? defaultValue : currentValue; }
bool isDefault() const { return is_default; }
bool isExplicit() const { return is_explicit; }
private:
T currentValue;
T defaultValue;
bool is_default = true;
bool is_explicit = false;
};

View file

@ -44,4 +44,4 @@ QIcon FastFileIconProvider::icon(const QFileInfo& info) const
}
return QApplication::style()->standardIcon(icon);
}
}

View file

@ -23,4 +23,4 @@
class FastFileIconProvider : public QFileIconProvider {
public:
QIcon icon(const QFileInfo& info) const override;
};
};

View file

@ -40,11 +40,12 @@
#include <QFileSystemModel>
#include <QSortFilterProxyModel>
#include <QStack>
#include <algorithm>
#include "FileSystem.h"
#include "SeparatorPrefixTree.h"
#include "StringUtils.h"
FileIgnoreProxy::FileIgnoreProxy(QString root, QObject* parent) : QSortFilterProxyModel(parent), m_root(root) {}
FileIgnoreProxy::FileIgnoreProxy(QString root, QObject* parent) : QSortFilterProxyModel(parent), root(root) {}
// NOTE: Sadly, we have to do sorting ourselves.
bool FileIgnoreProxy::lessThan(const QModelIndex& left, const QModelIndex& right) const
{
@ -103,10 +104,10 @@ QVariant FileIgnoreProxy::data(const QModelIndex& index, int role) const
if (index.column() == 0 && role == Qt::CheckStateRole) {
QFileSystemModel* fsm = qobject_cast<QFileSystemModel*>(sourceModel());
auto blockedPath = relPath(fsm->filePath(sourceIndex));
auto cover = m_blocked.cover(blockedPath);
auto cover = blocked.cover(blockedPath);
if (!cover.isNull()) {
return QVariant(Qt::Unchecked);
} else if (m_blocked.exists(blockedPath)) {
} else if (blocked.exists(blockedPath)) {
return QVariant(Qt::PartiallyChecked);
} else {
return QVariant(Qt::Checked);
@ -129,7 +130,7 @@ bool FileIgnoreProxy::setData(const QModelIndex& index, const QVariant& value, i
QString FileIgnoreProxy::relPath(const QString& path) const
{
return QDir(m_root).relativeFilePath(path);
return QDir(root).relativeFilePath(path);
}
bool FileIgnoreProxy::setFilterState(QModelIndex index, Qt::CheckState state)
@ -145,18 +146,18 @@ bool FileIgnoreProxy::setFilterState(QModelIndex index, Qt::CheckState state)
bool changed = false;
if (state == Qt::Unchecked) {
// blocking a path
auto& node = m_blocked.insert(blockedPath);
auto& node = blocked.insert(blockedPath);
// get rid of all blocked nodes below
node.clear();
changed = true;
} else if (state == Qt::Checked || state == Qt::PartiallyChecked) {
if (!m_blocked.remove(blockedPath)) {
auto cover = m_blocked.cover(blockedPath);
if (!blocked.remove(blockedPath)) {
auto cover = blocked.cover(blockedPath);
qDebug() << "Blocked by cover" << cover;
// uncover
m_blocked.remove(cover);
blocked.remove(cover);
// block all contents, except for any cover
QModelIndex rootIndex = fsm->index(FS::PathCombine(m_root, cover));
QModelIndex rootIndex = fsm->index(FS::PathCombine(root, cover));
QModelIndex doing = rootIndex;
int row = 0;
QStack<QModelIndex> todo;
@ -178,7 +179,7 @@ bool FileIgnoreProxy::setFilterState(QModelIndex index, Qt::CheckState state)
todo.push(node);
} else {
// or just block this one.
m_blocked.insert(relpath);
blocked.insert(relpath);
}
row++;
}
@ -228,7 +229,7 @@ bool FileIgnoreProxy::shouldExpand(QModelIndex index)
return false;
}
auto blockedPath = relPath(fsm->filePath(sourceIndex));
auto found = m_blocked.find(blockedPath);
auto found = blocked.find(blockedPath);
if (found) {
return !found->leaf();
}
@ -238,8 +239,8 @@ bool FileIgnoreProxy::shouldExpand(QModelIndex index)
void FileIgnoreProxy::setBlockedPaths(QStringList paths)
{
beginResetModel();
m_blocked.clear();
m_blocked.insert(paths);
blocked.clear();
blocked.insert(paths);
endResetModel();
}
@ -266,45 +267,10 @@ bool FileIgnoreProxy::filterAcceptsRow(int sourceRow, const QModelIndex& sourceP
bool FileIgnoreProxy::ignoreFile(QFileInfo fileInfo) const
{
if (m_ignoreFiles.contains(fileInfo.fileName())) {
return true;
}
for (const auto& suffix : m_ignoreFilesSuffixes) {
if (fileInfo.fileName().endsWith(suffix)) {
return true;
}
}
if (m_ignoreFilePaths.covers(relPath(fileInfo.absoluteFilePath()))) {
return true;
}
return false;
return m_ignoreFiles.contains(fileInfo.fileName()) || m_ignoreFilePaths.covers(relPath(fileInfo.absoluteFilePath()));
}
bool FileIgnoreProxy::filterFile(const QFileInfo& file) const
bool FileIgnoreProxy::filterFile(const QString& fileName) const
{
return m_blocked.covers(relPath(file.absoluteFilePath())) || ignoreFile(file);
}
void FileIgnoreProxy::loadBlockedPathsFromFile(const QString& fileName)
{
QFile ignoreFile(fileName);
if (!ignoreFile.open(QIODevice::ReadOnly)) {
return;
}
auto ignoreData = ignoreFile.readAll();
auto string = QString::fromUtf8(ignoreData);
setBlockedPaths(string.split('\n', Qt::SkipEmptyParts));
}
void FileIgnoreProxy::saveBlockedPathsToFile(const QString& fileName)
{
auto ignoreData = blockedPaths().toStringList().join('\n').toUtf8();
try {
FS::write(fileName, ignoreData);
} catch (const Exception& e) {
qWarning() << e.cause();
}
return blocked.covers(fileName) || ignoreFile(QFileInfo(QDir(root), fileName));
}

View file

@ -61,20 +61,15 @@ class FileIgnoreProxy : public QSortFilterProxyModel {
void setBlockedPaths(QStringList paths);
inline const SeparatorPrefixTree<'/'>& blockedPaths() const { return m_blocked; }
inline SeparatorPrefixTree<'/'>& blockedPaths() { return m_blocked; }
inline const SeparatorPrefixTree<'/'>& blockedPaths() const { return blocked; }
inline SeparatorPrefixTree<'/'>& blockedPaths() { return blocked; }
// list of file names that need to be removed completely from model
inline QStringList& ignoreFilesWithName() { return m_ignoreFiles; }
inline QStringList& ignoreFilesWithSuffix() { return m_ignoreFilesSuffixes; }
// list of relative paths that need to be removed completely from model
inline SeparatorPrefixTree<'/'>& ignoreFilesWithPath() { return m_ignoreFilePaths; }
bool filterFile(const QFileInfo& fileName) const;
void loadBlockedPathsFromFile(const QString& fileName);
void saveBlockedPathsToFile(const QString& fileName);
bool filterFile(const QString& fileName) const;
protected:
bool filterAcceptsColumn(int source_column, const QModelIndex& source_parent) const;
@ -83,9 +78,8 @@ class FileIgnoreProxy : public QSortFilterProxyModel {
bool ignoreFile(QFileInfo file) const;
private:
const QString m_root;
SeparatorPrefixTree<'/'> m_blocked;
const QString root;
SeparatorPrefixTree<'/'> blocked;
QStringList m_ignoreFiles;
QStringList m_ignoreFilesSuffixes;
SeparatorPrefixTree<'/'> m_ignoreFilePaths;
};

View file

@ -36,7 +36,6 @@
*/
#include "FileSystem.h"
#include <qcontainerfwd.h>
#include <QPair>
#include "BuildConfig.h"
@ -60,8 +59,10 @@
#if defined Q_OS_WIN32
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <objbase.h>
#include <objidl.h>
#include <shlguid.h>
#include <shlobj.h>
#include <shobjidl.h>
#include <sys/utime.h>
#include <versionhelpers.h>
@ -76,8 +77,24 @@
#include <utime.h>
#endif
// Snippet from https://github.com/gulrak/filesystem#using-it-as-single-file-header
#ifdef __APPLE__
#include <Availability.h> // for deployment target to support pre-catalina targets without std::fs
#endif // __APPLE__
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
#define GHC_USE_STD_FS
#include <filesystem>
namespace fs = std::filesystem;
#endif // MacOS min version check
#endif // Other OSes version check
#ifndef GHC_USE_STD_FS
#include <ghc/filesystem.hpp>
namespace fs = ghc::filesystem;
#endif
// clone
#if defined(Q_OS_LINUX)
@ -106,10 +123,6 @@ namespace fs = std::filesystem;
#if defined(__MINGW32__)
// Avoid re-defining structs retroactively added to MinGW
// https://github.com/mingw-w64/mingw-w64/issues/90#issuecomment-2829284729
#if __MINGW64_VERSION_MAJOR < 13
struct _DUPLICATE_EXTENTS_DATA {
HANDLE FileHandle;
LARGE_INTEGER SourceFileOffset;
@ -119,7 +132,6 @@ struct _DUPLICATE_EXTENTS_DATA {
using DUPLICATE_EXTENTS_DATA = _DUPLICATE_EXTENTS_DATA;
using PDUPLICATE_EXTENTS_DATA = _DUPLICATE_EXTENTS_DATA*;
#endif
struct _FSCTL_GET_INTEGRITY_INFORMATION_BUFFER {
WORD ChecksumAlgorithm; // Checksum algorithm. e.g. CHECKSUM_TYPE_UNCHANGED, CHECKSUM_TYPE_NONE, CHECKSUM_TYPE_CRC32
@ -283,9 +295,6 @@ bool copyFileAttributes(QString src, QString dst)
if (attrs == INVALID_FILE_ATTRIBUTES)
return false;
return SetFileAttributesW(dst.toStdWString().c_str(), attrs);
#else
Q_UNUSED(src);
Q_UNUSED(dst);
#endif
return true;
}
@ -332,8 +341,8 @@ bool copy::operator()(const QString& offset, bool dryRun)
opt |= copy_opts::overwrite_existing;
// Function that'll do the actual copying
auto copy_file = [this, dryRun, src, dst, opt, &err](QString src_path, QString relative_dst_path) {
if (m_matcher && (m_matcher(relative_dst_path) != m_whitelist))
auto copy_file = [&](QString src_path, QString relative_dst_path) {
if (m_matcher && (m_matcher->matches(relative_dst_path) != m_whitelist))
return;
auto dst_path = PathCombine(dst, relative_dst_path);
@ -419,8 +428,8 @@ void create_link::make_link_list(const QString& offset)
m_recursive = true;
// Function that'll do the actual linking
auto link_file = [this, dst](QString src_path, QString relative_dst_path) {
if (m_matcher && (m_matcher(relative_dst_path) != m_whitelist)) {
auto link_file = [&](QString src_path, QString relative_dst_path) {
if (m_matcher && (m_matcher->matches(relative_dst_path) != m_whitelist)) {
qDebug() << "path" << relative_dst_path << "in black list or not in whitelist";
return;
}
@ -436,7 +445,7 @@ void create_link::make_link_list(const QString& offset)
link_file(src, "");
} else {
if (m_debug)
qDebug().nospace() << "linking recursively: " << src << " to " << dst << ", max_depth: " << m_max_depth;
qDebug() << "linking recursively:" << src << "to" << dst << ", max_depth:" << m_max_depth;
QDir src_dir(src);
QDirIterator source_it(src, QDir::Filter::Files | QDir::Filter::Hidden, QDirIterator::Subdirectories);
@ -514,7 +523,7 @@ void create_link::runPrivileged(const QString& offset)
QString serverName = BuildConfig.LAUNCHER_APP_BINARY_NAME + "_filelink_server" + StringUtils::getRandomAlphaNumeric();
connect(&m_linkServer, &QLocalServer::newConnection, this, [this, &gotResults]() {
connect(&m_linkServer, &QLocalServer::newConnection, this, [&]() {
qDebug() << "Client connected, sending out pairs";
// construct block of data to send
QByteArray block;
@ -596,7 +605,7 @@ void create_link::runPrivileged(const QString& offset)
}
ExternalLinkFileProcess* linkFileProcess = new ExternalLinkFileProcess(serverName, m_useHardLinks, this);
connect(linkFileProcess, &ExternalLinkFileProcess::processExited, this, [this, &gotResults]() { emit finishedPrivileged(gotResults); });
connect(linkFileProcess, &ExternalLinkFileProcess::processExited, this, [&]() { emit finishedPrivileged(gotResults); });
connect(linkFileProcess, &ExternalLinkFileProcess::finished, linkFileProcess, &QObject::deleteLater);
linkFileProcess->start();
@ -684,34 +693,11 @@ bool deletePath(QString path)
return err.value() == 0;
}
bool deleteContents(const QString& path)
{
const QFileInfo info(path);
if (!info.exists()) {
return true;
}
if (!info.isDir()) {
qWarning() << "Attempted to delete contents of non-directory path:" << path;
return false;
}
bool ret = true;
for (const auto& entry : fs::directory_iterator(StringUtils::toStdString(path))) {
std::error_code err;
fs::remove_all(entry.path(), err);
if (err.value() != 0) {
qWarning().nospace() << "Could not delete directory entry " << entry.path() << ": " << QString::fromStdString(err.message());
ret = false;
}
}
return ret;
}
bool trash(QString path, QString* pathInTrash)
{
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
return false;
#else
// FIXME: Figure out trash in Flatpak. Qt seemingly doesn't use the Trash portal
if (DesktopServices::isFlatpak())
return false;
@ -720,6 +706,7 @@ bool trash(QString path, QString* pathInTrash)
return false;
#endif
return QFile::moveToTrash(path, pathInTrash);
#endif
}
QString PathCombine(const QString& path1, const QString& path2)
@ -753,7 +740,11 @@ int pathDepth(const QString& path)
QFileInfo info(path);
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
auto parts = QDir::toNativeSeparators(info.path()).split(QDir::separator(), QString::SkipEmptyParts);
#else
auto parts = QDir::toNativeSeparators(info.path()).split(QDir::separator(), Qt::SkipEmptyParts);
#endif
int numParts = parts.length();
numParts -= parts.count(".");
@ -773,7 +764,11 @@ QString pathTruncate(const QString& path, int depth)
return pathTruncate(trunc, depth);
}
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
auto parts = QDir::toNativeSeparators(trunc).split(QDir::separator(), QString::SkipEmptyParts);
#else
auto parts = QDir::toNativeSeparators(trunc).split(QDir::separator(), Qt::SkipEmptyParts);
#endif
if (parts.startsWith(".") && !path.startsWith(".")) {
parts.removeFirst();
@ -823,33 +818,68 @@ QString NormalizePath(QString path)
}
}
namespace {
const QString g_badChars = "<>:\"|?*\r\n!";
QString removeChars(QString source, QChar replace, const QString& extraChars = "")
{
auto badChars = g_badChars;
if (!extraChars.isEmpty()) {
badChars += extraChars;
}
static const QString BAD_WIN_CHARS = "<>:\"|?*\r\n";
static const QString BAD_NTFS_CHARS = "<>:\"|?*";
static const QString BAD_HFS_CHARS = ":";
for (auto& c : source) {
if (c.unicode() < 0x20 || !c.isPrint() || badChars.contains(c)) {
c = replace;
}
}
return source;
}
} // namespace
static const QString BAD_FILENAME_CHARS = BAD_WIN_CHARS + "\\/";
QString RemoveInvalidFilenameChars(QString string, QChar replaceWith)
{
return removeChars(std::move(string), replaceWith, "\\/");
for (int i = 0; i < string.length(); i++)
if (string.at(i) < ' ' || BAD_FILENAME_CHARS.contains(string.at(i)))
string[i] = replaceWith;
return string;
}
QString RemoveInvalidPathChars(QString string, QChar replaceWith)
QString RemoveInvalidPathChars(QString path, QChar replaceWith)
{
return removeChars(std::move(string), replaceWith);
QString invalidChars;
#ifdef Q_OS_WIN
invalidChars = BAD_WIN_CHARS;
#endif
// the null character is ignored in this check as it was not a problem until now
switch (statFS(path).fsType) {
case FilesystemType::FAT: // similar to NTFS
/* fallthrough */
case FilesystemType::NTFS:
/* fallthrough */
case FilesystemType::REFS: // similar to NTFS(should be available only on windows)
invalidChars += BAD_NTFS_CHARS;
break;
// case FilesystemType::EXT:
// case FilesystemType::EXT_2_OLD:
// case FilesystemType::EXT_2_3_4:
// case FilesystemType::XFS:
// case FilesystemType::BTRFS:
// case FilesystemType::NFS:
// case FilesystemType::ZFS:
case FilesystemType::APFS:
/* fallthrough */
case FilesystemType::HFS:
/* fallthrough */
case FilesystemType::HFSPLUS:
/* fallthrough */
case FilesystemType::HFSX:
invalidChars += BAD_HFS_CHARS;
break;
// case FilesystemType::FUSEBLK:
// case FilesystemType::F2FS:
// case FilesystemType::UNKNOWN:
default:
break;
}
if (invalidChars.size() != 0) {
for (int i = 0; i < path.length(); i++) {
if (path.at(i) < ' ' || invalidChars.contains(path.at(i))) {
path[i] = replaceWith;
}
}
}
return path;
}
QString DirNameFromString(QString string, QString inDir)
@ -885,70 +915,48 @@ QString getDesktopDir()
return QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
}
QString getApplicationsDir()
{
return QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation);
}
QString quoteArgs(const QStringList& args, const QString& wrap, const QString& escapeChar, bool wrapOnlyIfNeeded = false)
{
QString result;
auto size = args.size();
for (int i = 0; i < size; ++i) {
QString arg = args[i];
arg.replace(wrap, escapeChar);
bool needsWrapping = !wrapOnlyIfNeeded || arg.contains(' ') || arg.contains('\t') || arg.contains(wrap);
if (needsWrapping)
result += wrap + arg + wrap;
else
result += arg;
if (i < size - 1)
result += ' ';
}
return result;
}
// Cross-platform Shortcut creation
QString createShortcut(QString destination, QString target, QStringList args, QString name, QString icon)
bool createShortcut(QString destination, QString target, QStringList args, QString name, QString icon)
{
if (destination.isEmpty()) {
destination = PathCombine(getDesktopDir(), RemoveInvalidFilenameChars(name));
}
if (!ensureFilePathExists(destination)) {
qWarning() << "Destination path can't be created!";
return QString();
return false;
}
#if defined(Q_OS_MACOS)
QDir application = destination + ".app/";
// Create the Application
QDir applicationDirectory =
QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) + "/" + BuildConfig.LAUNCHER_NAME + " Instances/";
if (!applicationDirectory.mkpath(".")) {
qWarning() << "Couldn't create application directory";
return false;
}
QDir application = applicationDirectory.path() + "/" + name + ".app/";
if (application.exists()) {
qWarning() << "Application already exists!";
return QString();
return false;
}
if (!application.mkpath(".")) {
qWarning() << "Couldn't create application";
return QString();
return false;
}
QDir content = application.path() + "/Contents/";
QDir resources = content.path() + "/Resources/";
QDir binaryDir = content.path() + "/MacOS/";
QFile info(content.path() + "/Info.plist");
QFile info = content.path() + "/Info.plist";
if (!(content.mkpath(".") && resources.mkpath(".") && binaryDir.mkpath("."))) {
qWarning() << "Couldn't create directories within application";
return QString();
}
if (!info.open(QIODevice::WriteOnly | QIODevice::Text)) {
qWarning() << "Failed to open file" << info.fileName() << "for writing:" << info.errorString();
return QString();
return false;
}
info.open(QIODevice::WriteOnly | QIODevice::Text);
QFile(icon).rename(resources.path() + "/Icon.icns");
@ -956,13 +964,12 @@ QString createShortcut(QString destination, QString target, QStringList args, QS
QString exec = binaryDir.path() + "/Run.command";
QFile f(exec);
if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
qWarning() << "Failed to open file" << f.fileName() << "for writing:" << f.errorString();
return QString();
}
f.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream stream(&f);
auto argstring = quoteArgs(args, "\"", "\\\"");
QString argstring;
if (!args.empty())
argstring = " \"" + args.join("\" \"") + "\"";
stream << "#!/bin/bash" << "\n";
stream << "\"" << target << "\" " << argstring << "\n";
@ -996,23 +1003,22 @@ QString createShortcut(QString destination, QString target, QStringList args, QS
"</dict>\n"
"</plist>";
return application.path();
return true;
#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
if (!destination.endsWith(".desktop")) // in case of isFlatpak destination is already populated
destination += ".desktop";
QFile f(destination);
if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
qWarning() << "Failed to open file" << f.fileName() << "for writing:" << f.errorString();
return QString();
}
f.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream stream(&f);
auto argstring = quoteArgs(args, "'", "'\\''");
QString argstring;
if (!args.empty())
argstring = " '" + args.join("' '") + "'";
stream << "[Desktop Entry]" << "\n";
stream << "Type=Application" << "\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";
if (!icon.isEmpty()) {
stream << "Icon=" << icon.toLocal8Bit() << "\n";
@ -1023,38 +1029,51 @@ QString createShortcut(QString destination, QString target, QStringList args, QS
f.setPermissions(f.permissions() | QFileDevice::ExeOwner | QFileDevice::ExeGroup | QFileDevice::ExeOther);
return destination;
return true;
#elif defined(Q_OS_WIN)
QFileInfo targetInfo(target);
if (!targetInfo.exists()) {
qWarning() << "Target file does not exist!";
return QString();
return false;
}
target = targetInfo.absoluteFilePath();
if (target.length() >= MAX_PATH) {
qWarning() << "Target file path is too long!";
return QString();
return false;
}
if (!icon.isEmpty() && icon.length() >= MAX_PATH) {
qWarning() << "Icon path is too long!";
return QString();
return false;
}
destination += ".lnk";
if (destination.length() >= MAX_PATH) {
qWarning() << "Destination path is too long!";
return QString();
return false;
}
QString argStr;
int argCount = args.count();
for (int i = 0; i < argCount; i++) {
if (args[i].contains(' ')) {
argStr.append('"').append(args[i]).append('"');
} else {
argStr.append(args[i]);
}
if (i < argCount - 1) {
argStr.append(" ");
}
}
auto argStr = quoteArgs(args, "\"", "\\\"", true);
if (argStr.length() >= MAX_PATH) {
qWarning() << "Arguments string is too long!";
return QString();
return false;
}
HRESULT hres;
@ -1063,7 +1082,7 @@ QString createShortcut(QString destination, QString target, QStringList args, QS
hres = CoInitialize(nullptr);
if (FAILED(hres)) {
qWarning() << "Failed to initialize COM!";
return QString();
return false;
}
WCHAR wsz[MAX_PATH];
@ -1101,28 +1120,26 @@ QString createShortcut(QString destination, QString target, QStringList args, QS
hres = ppf->Save(wsz, TRUE);
if (FAILED(hres)) {
qWarning() << "IPresistFile->Save() failed";
qWarning() << "hres =" << hres;
qWarning() << "hres = " << hres;
}
ppf->Release();
} else {
qWarning() << "Failed to query IPersistFile interface from IShellLink instance";
qWarning() << "hres =" << hres;
qWarning() << "hres = " << hres;
}
psl->Release();
} else {
qWarning() << "Failed to create IShellLink instance";
qWarning() << "hres =" << hres;
qWarning() << "hres = " << hres;
}
// go away COM, nobody likes you
CoUninitialize();
if (SUCCEEDED(hres))
return destination;
return QString();
return SUCCEEDED(hres);
#else
qWarning("Desktop Shortcuts not supported on your platform!");
return QString();
return false;
#endif
}
@ -1278,8 +1295,8 @@ bool clone::operator()(const QString& offset, bool dryRun)
std::error_code err;
// Function that'll do the actual cloneing
auto cloneFile = [this, dryRun, dst, &err](QString src_path, QString relative_dst_path) {
if (m_matcher && (m_matcher(relative_dst_path) != m_whitelist))
auto cloneFile = [&](QString src_path, QString relative_dst_path) {
if (m_matcher && (m_matcher->matches(relative_dst_path) != m_whitelist))
return;
auto dst_path = PathCombine(dst, relative_dst_path);
@ -1400,14 +1417,14 @@ bool win_ioctl_clone(const std::wstring& src_path, const std::wstring& dst_path,
ULONG fs_flags;
if (!GetVolumeInformationByHandleW(hSourceFile, nullptr, 0, nullptr, nullptr, &fs_flags, nullptr, 0)) {
ec = std::error_code(GetLastError(), std::system_category());
qDebug() << "Failed to get Filesystem information for" << src_path.c_str();
qDebug() << "Failed to get Filesystem information for " << src_path.c_str();
CloseHandle(hSourceFile);
return false;
}
if (!(fs_flags & FILE_SUPPORTS_BLOCK_REFCOUNTING)) {
SetLastError(ERROR_NOT_CAPABLE);
ec = std::error_code(GetLastError(), std::system_category());
qWarning() << "Filesystem at" << src_path.c_str() << "does not support reflink";
qWarning() << "Filesystem at " << src_path.c_str() << " does not support reflink";
CloseHandle(hSourceFile);
return false;
}
@ -1703,14 +1720,4 @@ QString getUniqueResourceName(const QString& filePath)
return newFileName;
}
bool removeFiles(QStringList listFile)
{
bool ret = true;
// For each file
for (int i = 0; i < listFile.count(); i++) {
// Remove
ret = ret && QFile::remove(listFile.at(i));
}
return ret;
}
} // namespace FS

View file

@ -38,7 +38,7 @@
#pragma once
#include "Exception.h"
#include "Filter.h"
#include "pathmatcher/IPathMatcher.h"
#include <system_error>
@ -115,9 +115,9 @@ class copy : public QObject {
m_followSymlinks = follow;
return *this;
}
copy& matcher(Filter filter)
copy& matcher(const IPathMatcher* filter)
{
m_matcher = std::move(filter);
m_matcher = filter;
return *this;
}
copy& whitelist(bool whitelist)
@ -147,7 +147,7 @@ class copy : public QObject {
private:
bool m_followSymlinks = true;
Filter m_matcher = nullptr;
const IPathMatcher* m_matcher = nullptr;
bool m_whitelist = false;
bool m_overwrite = false;
QDir m_src;
@ -209,9 +209,9 @@ class create_link : public QObject {
m_useHardLinks = useHard;
return *this;
}
create_link& matcher(Filter filter)
create_link& matcher(const IPathMatcher* filter)
{
m_matcher = std::move(filter);
m_matcher = filter;
return *this;
}
create_link& whitelist(bool whitelist)
@ -260,7 +260,7 @@ class create_link : public QObject {
private:
bool m_useHardLinks = false;
Filter m_matcher = nullptr;
const IPathMatcher* m_matcher = nullptr;
bool m_whitelist = false;
bool m_recursive = true;
@ -291,15 +291,6 @@ bool move(const QString& source, const QString& dest);
*/
bool deletePath(QString path);
/**
* Delete a folder's contents recursively but not the folder itself.
* @param path The path to the folder.
* @return Whether the deletion was completely successful.
*/
bool deleteContents(const QString& path);
bool removeFiles(QStringList listFile);
/**
* Trash a folder / file
*/
@ -362,18 +353,14 @@ bool checkProblemticPathJava(QDir folder);
// Get the Directory representing the User's Desktop
QString getDesktopDir();
// Get the Directory representing the User's Applications directory
QString getApplicationsDir();
// Overrides one folder with the contents of another, preserving items exclusive to the first folder
// Equivalent to doing QDir::rename, but allowing for overrides
bool overrideFolder(QString overwritten_path, QString override_path);
/**
* Creates a shortcut to the specified target file at the specified destination path.
* Returns null QString if creation failed; otherwise returns the path to the created shortcut.
*/
QString createShortcut(QString destination, QString target, QStringList args, QString name, QString icon);
bool createShortcut(QString destination, QString target, QStringList args, QString name, QString icon);
enum class FilesystemType {
FAT,
@ -501,9 +488,9 @@ class clone : public QObject {
m_src.setPath(src);
m_dst.setPath(dst);
}
clone& matcher(Filter filter)
clone& matcher(const IPathMatcher* filter)
{
m_matcher = std::move(filter);
m_matcher = filter;
return *this;
}
clone& whitelist(bool whitelist)
@ -527,7 +514,7 @@ class clone : public QObject {
bool operator()(const QString& offset, bool dryRun = false);
private:
Filter m_matcher = nullptr;
const IPathMatcher* m_matcher = nullptr;
bool m_whitelist = false;
QDir m_src;
QDir m_dst;

37
launcher/Filter.cpp Normal file
View file

@ -0,0 +1,37 @@
#include "Filter.h"
ContainsFilter::ContainsFilter(const QString& pattern) : pattern(pattern) {}
bool ContainsFilter::accepts(const QString& value)
{
return value.contains(pattern);
}
ExactFilter::ExactFilter(const QString& pattern) : pattern(pattern) {}
bool ExactFilter::accepts(const QString& value)
{
return value == pattern;
}
ExactIfPresentFilter::ExactIfPresentFilter(const QString& pattern) : pattern(pattern) {}
bool ExactIfPresentFilter::accepts(const QString& value)
{
return value.isEmpty() || value == pattern;
}
RegexpFilter::RegexpFilter(const QString& regexp, bool invert) : invert(invert)
{
pattern.setPattern(regexp);
pattern.optimize();
}
bool RegexpFilter::accepts(const QString& value)
{
auto match = pattern.match(value);
bool matched = match.hasMatch();
return invert ? (!matched) : (matched);
}
ExactListFilter::ExactListFilter(const QStringList& pattern) : m_pattern(pattern) {}
bool ExactListFilter::accepts(const QString& value)
{
return m_pattern.isEmpty() || m_pattern.contains(value);
}

View file

@ -3,52 +3,59 @@
#include <QRegularExpression>
#include <QString>
using Filter = std::function<bool(const QString&)>;
class Filter {
public:
virtual ~Filter() = default;
virtual bool accepts(const QString& value) = 0;
};
namespace Filters {
inline Filter inverse(Filter filter)
{
return [filter = std::move(filter)](const QString& src) { return !filter(src); };
}
class ContainsFilter : public Filter {
public:
ContainsFilter(const QString& pattern);
virtual ~ContainsFilter() = default;
bool accepts(const QString& value) override;
inline Filter any(QList<Filter> filters)
{
return [filters = std::move(filters)](const QString& src) {
for (auto& filter : filters)
if (filter(src))
return true;
private:
QString pattern;
};
return false;
};
}
class ExactFilter : public Filter {
public:
ExactFilter(const QString& pattern);
virtual ~ExactFilter() = default;
bool accepts(const QString& value) override;
inline Filter equals(QString pattern)
{
return [pattern = std::move(pattern)](const QString& src) { return src == pattern; };
}
private:
QString pattern;
};
inline Filter equalsAny(QStringList patterns = {})
{
return [patterns = std::move(patterns)](const QString& src) { return patterns.isEmpty() || patterns.contains(src); };
}
class ExactIfPresentFilter : public Filter {
public:
ExactIfPresentFilter(const QString& pattern);
virtual ~ExactIfPresentFilter() override = default;
bool accepts(const QString& value) override;
inline Filter equalsOrEmpty(QString pattern)
{
return [pattern = std::move(pattern)](const QString& src) { return src.isEmpty() || src == pattern; };
}
private:
QString pattern;
};
inline Filter contains(QString pattern)
{
return [pattern = std::move(pattern)](const QString& src) { return src.contains(pattern); };
}
class RegexpFilter : public Filter {
public:
RegexpFilter(const QString& regexp, bool invert);
virtual ~RegexpFilter() = default;
bool accepts(const QString& value) override;
inline Filter startsWith(QString pattern)
{
return [pattern = std::move(pattern)](const QString& src) { return src.startsWith(pattern); };
}
private:
QRegularExpression pattern;
bool invert = false;
};
inline Filter regexp(QRegularExpression pattern)
{
return [pattern = std::move(pattern)](const QString& src) { return pattern.match(src).hasMatch(); };
}
} // namespace Filters
class ExactListFilter : public Filter {
public:
ExactListFilter(const QStringList& pattern = {});
virtual ~ExactListFilter() = default;
bool accepts(const QString& value) override;
private:
QStringList m_pattern;
};

View file

@ -36,8 +36,6 @@
#include "GZip.h"
#include <zlib.h>
#include <QByteArray>
#include <QDebug>
#include <QFile>
bool GZip::unzip(const QByteArray& compressedBytes, QByteArray& uncompressedBytes)
{
@ -138,82 +136,3 @@ bool GZip::zip(const QByteArray& uncompressedBytes, QByteArray& compressedBytes)
}
return true;
}
int inf(QFile* source, std::function<bool(const QByteArray&)> handleBlock)
{
constexpr auto CHUNK = 16384;
int ret;
unsigned have;
z_stream strm;
memset(&strm, 0, sizeof(strm));
char in[CHUNK];
unsigned char out[CHUNK];
ret = inflateInit2(&strm, (16 + MAX_WBITS));
if (ret != Z_OK)
return ret;
/* decompress until deflate stream ends or end of file */
do {
strm.avail_in = source->read(in, CHUNK);
if (source->error()) {
(void)inflateEnd(&strm);
return Z_ERRNO;
}
if (strm.avail_in == 0)
break;
strm.next_in = reinterpret_cast<Bytef*>(in);
/* run inflate() on input until output buffer not full */
do {
strm.avail_out = CHUNK;
strm.next_out = out;
ret = inflate(&strm, Z_NO_FLUSH);
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
switch (ret) {
case Z_NEED_DICT:
ret = Z_DATA_ERROR;
[[fallthrough]];
case Z_DATA_ERROR:
case Z_MEM_ERROR:
(void)inflateEnd(&strm);
return ret;
}
have = CHUNK - strm.avail_out;
if (!handleBlock(QByteArray(reinterpret_cast<const char*>(out), have))) {
(void)inflateEnd(&strm);
return Z_OK;
}
} while (strm.avail_out == 0);
/* done when inflate() says it's done */
} while (ret != Z_STREAM_END);
/* clean up and return */
(void)inflateEnd(&strm);
return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
}
QString zerr(int ret)
{
switch (ret) {
case Z_ERRNO:
return QObject::tr("error handling file");
case Z_STREAM_ERROR:
return QObject::tr("invalid compression level");
case Z_DATA_ERROR:
return QObject::tr("invalid or incomplete deflate data");
case Z_MEM_ERROR:
return QObject::tr("out of memory");
case Z_VERSION_ERROR:
return QObject::tr("zlib version mismatch!");
}
return {};
}
QString GZip::readGzFileByBlocks(QFile* source, std::function<bool(const QByteArray&)> handleBlock)
{
auto ret = inf(source, handleBlock);
return zerr(ret);
}

View file

@ -1,11 +1,8 @@
#pragma once
#include <QByteArray>
#include <QFile>
namespace GZip {
bool unzip(const QByteArray& compressedBytes, QByteArray& uncompressedBytes);
bool zip(const QByteArray& uncompressedBytes, QByteArray& compressedBytes);
QString readGzFileByBlocks(QFile* source, std::function<bool(const QByteArray&)> handleBlock);
} // namespace GZip
class GZip {
public:
static bool unzip(const QByteArray& compressedBytes, QByteArray& uncompressedBytes);
static bool zip(const QByteArray& uncompressedBytes, QByteArray& compressedBytes);
};

View file

@ -1,355 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2026 Octol1ttle <l1ttleofficial@outlook.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "HardwareInfo.h"
#include <QDebug>
#include <QStringList>
#if defined(Q_OS_MACOS) || defined(Q_OS_LINUX)
namespace {
QString afterColon(QString str)
{
return str.remove(0, str.indexOf(':') + 2).trimmed();
}
template <typename F>
bool readFromOutput(const char* command, F function)
{
FILE* file = popen(command, "r"); // NOLINT(*-command-processor)
if (!file) {
qWarning().nospace() << "Could not execute command '" << command << "': " << strerror(errno);
return false;
}
constexpr size_t bufferSize = 512;
std::array<char, bufferSize> buffer{};
while (fgets(buffer.data(), bufferSize, file) != nullptr) {
function(buffer.data());
}
const int exitCode = pclose(file);
if (exitCode != 0) {
if (exitCode == -1) {
qWarning().nospace() << "Could not close stream for command '" << command << "': " << strerror(errno);
} else {
qWarning().nospace() << "Command '" << command << "' exited with code " << exitCode;
}
return false;
}
return true;
}
} // namespace
#endif
#ifdef Q_OS_WINDOWS
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <QSettings>
#include <dxgi1_6.h>
#include <windows.h>
#include <wrl/client.h>
using Microsoft::WRL::ComPtr;
QString HardwareInfo::cpuInfo()
{
const QSettings registry(R"(HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessor\0)", QSettings::NativeFormat);
return registry.value("ProcessorNameString").toString();
}
uint64_t HardwareInfo::totalRamMiB()
{
MEMORYSTATUSEX status;
status.dwLength = sizeof status;
if (GlobalMemoryStatusEx(&status) == TRUE) {
// transforming bytes -> mib
return status.ullTotalPhys / 1024 / 1024;
}
qWarning() << "Could not get total RAM: GlobalMemoryStatusEx";
return 0;
}
uint64_t HardwareInfo::availableRamMiB()
{
MEMORYSTATUSEX status;
status.dwLength = sizeof status;
if (GlobalMemoryStatusEx(&status) == TRUE) {
// transforming bytes -> mib
return status.ullAvailPhys / 1024 / 1024;
}
qWarning() << "Could not get available RAM: GlobalMemoryStatusEx";
return 0;
}
QStringList HardwareInfo::gpuInfo()
{
ComPtr<IDXGIFactory6> factory;
HRESULT hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory));
if (FAILED(hr)) {
qWarning() << "Could not create DXGI factory:" << Qt::hex << hr;
return { "GPU discovery failed: could not create DXGI factory" };
}
UINT i = 0;
ComPtr<IDXGIAdapter> adapter;
QStringList out;
while (factory->EnumAdapterByGpuPreference(i, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, IID_PPV_ARGS(&adapter)) != DXGI_ERROR_NOT_FOUND) {
DXGI_ADAPTER_DESC desc;
hr = adapter->GetDesc(&desc);
if (SUCCEEDED(hr)) {
out << "GPU: " + QString::fromWCharArray(desc.Description); // NOLINT(*-pro-bounds-array-to-pointer-decay, *-no-array-decay)
} else {
qWarning() << "Could not get DXGI adapter description:" << Qt::hex << hr;
}
++i;
}
return out;
}
#elif defined(Q_OS_MACOS)
#include "sys/sysctl.h"
QString HardwareInfo::cpuInfo()
{
std::array<char, 512> buffer{};
size_t bufferSize = buffer.size();
if (sysctlbyname("machdep.cpu.brand_string", &buffer, &bufferSize, nullptr, 0) == 0) {
return { buffer.data() };
}
qWarning() << "Could not get CPU model: sysctlbyname";
return "";
}
uint64_t HardwareInfo::totalRamMiB()
{
uint64_t memsize = 0;
size_t memsizeSize = sizeof memsize;
if (sysctlbyname("hw.memsize", &memsize, &memsizeSize, nullptr, 0) == 0) {
// transforming bytes -> mib
return memsize / 1024 / 1024;
}
qWarning() << "Could not get total RAM: sysctlbyname";
return 0;
}
uint64_t HardwareInfo::availableRamMiB()
{
return 0;
}
MacOSHardwareInfo::MemoryPressureLevel MacOSHardwareInfo::memoryPressureLevel()
{
uint32_t level = 0;
size_t levelSize = sizeof level;
if (sysctlbyname("kern.memorystatus_vm_pressure_level", &level, &levelSize, nullptr, 0) == 0) {
return static_cast<MemoryPressureLevel>(level);
}
qWarning() << "Could not get memory pressure level: sysctlbyname";
return MemoryPressureLevel::Normal;
}
QString MacOSHardwareInfo::memoryPressureLevelName()
{
// The names are internal, users refer to levels by their graph colors in Activity Monitor
switch (memoryPressureLevel()) {
case MemoryPressureLevel::Normal:
return "Green";
case MemoryPressureLevel::Warning:
return "Yellow";
case MemoryPressureLevel::Critical:
return "Red";
default:
Q_ASSERT(false);
return "";
}
}
QStringList HardwareInfo::gpuInfo()
{
QStringList out;
const bool success = readFromOutput("system_profiler SPDisplaysDataType", [&](const QString& str) {
// Chipset Model: Intel HD Graphics 620
if (str.contains("Chipset Model")) {
out << "GPU: " + afterColon(str);
}
});
if (!success) {
return { "GPU discovery failed: could not read from system_profiler" };
}
return out;
}
#elif defined(Q_OS_LINUX)
#include <fstream>
QString HardwareInfo::cpuInfo()
{
std::ifstream cpuin("/proc/cpuinfo");
for (std::string line; std::getline(cpuin, line);) {
// model name : AMD Ryzen 7 5800X 8-Core Processor
if (const QString str = QString::fromStdString(line); str.startsWith("model name")) {
return afterColon(str);
}
}
qWarning() << "Could not get CPU model: /proc/cpuinfo";
return "unknown";
}
namespace {
uint64_t readMemInfo(const QString& searchTarget)
{
std::ifstream memin("/proc/meminfo");
for (std::string line; std::getline(memin, line);) {
// MemTotal: 16287480 kB
if (const QString str = QString::fromStdString(line); str.startsWith(searchTarget)) {
bool ok = false;
const uint total = str.simplified().section(' ', 1, 1).toUInt(&ok);
if (!ok) {
qWarning() << "Could not read /proc/meminfo: failed to parse string:" << str;
return 0;
}
// transforming kib -> mib
return total / 1024;
}
}
qWarning() << "Could not read /proc/meminfo: search target not found:" << searchTarget;
return 0;
}
} // namespace
uint64_t HardwareInfo::totalRamMiB()
{
return readMemInfo("MemTotal");
}
uint64_t HardwareInfo::availableRamMiB()
{
return readMemInfo("MemAvailable");
}
QStringList HardwareInfo::gpuInfo()
{
bool readingGpuInfo = false;
QString gpu;
QString driverInUse = "NONE";
QString driversAvailable = "NONE";
QStringList out;
const bool success = readFromOutput("lspci -k", [&](const QString& str) {
// clang-format off
// 04:00.0 VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Ellesmere [Radeon RX 470/480/570/570X/580/580X/590] (rev e7)
// Subsystem: Sapphire Technology Limited Radeon RX 580 Pulse 4GB
// Kernel driver in use: amdgpu
// Kernel modules: amdgpu
// clang-format on
if (str.contains("VGA compatible controller") || str.contains("3D controller")) {
readingGpuInfo = true;
} else if (!str.startsWith('\t')) {
if (readingGpuInfo) {
out << QString("GPU: %1 (driver in use: %2; drivers available: %3)").arg(gpu, driverInUse, driversAvailable);
driverInUse = "NONE";
driversAvailable = "NONE";
}
readingGpuInfo = false;
}
if (!readingGpuInfo) {
return;
}
const QString value = afterColon(str);
if (str.contains("Subsystem")) {
gpu = value;
}
if (str.contains("Kernel driver in use")) {
driverInUse = value;
}
if (str.contains("Kernel modules")) {
driversAvailable = value;
}
});
if (!success) {
return { "GPU discovery failed: could not read from lspci" };
}
return out;
}
#else
QString HardwareInfo::cpuInfo()
{
return "unknown";
}
#if defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
#include <cstdio>
uint64_t HardwareInfo::totalRamMiB()
{
uint64_t out = 0;
const bool success = readFromOutput("sysctl hw.physmem", [&](const QString& str) {
const uint64_t mem = str.mid(12).toULong();
// transforming kib -> mib
out = mem / 1024;
});
if (!success) {
qWarning() << "Could not get total RAM: could not read from sysctl";
return 0;
}
return out;
}
#else
uint64_t HardwareInfo::totalRamMiB()
{
return 0;
}
#endif
uint64_t HardwareInfo::availableRamMiB()
{
return 0;
}
QStringList HardwareInfo::gpuInfo()
{
return { "GPU discovery failed: not implemented for this OS" };
}
#endif

View file

@ -1,42 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2026 Octol1ttle <l1ttleofficial@outlook.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <QString>
#include <cstdint>
namespace HardwareInfo {
QString cpuInfo();
uint64_t totalRamMiB();
uint64_t availableRamMiB();
QStringList gpuInfo();
} // namespace HardwareInfo
#ifdef Q_OS_MACOS
namespace MacOSHardwareInfo {
enum class MemoryPressureLevel : uint8_t {
Normal = 1,
Warning = 2,
Critical = 4,
};
MemoryPressureLevel memoryPressureLevel();
QString memoryPressureLevelName();
} // namespace MacOSHardwareInfo
#endif

View file

@ -189,4 +189,4 @@ void InstanceCopyPrefs::enableDontLinkSaves(bool b)
void InstanceCopyPrefs::enableUseClone(bool b)
{
useClone = b;
}
}

View file

@ -8,23 +8,23 @@
struct InstanceCopyPrefs {
public:
bool allTrue() const;
QString getSelectedFiltersAsRegex() const;
QString getSelectedFiltersAsRegex(const QStringList& additionalFilters) const;
[[nodiscard]] bool allTrue() const;
[[nodiscard]] QString getSelectedFiltersAsRegex() const;
[[nodiscard]] QString getSelectedFiltersAsRegex(const QStringList& additionalFilters) const;
// Getters
bool isCopySavesEnabled() const;
bool isKeepPlaytimeEnabled() const;
bool isCopyGameOptionsEnabled() const;
bool isCopyResourcePacksEnabled() const;
bool isCopyShaderPacksEnabled() const;
bool isCopyServersEnabled() const;
bool isCopyModsEnabled() const;
bool isCopyScreenshotsEnabled() const;
bool isUseSymLinksEnabled() const;
bool isLinkRecursivelyEnabled() const;
bool isUseHardLinksEnabled() const;
bool isDontLinkSavesEnabled() const;
bool isUseCloneEnabled() const;
[[nodiscard]] bool isCopySavesEnabled() const;
[[nodiscard]] bool isKeepPlaytimeEnabled() const;
[[nodiscard]] bool isCopyGameOptionsEnabled() const;
[[nodiscard]] bool isCopyResourcePacksEnabled() const;
[[nodiscard]] bool isCopyShaderPacksEnabled() const;
[[nodiscard]] bool isCopyServersEnabled() const;
[[nodiscard]] bool isCopyModsEnabled() const;
[[nodiscard]] bool isCopyScreenshotsEnabled() const;
[[nodiscard]] bool isUseSymLinksEnabled() const;
[[nodiscard]] bool isLinkRecursivelyEnabled() const;
[[nodiscard]] bool isUseHardLinksEnabled() const;
[[nodiscard]] bool isDontLinkSavesEnabled() const;
[[nodiscard]] bool isUseCloneEnabled() const;
// Setters
void enableCopySaves(bool b);
void enableKeepPlaytime(bool b);

View file

@ -3,12 +3,12 @@
#include <QtConcurrentRun>
#include <memory>
#include "FileSystem.h"
#include "Filter.h"
#include "NullInstance.h"
#include "pathmatcher/RegexpMatcher.h"
#include "settings/INISettingsObject.h"
#include "tasks/Task.h"
InstanceCopyTask::InstanceCopyTask(BaseInstance* origInstance, const InstanceCopyPrefs& prefs)
InstanceCopyTask::InstanceCopyTask(InstancePtr origInstance, const InstanceCopyPrefs& prefs)
{
m_origInstance = origInstance;
m_keepPlaytime = prefs.isKeepPlaytimeEnabled();
@ -30,8 +30,9 @@ InstanceCopyTask::InstanceCopyTask(BaseInstance* origInstance, const InstanceCop
if (!filters.isEmpty()) {
// Set regex filter:
// FIXME: get this from the original instance type...
QRegularExpression regexp(filters, QRegularExpression::CaseInsensitiveOption);
m_matcher = Filters::regexp(regexp);
auto matcherReal = new RegexpMatcher(filters);
matcherReal->caseSensitive(false);
m_matcher.reset(matcherReal);
}
}
@ -42,7 +43,7 @@ void InstanceCopyTask::executeTask()
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [this] {
if (m_useClone) {
FS::clone folderClone(m_origInstance->instanceRoot(), m_stagingPath);
folderClone.matcher(m_matcher);
folderClone.matcher(m_matcher.get());
folderClone(true);
setProgress(0, folderClone.totalCloned());
@ -64,13 +65,14 @@ void InstanceCopyTask::executeTask()
savesCopy = std::make_unique<FS::copy>(FS::PathCombine(m_origInstance->gameRoot(), "saves"),
FS::PathCombine(staging_mc_dir, "saves"));
savesCopy->followSymlinks(true);
(*savesCopy)(true);
setProgress(0, savesCopy->totalCopied());
connect(savesCopy.get(), &FS::copy::fileCopied, [this](QString src) { setProgress(m_progress + 1, m_progressTotal); });
}
FS::create_link folderLink(m_origInstance->instanceRoot(), m_stagingPath);
int depth = m_linkRecursively ? -1 : 0; // we need to at least link the top level instead of the instance folder
folderLink.linkRecursively(true).setMaxDepth(depth).useHardLinks(m_useHardLinks).matcher(m_matcher);
folderLink.linkRecursively(true).setMaxDepth(depth).useHardLinks(m_useHardLinks).matcher(m_matcher.get());
folderLink(true);
setProgress(0, m_progressTotal + folderLink.totalToLink());
@ -89,7 +91,7 @@ void InstanceCopyTask::executeTask()
QEventLoop loop;
bool got_priv_results = false;
connect(&folderLink, &FS::create_link::finishedPrivileged, this, [&got_priv_results, &loop](bool gotResults) {
connect(&folderLink, &FS::create_link::finishedPrivileged, this, [&](bool gotResults) {
if (!gotResults) {
qDebug() << "Privileged run exited without results!";
}
@ -125,11 +127,11 @@ void InstanceCopyTask::executeTask()
return !there_were_errors;
}
FS::copy folderCopy(m_origInstance->instanceRoot(), m_stagingPath);
folderCopy.matcher(m_matcher);
folderCopy.followSymlinks(false).matcher(m_matcher.get());
folderCopy(true);
setProgress(0, folderCopy.totalCopied());
connect(&folderCopy, &FS::copy::fileCopied, [this]() { setProgress(m_progress + 1, m_progressTotal); });
connect(&folderCopy, &FS::copy::fileCopied, [this](QString src) { setProgress(m_progress + 1, m_progressTotal); });
return folderCopy();
});
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &InstanceCopyTask::copyFinished);
@ -146,9 +148,9 @@ void InstanceCopyTask::copyFinished()
}
// FIXME: shouldn't this be able to report errors?
auto instanceSettings = std::make_unique<INISettingsObject>(FS::PathCombine(m_stagingPath, "instance.cfg"));
auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(m_stagingPath, "instance.cfg"));
BaseInstance* inst(new NullInstance(m_globalSettings, std::move(instanceSettings), m_stagingPath));
InstancePtr inst(new NullInstance(m_globalSettings, instanceSettings, m_stagingPath));
inst->setName(name());
inst->setIconKey(m_instIcon);
if (!m_keepPlaytime) {
@ -196,4 +198,4 @@ bool InstanceCopyTask::abort()
return true;
}
return false;
}
}

View file

@ -5,7 +5,6 @@
#include <QUrl>
#include "BaseInstance.h"
#include "BaseVersion.h"
#include "Filter.h"
#include "InstanceCopyPrefs.h"
#include "InstanceTask.h"
#include "net/NetJob.h"
@ -15,7 +14,7 @@
class InstanceCopyTask : public InstanceTask {
Q_OBJECT
public:
explicit InstanceCopyTask(BaseInstance* origInstance, const InstanceCopyPrefs& prefs);
explicit InstanceCopyTask(InstancePtr origInstance, const InstanceCopyPrefs& prefs);
protected:
//! Entry point for tasks.
@ -26,10 +25,10 @@ class InstanceCopyTask : public InstanceTask {
private:
/* data */
BaseInstance* m_origInstance;
InstancePtr m_origInstance;
QFuture<bool> m_copyFuture;
QFutureWatcher<bool> m_copyFutureWatcher;
Filter m_matcher;
std::unique_ptr<IPathMatcher> m_matcher;
bool m_keepPlaytime;
bool m_useLinks = false;
bool m_useHardLinks = false;

View file

@ -2,25 +2,7 @@
#include <QDebug>
#include <QFile>
#include "Application.h"
#include "InstanceTask.h"
#include "minecraft/MinecraftLoadAndCheck.h"
#include "tasks/SequentialTask.h"
bool InstanceCreationTask::abort()
{
if (!canAbort()) {
return false;
}
m_abort = true;
if (m_gameFilesTask) {
return m_gameFilesTask->abort();
}
return InstanceTask::abort();
}
#include "FileSystem.h"
void InstanceCreationTask::executeTask()
{
@ -37,15 +19,13 @@ void InstanceCreationTask::executeTask()
return;
}
m_instance = createInstance();
if (!m_instance) {
if (m_abort) {
if (!createInstance()) {
if (m_abort)
return;
}
qWarning() << "Instance creation failed!";
if (!m_error_message.isEmpty()) {
qWarning() << "Reason:" << m_error_message;
qWarning() << "Reason: " << m_error_message;
emitFailed(tr("Error while creating new instance:\n%1").arg(m_error_message));
} else {
emitFailed(tr("Error while creating new instance."));
@ -64,10 +44,9 @@ void InstanceCreationTask::executeTask()
setStatus(tr("Removing old conflicting files..."));
qDebug() << "Removing old files";
for (const QString& path : m_filesToRemove) {
if (!QFile::exists(path)) {
for (const QString& path : m_files_to_remove) {
if (!QFile::exists(path))
continue;
}
qDebug() << "Removing" << path;
@ -82,61 +61,6 @@ void InstanceCreationTask::executeTask()
return;
}
}
if (!m_abort) {
if (!APPLICATION->settings()->get("DownloadGameFilesDuringInstanceCreation").toBool()) {
emitSucceeded();
return;
}
setAbortable(true);
setAbortButtonText(tr("Skip"));
qDebug() << "Downloading game files";
auto updateTasks = m_instance->createUpdateTask();
if (updateTasks.isEmpty()) {
emitSucceeded();
return;
}
auto task = makeShared<SequentialTask>();
task->addTask(makeShared<MinecraftLoadAndCheck>(m_instance.get(), Net::Mode::Online));
for (const auto& t : updateTasks) {
task->addTask(t);
}
connect(task.get(), &Task::finished, this, [this, task] {
if (task->wasSuccessful() || m_abort) {
emitSucceeded();
} else {
emitFailed(tr("Could not download game files: %1").arg(task->failReason()));
}
});
propagateFromOther(task.get());
setDetails(tr("Downloading game files"));
m_gameFilesTask = task;
m_gameFilesTask->start();
}
}
void InstanceCreationTask::scheduleToDelete(QWidget* parent, const QDir& dir, const QString& path, bool checkDisabled)
{
if (path.isEmpty()) {
return;
}
if (path.startsWith("saves/")) {
if (m_shouldDeleteSaves == ShouldDeleteSaves::NotAsked) {
m_shouldDeleteSaves = askIfShouldDeleteSaves(parent);
}
if (m_shouldDeleteSaves == ShouldDeleteSaves::No) {
return;
}
}
qDebug() << "Scheduling" << path << "for removal";
m_filesToRemove.append(dir.absoluteFilePath(path));
if (checkDisabled) {
if (path.endsWith(".disabled")) { // remove it if it was enabled/disabled by user
m_filesToRemove.append(dir.absoluteFilePath(path.chopped(9)));
} else {
m_filesToRemove.append(dir.absoluteFilePath(path + ".disabled"));
}
}
if (!m_abort)
emitSucceeded();
}

View file

@ -2,7 +2,6 @@
#include "BaseVersion.h"
#include "InstanceTask.h"
#include "minecraft/MinecraftInstance.h"
class InstanceCreationTask : public InstanceTask {
Q_OBJECT
@ -10,8 +9,6 @@ class InstanceCreationTask : public InstanceTask {
InstanceCreationTask() = default;
virtual ~InstanceCreationTask() = default;
bool abort() override;
protected:
void executeTask() final override;
@ -30,24 +27,20 @@ class InstanceCreationTask : public InstanceTask {
/**
* Creates a new instance.
*
* Returns the instance if it was created or nullptr otherwise.
* Returns whether the instance creation was successful (true) or not (false).
*/
virtual std::unique_ptr<MinecraftInstance> createInstance() { return nullptr; }
virtual bool createInstance() { return false; };
QString getError() const { return m_error_message; }
protected:
void setError(const QString& message) { m_error_message = message; };
void scheduleToDelete(QWidget* parent, const QDir& dir, const QString& path, bool checkDisabled = false);
protected:
bool m_abort = false;
QStringList m_filesToRemove;
ShouldDeleteSaves m_shouldDeleteSaves;
QStringList m_files_to_remove;
private:
QString m_error_message;
std::unique_ptr<MinecraftInstance> m_instance;
Task::Ptr m_gameFilesTask;
};

View file

@ -1,126 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft Launcher
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "InstanceDirUpdate.h"
#include <QCheckBox>
#include "Application.h"
#include "FileSystem.h"
#include "InstanceList.h"
#include "ui/dialogs/CustomMessageBox.h"
QString askToUpdateInstanceDirName(BaseInstance* instance, const QString& oldName, const QString& newName, QWidget* parent)
{
if (oldName == newName)
return QString();
QString renamingMode = APPLICATION->settings()->get("InstRenamingMode").toString();
if (renamingMode == "MetadataOnly")
return QString();
auto oldRoot = instance->instanceRoot();
auto newDirName = FS::DirNameFromString(newName, QFileInfo(oldRoot).dir().absolutePath());
auto newRoot = FS::PathCombine(QFileInfo(oldRoot).dir().absolutePath(), newDirName);
if (oldRoot == newRoot)
return QString();
if (oldRoot == FS::PathCombine(QFileInfo(oldRoot).dir().absolutePath(), newName))
return QString();
// Check for conflict
if (QDir(newRoot).exists()) {
QMessageBox::warning(parent, QObject::tr("Cannot rename instance"),
QObject::tr("New instance root (%1) already exists. <br />Only the metadata will be renamed.").arg(newRoot));
return QString();
}
// Ask if we should rename
if (renamingMode == "AskEverytime") {
auto checkBox = new QCheckBox(QObject::tr("&Remember my choice"), parent);
auto dialog =
CustomMessageBox::selectable(parent, QObject::tr("Rename instance folder"),
QObject::tr("Would you also like to rename the instance folder?\n\n"
"Old name: %1\n"
"New name: %2")
.arg(oldName, newName),
QMessageBox::Question, QMessageBox::No | QMessageBox::Yes, QMessageBox::NoButton, checkBox);
auto res = dialog->exec();
if (checkBox->isChecked()) {
if (res == QMessageBox::Yes)
APPLICATION->settings()->set("InstRenamingMode", "PhysicalDir");
else
APPLICATION->settings()->set("InstRenamingMode", "MetadataOnly");
}
if (res == QMessageBox::No)
return QString();
}
// Check for linked instances
if (!checkLinkedInstances(instance->id(), parent, QObject::tr("Renaming")))
return QString();
// Now we can confirm that a renaming is happening
if (!instance->syncInstanceDirName(newRoot)) {
QMessageBox::warning(parent, QObject::tr("Cannot rename instance"),
QObject::tr("An error occurred when performing the following renaming operation: <br/>"
" - Old instance root: %1<br/>"
" - New instance root: %2<br/>"
"Only the metadata is renamed.")
.arg(oldRoot, newRoot));
return QString();
}
return newRoot;
}
bool checkLinkedInstances(const QString& id, QWidget* parent, const QString& verb)
{
auto linkedInstances = APPLICATION->instances()->getLinkedInstancesById(id);
if (!linkedInstances.empty()) {
auto response = CustomMessageBox::selectable(parent, QObject::tr("There are linked instances"),
QObject::tr("The following instance(s) might reference files in this instance:\n\n"
"%1\n\n"
"%2 it could break the other instance(s), \n\n"
"Do you wish to proceed?",
nullptr, linkedInstances.count())
.arg(linkedInstances.join("\n"))
.arg(verb),
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
->exec();
if (response != QMessageBox::Yes)
return false;
}
return true;
}

View file

@ -1,43 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft Launcher
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "BaseInstance.h"
/// Update instanceRoot to make it sync with name/id; return newRoot if a directory rename happened
QString askToUpdateInstanceDirName(BaseInstance* instance, const QString& oldName, const QString& newName, QWidget* parent);
/// Check if there are linked instances, and display a warning; return true if the operation should proceed
bool checkLinkedInstances(const QString& id, QWidget* parent, const QString& verb);

View file

@ -38,11 +38,10 @@
#include "Application.h"
#include "FileSystem.h"
#include "MMCZip.h"
#include "NullInstance.h"
#include "QObjectPtr.h"
#include "archive/ArchiveReader.h"
#include "archive/ExtractZipTask.h"
#include "icons/IconList.h"
#include "icons/IconUtils.h"
@ -55,10 +54,12 @@
#include "net/ApiDownload.h"
#include <QFileInfo>
#include <QtConcurrentRun>
#include <algorithm>
#include <memory>
#include <quazip/quazipdir.h>
InstanceImportTask::InstanceImportTask(const QUrl& sourceUrl, QWidget* parent, QMap<QString, QString>&& extra_info)
: m_sourceUrl(sourceUrl), m_extra_info(extra_info), m_parent(parent)
{}
@ -71,6 +72,7 @@ bool InstanceImportTask::abort()
bool wasAborted = false;
if (m_task)
wasAborted = m_task->abort();
Task::abort();
return wasAborted;
}
@ -108,14 +110,39 @@ void InstanceImportTask::downloadFromUrl()
filesNetJob->start();
}
QString cleanPath(QString path)
QString InstanceImportTask::getRootFromZip(QuaZip* zip, const QString& root)
{
if (path == ".")
return QString();
QString result = path;
if (result.startsWith("./"))
result = result.mid(2);
return result;
if (!isRunning()) {
return {};
}
QuaZipDir rootDir(zip, root);
for (auto&& fileName : rootDir.entryList(QDir::Files)) {
setDetails(fileName);
if (fileName == "instance.cfg") {
qDebug() << "MultiMC:" << true;
m_modpackType = ModpackType::MultiMC;
return root;
}
if (fileName == "manifest.json") {
qDebug() << "Flame:" << true;
m_modpackType = ModpackType::Flame;
return root;
}
QCoreApplication::processEvents();
}
// Recurse the search to non-ignored subfolders
for (auto&& fileName : rootDir.entryList(QDir::Dirs)) {
if ("overrides/" == fileName)
continue;
QString result = getRootFromZip(zip, root + fileName);
if (!result.isEmpty())
return result;
}
return {};
}
void InstanceImportTask::processZipPack()
@ -125,47 +152,33 @@ void InstanceImportTask::processZipPack()
qDebug() << "Attempting to create instance from" << m_archivePath;
// open the zip and find relevant files in it
MMCZip::ArchiveReader packZip(m_archivePath);
auto packZip = std::make_shared<QuaZip>(m_archivePath);
if (!packZip->open(QuaZip::mdUnzip)) {
emitFailed(tr("Unable to open supplied modpack zip file."));
return;
}
QuaZipDir packZipDir(packZip.get());
qDebug() << "Attempting to determine instance type";
QString root;
// NOTE: Prioritize modpack platforms that aren't searched for recursively.
// Especially Flame has a very common filename for its manifest, which may appear inside overrides for example
// https://docs.modrinth.com/docs/modpacks/format_definition/#storage
auto detectInstance = [this, &extractDir, &root](MMCZip::ArchiveReader::File* f, bool& stop) {
if (!isRunning()) {
stop = true;
return true;
}
auto fileName = f->filename();
if (fileName == "modrinth.index.json") {
// process as Modrinth pack
qDebug() << "Modrinth:" << true;
m_modpackType = ModpackType::Modrinth;
stop = true;
} else if (fileName == "bin/modpack.jar" || fileName == "bin/version.json") {
// process as Technic pack
qDebug() << "Technic:" << true;
extractDir.mkpath("minecraft");
extractDir.cd("minecraft");
m_modpackType = ModpackType::Technic;
stop = true;
} else if (fileName == "manifest.json") {
qDebug() << "Flame:" << true;
m_modpackType = ModpackType::Flame;
stop = true;
} else if (QFileInfo fileInfo(fileName); fileInfo.fileName() == "instance.cfg") {
qDebug() << "MultiMC:" << true;
m_modpackType = ModpackType::MultiMC;
root = cleanPath(fileInfo.path());
stop = true;
}
QCoreApplication::processEvents();
return true;
};
if (!packZip.parse(detectInstance)) {
emitFailed(tr("Unable to open supplied modpack zip file."));
return;
if (packZipDir.exists("/modrinth.index.json")) {
// process as Modrinth pack
qDebug() << "Modrinth:" << true;
m_modpackType = ModpackType::Modrinth;
} else if (packZipDir.exists("/bin/modpack.jar") || packZipDir.exists("/bin/version.json")) {
// process as Technic pack
qDebug() << "Technic:" << true;
extractDir.mkpath("minecraft");
extractDir.cd("minecraft");
m_modpackType = ModpackType::Technic;
} else {
root = getRootFromZip(packZip.get());
setDetails("");
}
if (m_modpackType == ModpackType::Unknown) {
emitFailed(tr("Archive does not contain a recognized modpack type."));
@ -174,7 +187,7 @@ void InstanceImportTask::processZipPack()
setStatus(tr("Extracting modpack"));
// make sure we extract just the pack
auto zipTask = makeShared<MMCZip::ExtractZipTask>(m_archivePath, extractDir, root);
auto zipTask = makeShared<MMCZip::ExtractZipTask>(packZip, extractDir, root);
auto progressStep = std::make_shared<TaskStepProgress>();
connect(zipTask.get(), &Task::finished, this, [this, progressStep] {
@ -199,7 +212,6 @@ void InstanceImportTask::processZipPack()
progressStep->status = status;
stepProgress(*progressStep);
});
connect(zipTask.get(), &Task::warningLogged, this, [this](const QString& line) { m_Warnings.append(line); });
m_task.reset(zipTask);
zipTask->start();
}
@ -251,25 +263,6 @@ void InstanceImportTask::extractFinished()
}
}
bool installIcon(QString root, QString instIconKey)
{
auto importIconPath = IconUtils::findBestIconIn(root, instIconKey);
if (importIconPath.isNull() || !QFile::exists(importIconPath))
importIconPath = IconUtils::findBestIconIn(root, "icon.png");
if (importIconPath.isNull() || !QFile::exists(importIconPath))
importIconPath = IconUtils::findBestIconIn(FS::PathCombine(root, "overrides"), "icon.png");
if (!importIconPath.isNull() && QFile::exists(importIconPath)) {
// import icon
auto iconList = APPLICATION->icons();
if (iconList->iconFileExists(instIconKey)) {
iconList->deleteIcon(instIconKey);
}
iconList->installIcon(importIconPath, instIconKey + "." + QFileInfo(importIconPath).suffix());
return true;
}
return false;
}
void InstanceImportTask::processFlame()
{
shared_qobject_ptr<FlameCreationTask> inst_creation_task = nullptr;
@ -295,14 +288,6 @@ void InstanceImportTask::processFlame()
}
inst_creation_task->setName(*this);
// if the icon was specified by user, use that. otherwise pull icon from the pack
if (m_instIcon == "default") {
auto iconKey = QString("Flame_%1_Icon").arg(name());
if (installIcon(m_stagingPath, iconKey)) {
m_instIcon = iconKey;
}
}
inst_creation_task->setIcon(m_instIcon);
inst_creation_task->setGroup(m_instGroup);
inst_creation_task->setConfirmUpdate(shouldConfirmUpdate());
@ -320,11 +305,8 @@ void InstanceImportTask::processFlame()
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::aborted, this, &InstanceImportTask::emitAborted);
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::abortButtonTextChanged, this, &Task::setAbortButtonText);
connect(inst_creation_task.get(), &Task::warningLogged, this, [this](const QString& line) { m_Warnings.append(line); });
m_task.reset(inst_creation_task);
setAbortable(true);
@ -342,9 +324,9 @@ void InstanceImportTask::processTechnic()
void InstanceImportTask::processMultiMC()
{
QString configPath = FS::PathCombine(m_stagingPath, "instance.cfg");
auto instanceSettings = std::make_unique<INISettingsObject>(configPath);
auto instanceSettings = std::make_shared<INISettingsObject>(configPath);
NullInstance instance(m_globalSettings, std::move(instanceSettings), m_stagingPath);
NullInstance instance(m_globalSettings, instanceSettings, m_stagingPath);
// reset time played on import... because packs.
instance.resetTimePlayed();
@ -358,7 +340,17 @@ void InstanceImportTask::processMultiMC()
} else {
m_instIcon = instance.iconKey();
installIcon(instance.instanceRoot(), m_instIcon);
auto importIconPath = IconUtils::findBestIconIn(instance.instanceRoot(), m_instIcon);
if (importIconPath.isNull() || !QFile::exists(importIconPath))
importIconPath = IconUtils::findBestIconIn(instance.instanceRoot(), "icon.png");
if (!importIconPath.isNull() && QFile::exists(importIconPath)) {
// import icon
auto iconList = APPLICATION->icons();
if (iconList->iconFileExists(m_instIcon)) {
iconList->deleteIcon(m_instIcon);
}
iconList->installIcon(importIconPath, m_instIcon);
}
}
emitSucceeded();
}
@ -386,8 +378,8 @@ void InstanceImportTask::processModrinth()
} else {
QString pack_id;
if (!m_sourceUrl.isEmpty()) {
static const QRegularExpression s_regex(R"(data\/([^\/]*)\/versions)");
pack_id = s_regex.match(m_sourceUrl.toString()).captured(1);
QRegularExpression regex(R"(data\/([^\/]*)\/versions)");
pack_id = regex.match(m_sourceUrl.toString()).captured(1);
}
// FIXME: Find a way to get the ID in directly imported ZIPs
@ -395,14 +387,6 @@ void InstanceImportTask::processModrinth()
}
inst_creation_task->setName(*this);
// if the icon was specified by user, use that. otherwise pull icon from the pack
if (m_instIcon == "default") {
auto iconKey = QString("Modrinth_%1_Icon").arg(name());
if (installIcon(m_stagingPath, iconKey)) {
m_instIcon = iconKey;
}
}
inst_creation_task->setIcon(m_instIcon);
inst_creation_task->setGroup(m_instGroup);
inst_creation_task->setConfirmUpdate(shouldConfirmUpdate());
@ -420,11 +404,8 @@ void InstanceImportTask::processModrinth()
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::aborted, this, &InstanceImportTask::emitAborted);
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::abortButtonTextChanged, this, &Task::setAbortButtonText);
connect(inst_creation_task.get(), &Task::warningLogged, this, [this](const QString& line) { m_Warnings.append(line); });
m_task.reset(inst_creation_task);
setAbortable(true);

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