Compare commits

..

139 Commits
develop ... 8.3

Author SHA1 Message Date
TheKodeToad
4cd6ac5fe5
Merge pull request #2334 from PrismLauncher/backport-2333-to-release-8.x
[Backport release-8.x] Fix Minecraft Launcher runtime detection on Windows and macOS
2024-04-23 17:20:44 +01:00
Trial97
f06bd54d6f Removed duplicate local
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 10d1720da5c350250390fa8b38a5c4db6429462b)
2024-04-23 16:19:50 +00:00
Trial97
0b535e44e1 Changed env variable
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 73c3794c1bfa9d3cd01339039ad8597971b5fb53)
2024-04-23 16:19:50 +00:00
Trial97
877de6da40 Fixed windows appdata path
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit dac70278462913b7c0191c56a04e62529d5c774b)
2024-04-23 16:19:50 +00:00
Trial97
c330452e84 Fix bundled java detection on mac
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit dbfd535b38d799a773b3843709bbeae7f5a9e7d3)
2024-04-23 16:19:50 +00:00
Alexandru Ionut Tripon
3f3af4134e
Merge pull request #2330 from Trial97/appimage_backport
Removed java from appimage backport
2024-04-23 00:06:36 +03:00
Trial97
565c7d81b3
Removed java from appimage
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
2024-04-23 00:04:51 +03:00
Alexandru Ionut Tripon
a532c99aa5
Merge pull request #2329 from PrismLauncher/backport-2327-to-release-8.x
[Backport release-8.x] Add Gradle Toolchains to java scan list
2024-04-21 20:56:05 +03:00
William Gray
47bd02637a Update JavaUtils.cpp
Signed-off-by: William Gray <ruwagray@gmail.com>
(cherry picked from commit 9f4654ede91a81a3d1099c949164690e295995a4)
2024-04-21 17:45:15 +00:00
Alexandru Ionut Tripon
64797b8bff
Merge pull request #2322 from PrismLauncher/backport-2319-to-release-8.x
[Backport release-8.x] Support mod info for NeoForge 20.5
2024-04-20 12:04:47 +03:00
TheKodeToad
7960282e07 Support neoforge.mods.toml
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
(cherry picked from commit 252406ba3e793b4b096ed1e7bde43c2d2a9c2eca)
2024-04-20 07:50:01 +00:00
Alexandru Ionut Tripon
cb0fe08bed
Merge pull request #2314 from PrismLauncher/backport-2294-to-release-8.x
[Backport release-8.x] Fixed application close on open file dialog
2024-04-19 00:13:36 +03:00
Trial97
160c8cb70d Fixed application close on open file dialog
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 9f48694eb2be5f62efb122b554c7066e49f3383d)
2024-04-18 21:13:03 +00:00
TheKodeToad
13afbd5699
Merge pull request #2286 from DioEgizio/updates-backport
Update to Qt 6.6.3
2024-04-15 11:23:34 +01:00
Alexandru Ionut Tripon
7b1c5a7e1a
Merge pull request #2293 from PrismLauncher/backport-2291-to-release-8.x
[Backport release-8.x] Fixed crash on invalid curseforge link on import
2024-04-09 00:20:31 +03:00
Trial97
1a44258c9d Fixed crash on invalid curseforge link on import
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 9cc58fe62c776dd206bb6dd99c886ce491662214)
2024-04-08 21:20:14 +00:00
DioEgizio
95cfcedc96 chore: update to qt 6.6.3 on 8.x
qt bug fix release

Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
2024-04-06 20:23:01 +02:00
Alexandru Ionut Tripon
5f7a5bfa2d
Merge pull request #2281 from Scrumplex/bump-8.3
Bump to 8.3
2024-04-06 16:15:38 +03:00
Sefa Eyeoglu
f221b08f11
chore: bump to 8.3
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2024-04-06 15:12:41 +02:00
Alexandru Ionut Tripon
0af9bde06f
Merge pull request #2280 from PrismLauncher/backport-2225-to-release-8.x
[Backport release-8.x] Use UTF-8 for ZIP creation
2024-04-06 16:02:24 +03:00
TheKodeToad
d9b133a28d Use UTF-8 for ZIP creation
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
(cherry picked from commit d72bd70c055d23223ee78fa62e6ae4ccfcb490d7)
2024-04-06 13:01:11 +00:00
Alexandru Ionut Tripon
3477b8c2c2
Merge pull request #2279 from PrismLauncher/backport-2277-to-release-8.x
[Backport release-8.x] Fix unicode characters being invalid in filenames
2024-04-06 15:57:24 +03:00
TheKodeToad
e43341ce92 Fix unicode characters being invalid in filenames
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
(cherry picked from commit 9986fe4c45be7f3ce22fdce64812677f16cf7b4c)
2024-04-06 12:54:15 +00:00
Alexandru Ionut Tripon
acfd05a70e
Merge pull request #2278 from PrismLauncher/backport-2247-to-release-8.x
[Backport release-8.x] Fixed crash on non-latin instance name
2024-04-06 15:41:38 +03:00
Trial97
b2cca30cd9 Moved getPathNameInLocal8bit inside FileSystem namespace
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 3ddcadcdd1f72f8135333986e55cf583204da1e2)
2024-04-06 12:40:35 +00:00
Trial97
3e5e131a94 Moved the creation of natives folder in ExtractNatives task
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 8ecab305ac67afb70a278d286df13cc85134dec2)
2024-04-06 12:40:35 +00:00
Trial97
1e5a29c423 Fixed crash on non-latin instance name
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 450b73328e20941eba12be3b7c7f8bb13dc0f944)
2024-04-06 12:40:35 +00:00
timoreo
5b168dd7b1
Merge pull request #2276 from PrismLauncher/backport-2275-to-release-8.x 2024-04-06 14:28:40 +02:00
TheKodeToad
17d5d78a5b Replace invalid characters when extracting ZIP
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
(cherry picked from commit 8056a2fa460b11739b080d96deda35cd8897c40c)
2024-04-06 12:18:29 +00:00
Alexandru Ionut Tripon
58d32ea1af
Merge pull request #2273 from PrismLauncher/backport-2268-to-release-8.x
[Backport release-8.x] [Linux] Add jdk21 to Nix packages
2024-04-04 20:39:00 +03:00
Sefa Eyeoglu
0a3b85dbc5 fix(nix): add jdk21
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
(cherry picked from commit 0d372d2fbfd76b54f156faeca6a31fff80875999)
2024-04-04 17:38:47 +00:00
Alexandru Ionut Tripon
99203cbd9b
Merge pull request #2253 from Trial97/manual_backport
Manual backport to 8.x
2024-03-28 14:47:45 +02:00
Trial97
d262a081c5
fixed const stuff
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
2024-03-28 14:44:32 +02:00
Alexandru Ionut Tripon
f9df20aae3
Update launcher/ui/pages/modplatform/ImportPage.cpp
Co-authored-by: TheKodeToad <TheKodeToad@proton.me>
Signed-off-by: Alexandru Ionut Tripon <alexandru.tripon97@gmail.com>
2024-03-28 14:44:26 +02:00
Trial97
fc4b5205dd
Added all supported files filter
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
2024-03-28 14:44:20 +02:00
Alexandru Ionut Tripon
7c2a9df98e
Update launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp
Signed-off-by: Alexandru Ionut Tripon <alexandru.tripon97@gmail.com>
2024-03-28 14:43:49 +02:00
Alexandru Ionut Tripon
b854c56c8c
Update launcher/minecraft/auth/steps/XboxAuthorizationStep.cpp
Co-authored-by: Tayou <git@tayou.org>
Signed-off-by: Alexandru Ionut Tripon <alexandru.tripon97@gmail.com>
2024-03-28 14:43:40 +02:00
Trial97
2c864a4aad
added more microsoft error codes
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
2024-03-28 14:43:30 +02:00
DioEgizio
4642c13ca4
fix: include libbz2.so.1.0
fixes portable installs not working on fedora anymore

i did this only on portable builds and not system installs so that it doesn't create problems to people packaging them, as to fix system installs i would have to put it in bin/

Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
2024-03-28 14:42:04 +02:00
Trial97
b255c8b17f
Changed the trait name
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
2024-03-28 14:39:32 +02:00
Alexandru Ionut Tripon
c0f14c569b
Merge pull request #2252 from PrismLauncher/backport-2209-to-release-8.x
[Backport release-8.x] Add totalTimePlayed for FTBApp import
2024-03-28 14:36:47 +02:00
chouzz
ca3516d26d Add totalTimePlayed for FTBApp import
Signed-off-by: chouzz <zhouhua852@gmail.com>
(cherry picked from commit 92113e233aefbd2b255775d4e858e45845a94a2c)
2024-03-28 12:36:36 +00:00
timoreo
067fcaf0d9
Merge pull request #2250 from PrismLauncher/backport-2221-to-release-8.x
[Backport release-8.x] Set Forge version correctly when exporting to CurseForge
2024-03-28 09:56:40 +01:00
Trial97
1a379280b8 Fixed curesforge export
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 05487152fe4eae0ad3d12b18c398ea2a99b44e32)
2024-03-28 08:41:26 +00:00
Sefa Eyeoglu
284633ff91
Merge pull request #2188 from Scrumplex/bump-8.2 2024-03-03 20:37:21 +01:00
Sefa Eyeoglu
a7bfd08ce3
chore: bump to 8.2
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
2024-03-03 20:35:43 +01:00
Sefa Eyeoglu
8c5cc43fc5
Merge pull request #2186 from PrismLauncher/backport-1923-to-release-8.x 2024-03-03 18:40:15 +01:00
Tayou
a8553e7897 add line back to group separator
Signed-off-by: Tayou <git@tayou.org>
(cherry picked from commit 877eb4172a737c44505b3c784e84ab710b291e5e)
2024-03-03 17:38:44 +00:00
Tayou
ca1b68b7ca
Merge pull request #2185 from PrismLauncher/backport-2178-to-release-8.x
[Backport release-8.x] (More) mrpack export fixes
2024-03-03 16:46:48 +01:00
TheKodeToad
1fe710777a Allow multiline description
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
(cherry picked from commit 4101fbb63433d1ee90476f55d76a7a7f0ced6ccb)
2024-03-03 15:30:54 +00:00
TheKodeToad
e349e24548 Fix server side mods being marked as unsupported on client
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
(cherry picked from commit 138df66355b54151302f0b143ec1c2a5a4eb11c8)
2024-03-03 15:30:54 +00:00
Sefa Eyeoglu
8ad7c37d5e
Merge pull request #2184 from PrismLauncher/backport-2160-to-release-8.x 2024-03-03 15:18:38 +01:00
TheKodeToad
b7f079b006 Fix build on Windows and formatting
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
(cherry picked from commit c0eb80947db57c4b0de376213d53aac4f694e1b0)
2024-03-03 14:07:08 +00:00
TheKodeToad
c39ca8852d Fix a mistake
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
(cherry picked from commit fccf857d8e5040fd64d7bc302463c1c9184f110f)
2024-03-03 14:07:08 +00:00
TheKodeToad
69a10e4b3d Add upper-bound for randomisation
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
(cherry picked from commit bd0cd828269ee259dd10439c84baeaec2f1220df)
2024-03-03 14:07:08 +00:00
TheKodeToad
3b02b6b7d7 Add error when staging folder could not be created
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
(cherry picked from commit df60f5cc9650a111a65ada2ea589bf7ecf9ac506)
2024-03-03 14:07:08 +00:00
TheKodeToad
82584e5d7e Delete staging on abort
Previously instances would get "stuck" in the folder

Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
(cherry picked from commit 9574ebe480a6a837533fc4339c1f3605300555ca)
2024-03-03 14:07:08 +00:00
TheKodeToad
6c8ee3dfa9 Re-randomise key until it does not collide
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
(cherry picked from commit 6a9f5540d385cd2edf7e43f3ad308041571a9f83)
2024-03-03 14:07:08 +00:00
Trial97
f9ba4a746e Updated application manifest
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit aac6fea724e029b9ef4e4ed3e98b04c40149add0)
2024-03-03 14:07:08 +00:00
Trial97
e37cf125c3 Reduced temporary instance folder name
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 726b0ffb3b0488bd289d85feacea31066c464a45)
2024-03-03 14:07:08 +00:00
Sefa Eyeoglu
b7dc0b83b2
Merge pull request #2153 from PrismLauncher/backport-2141-to-release-8.x 2024-02-22 12:37:54 +01:00
crpz1
0113456dea Use empty list label code for welcome screen
Signed-off-by: crpz1 <8588315+crpz1@users.noreply.github.com>
(cherry picked from commit 9aa81cf00508c45ad6fe6b1d53c0933f1494571c)
2024-02-22 11:36:13 +00:00
seth
4add24696b
Merge pull request #2151 from DioEgizio/updates-backport
fix: fix sparkle signing backport
2024-02-22 06:10:30 -05:00
DioEgizio
c6441d231b fix: fix sparkle signing
Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
2024-02-22 11:53:48 +01:00
DioEgizio
438ccc41ef
Merge pull request #2136 from DioEgizio/updates-backport 2024-02-18 15:04:29 +01:00
Alexandru Ionut Tripon
80f863f6b6
Merge pull request #2135 from PrismLauncher/backport-2110-to-release-8.x
[Backport release-8.x] Fixed curseforge neoforge import for 1.20.1 versions
2024-02-18 15:02:54 +02:00
DioEgizio
d8e34e6c39 Merge pull request #2130 from DioEgizio/updates 2024-02-18 12:58:09 +01:00
Sefa Eyeoglu
c4cb36b9d5 Merge pull request #1951 from guihkx/sync-flatpak 2024-02-18 12:58:09 +01:00
Trial97
72c4a52119 Fixed curseforge neoforge export for 1.20.1
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit fdaaee64d193472144dd95c15c8d03f6fc4ed83a)
2024-02-18 11:42:43 +00:00
Alexandru Ionut Tripon
8eba326f62 Update launcher/modplatform/flame/FlameInstanceCreationTask.cpp
Signed-off-by: Alexandru Ionut Tripon <alexandru.tripon97@gmail.com>
(cherry picked from commit 29bf6cc68c132c036f8c9ee90a337fb2db7d3cf2)
2024-02-18 11:42:43 +00:00
Trial97
69d675dc76 Fixed curseforge neoforge import for 1.20.1 versions
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 830ce246e17e381807d9394819c175dc0b730ff8)
2024-02-18 11:42:43 +00:00
Sefa Eyeoglu
e9991e99c0
Merge pull request #2129 from PrismLauncher/backport-2126-to-release-8.x
[Backport release-8.x] Use absolute path to load MangoHUD library
2024-02-17 09:22:51 +01:00
Echo J
6da36140eb Use absolute path to load MangoHUD library
This should finally fix the Arch Linux Java symbol issue with MangoHUD
enabled: https://bugs.archlinux.org/task/77183

Signed-off-by: Echo J <tcg96nougat@gmail.com>
(cherry picked from commit 01180c20e19fcdd9a902d9cd51514549eeceb531)
2024-02-17 00:57:29 +00:00
Sefa Eyeoglu
816c900edc
Merge pull request #2122 from PrismLauncher/backport-2112-to-release-8.x 2024-02-13 09:16:10 +01:00
TheKodeToad
4ebce79353 Use QTextFragment for inserting log lines
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
(cherry picked from commit 7cac8ad2b42f19dd3f38fe5c5ef5f93116ca5aa9)
2024-02-13 08:16:01 +00:00
Sefa Eyeoglu
256ed2a038
Merge pull request #2121 from PrismLauncher/backport-2116-to-release-8.x 2024-02-13 09:15:05 +01:00
TheKodeToad
3f30e4c691 Fix formatting issues
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
(cherry picked from commit 8cf2a04f317c59920e8af90d7e16fea872b2c122)
2024-02-13 08:14:52 +00:00
TheKodeToad
ad9dbb4a68 Fix immediate free in Exception.h
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
(cherry picked from commit 7f4c74ffbe413fcf191842606c12056fbc6493c7)
2024-02-13 08:14:52 +00:00
TheKodeToad
fb04b6fa85 Fix ResourceModel error display
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
(cherry picked from commit ff989b4305d5ae4578d2154afe27ce6bf72cadaf)
2024-02-13 08:14:52 +00:00
TheKodeToad
6badd694c5 Fix NetJob use-after-free
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
(cherry picked from commit ded77e61832661557a6985d9aa587f3b5d1e1f87)
2024-02-13 08:14:52 +00:00
TheKodeToad
6f5cddeec8
Merge pull request #2091 from PrismLauncher/revert-2084-backport-2050-to-release-8.x
Revert "[Backport release-8.x] Use `minecraft` instead of `.minecraft` for better accessibility"
2024-02-04 16:09:36 +00:00
TheKodeToad
25ba275230
Revert "[Backport release-8.x] Use minecraft instead of .minecraft for better accessibility" 2024-02-04 16:08:16 +00:00
Tayou
cf6ffc3954
Merge pull request #2084 from PrismLauncher/backport-2050-to-release-8.x
[Backport release-8.x] Use `minecraft` instead of `.minecraft` for better accessibility
2024-02-01 18:29:46 +01:00
TheKodeToad
5e3b7d88ec Use minecraft instead of .minecraft for better accessibility
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
(cherry picked from commit f54ac25614b62b0a43d014d8b47f9faee8112d12)
2024-02-01 17:16:29 +00:00
Alexandru Ionut Tripon
1f5552dd81
Merge pull request #2064 from PrismLauncher/backport-2063-to-release-8.x
[Backport release-8.x] fix: remove alpha notice on modrinth packs
2024-01-24 18:13:58 +02:00
DioEgizio
a2aede0d94 fix: remove alpha notice on modrinth packs
with the modrinth app being released for quite a while now it's weird to still have this (tbh they've never been truly alpha)

Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
(cherry picked from commit 8de1060bfb8eba7ad6efbb2093df61992e25e3cd)
2024-01-24 16:13:32 +00:00
Sefa Eyeoglu
2fd5635b2d
Merge pull request #2057 from PrismLauncher/backport-2053-to-release-8.x 2024-01-23 09:30:59 +01:00
Trial97
bc63e1906f Fixed open path a second time
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 12bf91376411d74432f5e88c85d68cef003fd899)
2024-01-23 08:30:16 +00:00
Alexandru Ionut Tripon
a8b168dc1f
Merge pull request #2043 from PrismLauncher/backport-1913-to-release-8.x
[Backport release-8.x] Fixed askIfShouldUpdate dialog on mac
2024-01-18 22:06:12 +02:00
Trial97
fce2163350 Fixed askIfShouldUpdate dialog on mac
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 577c737d686df43ee777a3b0382b788bb34ec170)
2024-01-18 20:05:30 +00:00
Sefa Eyeoglu
5d0c83dec2
Merge pull request #1768 from Trial97/toggle_deps2 2024-01-18 18:19:17 +01:00
Sefa Eyeoglu
557fce577a
Merge pull request #1825 from Trial97/ftb_import 2024-01-18 18:19:17 +01:00
Sefa Eyeoglu
bcb5b9c9c2
Merge pull request #2034 from Scrumplex/feat/macos-signing 2024-01-18 17:00:00 +01:00
Sefa Eyeoglu
428260b91f
Merge pull request #2035 from PrismLauncher/backport-1954-to-release-8.x 2024-01-17 15:19:48 +01:00
Sefa Eyeoglu
fec1a00dc8 fix: simplify openPath calls
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
(cherry picked from commit 67d088dc53337fc2abeae3ce20c89c9495f5c9be)
2024-01-17 14:19:03 +00:00
Sefa Eyeoglu
8dd898f895 chore: improve param name
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
(cherry picked from commit e5b608447a1c4860343aed15ef1e1bd5940ba17d)
2024-01-17 14:19:03 +00:00
Sefa Eyeoglu
f8585602d9 chore: remove unused methods
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
(cherry picked from commit a8220cd296a5b9540df07bce7be7e1f6cc28ffe0)
2024-01-17 14:19:03 +00:00
Sefa Eyeoglu
0ec3b9ce0e chore: remove maybe_unused
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
(cherry picked from commit 213963257cf2b2f7a265893c3112cd71bbce6199)
2024-01-17 14:19:03 +00:00
Sefa Eyeoglu
6f5d074b4b fix: open paths directly
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
(cherry picked from commit 0ccdcd23e3f3889f3e516d48bb03b27d3ddb62cc)
2024-01-17 14:19:03 +00:00
seth
7d9b95b4ce
nix: add garnix cache to nixConfig
Signed-off-by: seth <getchoo@tuta.io>
(cherry picked from commit 839adfc90bac8204581b930efc7cf2ad55629546)
2024-01-11 09:51:53 +01:00
seth
c08890391c
nix: deduplicate nixpkgs input
Signed-off-by: seth <getchoo@tuta.io>
(cherry picked from commit 26474d13749dd81869e155d64125c4b7d73ff0f2)
2024-01-11 09:51:51 +01:00
Alexandru Ionut Tripon
422135b2ab
Merge pull request #1771 from Trial97/account
Try refreshing account on launch if needed
2024-01-10 16:24:34 +02:00
Tayou
b83b25cbe3
Merge pull request #2015 from PrismLauncher/backport-2012-to-release-8.x
[Backport release-8.x] Fixed openAL placeholder
2024-01-07 00:32:17 +01:00
Trial97
4a17799449 Fixed openAL placeholder
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 219e2862f9d67d6a81ef634846237e1eec177d69)
2024-01-06 23:23:49 +00:00
Alexandru Ionut Tripon
3fe18e0810
Merge pull request #2008 from PrismLauncher/backport-1983-to-release-8.x
[Backport release-8.x] remove legacy processArguments code
2024-01-05 15:24:54 +02:00
tildejustin
5f4e0dfc14 remove legacy processArguments code
Signed-off-by: tildejustin <spacepepper3.14@gmail.com>
(cherry picked from commit eca5d88576900d32edea2000258f37d700af5f06)
2024-01-05 12:27:13 +00:00
Alexandru Ionut Tripon
afc73ffa16
Merge pull request #2007 from PrismLauncher/backport-2005-to-release-8.x
[Backport release-8.x] Format java code
2024-01-04 22:29:21 +02:00
Trial97
7ae3c05f1d Format java code
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 786e03571b529c610ada33d87581e65cefc4cae3)
2024-01-04 20:18:56 +00:00
Alexandru Ionut Tripon
744b81fc30
Merge pull request #2004 from PrismLauncher/backport-1979-to-release-8.x
[Backport release-8.x] Mod downloader page improvements
2024-01-03 22:47:27 +02:00
lumiscosity
f4617d7c90 fix styling
Signed-off-by: lumiscosity <averyrudelphe@gmail.com>
(cherry picked from commit c29af83dc328612d340c54e3ec037b1264d66d51)
2024-01-03 20:46:44 +00:00
lumiscosity
a00966986c move simplify call to drawing
Signed-off-by: lumiscosity <averyrudelphe@gmail.com>
(cherry picked from commit 1e48bf838db3f72fd391ecf9c91aa8e693daf213)
2024-01-03 20:46:44 +00:00
lumiscosity
42ea2ecbc8 Strip newlines in mod descriptions
Mirrors Modrinth page behaviour.

Signed-off-by: lumiscosity <averyrudelphe@gmail.com>
(cherry picked from commit 1bf386603dece42df0815495ae6b43b0e2d665c8)
2024-01-03 20:46:44 +00:00
lumiscosity
568734eb8a add archived project warning
Signed-off-by: lumiscosity <averyrudelphe@gmail.com>
(cherry picked from commit 358cf5b3485cfb23cce226c02fef03523468d4eb)
2024-01-03 20:46:44 +00:00
Alexandru Ionut Tripon
3b578ecfe0
Merge pull request #2003 from PrismLauncher/backport-1978-to-release-8.x
[Backport release-8.x] Fixed openURL cast for resource
2024-01-03 22:44:59 +02:00
Trial97
bb843b86ab Fixed openURL cast for resource
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
(cherry picked from commit 9a33bdcf501655dbef2981094ee05662f34cd671)
2024-01-03 20:44:44 +00:00
Sefa Eyeoglu
b12dffe420
Merge pull request #2001 from PrismLauncher/backport-1999-to-release-8.x 2024-01-03 18:26:32 +01:00
TheKodeToad
36d8ffd3c1 Pass proxy
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
(cherry picked from commit 345cdf5c9d6417b5c2ce15e8967de3886d1113f1)
2024-01-03 17:25:14 +00:00
TheKodeToad
f31bf5a1f1 Add online mode fix for legacy versions; minor refactors in legacy
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
(cherry picked from commit 05e453309629d2c4cc1cf4b1322669cb8aed21ff)
2024-01-03 17:25:14 +00:00
Sefa Eyeoglu
270accf6d7
Merge pull request #2000 from PrismLauncher/backport-1998-to-release-8.x 2024-01-03 18:15:52 +01:00
TheKodeToad
6816364354 Happy new year :D
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
(cherry picked from commit 1130fe851012b3d7deff207db495b455501e17fc)
2024-01-03 17:13:30 +00:00
TheKodeToad
2f3715beed
Merge pull request #1968 from PrismLauncher/backport-1964-to-release-8.x
[Backport release-8.x] Don't log Microsoft refresh tokens
2023-12-19 11:30:19 +00:00
Sefa Eyeoglu
6912782f4b fix: don't log katabasis by default
Signed-off-by: Sefa Eyeoglu <contact@scrumplex.net>
(cherry picked from commit a1e3901b3f4e4910e3fe40206879907a1f7ff03c)
2023-12-19 11:25:00 +00:00
Sefa Eyeoglu
d8809197f8
Merge pull request #1962 from PrismLauncher/backport-1960-to-release-8.x
[Backport release-8.x] Minor spelling fixes
2023-12-16 17:28:07 +01:00
lumiscosity
199312dd5a one more
Signed-off-by: lumiscosity <averyrudelphe@gmail.com>
(cherry picked from commit eb8e150fa804f0b34b21d7a95e840516cd119c97)
2023-12-16 16:25:35 +00:00
lumiscosity
a108a01be7 Update ModFolderPage.cpp
Signed-off-by: lumiscosity <averyrudelphe@gmail.com>
(cherry picked from commit 56397446dbe05ea346359f401587383d4a1a84dd)
2023-12-16 16:25:35 +00:00
lumiscosity
7568e90655 Update GetModDependenciesTask.cpp
Signed-off-by: lumiscosity <averyrudelphe@gmail.com>
(cherry picked from commit 8cbdecc454de7ee8f3dadbd00c35b339a8581c45)
2023-12-16 16:25:35 +00:00
Alexandru Ionut Tripon
c216713844
Merge pull request #1952 from PrismLauncher/backport-1947-to-release-8.x
[Backport release-8.x] fix: Minimized windows dont get shown
2023-12-13 20:31:31 +02:00
TheKodeToad
4dfe925cf9 Revert change to .gitignore
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
(cherry picked from commit 2391ad200f80ef6a84ffef246ed236d66928f0e4)
2023-12-13 18:24:40 +00:00
theMackabu
534b4e4aa3 remove: maidfile.toml (local build tool)
Signed-off-by: theMackabu <theMackabu@gmail.com>
(cherry picked from commit 7c33a8e448d238960b89f1e1c2f14a18d12040eb)
2023-12-13 18:24:40 +00:00
theMackabu
9aa8e1d7ad clang-format: fix formatting
Signed-off-by: theMackabu <theMackabu@gmail.com>
(cherry picked from commit 201c9783d56cef2e1bba1fdbffdc377bdf294468)
2023-12-13 18:24:40 +00:00
theMackabu
ff146d5855 #1945 resolve issue on windows
Signed-off-by: theMackabu <theMackabu@gmail.com>
(cherry picked from commit 836f74cd4629748ce8056f9f186284fc55d0d8b4)
2023-12-13 18:24:40 +00:00
theMackabu
d0cb62cb62 #1945 resolve minimized windows pull from dock
Signed-off-by: theMackabu <theMackabu@gmail.com>
(cherry picked from commit 3567369d44c6ba9a3b702caf2db18b126f1b4fc4)
2023-12-13 18:24:40 +00:00
timoreo
743d48744a
Merge pull request #1712 from Trial97/current_time 2023-12-11 16:14:52 +01:00
Sefa Eyeoglu
2837ae8bff
Merge pull request #1738 from Trial97/some_removals 2023-12-11 11:31:55 +01:00
Sefa Eyeoglu
3e54d4ddbb
Merge pull request #1732 from Trial97/update_file2 2023-12-11 11:25:10 +01:00
Sefa Eyeoglu
426deb4454
Merge pull request #1694 from Trial97/concurrent 2023-12-11 11:20:17 +01:00
Sefa Eyeoglu
52ccf3d93b
Merge pull request #1857 from Trial97/copy_time 2023-12-11 11:02:12 +01:00
Sefa Eyeoglu
b6a366ed97
Merge pull request #1944 from PrismLauncher/backport-1908-to-release-8.x 2023-12-11 11:00:57 +01:00
DioEgizio
1ba6ed9fe9 chore: update qt to qt 6.6.1
Signed-off-by: DioEgizio <83089242+DioEgizio@users.noreply.github.com>
(cherry picked from commit eb011e6729fe49da867e6ae1ab2524424eedac46)
2023-12-11 10:00:43 +00:00
1001 changed files with 17004 additions and 34326 deletions

View File

@ -1,23 +1,5 @@
Checks: Checks:
- modernize-use-using - modernize-use-using
- readability-avoid-const-params-in-decls - readability-avoid-const-params-in-decls
- misc-unused-parameters,
- readability-identifier-naming
# ^ Without unused-parameters the readability-identifier-naming check doesn't cause any warnings. SystemHeaders: false
CheckOptions:
- { key: readability-identifier-naming.ClassCase, value: PascalCase }
- { key: readability-identifier-naming.EnumCase, value: PascalCase }
- { key: readability-identifier-naming.FunctionCase, value: camelCase }
- { key: readability-identifier-naming.GlobalVariableCase, value: camelCase }
- { key: readability-identifier-naming.GlobalFunctionCase, value: camelCase }
- { key: readability-identifier-naming.GlobalConstantCase, value: SCREAMING_SNAKE_CASE }
- { key: readability-identifier-naming.MacroDefinitionCase, value: SCREAMING_SNAKE_CASE }
- { key: readability-identifier-naming.ClassMemberCase, value: camelCase }
- { key: readability-identifier-naming.PrivateMemberPrefix, value: m_ }
- { key: readability-identifier-naming.ProtectedMemberPrefix, value: m_ }
- { key: readability-identifier-naming.PrivateStaticMemberPrefix, value: s_ }
- { key: readability-identifier-naming.ProtectedStaticMemberPrefix, value: s_ }
- { key: readability-identifier-naming.PublicStaticConstantCase, value: SCREAMING_SNAKE_CASE }
- { key: readability-identifier-naming.EnumConstantCase, value: SCREAMING_SNAKE_CASE }

2
.envrc
View File

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

View File

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

View File

@ -1,103 +0,0 @@
# This file incorporates work covered by the following copyright and
# permission notice
#
# Copyright (c) 2003-2025 Eelco Dolstra and the Nixpkgs/NixOS contributors
#
# 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.
name: Get merge commit
description: Get a merge commit of a given pull request
inputs:
repository:
description: Repository containing the pull request
required: false
pull-request-id:
description: ID of a pull request
required: true
outputs:
merge-commit-sha:
description: Git SHA of a merge commit
value: ${{ steps.query.outputs.merge-commit-sha }}
runs:
using: composite
steps:
- name: Wait for GitHub to report merge commit
id: query
shell: bash
env:
GITHUB_REPO: ${{ inputs.repository || github.repository }}
PR_ID: ${{ inputs.pull-request-id }}
# https://github.com/NixOS/nixpkgs/blob/8f77f3600f1ee775b85dc2c72fd842768e486ec9/ci/get-merge-commit.sh
run: |
set -euo pipefail
log() {
echo "$@" >&2
}
# Retry the API query this many times
retryCount=5
# Start with 5 seconds, but double every retry
retryInterval=5
while true; do
log "Checking whether the pull request can be merged"
prInfo=$(gh api \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"/repos/$GITHUB_REPO/pulls/$PR_ID")
# Non-open PRs won't have their mergeability computed no matter what
state=$(jq -r .state <<<"$prInfo")
if [[ "$state" != open ]]; then
log "PR is not open anymore"
exit 1
fi
mergeable=$(jq -r .mergeable <<<"$prInfo")
if [[ "$mergeable" == "null" ]]; then
if ((retryCount == 0)); then
log "Not retrying anymore. It's likely that GitHub is having internal issues: check https://www.githubstatus.com/"
exit 3
else
((retryCount -= 1)) || true
# null indicates that GitHub is still computing whether it's mergeable
# Wait a couple seconds before trying again
log "GitHub is still computing whether this PR can be merged, waiting $retryInterval seconds before trying again ($retryCount retries left)"
sleep "$retryInterval"
((retryInterval *= 2)) || true
fi
else
break
fi
done
if [[ "$mergeable" == "true" ]]; then
echo "merge-commit-sha=$(jq -r .merge_commit_sha <<<"$prInfo")" >> "$GITHUB_OUTPUT"
else
echo "# 🚨 The PR has a merge conflict!" >> "$GITHUB_STEP_SUMMARY"
exit 2
fi

View File

@ -1,124 +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
cmake-preset:
description: Base CMake preset previously used for the build
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: Package AppImage
shell: bash
env:
VERSION: ${{ inputs.version }}
BUILD_DIR: build
INSTALL_APPIMAGE_DIR: install-appdir
GPG_PRIVATE_KEY: ${{ inputs.gpg-private-key }}
run: |
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_APPIMAGE_DIR }}/usr
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/${{ inputs.qt-version }}/gcc_64/plugins/iconengines/* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/plugins/iconengines
cp /usr/lib/x86_64-linux-gnu/libcrypto.so.* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/
cp /usr/lib/x86_64-linux-gnu/libssl.so.* ${{ 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 [ '${{ inputs.gpg-private-key-id }}' != '' ]; then
export SIGN=1
export SIGN_KEY=${{ inputs.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 portable tarball
shell: bash
env:
BUILD_DIR: build
CMAKE_PRESET: ${{ inputs.cmake-preset }}
INSTALL_PORTABLE_DIR: install-portable
run: |
cmake --preset "$CMAKE_PRESET" -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_PORTABLE_DIR }} -DINSTALL_BUNDLE=full
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.* ${{ env.INSTALL_PORTABLE_DIR }}/lib
cp /usr/lib/x86_64-linux-gnu/libssl.so.* ${{ env.INSTALL_PORTABLE_DIR }}/lib
cp /usr/lib/x86_64-linux-gnu/libffi.so.*.* ${{ 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 *
- name: Upload binary tarball
uses: actions/upload-artifact@v4
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@v4
with:
name: PrismLauncher-${{ inputs.artifact-name }}-${{ inputs.version }}-${{ inputs.build-type }}-x86_64.AppImage
path: PrismLauncher-${{ runner.os }}-${{ inputs.version }}-${{ inputs.build-type }}-x86_64.AppImage
- name: Upload AppImage Zsync
uses: actions/upload-artifact@v4
with:
name: PrismLauncher-${{ inputs.artifact-name }}-${{ inputs.version }}-${{ inputs.build-type }}-x86_64.AppImage.zsync
path: PrismLauncher-Linux-x86_64.AppImage.zsync

View File

@ -1,121 +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 }}
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: Make Sparkle signature
shell: bash
run: |
if [ '${{ inputs.sparkle-ed25519-key }}' != '' ]; then
echo '${{ inputs.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: Upload binary tarball
uses: actions/upload-artifact@v4
with:
name: PrismLauncher-${{ inputs.artifact-name }}-${{ inputs.version }}-${{ inputs.build-type }}
path: PrismLauncher.zip

View File

@ -1,143 +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: true
default: false
windows-codesign-cert:
description: Certificate for signing Windows builds
required: false
windows-codesign-password:
description: Password for signing Windows builds
required: false
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 }}
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: Fetch codesign certificate
shell: bash # yes, we are not using MSYS2 or PowerShell here
run: |
echo '${{ inputs.windows-codesign-cert }}' | base64 --decode > codesign.pfx
- name: Sign executable
shell: pwsh
env:
INSTALL_DIR: install
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 '${{ inputs.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 (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 }} --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 }} --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
shell: pwsh
run: |
if (Get-Content ./codesign.pfx){
SignTool sign /fd sha256 /td sha256 /f codesign.pfx /p '${{ inputs.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: Upload binary zip
uses: actions/upload-artifact@v4
with:
name: PrismLauncher-${{ inputs.artifact-name }}-${{ inputs.version }}-${{ inputs.build-type }}
path: install/**
- name: Upload portable zip
uses: actions/upload-artifact@v4
with:
name: PrismLauncher-${{ inputs.artifact-name }}-Portable-${{ inputs.version }}-${{ inputs.build-type }}
path: install-portable/**
- name: Upload installer
uses: actions/upload-artifact@v4
with:
name: PrismLauncher-${{ inputs.artifact-name }}-Setup-${{ inputs.version }}-${{ inputs.build-type }}
path: PrismLauncher-Setup.exe

View File

@ -1,78 +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
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
default: 6.8.1
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
- 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.18
with:
variant: ${{ runner.os == 'Windows' && 'sccache' || 'ccache' }}
create-symlink: ${{ runner.os != 'Windows' }}
key: ${{ runner.os }}-qt${{ inputs.qt_ver }}-${{ inputs.architecture }}
- name: Use ccache on debug builds
if: ${{ inputs.build-type == 'Debug' }}
shell: bash
env:
# Only use sccache on MSVC
CCACHE_VARIANT: ${{ (runner.os == 'Windows' && inputs.msystem == '') && 'sccache' || 'ccache' }}
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 }}
arch: ${{ inputs.qt-architecture }}
modules: qt5compat qtimageformats qtnetworkauth
cache: ${{ inputs.build-type == 'Debug' }}

View File

@ -1,26 +0,0 @@
name: Setup Linux dependencies
runs:
using: composite
steps:
- name: Install host dependencies
shell: bash
run: |
sudo apt-get -y update
sudo apt-get -y install ninja-build extra-cmake-modules scdoc appstream libxcb-cursor-dev
- name: Setup AppImage tooling
shell: bash
run: |
declare -A appimage_deps
appimage_deps["https://github.com/linuxdeploy/linuxdeploy/releases/download/1-alpha-20250213-2/linuxdeploy-x86_64.AppImage"]="4648f278ab3ef31f819e67c30d50f462640e5365a77637d7e6f2ad9fd0b4522a linuxdeploy-x86_64.AppImage"
appimage_deps["https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/1-alpha-20250213-1/linuxdeploy-plugin-qt-x86_64.AppImage"]="15106be885c1c48a021198e7e1e9a48ce9d02a86dd0a1848f00bdbf3c1c92724 linuxdeploy-plugin-qt-x86_64.AppImage"
appimage_deps["https://github.com/AppImageCommunity/AppImageUpdate/releases/download/2.0.0-alpha-1-20241225/AppImageUpdate-x86_64.AppImage"]="f1747cf60058e99f1bb9099ee9787d16c10241313b7acec81810ea1b1e568c11 AppImageUpdate-x86_64.AppImage"
for url in "${!appimage_deps[@]}"; do
curl -LO "$url"
sha256sum -c - <<< "${appimage_deps[$url]}"
done
sudo apt -y install libopengl0

View File

@ -1,16 +0,0 @@
name: Setup macOS dependencies
runs:
using: composite
steps:
- name: Install dependencies
shell: bash
run: |
brew update
brew install ninja extra-cmake-modules temurin@17
- name: Set JAVA_HOME
shell: bash
run: |
echo "JAVA_HOME=$(/usr/libexec/java_home -v 17)" >> "$GITHUB_ENV"

View File

@ -1,66 +0,0 @@
name: Setup Windows Dependencies
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 MSYS2 (MinGW-64)
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-5compat:p
qt6-networkauth:p
cmark:p
quazip-qt6:p
- name: Retrieve ccache cache (MinGW)
if: ${{ inputs.msystem != '' && inputs.build-type == 'Debug' }}
uses: actions/cache@v4.2.3
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

@ -16,7 +16,6 @@ jobs:
permissions: permissions:
contents: write # for korthout/backport-action to create branch contents: write # for korthout/backport-action to create branch
pull-requests: write # for korthout/backport-action to create PR to backport pull-requests: write # for korthout/backport-action to create PR to backport
actions: write # for korthout/backport-action to create PR with workflow changes
name: Backport Pull Request 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)) if: github.repository_owner == 'PrismLauncher' && github.event.pull_request.merged == true && (github.event_name != 'labeled' || startsWith('backport', github.event.label.name))
runs-on: ubuntu-latest runs-on: ubuntu-latest
@ -25,7 +24,7 @@ jobs:
with: with:
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}
- name: Create backport PRs - name: Create backport PRs
uses: korthout/backport-action@v3.2.0 uses: korthout/backport-action@v2.1.1
with: with:
# Config README: https://github.com/korthout/backport-action#backport-action # Config README: https://github.com/korthout/backport-action#backport-action
pull_description: |- pull_description: |-

View File

@ -1,255 +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
jobs:
blocked_status:
name: Check Blocked Status
runs-on: ubuntu-latest
steps:
- name: Generate token
id: generate-token
uses: actions/create-github-app-token@v2
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("blocked (?:by|on):? #([0-9]+)")
| map({
"type": "Blocked on",
"number": ( . | tonumber )
})
) as $i ([]; . + [$i[]])
) as $bprs
| (
$body |
reduce (
. | scan("stacked on:? #([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, '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 '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 '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 '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,195 +1,657 @@
name: Build name: Build
on: on:
push:
branches-ignore:
- "renovate/**"
paths:
# File types
- "**.cpp"
- "**.h"
- "**.java"
# Directories
- "buildconfig/"
- "cmake/"
- "launcher/"
- "libraries/"
- "program_info/"
- "tests/"
# Files
- "CMakeLists.txt"
- "COPYING.md"
# Workflows
- ".github/workflows/build.yml"
pull_request:
paths:
# File types
- "**.cpp"
- "**.h"
# Directories
- "buildconfig/"
- "cmake/"
- "launcher/"
- "libraries/"
- "program_info/"
- "tests/"
# Files
- "CMakeLists.txt"
- "COPYING.md"
# Workflows
- ".github/workflows/build.yml"
workflow_call: workflow_call:
inputs: inputs:
build-type: build_type:
description: Type of build (Debug or Release) description: Type of build (Debug, Release, RelWithDebInfo, MinSizeRel)
type: string type: string
default: Debug default: Debug
workflow_dispatch: is_qt_cached:
inputs: description: Enable Qt caching or not
build-type:
description: Type of build (Debug or Release)
type: string type: string
default: Debug 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
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: jobs:
build: build:
name: Build (${{ matrix.artifact-name }})
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
- os: ubuntu-22.04 - os: ubuntu-20.04
artifact-name: Linux qt_ver: 5
base-cmake-preset: linux
- os: ubuntu-20.04
qt_ver: 6
qt_host: linux
qt_arch: ""
qt_version: "6.2.4"
qt_modules: "qt5compat qtimageformats"
qt_tools: ""
- os: windows-2022 - os: windows-2022
artifact-name: Windows-MinGW-w64 name: "Windows-MinGW-w64"
base-cmake-preset: windows_mingw msystem: clang64
msystem: CLANG64 vcvars_arch: "amd64_x86"
vcvars-arch: amd64_x86
- os: windows-11-arm
artifact-name: Windows-MinGW-arm64
base-cmake-preset: windows_mingw
msystem: CLANGARM64
vcvars-arch: arm64
- os: windows-2022 - os: windows-2022
artifact-name: Windows-MSVC name: "Windows-MSVC"
base-cmake-preset: windows_msvc msystem: ""
# TODO(@getchoo): This is the default in setup-dependencies/windows. Why isn't it working?!?! architecture: "x64"
vcvars-arch: amd64 vcvars_arch: "amd64"
qt_ver: 6
qt_host: windows
qt_arch: ''
qt_version: '6.6.3'
qt_modules: 'qt5compat qtimageformats'
qt_tools: ''
- os: windows-2022 - os: windows-2022
artifact-name: Windows-MSVC-arm64 name: "Windows-MSVC-arm64"
base-cmake-preset: windows_msvc_arm64_cross msystem: ""
vcvars-arch: amd64_arm64 architecture: "arm64"
qt-architecture: win64_msvc2022_arm64_cross_compiled vcvars_arch: "amd64_arm64"
qt_ver: 6
qt_host: windows
qt_arch: 'win64_msvc2019_arm64'
qt_version: '6.6.3'
qt_modules: 'qt5compat qtimageformats'
qt_tools: ''
- os: macos-14 - os: macos-12
artifact-name: macOS name: macOS
base-cmake-preset: ${{ (inputs.build-type || 'Debug') == 'Debug' && 'macos_universal' || 'macos' }} macosx_deployment_target: 11.0
macosx-deployment-target: 12.0 qt_ver: 6
qt_host: mac
qt_arch: ''
qt_version: '6.6.3'
qt_modules: 'qt5compat qtimageformats'
qt_tools: ''
- os: macos-12
name: macOS-Legacy
macosx_deployment_target: 10.13
qt_ver: 5
qt_host: mac
qt_version: "5.15.2"
qt_modules: ""
qt_tools: ""
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
defaults:
run:
shell: ${{ matrix.msystem != '' && 'msys2 {0}' || 'bash' }}
env: env:
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: steps:
## ##
# SETUP # PREPARE
## ##
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
submodules: true submodules: "true"
- name: Setup dependencies - name: "Setup MSYS2"
id: setup-dependencies if: runner.os == 'Windows' && matrix.msystem != ''
uses: ./.github/actions/setup-dependencies uses: msys2/setup-msys2@v2
with: with:
build-type: ${{ inputs.build-type || 'Debug' }}
msystem: ${{ matrix.msystem }} msystem: ${{ matrix.msystem }}
vcvars-arch: ${{ matrix.vcvars-arch }} update: true
qt-architecture: ${{ matrix.qt-architecture }} 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
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.10
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@v3.3.2
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
- name: Install Dependencies (macOS)
if: runner.os == 'macOS'
run: |
brew update
brew install ninja extra-cmake-modules
- name: Install Qt (Linux)
if: runner.os == 'Linux' && matrix.qt_ver != 6
run: |
sudo apt-get -y install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5
- 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 }}
tools: ${{ matrix.qt_tools }}
cache: ${{ inputs.is_qt_cached }}
cache-key-prefix: host-qt-arm64-windows
dir: ${{ github.workspace }}\HostQt
set-env: false
- name: Install Qt (macOS, Linux, Qt 6 & Windows MSVC)
if: runner.os == 'Linux' && matrix.qt_ver == 6 || runner.os == 'macOS' || (runner.os == 'Windows' && matrix.msystem == '')
uses: jurplel/install-qt-action@v3
with:
aqtversion: "==3.1.*"
py7zrversion: ">=0.20.2"
version: ${{ matrix.qt_version }}
host: ${{ matrix.qt_host }}
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
##
# CONFIGURE
##
- 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_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -G Ninja
- name: Configure CMake (macOS-Legacy)
if: runner.os == 'macOS' && matrix.qt_ver == 5
run: |
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DMACOSX_SPARKLE_UPDATE_PUBLIC_KEY="" -DMACOSX_SPARKLE_UPDATE_FEED_URL="" -G Ninja
- name: Configure CMake (Windows MinGW-w64)
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_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_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_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DLauncher_BUILD_ARTIFACT=Linux-Qt${{ matrix.qt_ver }} -G Ninja
## ##
# BUILD # BUILD
## ##
- name: Get CMake preset - name: Build
id: cmake-preset if: runner.os != 'Windows'
env:
BASE_CMAKE_PRESET: ${{ matrix.base-cmake-preset }}
PRESET_TYPE: ${{ (inputs.build-type || 'Debug') == 'Debug' && 'debug' || 'ci' }}
run: | run: |
echo preset="$BASE_CMAKE_PRESET"_"$PRESET_TYPE" >> "$GITHUB_OUTPUT" cmake --build ${{ env.BUILD_DIR }}
- name: Run CMake workflow - name: Build (Windows MinGW-w64)
env: if: runner.os == 'Windows' && matrix.msystem != ''
CMAKE_PRESET: ${{ steps.cmake-preset.outputs.preset }} shell: msys2 {0}
run: | run: |
cmake --workflow --preset "$CMAKE_PRESET" cmake --build ${{ env.BUILD_DIR }}
- name: Build (Windows MSVC)
if: runner.os == 'Windows' && matrix.msystem == ''
run: |
cmake --build ${{ env.BUILD_DIR }} --config ${{ inputs.build_type }}
## ##
# PACKAGE # TEST
## ##
- name: Get short version - name: Test
id: short-version if: runner.os != 'Windows'
shell: bash
run: | run: |
echo "version=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT" ctest -E "^example64|example$" --test-dir build --output-on-failure
- name: Package (Linux) - name: Test (Windows MinGW-w64)
if: ${{ runner.os == 'Linux' }} if: runner.os == 'Windows' && matrix.msystem != ''
uses: ./.github/actions/package/linux shell: msys2 {0}
with: run: |
version: ${{ steps.short-version.outputs.version }} ctest -E "^example64|example$" --test-dir build --output-on-failure
build-type: ${{ steps.setup-dependencies.outputs.build-type }}
cmake-preset: ${{ steps.cmake-preset.outputs.preset }}
qt-version: ${{ steps.setup-dependencies.outputs.qt-version }}
gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} - name: Test (Windows MSVC)
gpg-private-key-id: ${{ secrets.GPG_PRIVATE_KEY_ID }} 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) - name: Package (macOS)
if: ${{ runner.os == 'macOS' }} if: runner.os == 'macOS'
uses: ./.github/actions/package/macos run: |
cmake --install ${{ env.BUILD_DIR }}
cd ${{ env.INSTALL_DIR }}
chmod +x "PrismLauncher.app/Contents/MacOS/prismlauncher"
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
brew install openssl@3
echo '${{ secrets.SPARKLE_ED25519_KEY }}' > ed25519-priv.pem
signature=$(/usr/local/opt/openssl@3/bin/openssl pkeyutl -sign -rawin -in ${{ github.workspace }}/PrismLauncher.zip -inkey ed25519-priv.pem | openssl base64 | tr -d \\n)
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 ${{ env.INSTALL_DIR }}
if ("${{ matrix.qt_ver }}" -eq "5")
{
Copy-Item ${{ runner.workspace }}/Qt/Tools/OpenSSL/Win_x86/bin/libcrypto-1_1.dll -Destination libcrypto-1_1.dll
Copy-Item ${{ runner.workspace }}/Qt/Tools/OpenSSL/Win_x86/bin/libssl-1_1.dll -Destination libssl-1_1.dll
}
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: |
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 (Linux)
if: runner.os == 'Linux'
run: |
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_DIR }}
for l in $(find ${{ env.INSTALL_DIR }} -type f); do l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_DIR }}/}; l=${l#./}; echo $l; done > ${{ env.INSTALL_DIR }}/manifest.txt
cd ${{ env.INSTALL_DIR }}
tar --owner root --group root -czf ../PrismLauncher.tar.gz *
- name: Package (Linux, portable)
if: runner.os == 'Linux'
run: |
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }}
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable
# workaround to make portable installs to work on fedora
mkdir ${{ env.INSTALL_PORTABLE_DIR }}/lib
cp /lib/x86_64-linux-gnu/libbz2.so.1.0 ${{ 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 *
- name: Package AppImage (Linux)
if: runner.os == 'Linux' && matrix.qt_ver != 5
shell: bash
env:
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
run: |
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_APPIMAGE_DIR }}/usr
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"
##
# UPLOAD BUILDS
##
- name: Upload binary tarball (macOS)
if: runner.os == 'macOS'
uses: actions/upload-artifact@v3
with: with:
version: ${{ steps.short-version.outputs.version }} name: PrismLauncher-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
build-type: ${{ steps.setup-dependencies.outputs.build-type }} path: PrismLauncher.zip
artifact-name: ${{ matrix.artifact-name }}
apple-codesign-cert: ${{ secrets.APPLE-CODESIGN-CERT }} - name: Upload binary zip (Windows)
apple-codesign-password: ${{ secrets.APPLE-CODESIGN_PASSWORD }} if: runner.os == 'Windows'
apple-codesign-id: ${{ secrets.APPLE-CODESIGN_ID }} uses: actions/upload-artifact@v3
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 }}
- name: Package (Windows)
if: ${{ runner.os == 'Windows' }}
uses: ./.github/actions/package/windows
with: with:
version: ${{ steps.short-version.outputs.version }} name: PrismLauncher-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
build-type: ${{ steps.setup-dependencies.outputs.build-type }} path: ${{ env.INSTALL_DIR }}/**
artifact-name: ${{ matrix.artifact-name }}
msystem: ${{ matrix.msystem }}
windows-codesign-cert: ${{ secrets.WINDOWS_CODESIGN_CERT }} - name: Upload binary zip (Windows, portable)
windows-codesign-password: ${{ secrets.WINDOWS_CODESIGN_PASSWORD }} if: runner.os == 'Windows'
uses: actions/upload-artifact@v3
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@v3
with:
name: PrismLauncher-${{ matrix.name }}-Setup-${{ env.VERSION }}-${{ inputs.build_type }}
path: PrismLauncher-Setup.exe
- name: Upload binary tarball (Linux, Qt 5)
if: runner.os == 'Linux' && matrix.qt_ver != 6
uses: actions/upload-artifact@v3
with:
name: PrismLauncher-${{ runner.os }}-Qt5-${{ env.VERSION }}-${{ inputs.build_type }}
path: PrismLauncher.tar.gz
- name: Upload binary tarball (Linux, portable, Qt 5)
if: runner.os == 'Linux' && matrix.qt_ver != 6
uses: actions/upload-artifact@v3
with:
name: PrismLauncher-${{ runner.os }}-Qt5-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
path: PrismLauncher-portable.tar.gz
- name: Upload binary tarball (Linux, Qt 6)
if: runner.os == 'Linux' && matrix.qt_ver !=5
uses: actions/upload-artifact@v3
with:
name: PrismLauncher-${{ runner.os }}-Qt6-${{ env.VERSION }}-${{ inputs.build_type }}
path: PrismLauncher.tar.gz
- name: Upload binary tarball (Linux, portable, Qt 6)
if: runner.os == 'Linux' && matrix.qt_ver != 5
uses: actions/upload-artifact@v3
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@v3
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@v3
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: bilelmoussaoui/flatpak-github-actions:kde-5.15-23.08
options: --privileged
steps:
- name: Checkout
uses: actions/checkout@v4
if: inputs.build_type == 'Debug'
with:
submodules: "true"
- name: Build Flatpak (Linux)
if: inputs.build_type == 'Debug'
uses: flatpak/flatpak-github-actions/flatpak-builder@v6
with:
bundle: "Prism Launcher.flatpak"
manifest-path: flatpak/org.prismlauncher.PrismLauncher.yml

View File

@ -1,50 +1,6 @@
name: "CodeQL Code Scanning" name: "CodeQL Code Scanning"
on: on: [ push, pull_request, workflow_dispatch ]
push:
paths:
# File types
- "**.cpp"
- "**.h"
- "**.java"
# Directories
- "buildconfig/"
- "cmake/"
- "launcher/"
- "libraries/"
- "program_info/"
- "tests/"
# Files
- "CMakeLists.txt"
- "COPYING.md"
# Workflows
- ".github/codeql"
- ".github/workflows/codeql.yml"
pull_request:
paths:
# File types
- "**.cpp"
- "**.h"
# Directories
- "buildconfig/"
- "cmake/"
- "launcher/"
- "libraries/"
- "program_info/"
- "tests/"
# Files
- "CMakeLists.txt"
- "COPYING.md"
# Workflows
- ".github/codeql"
- ".github/workflows/codeql.yml"
workflow_dispatch:
jobs: jobs:
CodeQL: CodeQL:
@ -54,24 +10,26 @@ jobs:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
submodules: "true" submodules: 'true'
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v3 uses: github/codeql-action/init@v2
with: with:
config-file: ./.github/codeql/codeql-config.yml config-file: ./.github/codeql/codeql-config.yml
queries: security-and-quality queries: security-and-quality
languages: cpp, java languages: cpp, java
- name: Setup dependencies - name: Install Dependencies
uses: ./.github/actions/setup-dependencies run:
with: sudo apt-get -y update
build-type: Debug
sudo apt-get -y install ninja-build extra-cmake-modules scdoc qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5
- name: Configure and Build - name: Configure and Build
run: | run: |
cmake --preset linux_debug cmake -S . -B build -DCMAKE_INSTALL_PREFIX=/usr -DLauncher_QT_VERSION_MAJOR=5 -G Ninja
cmake --build --preset linux_debug
cmake --build build
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3 uses: github/codeql-action/analyze@v2

View File

@ -1,95 +0,0 @@
name: Flatpak
on:
push:
# We don't do anything with these artifacts on releases. They go to Flathub
tags-ignore:
- "*"
paths:
# File types
- "**.cpp"
- "**.h"
- "**.java"
# Build files
- "flatpak/"
# Directories
- "buildconfig/"
- "cmake/"
- "launcher/"
- "libraries/"
- "program_info/"
- "tests/"
# Files
- "CMakeLists.txt"
- "COPYING.md"
# Workflows
- ".github/workflows/flatpak.yml"
pull_request:
paths:
# File types
- "**.cpp"
- "**.h"
# Build files
- "flatpak/"
# Directories
- "buildconfig/"
- "cmake/"
- "launcher/"
- "libraries/"
- "program_info/"
- "tests/"
# Files
- "CMakeLists.txt"
- "COPYING.md"
# Workflows
- ".github/workflows/flatpak.yml"
workflow_dispatch:
permissions:
contents: read
jobs:
build:
name: Build (${{ matrix.arch }})
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-22.04
arch: x86_64
- os: ubuntu-22.04-arm
arch: aarch64
runs-on: ${{ matrix.os }}
container:
image: ghcr.io/flathub-infra/flatpak-github-actions:kde-6.8
options: --privileged
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: true
- name: Set short version
shell: bash
run: |
echo "VERSION=${GITHUB_SHA::7}" >> "$GITHUB_ENV"
- name: Build Flatpak
uses: flatpak/flatpak-github-actions/flatpak-builder@v6
with:
bundle: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-Flatpak.flatpak
manifest-path: flatpak/org.prismlauncher.PrismLauncher.yml
arch: ${{ matrix.arch }}

View File

@ -1,62 +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
jobs:
update-blocked-status:
name: Update Blocked Status
runs-on: ubuntu-latest
# 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, 'blocking') }}
steps:
- name: Generate token
id: generate-token
uses: actions/create-github-app-token@v2
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 '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,143 +0,0 @@
name: Nix
on:
push:
tags:
- "*"
paths:
# File types
- "**.cpp"
- "**.h"
- "**.java"
# Build files
- "**.nix"
- "nix/"
- "flake.lock"
# Directories
- "buildconfig/"
- "cmake/"
- "launcher/"
- "libraries/"
- "program_info/"
- "tests/"
# Files
- "CMakeLists.txt"
- "COPYING.md"
# Workflows
- ".github/workflows/nix.yml"
pull_request_target:
paths:
# File types
- "**.cpp"
- "**.h"
# Build files
- "**.nix"
- "nix/"
- "flake.lock"
# Directories
- "buildconfig/"
- "cmake/"
- "launcher/"
- "libraries/"
- "program_info/"
- "tests/"
# Files
- "CMakeLists.txt"
- "COPYING.md"
# Workflows
- ".github/workflows/nix.yml"
workflow_dispatch:
permissions:
contents: read
env:
DEBUG: ${{ github.ref_type != 'tag' }}
USE_DETERMINATE: ${{ github.event_name == 'pull_request' }}
jobs:
build:
name: Build (${{ matrix.system }})
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-22.04
system: x86_64-linux
- os: ubuntu-22.04-arm
system: aarch64-linux
- os: macos-13
system: x86_64-darwin
- os: macos-14
system: aarch64-darwin
runs-on: ${{ matrix.os }}
permissions:
id-token: write
steps:
- name: Get merge commit
if: ${{ github.event_name == 'pull_request_target' }}
id: merge-commit
uses: PrismLauncher/PrismLauncher/.github/actions/get-merge-commit@develop
with:
pull-request-id: ${{ github.event.number }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ steps.merge-commit.outputs.merge-commit-sha || github.sha }}
- name: Install Nix
uses: DeterminateSystems/nix-installer-action@v17
with:
determinate: ${{ env.USE_DETERMINATE }}
# For PRs
- name: Setup Nix Magic Cache
if: ${{ env.USE_DETERMINATE == 'true' }}
uses: DeterminateSystems/flakehub-cache-action@v1
# For in-tree builds
- name: Setup Cachix
if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }}
uses: cachix/cachix-action@v16
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"

View File

@ -1,29 +0,0 @@
name: Stale
on:
schedule:
# run weekly on sunday
- cron: "0 0 * * 0"
workflow_dispatch:
jobs:
label:
name: Label issues and PRs
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v9
with:
days-before-stale: 60
days-before-close: -1 # Don't close anything
exempt-issue-labels: rfc,nostale,help wanted
exempt-all-milestones: true
exempt-all-assignees: true
operations-per-run: 1000
stale-issue-label: inactive
stale-pr-label: inactive

42
.github/workflows/trigger_builds.yml vendored Normal file
View File

@ -0,0 +1,42 @@
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 }}
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
GPG_PRIVATE_KEY_ID: ${{ secrets.GPG_PRIVATE_KEY_ID }}

View File

@ -10,8 +10,20 @@ jobs:
name: Build Release name: Build Release
uses: ./.github/workflows/build.yml uses: ./.github/workflows/build.yml
with: with:
build-type: Release build_type: Release
secrets: inherit 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 }}
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
GPG_PRIVATE_KEY_ID: ${{ secrets.GPG_PRIVATE_KEY_ID }}
create_release: create_release:
needs: build_release needs: build_release
@ -25,7 +37,7 @@ jobs:
submodules: "true" submodules: "true"
path: "PrismLauncher-source" path: "PrismLauncher-source"
- name: Download artifacts - name: Download artifacts
uses: actions/download-artifact@v4 uses: actions/download-artifact@v3
- name: Grab and store version - name: Grab and store version
run: | run: |
tag_name=$(echo ${{ github.ref }} | grep -oE "[^/]+$") tag_name=$(echo ${{ github.ref }} | grep -oE "[^/]+$")
@ -34,8 +46,12 @@ jobs:
run: | run: |
mv ${{ github.workspace }}/PrismLauncher-source PrismLauncher-${{ env.VERSION }} 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-Qt6-Portable*/PrismLauncher-portable.tar.gz PrismLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz
mv PrismLauncher-Linux-Qt6*/PrismLauncher.tar.gz PrismLauncher-Linux-Qt6-${{ env.VERSION }}.tar.gz
mv PrismLauncher-Linux-Qt5-Portable*/PrismLauncher-portable.tar.gz PrismLauncher-Linux-Qt5-Portable-${{ env.VERSION }}.tar.gz
mv PrismLauncher-Linux-Qt5*/PrismLauncher.tar.gz PrismLauncher-Linux-Qt5-${{ env.VERSION }}.tar.gz
mv PrismLauncher-*.AppImage/PrismLauncher-*.AppImage PrismLauncher-Linux-x86_64.AppImage 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-*.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.zip PrismLauncher-macOS-${{ env.VERSION }}.zip
tar --exclude='.git' -czf PrismLauncher-${{ env.VERSION }}.tar.gz PrismLauncher-${{ env.VERSION }} tar --exclude='.git' -czf PrismLauncher-${{ env.VERSION }}.tar.gz PrismLauncher-${{ env.VERSION }}
@ -68,7 +84,7 @@ jobs:
- name: Create release - name: Create release
id: create_release id: create_release
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@v1
with: with:
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
tag_name: ${{ github.ref }} tag_name: ${{ github.ref }}
@ -76,15 +92,15 @@ jobs:
draft: true draft: true
prerelease: false prerelease: false
files: | files: |
PrismLauncher-Linux-Qt5-${{ env.VERSION }}.tar.gz
PrismLauncher-Linux-Qt5-Portable-${{ env.VERSION }}.tar.gz
PrismLauncher-Linux-x86_64.AppImage PrismLauncher-Linux-x86_64.AppImage
PrismLauncher-Linux-x86_64.AppImage.zsync PrismLauncher-Linux-x86_64.AppImage.zsync
PrismLauncher-Linux-Qt6-${{ env.VERSION }}.tar.gz
PrismLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz PrismLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz
PrismLauncher-Windows-MinGW-w64-${{ env.VERSION }}.zip PrismLauncher-Windows-MinGW-w64-${{ env.VERSION }}.zip
PrismLauncher-Windows-MinGW-w64-Portable-${{ env.VERSION }}.zip PrismLauncher-Windows-MinGW-w64-Portable-${{ env.VERSION }}.zip
PrismLauncher-Windows-MinGW-w64-Setup-${{ env.VERSION }}.exe 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-${{ env.VERSION }}.zip
PrismLauncher-Windows-MSVC-arm64-Portable-${{ env.VERSION }}.zip PrismLauncher-Windows-MSVC-arm64-Portable-${{ env.VERSION }}.zip
PrismLauncher-Windows-MSVC-arm64-Setup-${{ env.VERSION }}.exe PrismLauncher-Windows-MSVC-arm64-Setup-${{ env.VERSION }}.exe
@ -92,4 +108,5 @@ jobs:
PrismLauncher-Windows-MSVC-Portable-${{ env.VERSION }}.zip PrismLauncher-Windows-MSVC-Portable-${{ env.VERSION }}.zip
PrismLauncher-Windows-MSVC-Setup-${{ env.VERSION }}.exe PrismLauncher-Windows-MSVC-Setup-${{ env.VERSION }}.exe
PrismLauncher-macOS-${{ env.VERSION }}.zip PrismLauncher-macOS-${{ env.VERSION }}.zip
PrismLauncher-macOS-Legacy-${{ env.VERSION }}.zip
PrismLauncher-${{ env.VERSION }}.tar.gz PrismLauncher-${{ env.VERSION }}.tar.gz

View File

@ -17,9 +17,9 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@526118121621777ccd86f79b04685a9319637641 # v31 - uses: cachix/install-nix-action@7ac1ec25491415c381d9b62f0657c7a028df52a7 # v24
- uses: DeterminateSystems/update-flake-lock@v24 - uses: DeterminateSystems/update-flake-lock@v20
with: with:
commit-msg: "chore(nix): update lockfile" commit-msg: "chore(nix): update lockfile"
pr-title: "chore(nix): update lockfile" pr-title: "chore(nix): update lockfile"

View File

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

8
.gitignore vendored
View File

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

6
.gitmodules vendored
View File

@ -4,6 +4,9 @@
[submodule "libraries/tomlplusplus"] [submodule "libraries/tomlplusplus"]
path = libraries/tomlplusplus path = libraries/tomlplusplus
url = https://github.com/marzer/tomlplusplus.git url = https://github.com/marzer/tomlplusplus.git
[submodule "libraries/filesystem"]
path = libraries/filesystem
url = https://github.com/gulrak/filesystem
[submodule "libraries/libnbtplusplus"] [submodule "libraries/libnbtplusplus"]
path = libraries/libnbtplusplus path = libraries/libnbtplusplus
url = https://github.com/PrismLauncher/libnbtplusplus.git url = https://github.com/PrismLauncher/libnbtplusplus.git
@ -19,6 +22,3 @@
[submodule "flatpak/shared-modules"] [submodule "flatpak/shared-modules"]
path = flatpak/shared-modules path = flatpak/shared-modules
url = https://github.com/flathub/shared-modules.git url = https://github.com/flathub/shared-modules.git
[submodule "libraries/qt-qrcodegenerator/QR-Code-generator"]
path = libraries/qt-qrcodegenerator/QR-Code-generator
url = https://github.com/nayuki/QR-Code-generator

3
BUILD.md Normal file
View File

@ -0,0 +1,3 @@
# Build Instructions
Full build instructions are available on [the website](https://prismlauncher.org/wiki/development/build-instructions/).

View File

@ -78,18 +78,13 @@ else()
# ATL's pack list needs more than the default 1 Mib stack on windows # ATL's pack list needs more than the default 1 Mib stack on windows
if(WIN32) if(WIN32)
set(CMAKE_EXE_LINKER_FLAGS "-Wl,--stack,8388608 ${CMAKE_EXE_LINKER_FLAGS}") set(CMAKE_EXE_LINKER_FLAGS "-Wl,--stack,8388608 ${CMAKE_EXE_LINKER_FLAGS}")
# -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
foreach(lang C CXX)
set("CMAKE_${lang}_FLAGS_RELEASE" "-ffunction-sections -fdata-sections -mguard=cf")
endforeach()
endif() endif()
endif() endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_WARN_DEPRECATED_UP_TO=0x060200") # Fix build with Qt 5.13
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_DISABLE_DEPRECATED_UP_TO=0x060000") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_NO_DEPRECATED_WARNINGS=Y")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_DISABLE_DEPRECATED_BEFORE=0x050C00")
# Fix aarch64 build for toml++ # Fix aarch64 build for toml++
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DTOML_ENABLE_FLOAT16=0") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DTOML_ENABLE_FLOAT16=0")
@ -97,12 +92,6 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DTOML_ENABLE_FLOAT16=0")
# set CXXFLAGS for build targets # set CXXFLAGS for build targets
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -D_FORTIFY_SOURCE=2 ${CMAKE_CXX_FLAGS_RELEASE}") set(CMAKE_CXX_FLAGS_RELEASE "-O2 -D_FORTIFY_SOURCE=2 ${CMAKE_CXX_FLAGS_RELEASE}")
# 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 STREQUAL "Ninja" AND CMAKE_BUILD_TYPE STREQUAL "Debug")
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
endif()
option(DEBUG_ADDRESS_SANITIZER "Enable Address Sanitizer in Debug builds" OFF) option(DEBUG_ADDRESS_SANITIZER "Enable Address Sanitizer in Debug builds" OFF)
# If this is a Debug build turn on address sanitiser # If this is a Debug build turn on address sanitiser
@ -117,14 +106,14 @@ if ((CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebI
else() else()
# AppleClang and Clang # AppleClang and Clang
message(STATUS "Address Sanitizer available on Clang") message(STATUS "Address Sanitizer available on Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined -fno-sanitize-recover=null") 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 -fsanitize=undefined -fno-sanitize-recover=null") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
endif() endif()
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
# GCC # GCC
message(STATUS "Address Sanitizer available on GCC") message(STATUS "Address Sanitizer available on GCC")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined -fno-sanitize-recover") 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 -fsanitize=undefined -fno-sanitize-recover") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
link_libraries("asan") link_libraries("asan")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
message(STATUS "Address Sanitizer available on MSVC") message(STATUS "Address Sanitizer available on MSVC")
@ -187,17 +176,14 @@ endif()
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_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_NEWS_OPEN_URL "https://prismlauncher.org/news" CACHE STRING "URL that gets opened when the user clicks 'More News'")
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_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_FMLLIBS_BASE_URL "https://files.prismlauncher.org/fmllibs/" CACHE STRING "URL for FML Libraries.")
######## Set version numbers ######## ######## Set version numbers ########
set(Launcher_VERSION_MAJOR 10) set(Launcher_VERSION_MAJOR 8)
set(Launcher_VERSION_MINOR 0) set(Launcher_VERSION_MINOR 3)
set(Launcher_VERSION_PATCH 0)
set(Launcher_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_PATCH}") set(Launcher_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}")
set(Launcher_VERSION_NAME4 "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_PATCH}.0") set(Launcher_VERSION_NAME4 "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.0.0")
set(Launcher_VERSION_NAME4_COMMA "${Launcher_VERSION_MAJOR},${Launcher_VERSION_MINOR},${Launcher_VERSION_PATCH},0") set(Launcher_VERSION_NAME4_COMMA "${Launcher_VERSION_MAJOR},${Launcher_VERSION_MINOR},0,0")
# Build platform. # 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.") 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.")
@ -219,7 +205,6 @@ set(Launcher_BUG_TRACKER_URL "https://github.com/PrismLauncher/PrismLauncher/iss
# Translations Platform URL # Translations Platform URL
set(Launcher_TRANSLATIONS_URL "https://hosted.weblate.org/projects/prismlauncher/launcher/" CACHE STRING "URL for the translations platform.") set(Launcher_TRANSLATIONS_URL "https://hosted.weblate.org/projects/prismlauncher/launcher/" CACHE STRING "URL for the translations platform.")
set(Launcher_TRANSLATION_FILES_URL "https://i18n.prismlauncher.org/" CACHE STRING "URL for the translations files.")
# Matrix Space # Matrix Space
set(Launcher_MATRIX_URL "https://prismlauncher.org/matrix" CACHE STRING "URL to the Matrix Space") set(Launcher_MATRIX_URL "https://prismlauncher.org/matrix" CACHE STRING "URL to the Matrix Space")
@ -234,19 +219,6 @@ set(Launcher_SUBREDDIT_URL "https://prismlauncher.org/reddit" CACHE STRING "URL
set(Launcher_FORCE_BUNDLED_LIBS OFF CACHE BOOL "Prevent using system libraries, if they are available as submodules") set(Launcher_FORCE_BUNDLED_LIBS OFF CACHE BOOL "Prevent using system libraries, if they are available as submodules")
set(Launcher_QT_VERSION_MAJOR "6" CACHE STRING "Major Qt version to build against") set(Launcher_QT_VERSION_MAJOR "6" CACHE STRING "Major Qt version to build against")
# Java downloader
set(Launcher_ENABLE_JAVA_DOWNLOADER_DEFAULT ON)
# Although we recommend enabling this, we cannot guarantee binary compatibility on
# differing Linux/BSD/etc distributions. Downstream packagers should be explicitly opt-ing into this
# feature if they know it will work with their distribution.
if(UNIX AND NOT APPLE)
set(Launcher_ENABLE_JAVA_DOWNLOADER_DEFAULT OFF)
endif()
# Java downloader
option(Launcher_ENABLE_JAVA_DOWNLOADER "Build the java downloader feature" ${Launcher_ENABLE_JAVA_DOWNLOADER_DEFAULT})
# Native libraries # Native libraries
if(UNIX AND APPLE) if(UNIX AND APPLE)
set(Launcher_GLFW_LIBRARY_NAME "libglfw.dylib" CACHE STRING "Name of native glfw library") set(Launcher_GLFW_LIBRARY_NAME "libglfw.dylib" CACHE STRING "Name of native glfw library")
@ -308,11 +280,23 @@ endif()
# Find the required Qt parts # Find the required Qt parts
include(QtVersionlessBackport) include(QtVersionlessBackport)
if(Launcher_QT_VERSION_MAJOR EQUAL 6) if(Launcher_QT_VERSION_MAJOR EQUAL 5)
set(QT_VERSION_MAJOR 5)
find_package(Qt5 REQUIRED COMPONENTS Core Widgets Concurrent Network Test Xml)
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) set(QT_VERSION_MAJOR 6)
find_package(Qt6 REQUIRED COMPONENTS Core CoreTools Widgets Concurrent Network Test Xml Core5Compat NetworkAuth OpenGL) find_package(Qt6 REQUIRED COMPONENTS Core CoreTools Widgets Concurrent Network Test Xml Core5Compat)
find_package(Qt6 COMPONENTS DBus)
list(APPEND Launcher_QT_DBUS Qt6::DBus)
list(APPEND Launcher_QT_LIBS Qt6::Core5Compat) list(APPEND Launcher_QT_LIBS Qt6::Core5Compat)
if(NOT Launcher_FORCE_BUNDLED_LIBS) if(NOT Launcher_FORCE_BUNDLED_LIBS)
@ -326,16 +310,29 @@ else()
message(FATAL_ERROR "Qt version ${Launcher_QT_VERSION_MAJOR} is not supported") message(FATAL_ERROR "Qt version ${Launcher_QT_VERSION_MAJOR} is not supported")
endif() 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_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_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}) set(QT_LIBEXECS_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_LIBEXECS})
endif() endif()
# NOTE: Qt 6 already sets this by default
if (Qt5_POSITION_INDEPENDENT_CODE)
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
if(NOT Launcher_FORCE_BUNDLED_LIBS) if(NOT Launcher_FORCE_BUNDLED_LIBS)
# Find toml++ # Find toml++
find_package(tomlplusplus 3.2.0 QUIET) find_package(tomlplusplus 3.2.0 QUIET)
# Find ghc_filesystem
find_package(ghc_filesystem QUIET)
# Find cmark # Find cmark
find_package(cmark QUIET) find_package(cmark QUIET)
endif() endif()
@ -353,7 +350,7 @@ set(Launcher_ENABLE_UPDATER NO)
set(Launcher_BUILD_UPDATER NO) set(Launcher_BUILD_UPDATER NO)
if (NOT APPLE AND (NOT Launcher_UPDATER_GITHUB_REPO STREQUAL "" AND NOT Launcher_BUILD_ARTIFACT STREQUAL "")) 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() endif()
if(NOT (UNIX AND APPLE)) if(NOT (UNIX AND APPLE))
@ -384,8 +381,8 @@ if(UNIX AND APPLE)
set(MACOSX_SPARKLE_UPDATE_PUBLIC_KEY "v55ZWWD6QlPoXGV6VLzOTZxZUggWeE51X8cRQyQh6vA=" CACHE STRING "Public key for Sparkle update feed") set(MACOSX_SPARKLE_UPDATE_PUBLIC_KEY "v55ZWWD6QlPoXGV6VLzOTZxZUggWeE51X8cRQyQh6vA=" CACHE STRING "Public key for Sparkle update feed")
set(MACOSX_SPARKLE_UPDATE_FEED_URL "https://prismlauncher.org/feed/appcast.xml" CACHE STRING "URL for Sparkle update feed") set(MACOSX_SPARKLE_UPDATE_FEED_URL "https://prismlauncher.org/feed/appcast.xml" CACHE STRING "URL for Sparkle update feed")
set(MACOSX_SPARKLE_DOWNLOAD_URL "https://github.com/sparkle-project/Sparkle/releases/download/2.6.4/Sparkle-2.6.4.tar.xz" CACHE STRING "URL to Sparkle release archive") set(MACOSX_SPARKLE_DOWNLOAD_URL "https://github.com/sparkle-project/Sparkle/releases/download/2.5.2/Sparkle-2.5.2.tar.xz" CACHE STRING "URL to Sparkle release archive")
set(MACOSX_SPARKLE_SHA256 "50612a06038abc931f16011d7903b8326a362c1074dabccb718404ce8e585f0b" CACHE STRING "SHA256 checksum for Sparkle release archive") set(MACOSX_SPARKLE_SHA256 "572dd67ae398a466f19f343a449e1890bac1ef74885b4739f68f979a8a89884b" CACHE STRING "SHA256 checksum for Sparkle release archive")
set(MACOSX_SPARKLE_DIR "${CMAKE_BINARY_DIR}/frameworks/Sparkle") set(MACOSX_SPARKLE_DIR "${CMAKE_BINARY_DIR}/frameworks/Sparkle")
# directories to look for dependencies # directories to look for dependencies
@ -421,18 +418,6 @@ elseif(UNIX)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/launcher/qtlogging.ini" DESTINATION "share/${Launcher_Name}") install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/launcher/qtlogging.ini" DESTINATION "share/${Launcher_Name}")
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) if(Launcher_ManPage)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_ManPage} DESTINATION "${KDE_INSTALL_MANDIR}/man6") install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_ManPage} DESTINATION "${KDE_INSTALL_MANDIR}/man6")
endif() endif()
@ -475,7 +460,6 @@ add_subdirectory(libraries/libnbtplusplus)
add_subdirectory(libraries/systeminfo) # system information library add_subdirectory(libraries/systeminfo) # system information library
add_subdirectory(libraries/launcher) # java based launcher part for Minecraft add_subdirectory(libraries/launcher) # java based launcher part for Minecraft
add_subdirectory(libraries/javacheck) # java compatibility checker add_subdirectory(libraries/javacheck) # java compatibility checker
add_subdirectory(libraries/qt-qrcodegenerator) # qr code generator
if(FORCE_BUNDLED_ZLIB) if(FORCE_BUNDLED_ZLIB)
message(STATUS "Using bundled zlib") message(STATUS "Using bundled zlib")
@ -520,17 +504,22 @@ else()
endif() endif()
if(NOT cmark_FOUND) if(NOT cmark_FOUND)
message(STATUS "Using bundled cmark") message(STATUS "Using bundled cmark")
set(ORIGINAL_BUILD_TESTING ${BUILD_TESTING})
set(BUILD_TESTING 0) set(BUILD_TESTING 0)
set(BUILD_SHARED_LIBS 0) set(BUILD_SHARED_LIBS 0)
add_subdirectory(libraries/cmark EXCLUDE_FROM_ALL) # Markdown parser add_subdirectory(libraries/cmark EXCLUDE_FROM_ALL) # Markdown parser
add_library(cmark::cmark ALIAS cmark) add_library(cmark::cmark ALIAS cmark)
set(BUILD_TESTING ${ORIGINAL_BUILD_TESTING})
else() else()
message(STATUS "Using system cmark") message(STATUS "Using system cmark")
endif() endif()
add_subdirectory(libraries/katabasis) # An OAuth2 library that tried to do too much
add_subdirectory(libraries/gamemode) add_subdirectory(libraries/gamemode)
add_subdirectory(libraries/murmur2) # Hash for usage with the CurseForge API add_subdirectory(libraries/murmur2) # Hash for usage with the CurseForge API
if (NOT ghc_filesystem_FOUND)
message(STATUS "Using bundled ghc_filesystem")
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 add_subdirectory(libraries/qdcss) # css parser
############################### Built Artifacts ############################### ############################### Built Artifacts ###############################

View File

@ -1,14 +0,0 @@
{
"$schema": "https://cmake.org/cmake/help/latest/_downloads/3e2d73bff478d88a7de0de736ba5e361/schema.json",
"version": 8,
"cmakeMinimumRequired": {
"major": 3,
"minor": 28
},
"include": [
"cmake/linuxPreset.json",
"cmake/macosPreset.json",
"cmake/windowsMinGWPreset.json",
"cmake/windowsMSVCPreset.json"
]
}

View File

@ -2,59 +2,16 @@
## Code formatting ## Code formatting
All files are formatted with `clang-format` using the configuration in `.clang-format`. Ensure it is run on changed files before committing! Try to follow the existing formatting.
If there is no existing formatting, you may use `clang-format` with our included `.clang-format` configuration.
Please also follow the project's conventions for C++: In general, in order of importance:
- Class and type names should be formatted as `PascalCase`: `MyClass`. - Make sure your IDE is not messing up line endings or whitespace and avoid using linters.
- Private or protected class data members should be formatted as `camelCase` prefixed with `m_`: `m_myCounter`. - Prefer readability over dogma.
- Private or protected `static` class data members should be formatted as `camelCase` prefixed with `s_`: `s_instance`. - Keep to the existing formatting.
- Public class data members should be formatted as `camelCase` without the prefix: `dateOfBirth`. - Indent with 4 space unless it's in a submodule.
- Public, private or protected `static const` class data members should be formatted as `SCREAMING_SNAKE_CASE`: `MAX_VALUE`. - Keep lists (of arguments, parameters, initializers...) as lists, not paragraphs. It should either read from top to bottom, or left to right. Not both.
- 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, macros, and enum constants should be formatted as `SCREAMING_SNAKE_CASE`: `LIGHT_GRAY`.
- Avoid inventing acronyms or abbreviations especially for a name of multiple words - like `tp` for `texturePack`.
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 { HAM_AND_PINEAPPLE, OREO_AND_KETCHUP };
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.
## Signing your work ## Signing your work

View File

@ -1,7 +1,7 @@
## Prism Launcher ## Prism Launcher
Prism Launcher - Minecraft Launcher Prism Launcher - Minecraft Launcher
Copyright (C) 2022-2025 Prism Launcher Contributors Copyright (C) 2022-2024 Prism Launcher Contributors
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -108,7 +108,7 @@
Information on third party licenses used in MinGW-w64 can be found in its COPYING.MinGW-w64-runtime.txt. 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. Copyright (C) 2022 The Qt Company Ltd and other contributors.
Contact: https://www.qt.io/licensing Contact: https://www.qt.io/licensing
@ -333,6 +333,32 @@
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT 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. OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
## O2 (Katabasis fork)
Copyright (c) 2012, Akos Polster
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.
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.
## Gamemode ## Gamemode
Copyright (c) 2017-2022, Feral Interactive Copyright (c) 2017-2022, Feral Interactive
@ -362,6 +388,28 @@
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. POSSIBILITY OF SUCH DAMAGE.
## gulrak/filesystem
Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
## Breeze icons ## Breeze icons
Copyright (C) 2014 Uri Herrera <uri_herrera@nitrux.in> and others Copyright (C) 2014 Uri Herrera <uri_herrera@nitrux.in> and others
@ -403,12 +451,3 @@
You should have received a copy of the GNU Lesser General Public 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/>. License along with this library. If not, see <http://www.gnu.org/licenses/>.
## qt-qrcodegenerator (`libraries/qt-qrcodegenerator`)
Copyright © 2024 Project Nayuki. (MIT License)
https://www.nayuki.io/page/qr-code-generator-library
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

@ -61,12 +61,7 @@ The translation effort for Prism Launcher is hosted on [Weblate](https://hosted.
## Building ## Building
If you want to build Prism Launcher yourself, check the build instructions: If you want to build Prism Launcher yourself, check the [Build Instructions](https://prismlauncher.org/wiki/development/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 ## Sponsors & Partners

View File

@ -34,8 +34,8 @@
*/ */
#include <qstringliteral.h> #include <qstringliteral.h>
#include <QObject>
#include "BuildConfig.h" #include "BuildConfig.h"
#include <QObject>
const Config BuildConfig; const Config BuildConfig;
@ -49,7 +49,7 @@ Config::Config()
LAUNCHER_DOMAIN = "@Launcher_Domain@"; LAUNCHER_DOMAIN = "@Launcher_Domain@";
LAUNCHER_CONFIGFILE = "@Launcher_ConfigFile@"; LAUNCHER_CONFIGFILE = "@Launcher_ConfigFile@";
LAUNCHER_GIT = "@Launcher_Git@"; LAUNCHER_GIT = "@Launcher_Git@";
LAUNCHER_APPID = "@Launcher_AppID@"; LAUNCHER_DESKTOPFILENAME = "@Launcher_DesktopFileName@";
LAUNCHER_SVGFILENAME = "@Launcher_SVGFileName@"; LAUNCHER_SVGFILENAME = "@Launcher_SVGFileName@";
USER_AGENT = "@Launcher_UserAgent@"; USER_AGENT = "@Launcher_UserAgent@";
@ -58,7 +58,6 @@ Config::Config()
// Version information // Version information
VERSION_MAJOR = @Launcher_VERSION_MAJOR@; VERSION_MAJOR = @Launcher_VERSION_MAJOR@;
VERSION_MINOR = @Launcher_VERSION_MINOR@; VERSION_MINOR = @Launcher_VERSION_MINOR@;
VERSION_PATCH = @Launcher_VERSION_PATCH@;
BUILD_PLATFORM = "@Launcher_BUILD_PLATFORM@"; BUILD_PLATFORM = "@Launcher_BUILD_PLATFORM@";
BUILD_ARTIFACT = "@Launcher_BUILD_ARTIFACT@"; BUILD_ARTIFACT = "@Launcher_BUILD_ARTIFACT@";
@ -75,52 +74,55 @@ Config::Config()
MAC_SPARKLE_PUB_KEY = "@MACOSX_SPARKLE_UPDATE_PUBLIC_KEY@"; MAC_SPARKLE_PUB_KEY = "@MACOSX_SPARKLE_UPDATE_PUBLIC_KEY@";
MAC_SPARKLE_APPCAST_URL = "@MACOSX_SPARKLE_UPDATE_FEED_URL@"; 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; UPDATER_ENABLED = true;
} else if (!UPDATER_GITHUB_REPO.isEmpty() && !BUILD_ARTIFACT.isEmpty()) { } else if(!UPDATER_GITHUB_REPO.isEmpty() && !BUILD_ARTIFACT.isEmpty()) {
UPDATER_ENABLED = true; UPDATER_ENABLED = true;
} }
#cmakedefine01 Launcher_ENABLE_JAVA_DOWNLOADER
JAVA_DOWNLOADER_ENABLED = Launcher_ENABLE_JAVA_DOWNLOADER;
GIT_COMMIT = "@Launcher_GIT_COMMIT@"; GIT_COMMIT = "@Launcher_GIT_COMMIT@";
GIT_TAG = "@Launcher_GIT_TAG@"; GIT_TAG = "@Launcher_GIT_TAG@";
GIT_REFSPEC = "@Launcher_GIT_REFSPEC@"; GIT_REFSPEC = "@Launcher_GIT_REFSPEC@";
// Assume that builds outside of Git repos are "stable" // Assume that builds outside of Git repos are "stable"
if (GIT_REFSPEC == QStringLiteral("GITDIR-NOTFOUND") || GIT_TAG == QStringLiteral("GITDIR-NOTFOUND") || if (GIT_REFSPEC == QStringLiteral("GITDIR-NOTFOUND")
GIT_REFSPEC == QStringLiteral("") || GIT_TAG == QStringLiteral("GIT-NOTFOUND")) { || GIT_TAG == QStringLiteral("GITDIR-NOTFOUND")
|| GIT_REFSPEC == QStringLiteral("")
|| GIT_TAG == QStringLiteral("GIT-NOTFOUND"))
{
GIT_REFSPEC = "refs/heads/stable"; GIT_REFSPEC = "refs/heads/stable";
GIT_TAG = versionString(); GIT_TAG = versionString();
GIT_COMMIT = ""; GIT_COMMIT = "";
} }
if (GIT_REFSPEC.startsWith("refs/heads/")) { if (GIT_REFSPEC.startsWith("refs/heads/"))
{
VERSION_CHANNEL = GIT_REFSPEC; VERSION_CHANNEL = GIT_REFSPEC;
VERSION_CHANNEL.remove("refs/heads/"); VERSION_CHANNEL.remove("refs/heads/");
} else if (!GIT_COMMIT.isEmpty()) { }
else if (!GIT_COMMIT.isEmpty())
{
VERSION_CHANNEL = GIT_COMMIT.mid(0, 8); VERSION_CHANNEL = GIT_COMMIT.mid(0, 8);
} else { }
else
{
VERSION_CHANNEL = "unknown"; VERSION_CHANNEL = "unknown";
} }
NEWS_RSS_URL = "@Launcher_NEWS_RSS_URL@"; NEWS_RSS_URL = "@Launcher_NEWS_RSS_URL@";
NEWS_OPEN_URL = "@Launcher_NEWS_OPEN_URL@"; NEWS_OPEN_URL = "@Launcher_NEWS_OPEN_URL@";
HELP_URL = "@Launcher_HELP_URL@"; HELP_URL = "@Launcher_HELP_URL@";
LOGIN_CALLBACK_URL = "@Launcher_LOGIN_CALLBACK_URL@";
IMGUR_CLIENT_ID = "@Launcher_IMGUR_CLIENT_ID@"; IMGUR_CLIENT_ID = "@Launcher_IMGUR_CLIENT_ID@";
MSA_CLIENT_ID = "@Launcher_MSA_CLIENT_ID@"; MSA_CLIENT_ID = "@Launcher_MSA_CLIENT_ID@";
FLAME_API_KEY = "@Launcher_CURSEFORGE_API_KEY@"; FLAME_API_KEY = "@Launcher_CURSEFORGE_API_KEY@";
META_URL = "@Launcher_META_URL@"; META_URL = "@Launcher_META_URL@";
FMLLIBS_BASE_URL = "@Launcher_FMLLIBS_BASE_URL@";
GLFW_LIBRARY_NAME = "@Launcher_GLFW_LIBRARY_NAME@"; GLFW_LIBRARY_NAME = "@Launcher_GLFW_LIBRARY_NAME@";
OPENAL_LIBRARY_NAME = "@Launcher_OPENAL_LIBRARY_NAME@"; OPENAL_LIBRARY_NAME = "@Launcher_OPENAL_LIBRARY_NAME@";
BUG_TRACKER_URL = "@Launcher_BUG_TRACKER_URL@"; BUG_TRACKER_URL = "@Launcher_BUG_TRACKER_URL@";
TRANSLATIONS_URL = "@Launcher_TRANSLATIONS_URL@"; TRANSLATIONS_URL = "@Launcher_TRANSLATIONS_URL@";
TRANSLATION_FILES_URL = "@Launcher_TRANSLATION_FILES_URL@";
MATRIX_URL = "@Launcher_MATRIX_URL@"; MATRIX_URL = "@Launcher_MATRIX_URL@";
DISCORD_URL = "@Launcher_DISCORD_URL@"; DISCORD_URL = "@Launcher_DISCORD_URL@";
SUBREDDIT_URL = "@Launcher_SUBREDDIT_URL@"; SUBREDDIT_URL = "@Launcher_SUBREDDIT_URL@";
@ -128,7 +130,7 @@ Config::Config()
QString Config::versionString() const 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 QString Config::printableVersionString() const
@ -136,7 +138,8 @@ QString Config::printableVersionString() const
QString vstr = versionString(); QString vstr = versionString();
// If the build is not a main release, append the channel // 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; vstr += "-" + VERSION_CHANNEL;
} }
return vstr; return vstr;
@ -153,3 +156,4 @@ QString Config::systemID() const
{ {
return QStringLiteral("%1 %2 %3").arg(COMPILER_TARGET_SYSTEM, COMPILER_TARGET_SYSTEM_VERSION, COMPILER_TARGET_SYSTEM_PROCESSOR); return QStringLiteral("%1 %2 %3").arg(COMPILER_TARGET_SYSTEM, COMPILER_TARGET_SYSTEM_VERSION, COMPILER_TARGET_SYSTEM_PROCESSOR);
} }

View File

@ -52,15 +52,13 @@ class Config {
QString LAUNCHER_DOMAIN; QString LAUNCHER_DOMAIN;
QString LAUNCHER_CONFIGFILE; QString LAUNCHER_CONFIGFILE;
QString LAUNCHER_GIT; QString LAUNCHER_GIT;
QString LAUNCHER_APPID; QString LAUNCHER_DESKTOPFILENAME;
QString LAUNCHER_SVGFILENAME; QString LAUNCHER_SVGFILENAME;
/// The major version number. /// The major version number.
int VERSION_MAJOR; int VERSION_MAJOR;
/// The minor version number. /// The minor version number.
int VERSION_MINOR; int VERSION_MINOR;
/// The patch version number.
int VERSION_PATCH;
/** /**
* The version channel * The version channel
@ -69,7 +67,6 @@ class Config {
QString VERSION_CHANNEL; QString VERSION_CHANNEL;
bool UPDATER_ENABLED = false; bool UPDATER_ENABLED = false;
bool JAVA_DOWNLOADER_ENABLED = false;
/// A short string identifying this build's platform or distribution. /// A short string identifying this build's platform or distribution.
QString BUILD_PLATFORM; QString BUILD_PLATFORM;
@ -135,11 +132,6 @@ class Config {
*/ */
QString HELP_URL; QString HELP_URL;
/**
* URL that gets opened when the user succesfully logins.
*/
QString LOGIN_CALLBACK_URL;
/** /**
* Client ID you can get from Imgur when you register an application * Client ID you can get from Imgur when you register an application
*/ */
@ -171,9 +163,10 @@ class Config {
QString RESOURCE_BASE = "https://resources.download.minecraft.net/"; QString RESOURCE_BASE = "https://resources.download.minecraft.net/";
QString LIBRARY_BASE = "https://libraries.minecraft.net/"; QString LIBRARY_BASE = "https://libraries.minecraft.net/";
QString AUTH_BASE = "https://authserver.mojang.com/";
QString IMGUR_BASE_URL = "https://api.imgur.com/3/"; QString IMGUR_BASE_URL = "https://api.imgur.com/3/";
QString FMLLIBS_BASE_URL; QString FMLLIBS_BASE_URL = "https://files.prismlauncher.org/fmllibs/"; // FIXME: move into CMakeLists
QString TRANSLATION_FILES_URL; QString TRANSLATIONS_BASE_URL = "https://i18n.prismlauncher.org/"; // FIXME: move into CMakeLists
QString MODPACKSCH_API_BASE_URL = "https://api.modpacks.ch/"; QString MODPACKSCH_API_BASE_URL = "https://api.modpacks.ch/";

View File

@ -6,10 +6,6 @@
<string>A Minecraft mod wants to access your camera.</string> <string>A Minecraft mod wants to access your camera.</string>
<key>NSMicrophoneUsageDescription</key> <key>NSMicrophoneUsageDescription</key>
<string>A Minecraft mod wants to access your microphone.</string> <string>A Minecraft mod wants to access your microphone.</string>
<key>NSDownloadsFolderUsageDescription</key>
<string>Prism uses access to your Downloads folder to help you more quickly add mods that can't be automatically downloaded to your instance. You can change where Prism scans for downloaded mods in Settings or the prompt that appears.</string>
<key>NSLocalNetworkUsageDescription</key>
<string>Minecraft uses the local network to find and connect to LAN servers.</string>
<key>NSPrincipalClass</key> <key>NSPrincipalClass</key>
<string>NSApplication</string> <string>NSApplication</string>
<key>NSHighResolutionCapable</key> <key>NSHighResolutionCapable</key>
@ -81,14 +77,6 @@
<string>curseforge</string> <string>curseforge</string>
</array> </array>
</dict> </dict>
<dict>
<key>CFBundleURLName</key>
<string>Prismlauncher</string>
<key>CFBundleURLSchemes</key>
<array>
<string>prismlauncher</string>
</array>
</dict>
</array> </array>
</dict> </dict>
</plist> </plist>

View File

@ -1,81 +0,0 @@
{
"$schema": "https://cmake.org/cmake/help/latest/_downloads/3e2d73bff478d88a7de0de736ba5e361/schema.json",
"version": 8,
"configurePresets": [
{
"name": "base",
"hidden": true,
"binaryDir": "build",
"installDir": "install",
"cacheVariables": {
"Launcher_BUILD_PLATFORM": "custom"
}
},
{
"name": "base_debug",
"hidden": true,
"inherits": [
"base"
],
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "base_release",
"hidden": true,
"inherits": [
"base"
],
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"ENABLE_LTO": "ON"
}
},
{
"name": "base_ci",
"hidden": true,
"inherits": [
"base_release"
],
"cacheVariables": {
"Launcher_BUILD_PLATFORM": "official",
"Launcher_FORCE_BUNDLED_LIBS": "ON"
}
}
],
"testPresets": [
{
"name": "base",
"hidden": true,
"output": {
"outputOnFailure": true
},
"execution": {
"noTestsAction": "error"
},
"filter": {
"exclude": {
"name": "^example64|example$"
}
}
},
{
"name": "base_debug",
"hidden": true,
"inherits": [
"base"
],
"output": {
"debug": true
}
},
{
"name": "base_release",
"hidden": true,
"inherits": [
"base"
]
}
]
}

View File

@ -1,180 +0,0 @@
{
"$schema": "https://cmake.org/cmake/help/latest/_downloads/3e2d73bff478d88a7de0de736ba5e361/schema.json",
"version": 8,
"include": [
"commonPresets.json"
],
"configurePresets": [
{
"name": "linux_base",
"hidden": true,
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
},
"generator": "Ninja",
"cacheVariables": {
"Launcher_BUILD_ARTIFACT": "Linux-Qt6",
"Launcher_ENABLE_JAVA_DOWNLOADER": "ON"
}
},
{
"name": "linux_debug",
"inherits": [
"base_debug",
"linux_base"
],
"displayName": "Linux (Debug)"
},
{
"name": "linux_release",
"inherits": [
"base_release",
"linux_base"
],
"displayName": "Linux (Release)"
},
{
"name": "linux_ci",
"inherits": [
"base_ci",
"linux_base"
],
"displayName": "Linux (CI)",
"cacheVariables": {
"Launcher_BUILD_ARTIFACT": "Linux-Qt6"
},
"installDir": "/usr"
}
],
"buildPresets": [
{
"name": "linux_base",
"hidden": true,
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
}
},
{
"name": "linux_debug",
"inherits": [
"linux_base"
],
"displayName": "Linux (Debug)",
"configurePreset": "linux_debug"
},
{
"name": "linux_release",
"inherits": [
"linux_base"
],
"displayName": "Linux (Release)",
"configurePreset": "linux_release"
},
{
"name": "linux_ci",
"inherits": [
"linux_base"
],
"displayName": "Linux (CI)",
"configurePreset": "linux_ci"
}
],
"testPresets": [
{
"name": "linux_base",
"hidden": true,
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
}
},
{
"name": "linux_debug",
"inherits": [
"base_debug",
"linux_base"
],
"displayName": "Linux (Debug)",
"configurePreset": "linux_debug"
},
{
"name": "linux_release",
"inherits": [
"base_release",
"linux_base"
],
"displayName": "Linux (Release)",
"configurePreset": "linux_release"
},
{
"name": "linux_ci",
"inherits": [
"base_release",
"linux_base"
],
"displayName": "Linux (CI)",
"configurePreset": "linux_ci"
}
],
"workflowPresets": [
{
"name": "linux_debug",
"displayName": "Linux (Debug)",
"steps": [
{
"type": "configure",
"name": "linux_debug"
},
{
"type": "build",
"name": "linux_debug"
},
{
"type": "test",
"name": "linux_debug"
}
]
},
{
"name": "linux",
"displayName": "Linux (Release)",
"steps": [
{
"type": "configure",
"name": "linux_release"
},
{
"type": "build",
"name": "linux_release"
},
{
"type": "test",
"name": "linux_release"
}
]
},
{
"name": "linux_ci",
"displayName": "Linux (CI)",
"steps": [
{
"type": "configure",
"name": "linux_ci"
},
{
"type": "build",
"name": "linux_ci"
},
{
"type": "test",
"name": "linux_ci"
}
]
}
]
}

View File

@ -1,272 +0,0 @@
{
"$schema": "https://cmake.org/cmake/help/latest/_downloads/3e2d73bff478d88a7de0de736ba5e361/schema.json",
"version": 8,
"include": [
"commonPresets.json"
],
"configurePresets": [
{
"name": "macos_base",
"hidden": true,
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Darwin"
},
"generator": "Ninja"
},
{
"name": "macos_universal_base",
"hidden": true,
"inherits": [
"macos_base"
],
"cacheVariables": {
"CMAKE_OSX_ARCHITECTURES": "x86_64;arm64",
"Launcher_BUILD_ARTIFACT": "macOS-Qt6"
}
},
{
"name": "macos_debug",
"inherits": [
"base_debug",
"macos_base"
],
"displayName": "macOS (Debug)"
},
{
"name": "macos_release",
"inherits": [
"base_release",
"macos_base"
],
"displayName": "macOS (Release)"
},
{
"name": "macos_universal_debug",
"inherits": [
"base_debug",
"macos_universal_base"
],
"displayName": "macOS (Universal Binary, Debug)"
},
{
"name": "macos_universal_release",
"inherits": [
"base_release",
"macos_universal_base"
],
"displayName": "macOS (Universal Binary, Release)"
},
{
"name": "macos_ci",
"inherits": [
"base_ci",
"macos_universal_base"
],
"displayName": "macOS (CI)",
"cacheVariables": {
"Launcher_BUILD_ARTIFACT": "macOS-Qt6"
}
}
],
"buildPresets": [
{
"name": "macos_base",
"hidden": true,
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Darwin"
}
},
{
"name": "macos_debug",
"inherits": [
"macos_base"
],
"displayName": "macOS (Debug)",
"configurePreset": "macos_debug"
},
{
"name": "macos_release",
"inherits": [
"macos_base"
],
"displayName": "macOS (Release)",
"configurePreset": "macos_release"
},
{
"name": "macos_universal_debug",
"inherits": [
"macos_base"
],
"displayName": "macOS (Universal Binary, Debug)",
"configurePreset": "macos_universal_debug"
},
{
"name": "macos_universal_release",
"inherits": [
"macos_base"
],
"displayName": "macOS (Universal Binary, Release)",
"configurePreset": "macos_universal_release"
},
{
"name": "macos_ci",
"inherits": [
"macos_base"
],
"displayName": "macOS (CI)",
"configurePreset": "macos_ci"
}
],
"testPresets": [
{
"name": "macos_base",
"hidden": true,
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Darwin"
}
},
{
"name": "macos_debug",
"inherits": [
"base_debug",
"macos_base"
],
"displayName": "MacOS (Debug)",
"configurePreset": "macos_debug"
},
{
"name": "macos_release",
"inherits": [
"base_release",
"macos_base"
],
"displayName": "macOS (Release)",
"configurePreset": "macos_release"
},
{
"name": "macos_universal_debug",
"inherits": [
"base_debug",
"macos_base"
],
"displayName": "MacOS (Universal Binary, Debug)",
"configurePreset": "macos_universal_debug"
},
{
"name": "macos_universal_release",
"inherits": [
"base_release",
"macos_base"
],
"displayName": "macOS (Universal Binary, Release)",
"configurePreset": "macos_universal_release"
},
{
"name": "macos_ci",
"inherits": [
"base_release",
"macos_base"
],
"displayName": "macOS (CI)",
"configurePreset": "macos_ci"
}
],
"workflowPresets": [
{
"name": "macos_debug",
"displayName": "macOS (Debug)",
"steps": [
{
"type": "configure",
"name": "macos_debug"
},
{
"type": "build",
"name": "macos_debug"
},
{
"type": "test",
"name": "macos_debug"
}
]
},
{
"name": "macos",
"displayName": "macOS (Release)",
"steps": [
{
"type": "configure",
"name": "macos_release"
},
{
"type": "build",
"name": "macos_release"
},
{
"type": "test",
"name": "macos_release"
}
]
},
{
"name": "macos_universal_debug",
"displayName": "macOS (Universal Binary, Debug)",
"steps": [
{
"type": "configure",
"name": "macos_universal_debug"
},
{
"type": "build",
"name": "macos_universal_debug"
},
{
"type": "test",
"name": "macos_universal_debug"
}
]
},
{
"name": "macos_universal",
"displayName": "macOS (Universal Binary, Release)",
"steps": [
{
"type": "configure",
"name": "macos_universal_release"
},
{
"type": "build",
"name": "macos_universal_release"
},
{
"type": "test",
"name": "macos_universal_release"
}
]
},
{
"name": "macos_ci",
"displayName": "macOS (CI)",
"steps": [
{
"type": "configure",
"name": "macos_ci"
},
{
"type": "build",
"name": "macos_ci"
},
{
"type": "test",
"name": "macos_ci"
}
]
}
]
}

View File

@ -1,311 +0,0 @@
{
"$schema": "https://cmake.org/cmake/help/latest/_downloads/3e2d73bff478d88a7de0de736ba5e361/schema.json",
"version": 8,
"include": [
"commonPresets.json"
],
"configurePresets": [
{
"name": "windows_msvc_base",
"hidden": true,
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
},
"cacheVariables": {
"Launcher_BUILD_ARTIFACT": "Windows-MSVC-Qt6"
}
},
{
"name": "windows_msvc_arm64_cross_base",
"hidden": true,
"inherits": [
"windows_msvc_base"
],
"architecture": "arm64",
"cacheVariables": {
"Launcher_BUILD_ARTIFACT": "Windows-MSVC-arm64-Qt6"
}
},
{
"name": "windows_msvc_debug",
"inherits": [
"base_debug",
"windows_msvc_base"
],
"displayName": "Windows MSVC (Debug)",
"generator": "Ninja"
},
{
"name": "windows_msvc_release",
"inherits": [
"base_release",
"windows_msvc_base"
],
"displayName": "Windows MSVC (Release)"
},
{
"name": "windows_msvc_arm64_cross_debug",
"inherits": [
"base_debug",
"windows_msvc_arm64_cross_base"
],
"displayName": "Windows MSVC (ARM64 cross, Debug)"
},
{
"name": "windows_msvc_arm64_cross_release",
"inherits": [
"base_release",
"windows_msvc_arm64_cross_base"
],
"displayName": "Windows MSVC (ARM64 cross, Release)"
},
{
"name": "windows_msvc_ci",
"inherits": [
"base_ci",
"windows_msvc_base"
],
"displayName": "Windows MSVC (CI)",
"cacheVariables": {
"Launcher_BUILD_ARTIFACT": "Windows-MSVC-Qt6"
}
},
{
"name": "windows_msvc_arm64_cross_ci",
"inherits": [
"base_ci",
"windows_msvc_arm64_cross_base"
],
"displayName": "Windows MSVC (ARM64 cross, CI)",
"cacheVariables": {
"Launcher_BUILD_ARTIFACT": "Windows-MSVC-arm64-Qt6"
}
}
],
"buildPresets": [
{
"name": "windows_msvc_base",
"hidden": true,
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
}
},
{
"name": "windows_msvc_debug",
"inherits": [
"windows_msvc_base"
],
"displayName": "Windows MSVC (Debug)",
"configurePreset": "windows_msvc_debug",
"configuration": "Debug"
},
{
"name": "windows_msvc_release",
"inherits": [
"windows_msvc_base"
],
"displayName": "Windows MSVC (Release)",
"configurePreset": "windows_msvc_release",
"configuration": "Release",
"nativeToolOptions": [
"/p:UseMultiToolTask=true",
"/p:EnforceProcessCountAcrossBuilds=true"
]
},
{
"name": "windows_msvc_arm64_cross_debug",
"inherits": [
"windows_msvc_base"
],
"displayName": "Windows MSVC (ARM64 cross, Debug)",
"configurePreset": "windows_msvc_arm64_cross_debug",
"configuration": "Debug",
"nativeToolOptions": [
"/p:UseMultiToolTask=true",
"/p:EnforceProcessCountAcrossBuilds=true"
]
},
{
"name": "windows_msvc_arm64_cross_release",
"inherits": [
"windows_msvc_base"
],
"displayName": "Windows MSVC (ARM64 cross, Release)",
"configurePreset": "windows_msvc_arm64_cross_release",
"configuration": "Release",
"nativeToolOptions": [
"/p:UseMultiToolTask=true",
"/p:EnforceProcessCountAcrossBuilds=true"
]
},
{
"name": "windows_msvc_ci",
"inherits": [
"windows_msvc_base"
],
"displayName": "Windows MSVC (CI)",
"configurePreset": "windows_msvc_ci",
"configuration": "Release",
"nativeToolOptions": [
"/p:UseMultiToolTask=true",
"/p:EnforceProcessCountAcrossBuilds=true"
]
},
{
"name": "windows_msvc_arm64_cross_ci",
"inherits": [
"windows_msvc_base"
],
"displayName": "Windows MSVC (ARM64 cross, CI)",
"configurePreset": "windows_msvc_arm64_cross_ci",
"configuration": "Release",
"nativeToolOptions": [
"/p:UseMultiToolTask=true",
"/p:EnforceProcessCountAcrossBuilds=true"
]
}
],
"testPresets": [
{
"name": "windows_msvc_base",
"hidden": true,
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
}
},
{
"name": "windows_msvc_debug",
"inherits": [
"base_debug",
"windows_msvc_base"
],
"displayName": "Windows MSVC (Debug)",
"configurePreset": "windows_msvc_debug",
"configuration": "Debug"
},
{
"name": "windows_msvc_release",
"inherits": [
"base_release",
"windows_msvc_base"
],
"displayName": "Windows MSVC (Release)",
"configurePreset": "windows_msvc_release",
"configuration": "Release"
},
{
"name": "windows_msvc_ci",
"inherits": [
"base_release",
"windows_msvc_base"
],
"displayName": "Windows MSVC (CI)",
"configurePreset": "windows_msvc_ci",
"configuration": "Release"
}
],
"workflowPresets": [
{
"name": "windows_msvc_debug",
"displayName": "Windows MSVC (Debug)",
"steps": [
{
"type": "configure",
"name": "windows_msvc_debug"
},
{
"type": "build",
"name": "windows_msvc_debug"
},
{
"type": "test",
"name": "windows_msvc_debug"
}
]
},
{
"name": "windows_msvc",
"displayName": "Windows MSVC (Release)",
"steps": [
{
"type": "configure",
"name": "windows_msvc_release"
},
{
"type": "build",
"name": "windows_msvc_release"
},
{
"type": "test",
"name": "windows_msvc_release"
}
]
},
{
"name": "windows_msvc_arm64_cross_debug",
"displayName": "Windows MSVC (ARM64 cross, Debug)",
"steps": [
{
"type": "configure",
"name": "windows_msvc_arm64_cross_debug"
},
{
"type": "build",
"name": "windows_msvc_arm64_cross_debug"
}
]
},
{
"name": "windows_msvc_arm64_cross",
"displayName": "Windows MSVC (ARM64 cross, Release)",
"steps": [
{
"type": "configure",
"name": "windows_msvc_arm64_cross_release"
},
{
"type": "build",
"name": "windows_msvc_arm64_cross_release"
}
]
},
{
"name": "windows_msvc_ci",
"displayName": "Windows MSVC (CI)",
"steps": [
{
"type": "configure",
"name": "windows_msvc_ci"
},
{
"type": "build",
"name": "windows_msvc_ci"
},
{
"type": "test",
"name": "windows_msvc_ci"
}
]
},
{
"name": "windows_msvc_arm64_cross_ci",
"displayName": "Windows MSVC (ARM64 cross, CI)",
"steps": [
{
"type": "configure",
"name": "windows_msvc_arm64_cross_ci"
},
{
"type": "build",
"name": "windows_msvc_arm64_cross_ci"
}
]
}
]
}

View File

@ -1,183 +0,0 @@
{
"$schema": "https://cmake.org/cmake/help/latest/_downloads/3e2d73bff478d88a7de0de736ba5e361/schema.json",
"version": 8,
"include": [
"commonPresets.json"
],
"configurePresets": [
{
"name": "windows_mingw_base",
"hidden": true,
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
},
"generator": "Ninja",
"cacheVariables": {
"Launcher_BUILD_ARTIFACT": "Windows-MinGW-w64-Qt6"
}
},
{
"name": "windows_mingw_debug",
"inherits": [
"base_debug",
"windows_mingw_base"
],
"displayName": "Windows MinGW (Debug)"
},
{
"name": "windows_mingw_release",
"inherits": [
"base_release",
"windows_mingw_base"
],
"displayName": "Windows MinGW (Release)"
},
{
"name": "windows_mingw_ci",
"inherits": [
"base_ci",
"windows_mingw_base"
],
"displayName": "Windows MinGW (CI)",
"cacheVariables": {
"Launcher_BUILD_ARTIFACT": "Windows-MinGW-w64-Qt6"
}
}
],
"buildPresets": [
{
"name": "windows_mingw_base",
"hidden": true,
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
}
},
{
"name": "windows_mingw_debug",
"inherits": [
"windows_mingw_base"
],
"displayName": "Windows MinGW (Debug)",
"configurePreset": "windows_mingw_debug"
},
{
"name": "windows_mingw_release",
"inherits": [
"windows_mingw_base"
],
"displayName": "Windows MinGW (Release)",
"configurePreset": "windows_mingw_release"
},
{
"name": "windows_mingw_ci",
"inherits": [
"windows_mingw_base"
],
"displayName": "Windows MinGW (CI)",
"configurePreset": "windows_mingw_ci"
}
],
"testPresets": [
{
"name": "windows_mingw_base",
"hidden": true,
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
},
"filter": {
"exclude": {
"name": "^example64|example$"
}
}
},
{
"name": "windows_mingw_debug",
"inherits": [
"base_debug",
"windows_mingw_base"
],
"displayName": "Windows MinGW (Debug)",
"configurePreset": "windows_mingw_debug"
},
{
"name": "windows_mingw_release",
"inherits": [
"base_release",
"windows_mingw_base"
],
"displayName": "Windows MinGW (Release)",
"configurePreset": "windows_mingw_release"
},
{
"name": "windows_mingw_ci",
"inherits": [
"base_release",
"windows_mingw_base"
],
"displayName": "Windows MinGW (CI)",
"configurePreset": "windows_mingw_ci"
}
],
"workflowPresets": [
{
"name": "windows_mingw_debug",
"displayName": "Windows MinGW (Debug)",
"steps": [
{
"type": "configure",
"name": "windows_mingw_debug"
},
{
"type": "build",
"name": "windows_mingw_debug"
},
{
"type": "test",
"name": "windows_mingw_debug"
}
]
},
{
"name": "windows_mingw",
"displayName": "Windows MinGW (Release)",
"steps": [
{
"type": "configure",
"name": "windows_mingw_release"
},
{
"type": "build",
"name": "windows_mingw_release"
},
{
"type": "test",
"name": "windows_mingw_release"
}
]
},
{
"name": "windows_mingw_ci",
"displayName": "Windows MinGW (CI)",
"steps": [
{
"type": "configure",
"name": "windows_mingw_ci"
},
{
"type": "build",
"name": "windows_mingw_ci"
},
{
"type": "test",
"name": "windows_mingw_ci"
}
]
}
]
}

View File

@ -1,4 +1,14 @@
(import (fetchTarball { (
url = "https://github.com/edolstra/flake-compat/archive/ff81ac966bb2cae68946d5ed5fc4994f96d0ffec.tar.gz"; import
sha256 = "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU="; (
}) { src = ./.; }).defaultNix 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

158
flake.lock generated
View File

@ -1,13 +1,88 @@
{ {
"nodes": { "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"
}
},
"flake-parts": {
"inputs": {
"nixpkgs-lib": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1698882062,
"narHash": "sha256-HkhafUayIqxXyHH1X8d9RDl1M2CkFgZLjKD3MzabiEo=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "8c9fa2545007b49a5db5f650ae91f227672c3877",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1685518550,
"narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"pre-commit-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1660459072,
"narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "a20de23b925fd8264fd7fad6454652e142fd7f73",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"libnbtplusplus": { "libnbtplusplus": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1744811532, "lastModified": 1699286814,
"narHash": "sha256-qhmjaRkt+O7A+gu6HjUkl7QzOEb4r8y8vWZMG2R/C6o=", "narHash": "sha256-yy0q+bky80LtK1GWzz7qpM+aAGrOqLuewbid8WT1ilk=",
"owner": "PrismLauncher", "owner": "PrismLauncher",
"repo": "libnbtplusplus", "repo": "libnbtplusplus",
"rev": "531449ba1c930c98e0bcf5d332b237a8566f9d78", "rev": "23b955121b8217c1c348a9ed2483167a6f3ff4ad",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -16,43 +91,88 @@
"type": "github" "type": "github"
} }
}, },
"nix-filter": {
"locked": {
"lastModified": 1694857738,
"narHash": "sha256-bxxNyLHjhu0N8T3REINXQ2ZkJco0ABFPn6PIe2QUfqo=",
"owner": "numtide",
"repo": "nix-filter",
"rev": "41fd48e00c22b4ced525af521ead8792402de0ea",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "nix-filter",
"type": "github"
}
},
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1745526057, "lastModified": 1700856099,
"narHash": "sha256-ITSpPDwvLBZBnPRS2bUcHY3gZSwis/uTe255QgMtTLA=", "narHash": "sha256-RnEA7iJ36Ay9jI0WwP+/y4zjEhmeN6Cjs9VOFBH7eVQ=",
"owner": "NixOS", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "f771eb401a46846c1aebd20552521b233dd7e18b", "rev": "0bd59c54ef06bc34eca01e37d689f5e46b3fe2f1",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NixOS", "owner": "nixos",
"ref": "nixos-unstable", "ref": "nixpkgs-unstable",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }
}, },
"qt-qrcodegenerator": { "pre-commit-hooks": {
"flake": false, "inputs": {
"flake-compat": [
"flake-compat"
],
"flake-utils": "flake-utils",
"gitignore": "gitignore",
"nixpkgs": [
"nixpkgs"
],
"nixpkgs-stable": [
"nixpkgs"
]
},
"locked": { "locked": {
"lastModified": 1737616857, "lastModified": 1700922917,
"narHash": "sha256-6SugPt0lp1Gz7nV23FLmsmpfzgFItkSw7jpGftsDPWc=", "narHash": "sha256-ej2fch/T584b5K9sk1UhmZF7W6wEfDHuoUYpFN8dtvM=",
"owner": "nayuki", "owner": "cachix",
"repo": "QR-Code-generator", "repo": "pre-commit-hooks.nix",
"rev": "2c9044de6b049ca25cb3cd1649ed7e27aa055138", "rev": "e5ee5c5f3844550c01d2131096c7271cec5e9b78",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "nayuki", "owner": "cachix",
"repo": "QR-Code-generator", "repo": "pre-commit-hooks.nix",
"type": "github" "type": "github"
} }
}, },
"root": { "root": {
"inputs": { "inputs": {
"flake-compat": "flake-compat",
"flake-parts": "flake-parts",
"libnbtplusplus": "libnbtplusplus", "libnbtplusplus": "libnbtplusplus",
"nix-filter": "nix-filter",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"qt-qrcodegenerator": "qt-qrcodegenerator" "pre-commit-hooks": "pre-commit-hooks"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
} }
} }
}, },

247
flake.nix
View File

@ -2,226 +2,53 @@
description = "A custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once (Fork of MultiMC)"; description = "A custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once (Fork of MultiMC)";
nixConfig = { nixConfig = {
extra-substituters = [ "https://prismlauncher.cachix.org" ]; extra-substituters = ["https://cache.garnix.io"];
extra-trusted-public-keys = [ extra-trusted-public-keys = ["cache.garnix.io:CTFPyKSLcx5RMJKfLo5EEPUObbA78b0YQ2DTCJXqr9g="];
"prismlauncher.cachix.org-1:9/n/FGyABA2jLUVfY+DEp4hKds/rwO+SCOtbOkDzd+c="
];
}; };
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
flake-parts = {
url = "github:hercules-ci/flake-parts";
inputs.nixpkgs-lib.follows = "nixpkgs";
};
nix-filter.url = "github:numtide/nix-filter";
pre-commit-hooks = {
url = "github:cachix/pre-commit-hooks.nix";
inputs = {
nixpkgs.follows = "nixpkgs";
nixpkgs-stable.follows = "nixpkgs";
flake-compat.follows = "flake-compat";
};
};
flake-compat = {
url = "github:edolstra/flake-compat";
flake = false;
};
libnbtplusplus = { libnbtplusplus = {
url = "github:PrismLauncher/libnbtplusplus"; url = "github:PrismLauncher/libnbtplusplus";
flake = false; flake = false;
}; };
qt-qrcodegenerator = {
url = "github:nayuki/QR-Code-generator";
flake = false;
};
}; };
outputs = outputs = {
{ flake-parts,
self, pre-commit-hooks,
nixpkgs, ...
libnbtplusplus, } @ inputs:
qt-qrcodegenerator, flake-parts.lib.mkFlake {inherit inputs;} {
}: imports = [
pre-commit-hooks.flakeModule
let ./nix/dev.nix
inherit (nixpkgs) lib; ./nix/distribution.nix
];
# While we only officially support aarch and x86_64 on Linux and MacOS, systems = [
# we expose a reasonable amount of other systems for users who want to "x86_64-linux"
# build for most exotic platforms "aarch64-linux"
systems = lib.systems.flakeExposed; "x86_64-darwin"
"aarch64-darwin"
forAllSystems = lib.genAttrs systems; ];
nixpkgsFor = forAllSystems (system: nixpkgs.legacyPackages.${system});
in
{
checks = forAllSystems (
system:
let
pkgs = nixpkgsFor.${system};
llvm = pkgs.llvmPackages_19;
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
'';
}
);
devShells = forAllSystems (
system:
let
pkgs = nixpkgsFor.${system};
llvm = pkgs.llvmPackages_19;
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 = pkgs.mkShell {
name = "prism-launcher";
inputsFrom = [ packages'.prismlauncher-unwrapped ];
packages = with pkgs; [
ccache
llvm.clang-tools
];
cmakeBuildType = "Debug";
cmakeFlags = [ "-GNinja" ] ++ packages'.prismlauncher.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: {
prismlauncher-unwrapped = prev.callPackage ./nix/unwrapped.nix {
inherit
libnbtplusplus
qt-qrcodegenerator
self
;
};
prismlauncher = final.callPackage ./nix/wrapper.nix { };
};
packages = forAllSystems (
system:
let
pkgs = nixpkgsFor.${system};
# Build a scope from our overlay
prismPackages = lib.makeScope pkgs.newScope (final: self.overlays.default final pkgs);
# Grab our packages from it and set the default
packages = {
inherit (prismPackages) prismlauncher-unwrapped prismlauncher;
default = prismPackages.prismlauncher;
};
in
# Only output them if they're available on the current system
lib.filterAttrs (_: lib.meta.availableOn pkgs.stdenv.hostPlatform) packages
);
# 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};
in
{
prismlauncher-debug = packages'.prismlauncher.override {
prismlauncher-unwrapped = legacyPackages'.prismlauncher-unwrapped-debug;
};
prismlauncher-unwrapped-debug = packages'.prismlauncher-unwrapped.overrideAttrs {
cmakeBuildType = "Debug";
dontStrip = true;
};
}
);
}; };
} }

View File

@ -1,20 +0,0 @@
{
"name": "flite",
"config-opts": [
"--enable-shared",
"--with-audio=pulseaudio"
],
"no-parallel-make": true,
"sources": [
{
"type": "git",
"url": "https://github.com/festvox/flite.git",
"tag": "v2.2",
"commit": "e9e2e37c329dbe98bfeb27a1828ef9a71fa84f88",
"x-checker-data": {
"type": "git",
"tag-pattern": "^v([\\d.]+)$"
}
}
]
}

View File

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

View File

@ -1,9 +1,10 @@
id: org.prismlauncher.PrismLauncher id: org.prismlauncher.PrismLauncher
runtime: org.kde.Platform runtime: org.kde.Platform
runtime-version: '6.8' runtime-version: 5.15-23.08
sdk: org.kde.Sdk sdk: org.kde.Sdk
sdk-extensions: sdk-extensions:
- org.freedesktop.Sdk.Extension.openjdk17 - org.freedesktop.Sdk.Extension.openjdk17
- org.freedesktop.Sdk.Extension.openjdk8
command: prismlauncher command: prismlauncher
finish-args: finish-args:
@ -19,12 +20,9 @@ finish-args:
- --filesystem=xdg-download:ro - --filesystem=xdg-download:ro
# FTBApp import # FTBApp import
- --filesystem=~/.ftba:ro - --filesystem=~/.ftba:ro
# Userspace visibility for manual hugepages configuration
# Required for -XX:+UseLargePages cleanup:
- --filesystem=/sys/kernel/mm/hugepages:ro - /lib/libGLU*
# Userspace visibility for transparent hugepages configuration
# Required for -XX:+UseTransparentHugePages
- --filesystem=/sys/kernel/mm/transparent_hugepage:ro
modules: modules:
# Might be needed by some Controller mods (see https://github.com/isXander/Controlify/issues/31) # Might be needed by some Controller mods (see https://github.com/isXander/Controlify/issues/31)
@ -33,39 +31,48 @@ modules:
# Needed for proper Wayland support # Needed for proper Wayland support
- libdecor.json - libdecor.json
# Text to Speech in the game
- flite.json
- name: prismlauncher - name: prismlauncher
buildsystem: cmake-ninja buildsystem: cmake-ninja
builddir: true builddir: true
config-opts: config-opts:
- -DLauncher_BUILD_PLATFORM=flatpak - -DLauncher_BUILD_PLATFORM=flatpak
# This allows us to manage and update Java independently of this Flatpak
- -DLauncher_ENABLE_JAVA_DOWNLOADER=ON
- -DCMAKE_BUILD_TYPE=RelWithDebInfo - -DCMAKE_BUILD_TYPE=RelWithDebInfo
- -DLauncher_QT_VERSION_MAJOR=5
build-options: build-options:
env: env:
JAVA_HOME: /usr/lib/sdk/openjdk17/jvm/openjdk-17 JAVA_HOME: /usr/lib/sdk/openjdk17/jvm/openjdk-17
JAVA_COMPILER: /usr/lib/sdk/openjdk17/jvm/openjdk-17/bin/javac JAVA_COMPILER: /usr/lib/sdk/openjdk17/jvm/openjdk-17/bin/javac
run-tests: true
sources: sources:
- type: dir - type: dir
path: ../ path: ../
- name: openjdk
buildsystem: simple
build-commands:
- mkdir -p /app/jdk/
- /usr/lib/sdk/openjdk17/install.sh
- mv /app/jre /app/jdk/17
- /usr/lib/sdk/openjdk8/install.sh
- mv /app/jre /app/jdk/8
cleanup:
- /jre
- name: glfw - name: glfw
buildsystem: cmake-ninja buildsystem: cmake-ninja
config-opts: config-opts:
- -DCMAKE_BUILD_TYPE=RelWithDebInfo - -DCMAKE_BUILD_TYPE=RelWithDebInfo
- -DBUILD_SHARED_LIBS:BOOL=ON - -DBUILD_SHARED_LIBS:BOOL=ON
- -DGLFW_BUILD_WAYLAND:BOOL=ON - -DGLFW_USE_WAYLAND=ON
- -DGLFW_BUILD_DOCS:BOOL=OFF
sources: sources:
- type: git - type: git
url: https://github.com/glfw/glfw.git url: https://github.com/glfw/glfw.git
commit: 7b6aead9fb88b3623e3b3725ebb42670cbe4c579 # 3.4 commit: 3fa2360720eeba1964df3c0ecf4b5df8648a8e52
- type: patch - type: patch
path: patches/0009-Defer-setting-cursor-position-until-the-cursor-is-lo.patch path: patches/0003-Don-t-crash-on-calls-to-focus-or-icon.patch
- type: patch
path: patches/0005-Add-warning-about-being-an-unofficial-patch.patch
- type: patch
path: patches/0007-Platform-Prefer-Wayland-over-X11.patch
cleanup: cleanup:
- /include - /include
- /lib/cmake - /lib/cmake
@ -75,8 +82,8 @@ modules:
buildsystem: autotools buildsystem: autotools
sources: sources:
- type: archive - type: archive
url: https://xorg.freedesktop.org/archive/individual/app/xrandr-1.5.3.tar.xz url: https://xorg.freedesktop.org/archive/individual/app/xrandr-1.5.2.tar.xz
sha256: f8dd7566adb74147fab9964680b6bbadee87cf406a7fcff51718a5e6949b841c sha256: c8bee4790d9058bacc4b6246456c58021db58a87ddda1a9d0139bf5f18f1f240
x-checker-data: x-checker-data:
type: anitya type: anitya
project-id: 14957 project-id: 14957
@ -98,8 +105,8 @@ modules:
sources: sources:
- type: archive - type: archive
dest-filename: gamemode.tar.gz dest-filename: gamemode.tar.gz
url: https://api.github.com/repos/FeralInteractive/gamemode/tarball/1.8.2 url: https://api.github.com/repos/FeralInteractive/gamemode/tarball/1.8.1
sha256: 2886d4ce543c78bd2a364316d5e7fd59ef06b71de63f896b37c6d3dc97658f60 sha256: 969cf85b5ca3944f3e315cd73a0ee9bea4f9c968cd7d485e9f4745bc1e679c4e
x-checker-data: x-checker-data:
type: json type: json
url: https://api.github.com/repos/FeralInteractive/gamemode/releases/latest url: https://api.github.com/repos/FeralInteractive/gamemode/releases/latest

View File

@ -0,0 +1,24 @@
diff --git a/src/wl_window.c b/src/wl_window.c
index 52d3b9eb..4ac4eb5d 100644
--- a/src/wl_window.c
+++ b/src/wl_window.c
@@ -2117,8 +2117,7 @@ void _glfwSetWindowTitleWayland(_GLFWwindow* window, const char* title)
void _glfwSetWindowIconWayland(_GLFWwindow* window,
int count, const GLFWimage* images)
{
- _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
- "Wayland: The platform does not support setting the window icon");
+ fprintf(stderr, "!!! Ignoring Error: Wayland: The platform does not support setting the window icon\n");
}
void _glfwGetWindowPosWayland(_GLFWwindow* window, int* xpos, int* ypos)
@@ -2361,8 +2360,7 @@ void _glfwRequestWindowAttentionWayland(_GLFWwindow* window)
void _glfwFocusWindowWayland(_GLFWwindow* window)
{
- _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
- "Wayland: The platform does not support setting the input focus");
+ fprintf(stderr, "!!! Ignoring Error: Wayland: The platform does not support setting the input focus\n");
}
void _glfwSetWindowMonitorWayland(_GLFWwindow* window,

View File

@ -0,0 +1,17 @@
diff --git a/src/init.c b/src/init.c
index 06dbb3f2..a7c6da86 100644
--- a/src/init.c
+++ b/src/init.c
@@ -449,6 +449,12 @@ GLFWAPI int glfwInit(void)
_glfw.initialized = GLFW_TRUE;
glfwDefaultWindowHints();
+
+ fprintf(stderr, "!!! Patched GLFW from https://github.com/Admicos/minecraft-wayland\n"
+ "!!! If any issues with the window, or some issues with rendering, occur, "
+ "first try with the built-in GLFW, and if that solves the issue, report there first.\n"
+ "!!! Use outside Minecraft is untested, and things might break.\n");
+
return GLFW_TRUE;
}

View File

@ -0,0 +1,20 @@
diff --git a/src/platform.c b/src/platform.c
index c5966ae7..3e7442f9 100644
--- a/src/platform.c
+++ b/src/platform.c
@@ -49,12 +49,12 @@ static const struct
#if defined(_GLFW_COCOA)
{ GLFW_PLATFORM_COCOA, _glfwConnectCocoa },
#endif
-#if defined(_GLFW_X11)
- { GLFW_PLATFORM_X11, _glfwConnectX11 },
-#endif
#if defined(_GLFW_WAYLAND)
{ GLFW_PLATFORM_WAYLAND, _glfwConnectWayland },
#endif
+#if defined(_GLFW_X11)
+ { GLFW_PLATFORM_X11, _glfwConnectX11 },
+#endif
};
GLFWbool _glfwSelectPlatform(int desiredID, _GLFWplatform* platform)

View File

@ -1,59 +0,0 @@
From 9997ae55a47de469ea26f8437c30b51483abda5f Mon Sep 17 00:00:00 2001
From: Dan Klishch <danilklishch@gmail.com>
Date: Sat, 30 Sep 2023 23:38:05 -0400
Subject: Defer setting cursor position until the cursor is locked
---
src/wl_platform.h | 3 +++
src/wl_window.c | 14 ++++++++++++--
2 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/src/wl_platform.h b/src/wl_platform.h
index ca34f66e..cd1f227f 100644
--- a/src/wl_platform.h
+++ b/src/wl_platform.h
@@ -403,6 +403,9 @@ typedef struct _GLFWwindowWayland
int scaleSize;
int compositorPreferredScale;
+ double askedCursorPosX, askedCursorPosY;
+ GLFWbool didAskForSetCursorPos;
+
struct zwp_relative_pointer_v1* relativePointer;
struct zwp_locked_pointer_v1* lockedPointer;
struct zwp_confined_pointer_v1* confinedPointer;
diff --git a/src/wl_window.c b/src/wl_window.c
index 1de26558..0df16747 100644
--- a/src/wl_window.c
+++ b/src/wl_window.c
@@ -2586,8 +2586,9 @@ void _glfwGetCursorPosWayland(_GLFWwindow* window, double* xpos, double* ypos)
void _glfwSetCursorPosWayland(_GLFWwindow* window, double x, double y)
{
- _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
- "Wayland: The platform does not support setting the cursor position");
+ window->wl.didAskForSetCursorPos = true;
+ window->wl.askedCursorPosX = x;
+ window->wl.askedCursorPosY = y;
}
void _glfwSetCursorModeWayland(_GLFWwindow* window, int mode)
@@ -2819,6 +2820,15 @@ static const struct zwp_relative_pointer_v1_listener relativePointerListener =
static void lockedPointerHandleLocked(void* userData,
struct zwp_locked_pointer_v1* lockedPointer)
{
+ _GLFWwindow* window = userData;
+
+ if (window->wl.didAskForSetCursorPos)
+ {
+ window->wl.didAskForSetCursorPos = false;
+ zwp_locked_pointer_v1_set_cursor_position_hint(window->wl.lockedPointer,
+ wl_fixed_from_double(window->wl.askedCursorPosX),
+ wl_fixed_from_double(window->wl.askedCursorPosY));
+ }
}
static void lockedPointerHandleUnlocked(void* userData,
--
2.42.0

View File

@ -0,0 +1,40 @@
diff --git a/src/libdecor.c b/src/libdecor.c
index a9c1106..1aa38b3 100644
--- a/src/libdecor.c
+++ b/src/libdecor.c
@@ -1391,22 +1391,32 @@ calculate_priority(const struct libdecor_plugin_description *plugin_description)
static bool
check_symbol_conflicts(const struct libdecor_plugin_description *plugin_description)
{
+ bool ret = true;
char * const *symbol;
+ void* main_prog = dlopen(NULL, RTLD_LAZY);
+ if (!main_prog) {
+ fprintf(stderr, "Plugin \"%s\" couldn't check conflicting symbols: \"%s\".\n",
+ plugin_description->description, dlerror());
+ return false;
+ }
+
symbol = plugin_description->conflicting_symbols;
while (*symbol) {
dlerror();
- dlsym (RTLD_DEFAULT, *symbol);
+ dlsym (main_prog, *symbol);
if (!dlerror()) {
fprintf(stderr, "Plugin \"%s\" uses conflicting symbol \"%s\".\n",
plugin_description->description, *symbol);
- return false;
+ ret = false;
+ break;
}
symbol++;
}
- return true;
+ dlclose(main_prog);
+ return ret;
}
static struct plugin_loader *

@ -1 +1 @@
Subproject commit 73f08ed2c3187f6648ca04ebef030930a6c9f0be Subproject commit f2b0c16a2a217a1822ce5a6538ba8f755ed1dd32

7
garnix.yaml Normal file
View File

@ -0,0 +1,7 @@
builds:
exclude:
- "*.x86_64-darwin.*"
include:
- "checks.x86_64-linux.*"
- "devShells.*.*"
- "packages.*.*"

File diff suppressed because it is too large Load Diff

View File

@ -42,13 +42,13 @@
#include <QDebug> #include <QDebug>
#include <QFlag> #include <QFlag>
#include <QIcon> #include <QIcon>
#include <QMutex>
#include <QUrl> #include <QUrl>
#include <memory> #include <memory>
#include <BaseInstance.h> #include <BaseInstance.h>
#include "minecraft/launch/MinecraftTarget.h" #include "minecraft/launch/MinecraftServerTarget.h"
#include "ui/themes/CatPack.h"
class LaunchController; class LaunchController;
class LocalPeer; class LocalPeer;
@ -82,12 +82,6 @@ class Index;
#endif #endif
#define APPLICATION (static_cast<Application*>(QCoreApplication::instance())) #define APPLICATION (static_cast<Application*>(QCoreApplication::instance()))
// Used for checking if is a test
#if defined(APPLICATION_DYN)
#undef APPLICATION_DYN
#endif
#define APPLICATION_DYN (dynamic_cast<Application*>(QCoreApplication::instance()))
class Application : public QApplication { class Application : public QApplication {
// friends for the purpose of limiting access to deprecated stuff // friends for the purpose of limiting access to deprecated stuff
Q_OBJECT Q_OBJECT
@ -112,7 +106,7 @@ class Application : public QApplication {
std::shared_ptr<SettingsObject> settings() const { return m_settings; } 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 getThemedIcon(const QString& name); QIcon getThemedIcon(const QString& name);
@ -168,9 +162,6 @@ class Application : public QApplication {
/// the data path the application is using /// the data path the application is using
const QString& dataRoot() { return m_dataPath; } const QString& dataRoot() { return m_dataPath; }
/// the java installed path the application is using
const QString javaPath();
bool isPortable() { return m_portable; } bool isPortable() { return m_portable; }
const Capabilities capabilities() { return m_capabilities; } const Capabilities capabilities() { return m_capabilities; }
@ -189,6 +180,8 @@ class Application : public QApplication {
void ShowGlobalSettings(class QWidget* parent, QString open_page = QString()); void ShowGlobalSettings(class QWidget* parent, QString open_page = QString());
int suitableMaxMem();
bool updaterEnabled(); bool updaterEnabled();
QString updaterBinaryName(); QString updaterBinaryName();
@ -200,8 +193,6 @@ class Application : public QApplication {
void globalSettingsClosed(); void globalSettingsClosed();
int currentCatChanged(int index); int currentCatChanged(int index);
void oauthReplyRecieved(QVariantMap);
#ifdef Q_OS_MACOS #ifdef Q_OS_MACOS
void clickedOnDock(); void clickedOnDock();
#endif #endif
@ -210,9 +201,8 @@ class Application : public QApplication {
bool launch(InstancePtr instance, bool launch(InstancePtr instance,
bool online = true, bool online = true,
bool demo = false, bool demo = false,
MinecraftTarget::Ptr targetToJoin = nullptr, MinecraftServerTargetPtr serverToJoin = nullptr,
MinecraftAccountPtr accountToUse = nullptr, MinecraftAccountPtr accountToUse = nullptr);
const QString& offlineName = QString());
bool kill(InstancePtr instance); bool kill(InstancePtr instance);
void closeCurrentWindow(); void closeCurrentWindow();
@ -237,7 +227,7 @@ class Application : public QApplication {
bool shouldExitNow() const; bool shouldExitNow() const;
private: private:
QDateTime m_startTime; QDateTime startTime;
shared_qobject_ptr<QNetworkAccessManager> m_network; shared_qobject_ptr<QNetworkAccessManager> m_network;
@ -280,7 +270,6 @@ class Application : public QApplication {
shared_qobject_ptr<LaunchController> controller; shared_qobject_ptr<LaunchController> controller;
}; };
std::map<QString, InstanceXtras> m_instanceExtras; std::map<QString, InstanceXtras> m_instanceExtras;
mutable QMutex m_instanceExtrasMutex;
// main state variables // main state variables
size_t m_openWindows = 0; size_t m_openWindows = 0;
@ -300,21 +289,9 @@ class Application : public QApplication {
QString m_detectedOpenALPath; QString m_detectedOpenALPath;
QString m_instanceIdToLaunch; QString m_instanceIdToLaunch;
QString m_serverToJoin; QString m_serverToJoin;
QString m_worldToJoin;
QString m_profileToUse; QString m_profileToUse;
bool m_offline = false;
QString m_offlineName;
bool m_liveCheck = false; bool m_liveCheck = false;
QList<QUrl> m_urlsToImport; QList<QUrl> m_urlsToImport;
QString m_instanceIdToShowWindowOf; QString m_instanceIdToShowWindowOf;
std::unique_ptr<QFile> logFile; std::unique_ptr<QFile> logFile;
public:
void addQSavePath(QString);
void removeQSavePath(QString);
bool checkQSavePath(QString);
private:
QHash<QString, int> m_qsaveResources;
mutable QMutex m_qsaveResourcesMutex;
}; };

View File

@ -16,7 +16,6 @@
#include <QFile> #include <QFile>
#include "BaseInstaller.h" #include "BaseInstaller.h"
#include "FileSystem.h"
#include "minecraft/MinecraftInstance.h" #include "minecraft/MinecraftInstance.h"
BaseInstaller::BaseInstaller() {} BaseInstaller::BaseInstaller() {}
@ -43,7 +42,7 @@ bool BaseInstaller::add(MinecraftInstance* to)
bool BaseInstaller::remove(MinecraftInstance* from) bool BaseInstaller::remove(MinecraftInstance* from)
{ {
return FS::deletePath(filename(from->instanceRoot())); return QFile::remove(filename(from->instanceRoot()));
} }
QString BaseInstaller::filename(const QString& root) const QString BaseInstaller::filename(const QString& root) const

View File

@ -29,7 +29,7 @@ class BaseVersion;
class BaseInstaller { class BaseInstaller {
public: public:
BaseInstaller(); BaseInstaller();
virtual ~BaseInstaller() {}; virtual ~BaseInstaller(){};
bool isApplied(MinecraftInstance* on); bool isApplied(MinecraftInstance* on);
virtual bool add(MinecraftInstance* to); virtual bool add(MinecraftInstance* to);

View File

@ -42,8 +42,8 @@
#include <QFileInfo> #include <QFileInfo>
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject> #include <QJsonObject>
#include <QRegularExpression>
#include "Application.h"
#include "settings/INISettingsObject.h" #include "settings/INISettingsObject.h"
#include "settings/OverrideSetting.h" #include "settings/OverrideSetting.h"
#include "settings/Setting.h" #include "settings/Setting.h"
@ -174,12 +174,6 @@ void BaseInstance::copyManagedPack(BaseInstance& other)
m_settings->set("ManagedPackName", other.getManagedPackName()); m_settings->set("ManagedPackName", other.getManagedPackName());
m_settings->set("ManagedPackVersionID", other.getManagedPackVersionID()); m_settings->set("ManagedPackVersionID", other.getManagedPackVersionID());
m_settings->set("ManagedPackVersionName", other.getManagedPackVersionName()); 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 int BaseInstance::getConsoleMaxLines() const
@ -275,18 +269,13 @@ void BaseInstance::setRunning(bool running)
m_isRunning = running; m_isRunning = running;
emit runningStatusChanged(running); if (!m_settings->get("RecordGameTime").toBool()) {
} emit runningStatusChanged(running);
void BaseInstance::setMinecraftRunning(bool running)
{
if (!settings()->get("RecordGameTime").toBool()) {
return; return;
} }
if (running) { if (running) {
m_timeStarted = QDateTime::currentDateTime(); m_timeStarted = QDateTime::currentDateTime();
setLastLaunch(m_timeStarted.toMSecsSinceEpoch());
} else { } else {
QDateTime timeEnded = QDateTime::currentDateTime(); QDateTime timeEnded = QDateTime::currentDateTime();
@ -296,6 +285,8 @@ void BaseInstance::setMinecraftRunning(bool running)
emit propertiesChanged(this); emit propertiesChanged(this);
} }
emit runningStatusChanged(running);
} }
int64_t BaseInstance::totalTimePlayed() const int64_t BaseInstance::totalTimePlayed() const
@ -392,12 +383,6 @@ void BaseInstance::setName(QString val)
emit propertiesChanged(this); emit propertiesChanged(this);
} }
bool BaseInstance::syncInstanceDirName(const QString& newRoot) const
{
auto oldRoot = instanceRoot();
return oldRoot == newRoot || QFile::rename(oldRoot, newRoot);
}
QString BaseInstance::name() const QString BaseInstance::name() const
{ {
return m_settings->get("name").toString(); return m_settings->get("name").toString();
@ -423,8 +408,3 @@ void BaseInstance::updateRuntimeContext()
{ {
// NOOP // NOOP
} }
bool BaseInstance::isLegacy()
{
return traits().contains("legacyLaunch") || traits().contains("alphaLaunch");
}

View File

@ -56,7 +56,7 @@
#include "net/Mode.h" #include "net/Mode.h"
#include "RuntimeContext.h" #include "RuntimeContext.h"
#include "minecraft/launch/MinecraftTarget.h" #include "minecraft/launch/MinecraftServerTarget.h"
class QDir; class QDir;
class Task; class Task;
@ -104,7 +104,6 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
/// be unique. /// be unique.
virtual QString id() const; virtual QString id() const;
void setMinecraftRunning(bool running);
void setRunning(bool running); void setRunning(bool running);
bool isRunning() const; bool isRunning() const;
int64_t totalTimePlayed() const; int64_t totalTimePlayed() const;
@ -126,9 +125,6 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
QString name() const; QString name() const;
void setName(QString val); void setName(QString val);
/// Sync name and rename instance dir accordingly; returns true if successful
bool syncInstanceDirName(const QString& newRoot) const;
/// Value used for instance window titles /// Value used for instance window titles
QString windowTitle() const; QString windowTitle() const;
@ -151,6 +147,9 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
void setManagedPack(const QString& type, const QString& id, const QString& name, const QString& versionId, const QString& version); void setManagedPack(const QString& type, const QString& id, const QString& name, const QString& versionId, const QString& version);
void copyManagedPack(BaseInstance& other); 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(); virtual QStringList extraArguments();
/// Traits. Normally inside the version, depends on instance implementation. /// Traits. Normally inside the version, depends on instance implementation.
@ -181,10 +180,10 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
virtual void loadSpecificSettings() = 0; virtual void loadSpecificSettings() = 0;
/// returns a valid update task /// returns a valid update task
virtual QList<Task::Ptr> createUpdateTask() = 0; virtual Task::Ptr createUpdateTask(Net::Mode mode) = 0;
/// returns a valid launcher (task container) /// returns a valid launcher (task container)
virtual shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account, MinecraftTarget::Ptr targetToJoin) = 0; virtual shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) = 0;
/// returns the current launch task (if any) /// returns the current launch task (if any)
shared_qobject_ptr<LaunchTask> getLaunchTask(); shared_qobject_ptr<LaunchTask> getLaunchTask();
@ -195,10 +194,15 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
virtual QProcessEnvironment createEnvironment() = 0; virtual QProcessEnvironment createEnvironment() = 0;
virtual QProcessEnvironment createLaunchEnvironment() = 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 * Returns the root folder to use for looking up log files
*/ */
virtual QStringList getLogFileSearchPaths() = 0; virtual QString getLogFileRoot() = 0;
virtual QString getStatusbarDescription() = 0; virtual QString getStatusbarDescription() = 0;
@ -210,7 +214,7 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
virtual QString typeName() const = 0; virtual QString typeName() const = 0;
virtual void updateRuntimeContext(); void updateRuntimeContext();
RuntimeContext runtimeContext() const { return m_runtimeContext; } RuntimeContext runtimeContext() const { return m_runtimeContext; }
bool hasVersionBroken() const { return m_hasBrokenVersion; } bool hasVersionBroken() const { return m_hasBrokenVersion; }
@ -251,7 +255,7 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
/** /**
* 'print' a verbose description of the instance into a QStringList * 'print' a verbose description of the instance into a QStringList
*/ */
virtual QStringList verboseDescription(AuthSessionPtr session, MinecraftTarget::Ptr targetToJoin) = 0; virtual QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) = 0;
Status currentStatus() const; Status currentStatus() const;
@ -264,8 +268,6 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
bool removeLinkedInstanceId(const QString& id); bool removeLinkedInstanceId(const QString& id);
bool isLinkedToInstanceId(const QString& id) const; bool isLinkedToInstanceId(const QString& id) const;
bool isLegacy();
protected: protected:
void changeStatus(Status newStatus); void changeStatus(Status newStatus);

View File

@ -78,14 +78,6 @@ QVariant BaseVersionList::data(const QModelIndex& index, int role) const
case TypeRole: case TypeRole:
return version->typeString(); return version->typeString();
case JavaMajorRole: {
auto major = version->name();
if (major.startsWith("java")) {
major = "Java " + major.mid(4);
}
return major;
}
default: default:
return QVariant(); return QVariant();
} }
@ -118,8 +110,6 @@ QHash<int, QByteArray> BaseVersionList::roleNames() const
roles.insert(TypeRole, "type"); roles.insert(TypeRole, "type");
roles.insert(BranchRole, "branch"); roles.insert(BranchRole, "branch");
roles.insert(PathRole, "path"); roles.insert(PathRole, "path");
roles.insert(JavaNameRole, "javaName"); roles.insert(ArchitectureRole, "architecture");
roles.insert(CPUArchitectureRole, "architecture");
roles.insert(JavaMajorRole, "javaMajor");
return roles; return roles;
} }

View File

@ -48,9 +48,7 @@ class BaseVersionList : public QAbstractListModel {
TypeRole, TypeRole,
BranchRole, BranchRole,
PathRole, PathRole,
JavaNameRole, ArchitectureRole,
JavaMajorRole,
CPUArchitectureRole,
SortRole SortRole
}; };
using RoleList = QList<int>; using RoleList = QList<int>;

View File

@ -21,18 +21,13 @@ set(CORE_SOURCES
BaseVersion.h BaseVersion.h
BaseInstance.h BaseInstance.h
BaseInstance.cpp BaseInstance.cpp
InstanceDirUpdate.h
InstanceDirUpdate.cpp
NullInstance.h NullInstance.h
MMCZip.h MMCZip.h
MMCZip.cpp MMCZip.cpp
Untar.h
Untar.cpp
StringUtils.h StringUtils.h
StringUtils.cpp StringUtils.cpp
QVariantUtils.h QVariantUtils.h
RuntimeContext.h RuntimeContext.h
PSaveFile.h
# Basic instance manipulation tasks (derived from InstanceTask) # Basic instance manipulation tasks (derived from InstanceTask)
InstanceCreationTask.h InstanceCreationTask.h
@ -99,7 +94,7 @@ set(CORE_SOURCES
MTPixmapCache.h MTPixmapCache.h
) )
if (UNIX AND NOT CYGWIN AND NOT APPLE) if (UNIX AND NOT CYGWIN AND NOT APPLE)
set(CORE_SOURCES set(CORE_SOURCES
${CORE_SOURCES} ${CORE_SOURCES}
# MangoHud # MangoHud
@ -131,6 +126,7 @@ set(NET_SOURCES
net/MetaCacheSink.h net/MetaCacheSink.h
net/Logging.h net/Logging.h
net/Logging.cpp net/Logging.cpp
net/NetAction.h
net/NetJob.cpp net/NetJob.cpp
net/NetJob.h net/NetJob.h
net/NetUtils.h net/NetUtils.h
@ -143,6 +139,7 @@ set(NET_SOURCES
net/HeaderProxy.h net/HeaderProxy.h
net/RawHeaderProxy.h net/RawHeaderProxy.h
net/ApiHeaderProxy.h net/ApiHeaderProxy.h
net/StaticHeaderProxy.h
net/ApiDownload.h net/ApiDownload.h
net/ApiDownload.cpp net/ApiDownload.cpp
net/ApiUpload.cpp net/ApiUpload.cpp
@ -163,20 +160,16 @@ set(LAUNCH_SOURCES
launch/steps/PreLaunchCommand.h launch/steps/PreLaunchCommand.h
launch/steps/TextPrint.cpp launch/steps/TextPrint.cpp
launch/steps/TextPrint.h launch/steps/TextPrint.h
launch/steps/Update.cpp
launch/steps/Update.h
launch/steps/QuitAfterGameStop.cpp launch/steps/QuitAfterGameStop.cpp
launch/steps/QuitAfterGameStop.h launch/steps/QuitAfterGameStop.h
launch/steps/PrintServers.cpp
launch/steps/PrintServers.h
launch/LaunchStep.cpp launch/LaunchStep.cpp
launch/LaunchStep.h launch/LaunchStep.h
launch/LaunchTask.cpp launch/LaunchTask.cpp
launch/LaunchTask.h launch/LaunchTask.h
launch/LogModel.cpp launch/LogModel.cpp
launch/LogModel.h launch/LogModel.h
launch/TaskStepWrapper.cpp
launch/TaskStepWrapper.h
logs/LogParser.cpp
logs/LogParser.h
) )
# Old update system # Old update system
@ -212,27 +205,33 @@ set(ICONS_SOURCES
# Support for Minecraft instances and launch # Support for Minecraft instances and launch
set(MINECRAFT_SOURCES set(MINECRAFT_SOURCES
# Logging
minecraft/Logging.h
minecraft/Logging.cpp
# Minecraft support # Minecraft support
minecraft/auth/AccountData.cpp minecraft/auth/AccountData.cpp
minecraft/auth/AccountData.h minecraft/auth/AccountData.h
minecraft/auth/AccountList.cpp minecraft/auth/AccountList.cpp
minecraft/auth/AccountList.h minecraft/auth/AccountList.h
minecraft/auth/AccountTask.cpp
minecraft/auth/AccountTask.h
minecraft/auth/AuthRequest.cpp
minecraft/auth/AuthRequest.h
minecraft/auth/AuthSession.cpp minecraft/auth/AuthSession.cpp
minecraft/auth/AuthSession.h minecraft/auth/AuthSession.h
minecraft/auth/AuthStep.cpp
minecraft/auth/AuthStep.h minecraft/auth/AuthStep.h
minecraft/auth/MinecraftAccount.cpp minecraft/auth/MinecraftAccount.cpp
minecraft/auth/MinecraftAccount.h minecraft/auth/MinecraftAccount.h
minecraft/auth/Parsers.cpp minecraft/auth/Parsers.cpp
minecraft/auth/Parsers.h minecraft/auth/Parsers.h
minecraft/auth/AuthFlow.cpp minecraft/auth/flows/AuthFlow.cpp
minecraft/auth/AuthFlow.h minecraft/auth/flows/AuthFlow.h
minecraft/auth/flows/MSA.cpp
minecraft/auth/flows/MSA.h
minecraft/auth/flows/Offline.cpp
minecraft/auth/flows/Offline.h
minecraft/auth/steps/OfflineStep.cpp
minecraft/auth/steps/OfflineStep.h
minecraft/auth/steps/EntitlementsStep.cpp minecraft/auth/steps/EntitlementsStep.cpp
minecraft/auth/steps/EntitlementsStep.h minecraft/auth/steps/EntitlementsStep.h
minecraft/auth/steps/GetSkinStep.cpp minecraft/auth/steps/GetSkinStep.cpp
@ -241,8 +240,6 @@ set(MINECRAFT_SOURCES
minecraft/auth/steps/LauncherLoginStep.h minecraft/auth/steps/LauncherLoginStep.h
minecraft/auth/steps/MinecraftProfileStep.cpp minecraft/auth/steps/MinecraftProfileStep.cpp
minecraft/auth/steps/MinecraftProfileStep.h minecraft/auth/steps/MinecraftProfileStep.h
minecraft/auth/steps/MSADeviceCodeStep.cpp
minecraft/auth/steps/MSADeviceCodeStep.h
minecraft/auth/steps/MSAStep.cpp minecraft/auth/steps/MSAStep.cpp
minecraft/auth/steps/MSAStep.h minecraft/auth/steps/MSAStep.h
minecraft/auth/steps/XboxAuthorizationStep.cpp minecraft/auth/steps/XboxAuthorizationStep.cpp
@ -274,8 +271,8 @@ set(MINECRAFT_SOURCES
minecraft/launch/ExtractNatives.h minecraft/launch/ExtractNatives.h
minecraft/launch/LauncherPartLaunch.cpp minecraft/launch/LauncherPartLaunch.cpp
minecraft/launch/LauncherPartLaunch.h minecraft/launch/LauncherPartLaunch.h
minecraft/launch/MinecraftTarget.cpp minecraft/launch/MinecraftServerTarget.cpp
minecraft/launch/MinecraftTarget.h minecraft/launch/MinecraftServerTarget.h
minecraft/launch/PrintInstanceInfo.cpp minecraft/launch/PrintInstanceInfo.cpp
minecraft/launch/PrintInstanceInfo.h minecraft/launch/PrintInstanceInfo.h
minecraft/launch/ReconstructAssets.cpp minecraft/launch/ReconstructAssets.cpp
@ -284,8 +281,6 @@ set(MINECRAFT_SOURCES
minecraft/launch/ScanModFolders.h minecraft/launch/ScanModFolders.h
minecraft/launch/VerifyJavaInstall.cpp minecraft/launch/VerifyJavaInstall.cpp
minecraft/launch/VerifyJavaInstall.h minecraft/launch/VerifyJavaInstall.h
minecraft/launch/AutoInstallJava.cpp
minecraft/launch/AutoInstallJava.h
minecraft/GradleSpecifier.h minecraft/GradleSpecifier.h
minecraft/MinecraftInstance.cpp minecraft/MinecraftInstance.cpp
@ -300,6 +295,8 @@ set(MINECRAFT_SOURCES
minecraft/ComponentUpdateTask.h minecraft/ComponentUpdateTask.h
minecraft/MinecraftLoadAndCheck.h minecraft/MinecraftLoadAndCheck.h
minecraft/MinecraftLoadAndCheck.cpp minecraft/MinecraftLoadAndCheck.cpp
minecraft/MinecraftUpdate.h
minecraft/MinecraftUpdate.cpp
minecraft/MojangVersionFormat.cpp minecraft/MojangVersionFormat.cpp
minecraft/MojangVersionFormat.h minecraft/MojangVersionFormat.h
minecraft/Rule.cpp minecraft/Rule.cpp
@ -349,12 +346,13 @@ set(MINECRAFT_SOURCES
minecraft/mod/TexturePackFolderModel.h minecraft/mod/TexturePackFolderModel.h
minecraft/mod/TexturePackFolderModel.cpp minecraft/mod/TexturePackFolderModel.cpp
minecraft/mod/ShaderPackFolderModel.h minecraft/mod/ShaderPackFolderModel.h
minecraft/mod/tasks/ResourceFolderLoadTask.h minecraft/mod/tasks/BasicFolderLoadTask.h
minecraft/mod/tasks/ResourceFolderLoadTask.cpp minecraft/mod/tasks/ModFolderLoadTask.h
minecraft/mod/tasks/ModFolderLoadTask.cpp
minecraft/mod/tasks/LocalModParseTask.h minecraft/mod/tasks/LocalModParseTask.h
minecraft/mod/tasks/LocalModParseTask.cpp minecraft/mod/tasks/LocalModParseTask.cpp
minecraft/mod/tasks/LocalResourceUpdateTask.h minecraft/mod/tasks/LocalModUpdateTask.h
minecraft/mod/tasks/LocalResourceUpdateTask.cpp minecraft/mod/tasks/LocalModUpdateTask.cpp
minecraft/mod/tasks/LocalDataPackParseTask.h minecraft/mod/tasks/LocalDataPackParseTask.h
minecraft/mod/tasks/LocalDataPackParseTask.cpp minecraft/mod/tasks/LocalDataPackParseTask.cpp
minecraft/mod/tasks/LocalResourcePackParseTask.h minecraft/mod/tasks/LocalResourcePackParseTask.h
@ -374,17 +372,13 @@ set(MINECRAFT_SOURCES
minecraft/AssetsUtils.h minecraft/AssetsUtils.h
minecraft/AssetsUtils.cpp minecraft/AssetsUtils.cpp
# Minecraft skins # Minecraft services
minecraft/skins/CapeChange.cpp minecraft/services/CapeChange.cpp
minecraft/skins/CapeChange.h minecraft/services/CapeChange.h
minecraft/skins/SkinUpload.cpp minecraft/services/SkinUpload.cpp
minecraft/skins/SkinUpload.h minecraft/services/SkinUpload.h
minecraft/skins/SkinDelete.cpp minecraft/services/SkinDelete.cpp
minecraft/skins/SkinDelete.h minecraft/services/SkinDelete.h
minecraft/skins/SkinModel.cpp
minecraft/skins/SkinModel.h
minecraft/skins/SkinList.cpp
minecraft/skins/SkinList.h
minecraft/Agent.h) minecraft/Agent.h)
@ -428,6 +422,8 @@ set(SETTINGS_SOURCES
set(JAVA_SOURCES set(JAVA_SOURCES
java/JavaChecker.h java/JavaChecker.h
java/JavaChecker.cpp java/JavaChecker.cpp
java/JavaCheckerJob.h
java/JavaCheckerJob.cpp
java/JavaInstall.h java/JavaInstall.h
java/JavaInstall.cpp java/JavaInstall.cpp
java/JavaInstallList.h java/JavaInstallList.h
@ -436,20 +432,6 @@ set(JAVA_SOURCES
java/JavaUtils.cpp java/JavaUtils.cpp
java/JavaVersion.h java/JavaVersion.h
java/JavaVersion.cpp java/JavaVersion.cpp
java/JavaMetadata.h
java/JavaMetadata.cpp
java/download/ArchiveDownloadTask.cpp
java/download/ArchiveDownloadTask.h
java/download/ManifestDownloadTask.cpp
java/download/ManifestDownloadTask.h
java/download/SymlinkTask.cpp
java/download/SymlinkTask.h
ui/java/InstallJavaDialog.h
ui/java/InstallJavaDialog.cpp
ui/java/VersionList.h
ui/java/VersionList.cpp
) )
set(TRANSLATIONS_SOURCES set(TRANSLATIONS_SOURCES
@ -471,8 +453,6 @@ set(TOOLS_SOURCES
tools/JVisualVM.h tools/JVisualVM.h
tools/MCEditTool.cpp tools/MCEditTool.cpp
tools/MCEditTool.h tools/MCEditTool.h
tools/GenericProfiler.cpp
tools/GenericProfiler.h
) )
set(META_SOURCES set(META_SOURCES
@ -591,8 +571,8 @@ set(ATLAUNCHER_SOURCES
) )
set(LINKEXE_SOURCES set(LINKEXE_SOURCES
console/WindowsConsole.h WindowsConsole.cpp
console/WindowsConsole.cpp WindowsConsole.h
filelink/FileLink.h filelink/FileLink.h
filelink/FileLink.cpp filelink/FileLink.cpp
@ -644,6 +624,7 @@ set(PRISMUPDATER_SOURCES
net/HttpMetaCache.h net/HttpMetaCache.h
net/Logging.h net/Logging.h
net/Logging.cpp net/Logging.cpp
net/NetAction.h
net/NetRequest.cpp net/NetRequest.cpp
net/NetRequest.h net/NetRequest.h
net/NetJob.cpp net/NetJob.cpp
@ -661,14 +642,6 @@ set(PRISMUPDATER_SOURCES
) )
if(WIN32)
set(PRISMUPDATER_SOURCES
console/WindowsConsole.h
console/WindowsConsole.cpp
${PRISMUPDATER_SOURCES}
)
endif()
######## Logging categories ######## ######## Logging categories ########
ecm_qt_declare_logging_category(CORE_SOURCES ecm_qt_declare_logging_category(CORE_SOURCES
@ -680,22 +653,6 @@ ecm_qt_declare_logging_category(CORE_SOURCES
EXPORT "${Launcher_Name}" EXPORT "${Launcher_Name}"
) )
ecm_qt_export_logging_category(
IDENTIFIER instanceProfileC
CATEGORY_NAME "launcher.instance.profile"
DEFAULT_SEVERITY Debug
DESCRIPTION "Profile actions"
EXPORT "${Launcher_Name}"
)
ecm_qt_export_logging_category(
IDENTIFIER instanceProfileResolveC
CATEGORY_NAME "launcher.instance.profile.resolve"
DEFAULT_SEVERITY Debug
DESCRIPTION "Profile component resolusion actions"
EXPORT "${Launcher_Name}"
)
ecm_qt_export_logging_category( ecm_qt_export_logging_category(
IDENTIFIER taskLogC IDENTIFIER taskLogC
CATEGORY_NAME "launcher.task" CATEGORY_NAME "launcher.task"
@ -708,7 +665,7 @@ ecm_qt_export_logging_category(
IDENTIFIER taskNetLogC IDENTIFIER taskNetLogC
CATEGORY_NAME "launcher.task.net" CATEGORY_NAME "launcher.task.net"
DEFAULT_SEVERITY Debug DEFAULT_SEVERITY Debug
DESCRIPTION "Task network action" DESCRIPTION "task network action"
EXPORT "${Launcher_Name}" EXPORT "${Launcher_Name}"
) )
@ -716,14 +673,14 @@ ecm_qt_export_logging_category(
IDENTIFIER taskDownloadLogC IDENTIFIER taskDownloadLogC
CATEGORY_NAME "launcher.task.net.download" CATEGORY_NAME "launcher.task.net.download"
DEFAULT_SEVERITY Debug DEFAULT_SEVERITY Debug
DESCRIPTION "Task network download actions" DESCRIPTION "task network download actions"
EXPORT "${Launcher_Name}" EXPORT "${Launcher_Name}"
) )
ecm_qt_export_logging_category( ecm_qt_export_logging_category(
IDENTIFIER taskUploadLogC IDENTIFIER taskUploadLogC
CATEGORY_NAME "launcher.task.net.upload" CATEGORY_NAME "launcher.task.net.upload"
DEFAULT_SEVERITY Debug DEFAULT_SEVERITY Debug
DESCRIPTION "Task network upload actions" DESCRIPTION "task network upload actions"
EXPORT "${Launcher_Name}" EXPORT "${Launcher_Name}"
) )
@ -793,11 +750,6 @@ SET(LAUNCHER_SOURCES
DataMigrationTask.cpp DataMigrationTask.cpp
ApplicationMessage.h ApplicationMessage.h
ApplicationMessage.cpp ApplicationMessage.cpp
SysInfo.h
SysInfo.cpp
# console utils
console/Console.h
# GUI - general utilities # GUI - general utilities
DesktopServices.h DesktopServices.h
@ -825,8 +777,7 @@ SET(LAUNCHER_SOURCES
resources/flat/flat.qrc resources/flat/flat.qrc
resources/flat_white/flat_white.qrc resources/flat_white/flat_white.qrc
resources/documents/documents.qrc resources/documents/documents.qrc
resources/shaders/shaders.qrc ../${Launcher_Branding_LogoQRC}
"${CMAKE_CURRENT_BINARY_DIR}/../${Launcher_Branding_LogoQRC}"
# Icons # Icons
icons/MMCIcon.h icons/MMCIcon.h
@ -837,12 +788,16 @@ SET(LAUNCHER_SOURCES
# GUI - windows # GUI - windows
ui/GuiUtil.h ui/GuiUtil.h
ui/GuiUtil.cpp ui/GuiUtil.cpp
ui/ColorCache.h
ui/ColorCache.cpp
ui/MainWindow.h ui/MainWindow.h
ui/MainWindow.cpp ui/MainWindow.cpp
ui/InstanceWindow.h ui/InstanceWindow.h
ui/InstanceWindow.cpp ui/InstanceWindow.cpp
# FIXME: maybe find a better home for this. # FIXME: maybe find a better home for this.
SkinUtils.cpp
SkinUtils.h
FileIgnoreProxy.cpp FileIgnoreProxy.cpp
FileIgnoreProxy.h FileIgnoreProxy.h
FastFileIconProvider.cpp FastFileIconProvider.cpp
@ -860,10 +815,6 @@ SET(LAUNCHER_SOURCES
ui/setupwizard/PasteWizardPage.h ui/setupwizard/PasteWizardPage.h
ui/setupwizard/ThemeWizardPage.cpp ui/setupwizard/ThemeWizardPage.cpp
ui/setupwizard/ThemeWizardPage.h ui/setupwizard/ThemeWizardPage.h
ui/setupwizard/AutoJavaWizardPage.cpp
ui/setupwizard/AutoJavaWizardPage.h
ui/setupwizard/LoginWizardPage.cpp
ui/setupwizard/LoginWizardPage.h
# GUI - themes # GUI - themes
ui/themes/FusionTheme.cpp ui/themes/FusionTheme.cpp
@ -876,8 +827,6 @@ SET(LAUNCHER_SOURCES
ui/themes/DarkTheme.h ui/themes/DarkTheme.h
ui/themes/ITheme.cpp ui/themes/ITheme.cpp
ui/themes/ITheme.h ui/themes/ITheme.h
ui/themes/HintOverrideProxyStyle.cpp
ui/themes/HintOverrideProxyStyle.h
ui/themes/SystemTheme.cpp ui/themes/SystemTheme.cpp
ui/themes/SystemTheme.h ui/themes/SystemTheme.h
ui/themes/IconTheme.cpp ui/themes/IconTheme.cpp
@ -924,6 +873,7 @@ SET(LAUNCHER_SOURCES
ui/pages/instance/NotesPage.h ui/pages/instance/NotesPage.h
ui/pages/instance/LogPage.cpp ui/pages/instance/LogPage.cpp
ui/pages/instance/LogPage.h ui/pages/instance/LogPage.h
ui/pages/instance/InstanceSettingsPage.cpp
ui/pages/instance/InstanceSettingsPage.h ui/pages/instance/InstanceSettingsPage.h
ui/pages/instance/ScreenshotsPage.cpp ui/pages/instance/ScreenshotsPage.cpp
ui/pages/instance/ScreenshotsPage.h ui/pages/instance/ScreenshotsPage.h
@ -933,22 +883,21 @@ SET(LAUNCHER_SOURCES
ui/pages/instance/ServersPage.h ui/pages/instance/ServersPage.h
ui/pages/instance/WorldListPage.cpp ui/pages/instance/WorldListPage.cpp
ui/pages/instance/WorldListPage.h ui/pages/instance/WorldListPage.h
ui/pages/instance/McClient.cpp
ui/pages/instance/McClient.h
ui/pages/instance/McResolver.cpp
ui/pages/instance/McResolver.h
ui/pages/instance/ServerPingTask.cpp
ui/pages/instance/ServerPingTask.h
# GUI - global settings pages # GUI - global settings pages
ui/pages/global/AccountListPage.cpp ui/pages/global/AccountListPage.cpp
ui/pages/global/AccountListPage.h ui/pages/global/AccountListPage.h
ui/pages/global/CustomCommandsPage.cpp
ui/pages/global/CustomCommandsPage.h
ui/pages/global/EnvironmentVariablesPage.cpp
ui/pages/global/EnvironmentVariablesPage.h
ui/pages/global/ExternalToolsPage.cpp ui/pages/global/ExternalToolsPage.cpp
ui/pages/global/ExternalToolsPage.h ui/pages/global/ExternalToolsPage.h
ui/pages/global/JavaPage.cpp ui/pages/global/JavaPage.cpp
ui/pages/global/JavaPage.h ui/pages/global/JavaPage.h
ui/pages/global/LanguagePage.cpp ui/pages/global/LanguagePage.cpp
ui/pages/global/LanguagePage.h ui/pages/global/LanguagePage.h
ui/pages/global/MinecraftPage.cpp
ui/pages/global/MinecraftPage.h ui/pages/global/MinecraftPage.h
ui/pages/global/LauncherPage.cpp ui/pages/global/LauncherPage.cpp
ui/pages/global/LauncherPage.h ui/pages/global/LauncherPage.h
@ -981,9 +930,6 @@ SET(LAUNCHER_SOURCES
ui/pages/modplatform/ShaderPackPage.cpp ui/pages/modplatform/ShaderPackPage.cpp
ui/pages/modplatform/ShaderPackModel.cpp ui/pages/modplatform/ShaderPackModel.cpp
ui/pages/modplatform/ModpackProviderBasePage.h
ui/pages/modplatform/atlauncher/AtlFilterModel.cpp ui/pages/modplatform/atlauncher/AtlFilterModel.cpp
ui/pages/modplatform/atlauncher/AtlFilterModel.h ui/pages/modplatform/atlauncher/AtlFilterModel.h
ui/pages/modplatform/atlauncher/AtlListModel.cpp ui/pages/modplatform/atlauncher/AtlListModel.cpp
@ -1046,6 +992,8 @@ SET(LAUNCHER_SOURCES
ui/dialogs/CopyInstanceDialog.h ui/dialogs/CopyInstanceDialog.h
ui/dialogs/CustomMessageBox.cpp ui/dialogs/CustomMessageBox.cpp
ui/dialogs/CustomMessageBox.h ui/dialogs/CustomMessageBox.h
ui/dialogs/EditAccountDialog.cpp
ui/dialogs/EditAccountDialog.h
ui/dialogs/ExportInstanceDialog.cpp ui/dialogs/ExportInstanceDialog.cpp
ui/dialogs/ExportInstanceDialog.h ui/dialogs/ExportInstanceDialog.h
ui/dialogs/ExportPackDialog.cpp ui/dialogs/ExportPackDialog.cpp
@ -1074,6 +1022,8 @@ SET(LAUNCHER_SOURCES
ui/dialogs/ReviewMessageBox.h ui/dialogs/ReviewMessageBox.h
ui/dialogs/VersionSelectDialog.cpp ui/dialogs/VersionSelectDialog.cpp
ui/dialogs/VersionSelectDialog.h ui/dialogs/VersionSelectDialog.h
ui/dialogs/SkinUploadDialog.cpp
ui/dialogs/SkinUploadDialog.h
ui/dialogs/ResourceDownloadDialog.cpp ui/dialogs/ResourceDownloadDialog.cpp
ui/dialogs/ResourceDownloadDialog.h ui/dialogs/ResourceDownloadDialog.h
ui/dialogs/ScrollMessageBox.cpp ui/dialogs/ScrollMessageBox.cpp
@ -1082,36 +1032,26 @@ SET(LAUNCHER_SOURCES
ui/dialogs/BlockedModsDialog.h ui/dialogs/BlockedModsDialog.h
ui/dialogs/ChooseProviderDialog.h ui/dialogs/ChooseProviderDialog.h
ui/dialogs/ChooseProviderDialog.cpp ui/dialogs/ChooseProviderDialog.cpp
ui/dialogs/ResourceUpdateDialog.cpp ui/dialogs/ModUpdateDialog.cpp
ui/dialogs/ResourceUpdateDialog.h ui/dialogs/ModUpdateDialog.h
ui/dialogs/InstallLoaderDialog.cpp ui/dialogs/InstallLoaderDialog.cpp
ui/dialogs/InstallLoaderDialog.h ui/dialogs/InstallLoaderDialog.h
ui/dialogs/skins/SkinManageDialog.cpp
ui/dialogs/skins/SkinManageDialog.h
ui/dialogs/skins/draw/SkinOpenGLWindow.h
ui/dialogs/skins/draw/SkinOpenGLWindow.cpp
ui/dialogs/skins/draw/Scene.h
ui/dialogs/skins/draw/Scene.cpp
ui/dialogs/skins/draw/BoxGeometry.h
ui/dialogs/skins/draw/BoxGeometry.cpp
# GUI - widgets # GUI - widgets
ui/widgets/CheckComboBox.cpp
ui/widgets/CheckComboBox.h
ui/widgets/Common.cpp ui/widgets/Common.cpp
ui/widgets/Common.h ui/widgets/Common.h
ui/widgets/CustomCommands.cpp ui/widgets/CustomCommands.cpp
ui/widgets/CustomCommands.h ui/widgets/CustomCommands.h
ui/widgets/EnvironmentVariables.cpp ui/widgets/EnvironmentVariables.cpp
ui/widgets/EnvironmentVariables.h ui/widgets/EnvironmentVariables.h
ui/widgets/DropLabel.cpp
ui/widgets/DropLabel.h
ui/widgets/FocusLineEdit.cpp ui/widgets/FocusLineEdit.cpp
ui/widgets/FocusLineEdit.h ui/widgets/FocusLineEdit.h
ui/widgets/IconLabel.cpp ui/widgets/IconLabel.cpp
ui/widgets/IconLabel.h ui/widgets/IconLabel.h
ui/widgets/JavaWizardWidget.cpp ui/widgets/JavaSettingsWidget.cpp
ui/widgets/JavaWizardWidget.h ui/widgets/JavaSettingsWidget.h
ui/widgets/LabeledToolButton.cpp ui/widgets/LabeledToolButton.cpp
ui/widgets/LabeledToolButton.h ui/widgets/LabeledToolButton.h
ui/widgets/LanguageSelectionWidget.cpp ui/widgets/LanguageSelectionWidget.cpp
@ -1147,10 +1087,6 @@ SET(LAUNCHER_SOURCES
ui/widgets/WideBar.cpp ui/widgets/WideBar.cpp
ui/widgets/ThemeCustomizationWidget.h ui/widgets/ThemeCustomizationWidget.h
ui/widgets/ThemeCustomizationWidget.cpp ui/widgets/ThemeCustomizationWidget.cpp
ui/widgets/MinecraftSettingsWidget.h
ui/widgets/MinecraftSettingsWidget.cpp
ui/widgets/JavaSettingsWidget.h
ui/widgets/JavaSettingsWidget.cpp
# GUI - instance group view # GUI - instance group view
ui/instanceview/InstanceProxyModel.cpp ui/instanceview/InstanceProxyModel.cpp
@ -1167,7 +1103,7 @@ SET(LAUNCHER_SOURCES
) )
if (NOT Apple) if (NOT Apple)
set(LAUNCHER_SOURCES set(LAUNCHER_SOURCES
${LAUNCHER_SOURCES} ${LAUNCHER_SOURCES}
ui/dialogs/UpdateAvailableDialog.h ui/dialogs/UpdateAvailableDialog.h
@ -1177,8 +1113,8 @@ endif()
if(WIN32) if(WIN32)
set(LAUNCHER_SOURCES set(LAUNCHER_SOURCES
console/WindowsConsole.h WindowsConsole.cpp
console/WindowsConsole.cpp WindowsConsole.h
${LAUNCHER_SOURCES} ${LAUNCHER_SOURCES}
) )
endif() endif()
@ -1186,14 +1122,13 @@ endif()
qt_wrap_ui(LAUNCHER_UI qt_wrap_ui(LAUNCHER_UI
ui/MainWindow.ui ui/MainWindow.ui
ui/setupwizard/PasteWizardPage.ui ui/setupwizard/PasteWizardPage.ui
ui/setupwizard/AutoJavaWizardPage.ui
ui/setupwizard/LoginWizardPage.ui
ui/setupwizard/ThemeWizardPage.ui ui/setupwizard/ThemeWizardPage.ui
ui/pages/global/AccountListPage.ui ui/pages/global/AccountListPage.ui
ui/pages/global/JavaPage.ui ui/pages/global/JavaPage.ui
ui/pages/global/LauncherPage.ui ui/pages/global/LauncherPage.ui
ui/pages/global/APIPage.ui ui/pages/global/APIPage.ui
ui/pages/global/ProxyPage.ui ui/pages/global/ProxyPage.ui
ui/pages/global/MinecraftPage.ui
ui/pages/global/ExternalToolsPage.ui ui/pages/global/ExternalToolsPage.ui
ui/pages/instance/ExternalResourcesPage.ui ui/pages/instance/ExternalResourcesPage.ui
ui/pages/instance/NotesPage.ui ui/pages/instance/NotesPage.ui
@ -1201,6 +1136,7 @@ qt_wrap_ui(LAUNCHER_UI
ui/pages/instance/ServersPage.ui ui/pages/instance/ServersPage.ui
ui/pages/instance/GameOptionsPage.ui ui/pages/instance/GameOptionsPage.ui
ui/pages/instance/OtherLogsPage.ui ui/pages/instance/OtherLogsPage.ui
ui/pages/instance/InstanceSettingsPage.ui
ui/pages/instance/VersionPage.ui ui/pages/instance/VersionPage.ui
ui/pages/instance/ManagedPackPage.ui ui/pages/instance/ManagedPackPage.ui
ui/pages/instance/WorldListPage.ui ui/pages/instance/WorldListPage.ui
@ -1223,8 +1159,6 @@ qt_wrap_ui(LAUNCHER_UI
ui/widgets/ModFilterWidget.ui ui/widgets/ModFilterWidget.ui
ui/widgets/SubTaskProgressBar.ui ui/widgets/SubTaskProgressBar.ui
ui/widgets/ThemeCustomizationWidget.ui ui/widgets/ThemeCustomizationWidget.ui
ui/widgets/MinecraftSettingsWidget.ui
ui/widgets/JavaSettingsWidget.ui
ui/dialogs/CopyInstanceDialog.ui ui/dialogs/CopyInstanceDialog.ui
ui/dialogs/ProfileSetupDialog.ui ui/dialogs/ProfileSetupDialog.ui
ui/dialogs/ProgressDialog.ui ui/dialogs/ProgressDialog.ui
@ -1232,6 +1166,7 @@ qt_wrap_ui(LAUNCHER_UI
ui/dialogs/NewComponentDialog.ui ui/dialogs/NewComponentDialog.ui
ui/dialogs/NewsDialog.ui ui/dialogs/NewsDialog.ui
ui/dialogs/ProfileSelectDialog.ui ui/dialogs/ProfileSelectDialog.ui
ui/dialogs/SkinUploadDialog.ui
ui/dialogs/ExportInstanceDialog.ui ui/dialogs/ExportInstanceDialog.ui
ui/dialogs/ExportPackDialog.ui ui/dialogs/ExportPackDialog.ui
ui/dialogs/ExportToModListDialog.ui ui/dialogs/ExportToModListDialog.ui
@ -1240,11 +1175,11 @@ qt_wrap_ui(LAUNCHER_UI
ui/dialogs/MSALoginDialog.ui ui/dialogs/MSALoginDialog.ui
ui/dialogs/OfflineLoginDialog.ui ui/dialogs/OfflineLoginDialog.ui
ui/dialogs/AboutDialog.ui ui/dialogs/AboutDialog.ui
ui/dialogs/EditAccountDialog.ui
ui/dialogs/ReviewMessageBox.ui ui/dialogs/ReviewMessageBox.ui
ui/dialogs/ScrollMessageBox.ui ui/dialogs/ScrollMessageBox.ui
ui/dialogs/BlockedModsDialog.ui ui/dialogs/BlockedModsDialog.ui
ui/dialogs/ChooseProviderDialog.ui ui/dialogs/ChooseProviderDialog.ui
ui/dialogs/skins/SkinManageDialog.ui
) )
qt_wrap_ui(PRISM_UPDATE_UI qt_wrap_ui(PRISM_UPDATE_UI
@ -1268,8 +1203,7 @@ qt_add_resources(LAUNCHER_RESOURCES
resources/iOS/iOS.qrc resources/iOS/iOS.qrc
resources/flat/flat.qrc resources/flat/flat.qrc
resources/documents/documents.qrc resources/documents/documents.qrc
resources/shaders/shaders.qrc ../${Launcher_Branding_LogoQRC}
"${CMAKE_CURRENT_BINARY_DIR}/../${Launcher_Branding_LogoQRC}"
) )
qt_wrap_ui(PRISMUPDATER_UI qt_wrap_ui(PRISMUPDATER_UI
@ -1287,10 +1221,14 @@ include(CompilerWarnings)
# Add executable # Add executable
add_library(Launcher_logic STATIC ${LOGIC_SOURCES} ${LAUNCHER_SOURCES} ${LAUNCHER_UI} ${LAUNCHER_RESOURCES}) add_library(Launcher_logic STATIC ${LOGIC_SOURCES} ${LAUNCHER_SOURCES} ${LAUNCHER_UI} ${LAUNCHER_RESOURCES})
if(BUILD_TESTING)
target_compile_definitions(Launcher_logic PUBLIC LAUNCHER_TEST)
endif()
set_project_warnings(Launcher_logic set_project_warnings(Launcher_logic
"${Launcher_MSVC_WARNINGS}" "${Launcher_MSVC_WARNINGS}"
"${Launcher_CLANG_WARNINGS}" "${Launcher_CLANG_WARNINGS}"
"${Launcher_GCC_WARNINGS}") "${Launcher_GCC_WARNINGS}")
target_compile_definitions(Launcher_logic PUBLIC LAUNCHER_APPLICATION)
target_include_directories(Launcher_logic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) target_include_directories(Launcher_logic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_definitions(Launcher_logic PUBLIC LAUNCHER_APPLICATION) target_compile_definitions(Launcher_logic PUBLIC LAUNCHER_APPLICATION)
target_link_libraries(Launcher_logic target_link_libraries(Launcher_logic
@ -1301,8 +1239,9 @@ target_link_libraries(Launcher_logic
tomlplusplus::tomlplusplus tomlplusplus::tomlplusplus
qdcss qdcss
BuildConfig BuildConfig
Katabasis
Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Widgets
qrcode ghcFilesystem::ghc_filesystem
) )
if (UNIX AND NOT CYGWIN AND NOT APPLE) if (UNIX AND NOT CYGWIN AND NOT APPLE)
@ -1318,9 +1257,6 @@ target_link_libraries(Launcher_logic
Qt${QT_VERSION_MAJOR}::Concurrent Qt${QT_VERSION_MAJOR}::Concurrent
Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Gui
Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Widgets
Qt${QT_VERSION_MAJOR}::NetworkAuth
Qt${QT_VERSION_MAJOR}::OpenGL
${Launcher_QT_DBUS}
${Launcher_QT_LIBS} ${Launcher_QT_LIBS}
) )
target_link_libraries(Launcher_logic target_link_libraries(Launcher_logic
@ -1329,20 +1265,16 @@ target_link_libraries(Launcher_logic
LocalPeer LocalPeer
Launcher_rainbow Launcher_rainbow
) )
if (TARGET ${Launcher_QT_DBUS})
add_compile_definitions(WITH_QTDBUS)
endif()
if(APPLE) if(APPLE)
set(CMAKE_MACOSX_RPATH 1) set(CMAKE_MACOSX_RPATH 1)
set(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks/") set(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks/")
if(Launcher_ENABLE_UPDATER) if(Launcher_ENABLE_UPDATER)
file(DOWNLOAD ${MACOSX_SPARKLE_DOWNLOAD_URL} ${CMAKE_BINARY_DIR}/Sparkle.tar.xz EXPECTED_HASH SHA256=${MACOSX_SPARKLE_SHA256}) file(DOWNLOAD ${MACOSX_SPARKLE_DOWNLOAD_URL} ${CMAKE_BINARY_DIR}/Sparkle.tar.xz EXPECTED_HASH SHA256=${MACOSX_SPARKLE_SHA256})
file(ARCHIVE_EXTRACT INPUT ${CMAKE_BINARY_DIR}/Sparkle.tar.xz DESTINATION ${CMAKE_BINARY_DIR}/frameworks/Sparkle) file(ARCHIVE_EXTRACT INPUT ${CMAKE_BINARY_DIR}/Sparkle.tar.xz DESTINATION ${CMAKE_BINARY_DIR}/frameworks/Sparkle)
find_library(SPARKLE_FRAMEWORK Sparkle "${CMAKE_BINARY_DIR}/frameworks/Sparkle") find_library(SPARKLE_FRAMEWORK Sparkle "${CMAKE_BINARY_DIR}/frameworks/Sparkle")
add_compile_definitions(SPARKLE_ENABLED) add_compile_definitions(SPARKLE_ENABLED)
endif() endif()
target_link_libraries(Launcher_logic target_link_libraries(Launcher_logic
@ -1352,7 +1284,7 @@ if(APPLE)
"-framework ApplicationServices" "-framework ApplicationServices"
) )
if(Launcher_ENABLE_UPDATER) if(Launcher_ENABLE_UPDATER)
target_link_libraries(Launcher_logic ${SPARKLE_FRAMEWORK}) target_link_libraries(Launcher_logic ${SPARKLE_FRAMEWORK})
endif() endif()
endif() endif()
@ -1389,11 +1321,13 @@ if(Launcher_BUILD_UPDATER)
${ZLIB_LIBRARIES} ${ZLIB_LIBRARIES}
systeminfo systeminfo
BuildConfig BuildConfig
ghcFilesystem::ghc_filesystem
Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Widgets
Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Network
${Launcher_QT_LIBS} ${Launcher_QT_LIBS}
cmark::cmark cmark::cmark
Katabasis
) )
add_executable("${Launcher_Name}_updater" WIN32 updater/prismupdater/updater_main.cpp) add_executable("${Launcher_Name}_updater" WIN32 updater/prismupdater/updater_main.cpp)
@ -1427,6 +1361,7 @@ if(WIN32 OR (DEFINED Launcher_BUILD_FILELINKER AND Launcher_BUILD_FILELINKER))
target_link_libraries(filelink_logic target_link_libraries(filelink_logic
systeminfo systeminfo
BuildConfig BuildConfig
ghcFilesystem::ghc_filesystem
Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Widgets
Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Network
@ -1557,6 +1492,7 @@ if(INSTALL_BUNDLE STREQUAL "full")
CONFIGURATIONS Debug RelWithDebInfo "" CONFIGURATIONS Debug RelWithDebInfo ""
DESTINATION ${PLUGIN_DEST_DIR} DESTINATION ${PLUGIN_DEST_DIR}
COMPONENT Runtime COMPONENT Runtime
PATTERN "*qopensslbackend*" EXCLUDE
PATTERN "*qcertonlybackend*" EXCLUDE PATTERN "*qcertonlybackend*" EXCLUDE
) )
install( install(
@ -1567,78 +1503,10 @@ if(INSTALL_BUNDLE STREQUAL "full")
REGEX "dd\\." EXCLUDE REGEX "dd\\." EXCLUDE
REGEX "_debug\\." EXCLUDE REGEX "_debug\\." EXCLUDE
REGEX "\\.dSYM" EXCLUDE REGEX "\\.dSYM" EXCLUDE
PATTERN "*qopensslbackend*" EXCLUDE
PATTERN "*qcertonlybackend*" EXCLUDE PATTERN "*qcertonlybackend*" EXCLUDE
) )
endif() endif()
# Wayland support
if(EXISTS "${QT_PLUGINS_DIR}/wayland-graphics-integration-client")
install(
DIRECTORY "${QT_PLUGINS_DIR}/wayland-graphics-integration-client"
CONFIGURATIONS Debug RelWithDebInfo ""
DESTINATION ${PLUGIN_DEST_DIR}
COMPONENT Runtime
)
install(
DIRECTORY "${QT_PLUGINS_DIR}/wayland-graphics-integration-client"
CONFIGURATIONS Release MinSizeRel
DESTINATION ${PLUGIN_DEST_DIR}
COMPONENT Runtime
REGEX "dd\\." EXCLUDE
REGEX "_debug\\." EXCLUDE
REGEX "\\.dSYM" EXCLUDE
)
endif()
if(EXISTS "${QT_PLUGINS_DIR}/wayland-graphics-integration-server")
install(
DIRECTORY "${QT_PLUGINS_DIR}/wayland-graphics-integration-server"
CONFIGURATIONS Debug RelWithDebInfo ""
DESTINATION ${PLUGIN_DEST_DIR}
COMPONENT Runtime
)
install(
DIRECTORY "${QT_PLUGINS_DIR}/wayland-graphics-integration-server"
CONFIGURATIONS Release MinSizeRel
DESTINATION ${PLUGIN_DEST_DIR}
COMPONENT Runtime
REGEX "dd\\." EXCLUDE
REGEX "_debug\\." EXCLUDE
REGEX "\\.dSYM" EXCLUDE
)
endif()
if(EXISTS "${QT_PLUGINS_DIR}/wayland-decoration-client")
install(
DIRECTORY "${QT_PLUGINS_DIR}/wayland-decoration-client"
CONFIGURATIONS Debug RelWithDebInfo ""
DESTINATION ${PLUGIN_DEST_DIR}
COMPONENT Runtime
)
install(
DIRECTORY "${QT_PLUGINS_DIR}/wayland-decoration-client"
CONFIGURATIONS Release MinSizeRel
DESTINATION ${PLUGIN_DEST_DIR}
COMPONENT Runtime
REGEX "dd\\." EXCLUDE
REGEX "_debug\\." EXCLUDE
REGEX "\\.dSYM" EXCLUDE
)
endif()
if(EXISTS "${QT_PLUGINS_DIR}/wayland-shell-integration")
install(
DIRECTORY "${QT_PLUGINS_DIR}/wayland-shell-integration"
CONFIGURATIONS Debug RelWithDebInfo ""
DESTINATION ${PLUGIN_DEST_DIR}
COMPONENT Runtime
)
install(
DIRECTORY "${QT_PLUGINS_DIR}/wayland-shell-integration"
CONFIGURATIONS Release MinSizeRel
DESTINATION ${PLUGIN_DEST_DIR}
COMPONENT Runtime
REGEX "dd\\." EXCLUDE
REGEX "_debug\\." EXCLUDE
REGEX "\\.dSYM" EXCLUDE
)
endif()
configure_file( configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/install_prereqs.cmake.in" "${CMAKE_CURRENT_SOURCE_DIR}/install_prereqs.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/install_prereqs.cmake" "${CMAKE_CURRENT_BINARY_DIR}/install_prereqs.cmake"

View File

@ -12,10 +12,13 @@
#include <QtConcurrent> #include <QtConcurrent>
DataMigrationTask::DataMigrationTask(const QString& sourcePath, const QString& targetPath, const IPathMatcher::Ptr pathMatcher) DataMigrationTask::DataMigrationTask(QObject* parent,
: Task(), m_sourcePath(sourcePath), m_targetPath(targetPath), m_pathMatcher(pathMatcher), m_copy(sourcePath, targetPath) const QString& sourcePath,
const QString& targetPath,
const IPathMatcher::Ptr pathMatcher)
: Task(parent), m_sourcePath(sourcePath), m_targetPath(targetPath), m_pathMatcher(pathMatcher), m_copy(sourcePath, targetPath)
{ {
m_copy.matcher(m_pathMatcher).whitelist(true); m_copy.matcher(m_pathMatcher.get()).whitelist(true);
} }
void DataMigrationTask::executeTask() void DataMigrationTask::executeTask()
@ -24,7 +27,7 @@ void DataMigrationTask::executeTask()
// 1. Scan // 1. Scan
// Check how many files we gotta copy // 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 return m_copy(true); // dry run to collect amount of files
}); });
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::dryRunFinished); connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::dryRunFinished);
@ -37,7 +40,11 @@ void DataMigrationTask::dryRunFinished()
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::dryRunFinished); disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::dryRunFinished);
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &DataMigrationTask::dryRunAborted); 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()) { if (!m_copyFuture.isValid() || !m_copyFuture.result()) {
#else
if (!m_copyFuture.result()) {
#endif
emitFailed(tr("Failed to scan source path.")); emitFailed(tr("Failed to scan source path."));
return; return;
} }
@ -53,7 +60,7 @@ void DataMigrationTask::dryRunFinished()
setProgress(m_copy.totalCopied(), m_toCopy); setProgress(m_copy.totalCopied(), m_toCopy);
setStatus(tr("Copying %1…").arg(shortenedName)); 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 return m_copy(false); // actually copy now
}); });
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::copyFinished); connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::copyFinished);
@ -71,7 +78,11 @@ void DataMigrationTask::copyFinished()
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::copyFinished); disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &DataMigrationTask::copyFinished);
disconnect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &DataMigrationTask::copyAborted); 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()) { if (!m_copyFuture.isValid() || !m_copyFuture.result()) {
#else
if (!m_copyFuture.result()) {
#endif
emitFailed(tr("Some paths could not be copied!")); emitFailed(tr("Some paths could not be copied!"));
return; return;
} }

View File

@ -18,7 +18,7 @@
class DataMigrationTask : public Task { class DataMigrationTask : public Task {
Q_OBJECT Q_OBJECT
public: public:
explicit DataMigrationTask(const QString& sourcePath, const QString& targetPath, IPathMatcher::Ptr pathmatcher); explicit DataMigrationTask(QObject* parent, const QString& sourcePath, const QString& targetPath, IPathMatcher::Ptr pathmatcher);
~DataMigrationTask() override = default; ~DataMigrationTask() override = default;
protected: protected:

View File

@ -40,11 +40,12 @@
#include <QFileSystemModel> #include <QFileSystemModel>
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>
#include <QStack> #include <QStack>
#include <algorithm>
#include "FileSystem.h" #include "FileSystem.h"
#include "SeparatorPrefixTree.h" #include "SeparatorPrefixTree.h"
#include "StringUtils.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. // NOTE: Sadly, we have to do sorting ourselves.
bool FileIgnoreProxy::lessThan(const QModelIndex& left, const QModelIndex& right) const 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) { if (index.column() == 0 && role == Qt::CheckStateRole) {
QFileSystemModel* fsm = qobject_cast<QFileSystemModel*>(sourceModel()); QFileSystemModel* fsm = qobject_cast<QFileSystemModel*>(sourceModel());
auto blockedPath = relPath(fsm->filePath(sourceIndex)); auto blockedPath = relPath(fsm->filePath(sourceIndex));
auto cover = m_blocked.cover(blockedPath); auto cover = blocked.cover(blockedPath);
if (!cover.isNull()) { if (!cover.isNull()) {
return QVariant(Qt::Unchecked); return QVariant(Qt::Unchecked);
} else if (m_blocked.exists(blockedPath)) { } else if (blocked.exists(blockedPath)) {
return QVariant(Qt::PartiallyChecked); return QVariant(Qt::PartiallyChecked);
} else { } else {
return QVariant(Qt::Checked); 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 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) bool FileIgnoreProxy::setFilterState(QModelIndex index, Qt::CheckState state)
@ -145,18 +146,18 @@ bool FileIgnoreProxy::setFilterState(QModelIndex index, Qt::CheckState state)
bool changed = false; bool changed = false;
if (state == Qt::Unchecked) { if (state == Qt::Unchecked) {
// blocking a path // blocking a path
auto& node = m_blocked.insert(blockedPath); auto& node = blocked.insert(blockedPath);
// get rid of all blocked nodes below // get rid of all blocked nodes below
node.clear(); node.clear();
changed = true; changed = true;
} else if (state == Qt::Checked || state == Qt::PartiallyChecked) { } else if (state == Qt::Checked || state == Qt::PartiallyChecked) {
if (!m_blocked.remove(blockedPath)) { if (!blocked.remove(blockedPath)) {
auto cover = m_blocked.cover(blockedPath); auto cover = blocked.cover(blockedPath);
qDebug() << "Blocked by cover" << cover; qDebug() << "Blocked by cover" << cover;
// uncover // uncover
m_blocked.remove(cover); blocked.remove(cover);
// block all contents, except for any 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; QModelIndex doing = rootIndex;
int row = 0; int row = 0;
QStack<QModelIndex> todo; QStack<QModelIndex> todo;
@ -178,7 +179,7 @@ bool FileIgnoreProxy::setFilterState(QModelIndex index, Qt::CheckState state)
todo.push(node); todo.push(node);
} else { } else {
// or just block this one. // or just block this one.
m_blocked.insert(relpath); blocked.insert(relpath);
} }
row++; row++;
} }
@ -228,7 +229,7 @@ bool FileIgnoreProxy::shouldExpand(QModelIndex index)
return false; return false;
} }
auto blockedPath = relPath(fsm->filePath(sourceIndex)); auto blockedPath = relPath(fsm->filePath(sourceIndex));
auto found = m_blocked.find(blockedPath); auto found = blocked.find(blockedPath);
if (found) { if (found) {
return !found->leaf(); return !found->leaf();
} }
@ -238,8 +239,8 @@ bool FileIgnoreProxy::shouldExpand(QModelIndex index)
void FileIgnoreProxy::setBlockedPaths(QStringList paths) void FileIgnoreProxy::setBlockedPaths(QStringList paths)
{ {
beginResetModel(); beginResetModel();
m_blocked.clear(); blocked.clear();
m_blocked.insert(paths); blocked.insert(paths);
endResetModel(); endResetModel();
} }
@ -269,28 +270,7 @@ bool FileIgnoreProxy::ignoreFile(QFileInfo fileInfo) const
return m_ignoreFiles.contains(fileInfo.fileName()) || m_ignoreFilePaths.covers(relPath(fileInfo.absoluteFilePath())); 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); return blocked.covers(fileName) || ignoreFile(QFileInfo(QDir(root), fileName));
}
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();
}
} }

View File

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

View File

@ -45,6 +45,7 @@
#include <QDirIterator> #include <QDirIterator>
#include <QFile> #include <QFile>
#include <QFileInfo> #include <QFileInfo>
#include <QSaveFile>
#include <QStandardPaths> #include <QStandardPaths>
#include <QStorageInfo> #include <QStorageInfo>
#include <QTextStream> #include <QTextStream>
@ -53,7 +54,6 @@
#include <system_error> #include <system_error>
#include "DesktopServices.h" #include "DesktopServices.h"
#include "PSaveFile.h"
#include "StringUtils.h" #include "StringUtils.h"
#if defined Q_OS_WIN32 #if defined Q_OS_WIN32
@ -77,8 +77,24 @@
#include <utime.h> #include <utime.h>
#endif #endif
// Snippet from https://github.com/gulrak/filesystem#using-it-as-single-file-header
#ifdef __APPLE__
#include <Availability.h> // for deployment target to support pre-catalina targets without std::fs
#endif // __APPLE__
#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || (defined(__cplusplus) && __cplusplus >= 201703L)) && defined(__has_include)
#if __has_include(<filesystem>) && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
#define GHC_USE_STD_FS
#include <filesystem> #include <filesystem>
namespace fs = std::filesystem; 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 // clone
#if defined(Q_OS_LINUX) #if defined(Q_OS_LINUX)
@ -107,10 +123,6 @@ namespace fs = std::filesystem;
#if defined(__MINGW32__) #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 { struct _DUPLICATE_EXTENTS_DATA {
HANDLE FileHandle; HANDLE FileHandle;
LARGE_INTEGER SourceFileOffset; LARGE_INTEGER SourceFileOffset;
@ -120,7 +132,6 @@ struct _DUPLICATE_EXTENTS_DATA {
using DUPLICATE_EXTENTS_DATA = _DUPLICATE_EXTENTS_DATA; using DUPLICATE_EXTENTS_DATA = _DUPLICATE_EXTENTS_DATA;
using PDUPLICATE_EXTENTS_DATA = _DUPLICATE_EXTENTS_DATA*; using PDUPLICATE_EXTENTS_DATA = _DUPLICATE_EXTENTS_DATA*;
#endif
struct _FSCTL_GET_INTEGRITY_INFORMATION_BUFFER { struct _FSCTL_GET_INTEGRITY_INFORMATION_BUFFER {
WORD ChecksumAlgorithm; // Checksum algorithm. e.g. CHECKSUM_TYPE_UNCHANGED, CHECKSUM_TYPE_NONE, CHECKSUM_TYPE_CRC32 WORD ChecksumAlgorithm; // Checksum algorithm. e.g. CHECKSUM_TYPE_UNCHANGED, CHECKSUM_TYPE_NONE, CHECKSUM_TYPE_CRC32
@ -180,8 +191,8 @@ void ensureExists(const QDir& dir)
void write(const QString& filename, const QByteArray& data) void write(const QString& filename, const QByteArray& data)
{ {
ensureExists(QFileInfo(filename).dir()); ensureExists(QFileInfo(filename).dir());
PSaveFile file(filename); QSaveFile file(filename);
if (!file.open(PSaveFile::WriteOnly)) { if (!file.open(QSaveFile::WriteOnly)) {
throw FileSystemException("Couldn't open " + filename + " for writing: " + file.errorString()); throw FileSystemException("Couldn't open " + filename + " for writing: " + file.errorString());
} }
if (data.size() != file.write(data)) { if (data.size() != file.write(data)) {
@ -202,8 +213,8 @@ void appendSafe(const QString& filename, const QByteArray& data)
buffer = QByteArray(); buffer = QByteArray();
} }
buffer.append(data); buffer.append(data);
PSaveFile file(filename); QSaveFile file(filename);
if (!file.open(PSaveFile::WriteOnly)) { if (!file.open(QSaveFile::WriteOnly)) {
throw FileSystemException("Couldn't open " + filename + " for writing: " + file.errorString()); throw FileSystemException("Couldn't open " + filename + " for writing: " + file.errorString());
} }
if (buffer.size() != file.write(buffer)) { if (buffer.size() != file.write(buffer)) {
@ -265,9 +276,6 @@ bool ensureFolderPathExists(const QFileInfo folderPath)
{ {
QDir dir; QDir dir;
QString ensuredPath = folderPath.filePath(); QString ensuredPath = folderPath.filePath();
if (folderPath.exists())
return true;
bool success = dir.mkpath(ensuredPath); bool success = dir.mkpath(ensuredPath);
return success; return success;
} }
@ -330,7 +338,7 @@ bool copy::operator()(const QString& offset, bool dryRun)
opt |= copy_opts::overwrite_existing; opt |= copy_opts::overwrite_existing;
// Function that'll do the actual copying // Function that'll do the actual copying
auto copy_file = [this, dryRun, src, dst, opt, &err](QString src_path, QString relative_dst_path) { auto copy_file = [&](QString src_path, QString relative_dst_path) {
if (m_matcher && (m_matcher->matches(relative_dst_path) != m_whitelist)) if (m_matcher && (m_matcher->matches(relative_dst_path) != m_whitelist))
return; return;
@ -417,7 +425,7 @@ void create_link::make_link_list(const QString& offset)
m_recursive = true; m_recursive = true;
// Function that'll do the actual linking // Function that'll do the actual linking
auto link_file = [this, dst](QString src_path, QString relative_dst_path) { auto link_file = [&](QString src_path, QString relative_dst_path) {
if (m_matcher && (m_matcher->matches(relative_dst_path) != m_whitelist)) { if (m_matcher && (m_matcher->matches(relative_dst_path) != m_whitelist)) {
qDebug() << "path" << relative_dst_path << "in black list or not in whitelist"; qDebug() << "path" << relative_dst_path << "in black list or not in whitelist";
return; return;
@ -512,7 +520,7 @@ void create_link::runPrivileged(const QString& offset)
QString serverName = BuildConfig.LAUNCHER_APP_BINARY_NAME + "_filelink_server" + StringUtils::getRandomAlphaNumeric(); 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"; qDebug() << "Client connected, sending out pairs";
// construct block of data to send // construct block of data to send
QByteArray block; QByteArray block;
@ -594,7 +602,7 @@ void create_link::runPrivileged(const QString& offset)
} }
ExternalLinkFileProcess* linkFileProcess = new ExternalLinkFileProcess(serverName, m_useHardLinks, this); 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); connect(linkFileProcess, &ExternalLinkFileProcess::finished, linkFileProcess, &QObject::deleteLater);
linkFileProcess->start(); linkFileProcess->start();
@ -639,19 +647,6 @@ void ExternalLinkFileProcess::runLinkFile()
qDebug() << "Process exited"; qDebug() << "Process exited";
} }
bool moveByCopy(const QString& source, const QString& dest)
{
if (!copy(source, dest)()) { // copy
qDebug() << "Copy of" << source << "to" << dest << "failed!";
return false;
}
if (!deletePath(source)) { // remove original
qDebug() << "Deletion of" << source << "failed!";
return false;
};
return true;
}
bool move(const QString& source, const QString& dest) bool move(const QString& source, const QString& dest)
{ {
std::error_code err; std::error_code err;
@ -659,14 +654,13 @@ bool move(const QString& source, const QString& dest)
ensureFilePathExists(dest); ensureFilePathExists(dest);
fs::rename(StringUtils::toStdString(source), StringUtils::toStdString(dest), err); fs::rename(StringUtils::toStdString(source), StringUtils::toStdString(dest), err);
if (err.value() != 0) { if (err) {
if (moveByCopy(source, dest)) qWarning() << "Failed to move file:" << QString::fromStdString(err.message());
return true; qDebug() << "Source file:" << source;
qDebug() << "Move of" << source << "to" << dest << "failed!"; qDebug() << "Destination file:" << dest;
qWarning() << "Failed to move file:" << QString::fromStdString(err.message()) << QString::number(err.value());
return false;
} }
return true;
return err.value() == 0;
} }
bool deletePath(QString path) bool deletePath(QString path)
@ -684,6 +678,9 @@ bool deletePath(QString path)
bool trash(QString path, QString* pathInTrash) 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 // FIXME: Figure out trash in Flatpak. Qt seemingly doesn't use the Trash portal
if (DesktopServices::isFlatpak()) if (DesktopServices::isFlatpak())
return false; return false;
@ -692,6 +689,7 @@ bool trash(QString path, QString* pathInTrash)
return false; return false;
#endif #endif
return QFile::moveToTrash(path, pathInTrash); return QFile::moveToTrash(path, pathInTrash);
#endif
} }
QString PathCombine(const QString& path1, const QString& path2) QString PathCombine(const QString& path1, const QString& path2)
@ -725,7 +723,11 @@ int pathDepth(const QString& path)
QFileInfo info(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); auto parts = QDir::toNativeSeparators(info.path()).split(QDir::separator(), Qt::SkipEmptyParts);
#endif
int numParts = parts.length(); int numParts = parts.length();
numParts -= parts.count("."); numParts -= parts.count(".");
@ -745,7 +747,11 @@ QString pathTruncate(const QString& path, int depth)
return pathTruncate(trunc, 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); auto parts = QDir::toNativeSeparators(trunc).split(QDir::separator(), Qt::SkipEmptyParts);
#endif
if (parts.startsWith(".") && !path.startsWith(".")) { if (parts.startsWith(".") && !path.startsWith(".")) {
parts.removeFirst(); parts.removeFirst();
@ -795,68 +801,25 @@ QString NormalizePath(QString path)
} }
} }
static const QString BAD_WIN_CHARS = "<>:\"|?*\r\n"; static const QString BAD_PATH_CHARS = "\"?<>:;*|!+\r\n";
static const QString BAD_NTFS_CHARS = "<>:\"|?*"; static const QString BAD_FILENAME_CHARS = BAD_PATH_CHARS + "\\/";
static const QString BAD_HFS_CHARS = ":";
static const QString BAD_FILENAME_CHARS = BAD_WIN_CHARS + "\\/";
QString RemoveInvalidFilenameChars(QString string, QChar replaceWith) QString RemoveInvalidFilenameChars(QString string, QChar replaceWith)
{ {
for (int i = 0; i < string.length(); i++) for (int i = 0; i < string.length(); i++)
if (string.at(i) < ' ' || BAD_FILENAME_CHARS.contains(string.at(i))) if (string.at(i) < ' ' || BAD_FILENAME_CHARS.contains(string.at(i)))
string[i] = replaceWith; string[i] = replaceWith;
return string; return string;
} }
QString RemoveInvalidPathChars(QString path, QChar replaceWith) QString RemoveInvalidPathChars(QString string, QChar replaceWith)
{ {
QString invalidChars; for (int i = 0; i < string.length(); i++)
#ifdef Q_OS_WIN if (string.at(i) < ' ' || BAD_PATH_CHARS.contains(string.at(i)))
invalidChars = BAD_WIN_CHARS; string[i] = replaceWith;
#endif
// the null character is ignored in this check as it was not a problem until now return string;
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) QString DirNameFromString(QString string, QString inDir)
@ -898,10 +861,6 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
if (destination.isEmpty()) { if (destination.isEmpty()) {
destination = PathCombine(getDesktopDir(), RemoveInvalidFilenameChars(name)); destination = PathCombine(getDesktopDir(), RemoveInvalidFilenameChars(name));
} }
if (!ensureFilePathExists(destination)) {
qWarning() << "Destination path can't be created!";
return false;
}
#if defined(Q_OS_MACOS) #if defined(Q_OS_MACOS)
// Create the Application // Create the Application
QDir applicationDirectory = QDir applicationDirectory =
@ -927,7 +886,7 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
QDir content = application.path() + "/Contents/"; QDir content = application.path() + "/Contents/";
QDir resources = content.path() + "/Resources/"; QDir resources = content.path() + "/Resources/";
QDir binaryDir = content.path() + "/MacOS/"; QDir binaryDir = content.path() + "/MacOS/";
QFile info(content.path() + "/Info.plist"); QFile info = content.path() + "/Info.plist";
if (!(content.mkpath(".") && resources.mkpath(".") && binaryDir.mkpath("."))) { if (!(content.mkpath(".") && resources.mkpath(".") && binaryDir.mkpath("."))) {
qWarning() << "Couldn't create directories within application"; qWarning() << "Couldn't create directories within application";
@ -948,7 +907,8 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
if (!args.empty()) if (!args.empty())
argstring = " \"" + args.join("\" \"") + "\""; argstring = " \"" + args.join("\" \"") + "\"";
stream << "#!/bin/bash" << "\n"; stream << "#!/bin/bash"
<< "\n";
stream << "\"" << target << "\" " << argstring << "\n"; stream << "\"" << target << "\" " << argstring << "\n";
stream.flush(); stream.flush();
@ -992,9 +952,12 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
if (!args.empty()) if (!args.empty())
argstring = " '" + args.join("' '") + "'"; argstring = " '" + args.join("' '") + "'";
stream << "[Desktop Entry]" << "\n"; stream << "[Desktop Entry]"
stream << "Type=Application" << "\n"; << "\n";
stream << "Categories=Game;ActionGame;AdventureGame;Simulation" << "\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"; stream << "Name=" << name.toLocal8Bit() << "\n";
if (!icon.isEmpty()) { if (!icon.isEmpty()) {
@ -1272,7 +1235,7 @@ bool clone::operator()(const QString& offset, bool dryRun)
std::error_code err; std::error_code err;
// Function that'll do the actual cloneing // Function that'll do the actual cloneing
auto cloneFile = [this, dryRun, dst, &err](QString src_path, QString relative_dst_path) { auto cloneFile = [&](QString src_path, QString relative_dst_path) {
if (m_matcher && (m_matcher->matches(relative_dst_path) != m_whitelist)) if (m_matcher && (m_matcher->matches(relative_dst_path) != m_whitelist))
return; return;
@ -1671,30 +1634,4 @@ QString getPathNameInLocal8bit(const QString& file)
} }
#endif #endif
QString getUniqueResourceName(const QString& filePath)
{
auto newFileName = filePath;
if (!newFileName.endsWith(".disabled")) {
return newFileName; // prioritize enabled mods
}
newFileName.chop(9);
if (!QFile::exists(newFileName)) {
return filePath;
}
QFileInfo fileInfo(filePath);
auto baseName = fileInfo.completeBaseName();
auto path = fileInfo.absolutePath();
int counter = 1;
do {
if (counter == 1) {
newFileName = FS::PathCombine(path, baseName + ".duplicate");
} else {
newFileName = FS::PathCombine(path, baseName + ".duplicate" + QString::number(counter));
}
counter++;
} while (QFile::exists(newFileName));
return newFileName;
}
} // namespace FS } // namespace FS

View File

@ -72,7 +72,7 @@ void appendSafe(const QString& filename, const QByteArray& data);
void append(const QString& filename, const QByteArray& data); void append(const QString& filename, const QByteArray& data);
/** /**
* read data from a file safely * read data from a file safely\
*/ */
QByteArray read(const QString& filename); QByteArray read(const QString& filename);
@ -115,7 +115,7 @@ class copy : public QObject {
m_followSymlinks = follow; m_followSymlinks = follow;
return *this; return *this;
} }
copy& matcher(IPathMatcher::Ptr filter) copy& matcher(const IPathMatcher* filter)
{ {
m_matcher = filter; m_matcher = filter;
return *this; return *this;
@ -147,7 +147,7 @@ class copy : public QObject {
private: private:
bool m_followSymlinks = true; bool m_followSymlinks = true;
IPathMatcher::Ptr m_matcher = nullptr; const IPathMatcher* m_matcher = nullptr;
bool m_whitelist = false; bool m_whitelist = false;
bool m_overwrite = false; bool m_overwrite = false;
QDir m_src; QDir m_src;
@ -209,7 +209,7 @@ class create_link : public QObject {
m_useHardLinks = useHard; m_useHardLinks = useHard;
return *this; return *this;
} }
create_link& matcher(IPathMatcher::Ptr filter) create_link& matcher(const IPathMatcher* filter)
{ {
m_matcher = filter; m_matcher = filter;
return *this; return *this;
@ -240,7 +240,6 @@ class create_link : public QObject {
bool operator()(bool dryRun = false) { return operator()(QString(), dryRun); } bool operator()(bool dryRun = false) { return operator()(QString(), dryRun); }
int totalLinked() { return m_linked; } int totalLinked() { return m_linked; }
int totalToLink() { return static_cast<int>(m_links_to_make.size()); }
void runPrivileged() { runPrivileged(QString()); } void runPrivileged() { runPrivileged(QString()); }
void runPrivileged(const QString& offset); void runPrivileged(const QString& offset);
@ -260,7 +259,7 @@ class create_link : public QObject {
private: private:
bool m_useHardLinks = false; bool m_useHardLinks = false;
IPathMatcher::Ptr m_matcher = nullptr; const IPathMatcher* m_matcher = nullptr;
bool m_whitelist = false; bool m_whitelist = false;
bool m_recursive = true; bool m_recursive = true;
@ -379,7 +378,6 @@ enum class FilesystemType {
HFSX, HFSX,
FUSEBLK, FUSEBLK,
F2FS, F2FS,
BCACHEFS,
UNKNOWN UNKNOWN
}; };
@ -408,7 +406,6 @@ static const QMap<FilesystemType, QStringList> s_filesystem_type_names = { { Fil
{ FilesystemType::HFSX, { "HFSX" } }, { FilesystemType::HFSX, { "HFSX" } },
{ FilesystemType::FUSEBLK, { "FUSEBLK" } }, { FilesystemType::FUSEBLK, { "FUSEBLK" } },
{ FilesystemType::F2FS, { "F2FS" } }, { FilesystemType::F2FS, { "F2FS" } },
{ FilesystemType::BCACHEFS, { "BCACHEFS" } },
{ FilesystemType::UNKNOWN, { "UNKNOWN" } } }; { FilesystemType::UNKNOWN, { "UNKNOWN" } } };
/** /**
@ -461,7 +458,7 @@ QString nearestExistentAncestor(const QString& path);
FilesystemInfo statFS(const QString& path); FilesystemInfo statFS(const QString& path);
static const QList<FilesystemType> s_clone_filesystems = { FilesystemType::BTRFS, FilesystemType::APFS, FilesystemType::ZFS, static const QList<FilesystemType> s_clone_filesystems = { FilesystemType::BTRFS, FilesystemType::APFS, FilesystemType::ZFS,
FilesystemType::XFS, FilesystemType::REFS, FilesystemType::BCACHEFS }; FilesystemType::XFS, FilesystemType::REFS };
/** /**
* @brief if the Filesystem is reflink/clone capable * @brief if the Filesystem is reflink/clone capable
@ -488,7 +485,7 @@ class clone : public QObject {
m_src.setPath(src); m_src.setPath(src);
m_dst.setPath(dst); m_dst.setPath(dst);
} }
clone& matcher(IPathMatcher::Ptr filter) clone& matcher(const IPathMatcher* filter)
{ {
m_matcher = filter; m_matcher = filter;
return *this; return *this;
@ -514,7 +511,7 @@ class clone : public QObject {
bool operator()(const QString& offset, bool dryRun = false); bool operator()(const QString& offset, bool dryRun = false);
private: private:
IPathMatcher::Ptr m_matcher = nullptr; const IPathMatcher* m_matcher = nullptr;
bool m_whitelist = false; bool m_whitelist = false;
QDir m_src; QDir m_src;
QDir m_dst; QDir m_dst;
@ -560,6 +557,4 @@ uintmax_t hardLinkCount(const QString& path);
QString getPathNameInLocal8bit(const QString& file); QString getPathNameInLocal8bit(const QString& file);
#endif #endif
QString getUniqueResourceName(const QString& filePath);
} // namespace FS } // namespace FS

View File

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

View File

@ -5,14 +5,14 @@
class Filter { class Filter {
public: public:
virtual ~Filter() = default; virtual ~Filter();
virtual bool accepts(const QString& value) = 0; virtual bool accepts(const QString& value) = 0;
}; };
class ContainsFilter : public Filter { class ContainsFilter : public Filter {
public: public:
ContainsFilter(const QString& pattern); ContainsFilter(const QString& pattern);
virtual ~ContainsFilter() = default; virtual ~ContainsFilter();
bool accepts(const QString& value) override; bool accepts(const QString& value) override;
private: private:
@ -22,7 +22,7 @@ class ContainsFilter : public Filter {
class ExactFilter : public Filter { class ExactFilter : public Filter {
public: public:
ExactFilter(const QString& pattern); ExactFilter(const QString& pattern);
virtual ~ExactFilter() = default; virtual ~ExactFilter();
bool accepts(const QString& value) override; bool accepts(const QString& value) override;
private: private:
@ -32,7 +32,7 @@ class ExactFilter : public Filter {
class ExactIfPresentFilter : public Filter { class ExactIfPresentFilter : public Filter {
public: public:
ExactIfPresentFilter(const QString& pattern); ExactIfPresentFilter(const QString& pattern);
virtual ~ExactIfPresentFilter() override = default; ~ExactIfPresentFilter() override = default;
bool accepts(const QString& value) override; bool accepts(const QString& value) override;
private: private:
@ -42,20 +42,10 @@ class ExactIfPresentFilter : public Filter {
class RegexpFilter : public Filter { class RegexpFilter : public Filter {
public: public:
RegexpFilter(const QString& regexp, bool invert); RegexpFilter(const QString& regexp, bool invert);
virtual ~RegexpFilter() = default; virtual ~RegexpFilter();
bool accepts(const QString& value) override; bool accepts(const QString& value) override;
private: private:
QRegularExpression pattern; QRegularExpression pattern;
bool invert = false; bool invert = false;
}; };
class ExactListFilter : public Filter {
public:
ExactListFilter(const QStringList& pattern = {});
virtual ~ExactListFilter() = default;
bool accepts(const QString& value) override;
private:
QStringList m_pattern;
};

View File

@ -36,8 +36,6 @@
#include "GZip.h" #include "GZip.h"
#include <zlib.h> #include <zlib.h>
#include <QByteArray> #include <QByteArray>
#include <QDebug>
#include <QFile>
bool GZip::unzip(const QByteArray& compressedBytes, QByteArray& uncompressedBytes) bool GZip::unzip(const QByteArray& compressedBytes, QByteArray& uncompressedBytes)
{ {
@ -138,81 +136,3 @@ bool GZip::zip(const QByteArray& uncompressedBytes, QByteArray& compressedBytes)
} }
return true; 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; /* and fall through */
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 #pragma once
#include <QByteArray> #include <QByteArray>
#include <QFile>
namespace GZip { class GZip {
public:
bool unzip(const QByteArray& compressedBytes, QByteArray& uncompressedBytes); static bool unzip(const QByteArray& compressedBytes, QByteArray& uncompressedBytes);
bool zip(const QByteArray& uncompressedBytes, QByteArray& compressedBytes); static bool zip(const QByteArray& uncompressedBytes, QByteArray& compressedBytes);
QString readGzFileByBlocks(QFile* source, std::function<bool(const QByteArray&)> handleBlock); };
} // namespace GZip

View File

@ -1,12 +1,10 @@
#include "InstanceCopyTask.h" #include "InstanceCopyTask.h"
#include <QDebug> #include <QDebug>
#include <QtConcurrentRun> #include <QtConcurrentRun>
#include <memory>
#include "FileSystem.h" #include "FileSystem.h"
#include "NullInstance.h" #include "NullInstance.h"
#include "pathmatcher/RegexpMatcher.h" #include "pathmatcher/RegexpMatcher.h"
#include "settings/INISettingsObject.h" #include "settings/INISettingsObject.h"
#include "tasks/Task.h"
InstanceCopyTask::InstanceCopyTask(InstancePtr origInstance, const InstanceCopyPrefs& prefs) InstanceCopyTask::InstanceCopyTask(InstancePtr origInstance, const InstanceCopyPrefs& prefs)
{ {
@ -40,50 +38,38 @@ void InstanceCopyTask::executeTask()
{ {
setStatus(tr("Copying instance %1").arg(m_origInstance->name())); setStatus(tr("Copying instance %1").arg(m_origInstance->name()));
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [this] { auto copySaves = [&]() {
QFileInfo mcDir(FS::PathCombine(m_stagingPath, "minecraft"));
QFileInfo dotMCDir(FS::PathCombine(m_stagingPath, ".minecraft"));
QString staging_mc_dir;
if (mcDir.exists() && !dotMCDir.exists())
staging_mc_dir = mcDir.filePath();
else
staging_mc_dir = dotMCDir.filePath();
FS::copy savesCopy(FS::PathCombine(m_origInstance->gameRoot(), "saves"), FS::PathCombine(staging_mc_dir, "saves"));
savesCopy.followSymlinks(true);
return savesCopy();
};
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [this, copySaves] {
if (m_useClone) { if (m_useClone) {
FS::clone folderClone(m_origInstance->instanceRoot(), m_stagingPath); FS::clone folderClone(m_origInstance->instanceRoot(), m_stagingPath);
folderClone.matcher(m_matcher); folderClone.matcher(m_matcher.get());
folderClone(true);
setProgress(0, folderClone.totalCloned());
connect(&folderClone, &FS::clone::fileCloned,
[this](QString src, QString dst) { setProgress(m_progress + 1, m_progressTotal); });
return folderClone(); return folderClone();
} } else if (m_useLinks || m_useHardLinks) {
if (m_useLinks || m_useHardLinks) {
std::unique_ptr<FS::copy> savesCopy;
if (m_copySaves) {
QFileInfo mcDir(FS::PathCombine(m_stagingPath, "minecraft"));
QFileInfo dotMCDir(FS::PathCombine(m_stagingPath, ".minecraft"));
QString staging_mc_dir;
if (dotMCDir.exists() && !mcDir.exists())
staging_mc_dir = dotMCDir.filePath();
else
staging_mc_dir = mcDir.filePath();
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); 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 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());
connect(&folderLink, &FS::create_link::fileLinked,
[this](QString src, QString dst) { setProgress(m_progress + 1, m_progressTotal); });
bool there_were_errors = false; bool there_were_errors = false;
if (!folderLink()) { if (!folderLink()) {
#if defined Q_OS_WIN32 #if defined Q_OS_WIN32
if (!m_useHardLinks) { if (!m_useHardLinks) {
setProgress(0, m_progressTotal);
qDebug() << "EXPECTED: Link failure, Windows requires permissions for symlinks"; qDebug() << "EXPECTED: Link failure, Windows requires permissions for symlinks";
qDebug() << "attempting to run with privelage"; qDebug() << "attempting to run with privelage";
@ -91,7 +77,7 @@ void InstanceCopyTask::executeTask()
QEventLoop loop; QEventLoop loop;
bool got_priv_results = false; 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) { if (!gotResults) {
qDebug() << "Privileged run exited without results!"; qDebug() << "Privileged run exited without results!";
} }
@ -108,11 +94,13 @@ void InstanceCopyTask::executeTask()
} }
} }
if (savesCopy) { if (m_copySaves) {
there_were_errors |= !(*savesCopy)(); there_were_errors |= !copySaves();
} }
return got_priv_results && !there_were_errors; return got_priv_results && !there_were_errors;
} else {
qDebug() << "Link Failed!" << folderLink.getOSError().value() << folderLink.getOSError().message().c_str();
} }
#else #else
qDebug() << "Link Failed!" << folderLink.getOSError().value() << folderLink.getOSError().message().c_str(); qDebug() << "Link Failed!" << folderLink.getOSError().value() << folderLink.getOSError().message().c_str();
@ -120,19 +108,17 @@ void InstanceCopyTask::executeTask()
return false; return false;
} }
if (savesCopy) { if (m_copySaves) {
there_were_errors |= !(*savesCopy)(); there_were_errors |= !copySaves();
} }
return !there_were_errors; return !there_were_errors;
} } else {
FS::copy folderCopy(m_origInstance->instanceRoot(), m_stagingPath); FS::copy folderCopy(m_origInstance->instanceRoot(), m_stagingPath);
folderCopy.followSymlinks(false).matcher(m_matcher); folderCopy.followSymlinks(false).matcher(m_matcher.get());
folderCopy(true); return folderCopy();
setProgress(0, folderCopy.totalCopied()); }
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); connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &InstanceCopyTask::copyFinished);
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &InstanceCopyTask::copyAborted); connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &InstanceCopyTask::copyAborted);
@ -173,11 +159,7 @@ void InstanceCopyTask::copyFinished()
allowed_symlinks_file allowed_symlinks_file
.filePath()); // we dont want to modify the original. also make sure the resulting file is not itself a link. .filePath()); // we dont want to modify the original. also make sure the resulting file is not itself a link.
try { FS::write(allowed_symlinks_file.filePath(), allowed_symlinks);
FS::write(allowed_symlinks_file.filePath(), allowed_symlinks);
} catch (const FS::FileSystemException& e) {
qCritical() << "Failed to write symlink :" << e.cause();
}
} }
emitSucceeded(); emitSucceeded();
@ -188,14 +170,3 @@ void InstanceCopyTask::copyAborted()
emitFailed(tr("Instance folder copy has been aborted.")); emitFailed(tr("Instance folder copy has been aborted."));
return; return;
} }
bool InstanceCopyTask::abort()
{
if (m_copyFutureWatcher.isRunning()) {
m_copyFutureWatcher.cancel();
// NOTE: Here we don't do `emitAborted()` because it will be done when `m_copyFutureWatcher` actually cancels, which may not occur
// immediately.
return true;
}
return false;
}

View File

@ -19,7 +19,6 @@ class InstanceCopyTask : public InstanceTask {
protected: protected:
//! Entry point for tasks. //! Entry point for tasks.
virtual void executeTask() override; virtual void executeTask() override;
bool abort() override;
void copyFinished(); void copyFinished();
void copyAborted(); void copyAborted();
@ -28,7 +27,7 @@ class InstanceCopyTask : public InstanceTask {
InstancePtr m_origInstance; InstancePtr m_origInstance;
QFuture<bool> m_copyFuture; QFuture<bool> m_copyFuture;
QFutureWatcher<bool> m_copyFutureWatcher; QFutureWatcher<bool> m_copyFutureWatcher;
IPathMatcher::Ptr m_matcher; std::unique_ptr<IPathMatcher> m_matcher;
bool m_keepPlaytime; bool m_keepPlaytime;
bool m_useLinks = false; bool m_useLinks = false;
bool m_useHardLinks = false; bool m_useHardLinks = false;

View File

@ -2,7 +2,8 @@
#include <QDebug> #include <QDebug>
#include <QFile> #include <QFile>
#include "FileSystem.h"
InstanceCreationTask::InstanceCreationTask() = default;
void InstanceCreationTask::executeTask() void InstanceCreationTask::executeTask()
{ {
@ -38,29 +39,22 @@ void InstanceCreationTask::executeTask()
// files scheduled to, and we'd better not let the user abort in the middle of it, since it'd // files scheduled to, and we'd better not let the user abort in the middle of it, since it'd
// put the instance in an invalid state. // put the instance in an invalid state.
if (shouldOverride()) { if (shouldOverride()) {
bool deleteFailed = false;
setAbortable(false); setAbortable(false);
setStatus(tr("Removing old conflicting files...")); setStatus(tr("Removing old conflicting files..."));
qDebug() << "Removing old files"; qDebug() << "Removing old files";
for (const QString& path : m_files_to_remove) { for (auto path : m_files_to_remove) {
if (!QFile::exists(path)) if (!QFile::exists(path))
continue; continue;
qDebug() << "Removing" << path; qDebug() << "Removing" << path;
if (!QFile::remove(path)) { if (!QFile::remove(path)) {
qCritical() << "Could not remove" << path; qCritical() << "Couldn't remove the old conflicting files.";
deleteFailed = true; emitFailed(tr("Failed to remove old conflicting files."));
return;
} }
} }
if (deleteFailed) {
emitFailed(tr("Failed to remove old conflicting files."));
return;
}
} }
if (!m_abort)
emitSucceeded(); emitSucceeded();
return;
} }

View File

@ -6,7 +6,7 @@
class InstanceCreationTask : public InstanceTask { class InstanceCreationTask : public InstanceTask {
Q_OBJECT Q_OBJECT
public: public:
InstanceCreationTask() = default; InstanceCreationTask();
virtual ~InstanceCreationTask() = default; virtual ~InstanceCreationTask() = default;
protected: protected:

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(InstancePtr 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(InstancePtr 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

@ -56,7 +56,6 @@
#include <QtConcurrentRun> #include <QtConcurrentRun>
#include <algorithm> #include <algorithm>
#include <memory>
#include <quazip/quazipdir.h> #include <quazip/quazipdir.h>
@ -69,10 +68,16 @@ bool InstanceImportTask::abort()
if (!canAbort()) if (!canAbort())
return false; return false;
bool wasAborted = false; if (m_filesNetJob)
if (m_task) m_filesNetJob->abort();
wasAborted = m_task->abort(); if (m_extractFuture.isRunning()) {
return wasAborted; // NOTE: The tasks created by QtConcurrent::run() can't actually get cancelled,
// but we can use this call to check the state when the extraction finishes.
m_extractFuture.cancel();
m_extractFuture.waitForFinished();
}
return Task::abort();
} }
void InstanceImportTask::executeTask() void InstanceImportTask::executeTask()
@ -84,6 +89,7 @@ void InstanceImportTask::executeTask()
processZipPack(); processZipPack();
} else { } else {
setStatus(tr("Downloading modpack:\n%1").arg(m_sourceUrl.toString())); setStatus(tr("Downloading modpack:\n%1").arg(m_sourceUrl.toString()));
m_downloadRequired = true;
downloadFromUrl(); downloadFromUrl();
} }
@ -91,133 +97,115 @@ void InstanceImportTask::executeTask()
void InstanceImportTask::downloadFromUrl() void InstanceImportTask::downloadFromUrl()
{ {
const QString path(m_sourceUrl.host() + '/' + m_sourceUrl.path()); const QString path = m_sourceUrl.host() + '/' + m_sourceUrl.path();
auto entry = APPLICATION->metacache()->resolveEntry("general", path); auto entry = APPLICATION->metacache()->resolveEntry("general", path);
entry->setStale(true); entry->setStale(true);
m_filesNetJob.reset(new NetJob(tr("Modpack download"), APPLICATION->network()));
m_filesNetJob->addNetAction(Net::ApiDownload::makeCached(m_sourceUrl, entry));
m_archivePath = entry->getFullPath(); m_archivePath = entry->getFullPath();
auto filesNetJob = makeShared<NetJob>(tr("Modpack download"), APPLICATION->network()); connect(m_filesNetJob.get(), &NetJob::succeeded, this, &InstanceImportTask::downloadSucceeded);
filesNetJob->addNetAction(Net::ApiDownload::makeCached(m_sourceUrl, entry)); connect(m_filesNetJob.get(), &NetJob::progress, this, &InstanceImportTask::downloadProgressChanged);
connect(m_filesNetJob.get(), &NetJob::stepProgress, this, &InstanceImportTask::propagateStepProgress);
connect(filesNetJob.get(), &NetJob::succeeded, this, &InstanceImportTask::processZipPack); connect(m_filesNetJob.get(), &NetJob::failed, this, &InstanceImportTask::downloadFailed);
connect(filesNetJob.get(), &NetJob::progress, this, &InstanceImportTask::setProgress); connect(m_filesNetJob.get(), &NetJob::aborted, this, &InstanceImportTask::downloadAborted);
connect(filesNetJob.get(), &NetJob::stepProgress, this, &InstanceImportTask::propagateStepProgress); m_filesNetJob->start();
connect(filesNetJob.get(), &NetJob::failed, this, &InstanceImportTask::emitFailed);
connect(filesNetJob.get(), &NetJob::aborted, this, &InstanceImportTask::emitAborted);
m_task.reset(filesNetJob);
filesNetJob->start();
} }
QString InstanceImportTask::getRootFromZip(QuaZip* zip, const QString& root) void InstanceImportTask::downloadSucceeded()
{ {
if (!isRunning()) { processZipPack();
return {}; m_filesNetJob.reset();
} }
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(); void InstanceImportTask::downloadFailed(QString reason)
} {
emitFailed(reason);
m_filesNetJob.reset();
}
// Recurse the search to non-ignored subfolders void InstanceImportTask::downloadProgressChanged(qint64 current, qint64 total)
for (auto&& fileName : rootDir.entryList(QDir::Dirs)) { {
if ("overrides/" == fileName) setProgress(current, total);
continue; }
QString result = getRootFromZip(zip, root + fileName); void InstanceImportTask::downloadAborted()
if (!result.isEmpty()) {
return result; emitAborted();
} m_filesNetJob.reset();
return {};
} }
void InstanceImportTask::processZipPack() void InstanceImportTask::processZipPack()
{ {
setStatus(tr("Attempting to determine instance type")); setStatus(tr("Extracting modpack"));
QDir extractDir(m_stagingPath); QDir extractDir(m_stagingPath);
qDebug() << "Attempting to create instance from" << m_archivePath; qDebug() << "Attempting to create instance from" << m_archivePath;
// open the zip and find relevant files in it // open the zip and find relevant files in it
auto packZip = std::make_shared<QuaZip>(m_archivePath); m_packZip.reset(new QuaZip(m_archivePath));
if (!packZip->open(QuaZip::mdUnzip)) { if (!m_packZip->open(QuaZip::mdUnzip)) {
emitFailed(tr("Unable to open supplied modpack zip file.")); emitFailed(tr("Unable to open supplied modpack zip file."));
return; return;
} }
QuaZipDir packZipDir(packZip.get()); QuaZipDir packZipDir(m_packZip.get());
qDebug() << "Attempting to determine instance type";
// https://docs.modrinth.com/docs/modpacks/format_definition/#storage
bool modrinthFound = packZipDir.exists("/modrinth.index.json");
bool technicFound = packZipDir.exists("/bin/modpack.jar") || packZipDir.exists("/bin/version.json");
QString root; QString root;
// NOTE: Prioritize modpack platforms that aren't searched for recursively. // 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 // 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 if (modrinthFound) {
if (packZipDir.exists("/modrinth.index.json")) {
// process as Modrinth pack // process as Modrinth pack
qDebug() << "Modrinth:" << true; qDebug() << "Modrinth:" << modrinthFound;
m_modpackType = ModpackType::Modrinth; m_modpackType = ModpackType::Modrinth;
} else if (packZipDir.exists("/bin/modpack.jar") || packZipDir.exists("/bin/version.json")) { } else if (technicFound) {
// process as Technic pack // process as Technic pack
qDebug() << "Technic:" << true; qDebug() << "Technic:" << technicFound;
extractDir.mkpath("minecraft"); extractDir.mkpath(".minecraft");
extractDir.cd("minecraft"); extractDir.cd(".minecraft");
m_modpackType = ModpackType::Technic; m_modpackType = ModpackType::Technic;
} else { } else {
root = getRootFromZip(packZip.get()); QStringList paths_to_ignore{ "overrides/" };
setDetails("");
if (QString mmcRoot = MMCZip::findFolderOfFileInZip(m_packZip.get(), "instance.cfg", paths_to_ignore); !mmcRoot.isNull()) {
// process as MultiMC instance/pack
qDebug() << "MultiMC:" << mmcRoot;
root = mmcRoot;
m_modpackType = ModpackType::MultiMC;
} else if (QString flameRoot = MMCZip::findFolderOfFileInZip(m_packZip.get(), "manifest.json", paths_to_ignore);
!flameRoot.isNull()) {
// process as Flame pack
qDebug() << "Flame:" << flameRoot;
root = flameRoot;
m_modpackType = ModpackType::Flame;
}
} }
if (m_modpackType == ModpackType::Unknown) { if (m_modpackType == ModpackType::Unknown) {
emitFailed(tr("Archive does not contain a recognized modpack type.")); emitFailed(tr("Archive does not contain a recognized modpack type."));
return; return;
} }
setStatus(tr("Extracting modpack"));
// make sure we extract just the pack // make sure we extract just the pack
auto zipTask = makeShared<MMCZip::ExtractZipTask>(packZip, extractDir, root); m_extractFuture =
QtConcurrent::run(QThreadPool::globalInstance(), MMCZip::extractSubDir, m_packZip.get(), root, extractDir.absolutePath());
auto progressStep = std::make_shared<TaskStepProgress>(); connect(&m_extractFutureWatcher, &QFutureWatcher<QStringList>::finished, this, &InstanceImportTask::extractFinished);
connect(zipTask.get(), &Task::finished, this, [this, progressStep] { m_extractFutureWatcher.setFuture(m_extractFuture);
progressStep->state = TaskStepState::Succeeded;
stepProgress(*progressStep);
});
connect(zipTask.get(), &Task::succeeded, this, &InstanceImportTask::extractFinished, Qt::QueuedConnection);
connect(zipTask.get(), &Task::aborted, this, &InstanceImportTask::emitAborted);
connect(zipTask.get(), &Task::failed, this, [this, progressStep](QString reason) {
progressStep->state = TaskStepState::Failed;
stepProgress(*progressStep);
emitFailed(reason);
});
connect(zipTask.get(), &Task::stepProgress, this, &InstanceImportTask::propagateStepProgress);
connect(zipTask.get(), &Task::progress, this, [this, progressStep](qint64 current, qint64 total) {
progressStep->update(current, total);
stepProgress(*progressStep);
});
connect(zipTask.get(), &Task::status, this, [this, progressStep](QString status) {
progressStep->status = status;
stepProgress(*progressStep);
});
m_task.reset(zipTask);
zipTask->start();
} }
void InstanceImportTask::extractFinished() void InstanceImportTask::extractFinished()
{ {
setAbortable(false); m_packZip.reset();
if (m_extractFuture.isCanceled())
return;
if (!m_extractFuture.result().has_value()) {
emitFailed(tr("Failed to extract modpack"));
return;
}
QDir extractDir(m_stagingPath); QDir extractDir(m_stagingPath);
qDebug() << "Fixing permissions for extracted pack files..."; qDebug() << "Fixing permissions for extracted pack files...";
@ -291,11 +279,8 @@ void InstanceImportTask::processFlame()
inst_creation_task->setGroup(m_instGroup); inst_creation_task->setGroup(m_instGroup);
inst_creation_task->setConfirmUpdate(shouldConfirmUpdate()); inst_creation_task->setConfirmUpdate(shouldConfirmUpdate());
auto weak = inst_creation_task.toWeakRef(); connect(inst_creation_task.get(), &Task::succeeded, this, [this, inst_creation_task] {
connect(inst_creation_task.get(), &Task::succeeded, this, [this, weak] { setOverride(inst_creation_task->shouldOverride(), inst_creation_task->originalInstanceID());
if (auto sp = weak.lock()) {
setOverride(sp->shouldOverride(), sp->originalInstanceID());
}
emitSucceeded(); emitSucceeded();
}); });
connect(inst_creation_task.get(), &Task::failed, this, &InstanceImportTask::emitFailed); connect(inst_creation_task.get(), &Task::failed, this, &InstanceImportTask::emitFailed);
@ -304,12 +289,11 @@ void InstanceImportTask::processFlame()
connect(inst_creation_task.get(), &Task::status, this, &InstanceImportTask::setStatus); connect(inst_creation_task.get(), &Task::status, this, &InstanceImportTask::setStatus);
connect(inst_creation_task.get(), &Task::details, this, &InstanceImportTask::setDetails); connect(inst_creation_task.get(), &Task::details, this, &InstanceImportTask::setDetails);
connect(inst_creation_task.get(), &Task::aborted, this, &InstanceImportTask::emitAborted); connect(this, &Task::aborted, inst_creation_task.get(), &InstanceCreationTask::abort);
connect(inst_creation_task.get(), &Task::aborted, this, &Task::abort);
connect(inst_creation_task.get(), &Task::abortStatusChanged, this, &Task::setAbortable); connect(inst_creation_task.get(), &Task::abortStatusChanged, this, &Task::setAbortable);
m_task.reset(inst_creation_task); inst_creation_task->start();
setAbortable(true);
m_task->start();
} }
void InstanceImportTask::processTechnic() void InstanceImportTask::processTechnic()
@ -340,15 +324,13 @@ void InstanceImportTask::processMultiMC()
m_instIcon = instance.iconKey(); m_instIcon = instance.iconKey();
auto importIconPath = IconUtils::findBestIconIn(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)) { if (!importIconPath.isNull() && QFile::exists(importIconPath)) {
// import icon // import icon
auto iconList = APPLICATION->icons(); auto iconList = APPLICATION->icons();
if (iconList->iconFileExists(m_instIcon)) { if (iconList->iconFileExists(m_instIcon)) {
iconList->deleteIcon(m_instIcon); iconList->deleteIcon(m_instIcon);
} }
iconList->installIcon(importIconPath, m_instIcon); iconList->installIcons({ importIconPath });
} }
} }
emitSucceeded(); emitSucceeded();
@ -356,7 +338,7 @@ void InstanceImportTask::processMultiMC()
void InstanceImportTask::processModrinth() void InstanceImportTask::processModrinth()
{ {
shared_qobject_ptr<ModrinthCreationTask> inst_creation_task = nullptr; ModrinthCreationTask* inst_creation_task = nullptr;
if (!m_extra_info.isEmpty()) { if (!m_extra_info.isEmpty()) {
auto pack_id_it = m_extra_info.constFind("pack_id"); auto pack_id_it = m_extra_info.constFind("pack_id");
Q_ASSERT(pack_id_it != m_extra_info.constEnd()); Q_ASSERT(pack_id_it != m_extra_info.constEnd());
@ -373,16 +355,16 @@ void InstanceImportTask::processModrinth()
original_instance_id = original_instance_id_it.value(); original_instance_id = original_instance_id_it.value();
inst_creation_task = inst_creation_task =
makeShared<ModrinthCreationTask>(m_stagingPath, m_globalSettings, m_parent, pack_id, pack_version_id, original_instance_id); new ModrinthCreationTask(m_stagingPath, m_globalSettings, m_parent, pack_id, pack_version_id, original_instance_id);
} else { } else {
QString pack_id; QString pack_id;
if (!m_sourceUrl.isEmpty()) { if (!m_sourceUrl.isEmpty()) {
static const QRegularExpression s_regex(R"(data\/([^\/]*)\/versions)"); QRegularExpression regex(R"(data\/([^\/]*)\/versions)");
pack_id = s_regex.match(m_sourceUrl.toString()).captured(1); pack_id = regex.match(m_sourceUrl.toString()).captured(1);
} }
// FIXME: Find a way to get the ID in directly imported ZIPs // FIXME: Find a way to get the ID in directly imported ZIPs
inst_creation_task = makeShared<ModrinthCreationTask>(m_stagingPath, m_globalSettings, m_parent, pack_id); inst_creation_task = new ModrinthCreationTask(m_stagingPath, m_globalSettings, m_parent, pack_id);
} }
inst_creation_task->setName(*this); inst_creation_task->setName(*this);
@ -390,23 +372,20 @@ void InstanceImportTask::processModrinth()
inst_creation_task->setGroup(m_instGroup); inst_creation_task->setGroup(m_instGroup);
inst_creation_task->setConfirmUpdate(shouldConfirmUpdate()); inst_creation_task->setConfirmUpdate(shouldConfirmUpdate());
auto weak = inst_creation_task.toWeakRef(); connect(inst_creation_task, &Task::succeeded, this, [this, inst_creation_task] {
connect(inst_creation_task.get(), &Task::succeeded, this, [this, weak] { setOverride(inst_creation_task->shouldOverride(), inst_creation_task->originalInstanceID());
if (auto sp = weak.lock()) {
setOverride(sp->shouldOverride(), sp->originalInstanceID());
}
emitSucceeded(); emitSucceeded();
}); });
connect(inst_creation_task.get(), &Task::failed, this, &InstanceImportTask::emitFailed); connect(inst_creation_task, &Task::failed, this, &InstanceImportTask::emitFailed);
connect(inst_creation_task.get(), &Task::progress, this, &InstanceImportTask::setProgress); connect(inst_creation_task, &Task::progress, this, &InstanceImportTask::setProgress);
connect(inst_creation_task.get(), &Task::stepProgress, this, &InstanceImportTask::propagateStepProgress); connect(inst_creation_task, &Task::stepProgress, this, &InstanceImportTask::propagateStepProgress);
connect(inst_creation_task.get(), &Task::status, this, &InstanceImportTask::setStatus); connect(inst_creation_task, &Task::status, this, &InstanceImportTask::setStatus);
connect(inst_creation_task.get(), &Task::details, this, &InstanceImportTask::setDetails); connect(inst_creation_task, &Task::details, this, &InstanceImportTask::setDetails);
connect(inst_creation_task, &Task::finished, inst_creation_task, &InstanceCreationTask::deleteLater);
connect(inst_creation_task.get(), &Task::aborted, this, &InstanceImportTask::emitAborted); connect(this, &Task::aborted, inst_creation_task, &InstanceCreationTask::abort);
connect(inst_creation_task.get(), &Task::abortStatusChanged, this, &Task::setAbortable); connect(inst_creation_task, &Task::aborted, this, &Task::abort);
connect(inst_creation_task, &Task::abortStatusChanged, this, &Task::setAbortable);
m_task.reset(inst_creation_task); inst_creation_task->start();
setAbortable(true);
m_task->start();
} }

View File

@ -39,6 +39,12 @@
#include <QFutureWatcher> #include <QFutureWatcher>
#include <QUrl> #include <QUrl>
#include "InstanceTask.h" #include "InstanceTask.h"
#include "QObjectPtr.h"
#include "modplatform/flame/PackManifest.h"
#include "net/NetJob.h"
#include "settings/SettingsObject.h"
#include <optional>
class QuaZip; class QuaZip;
@ -46,28 +52,37 @@ class InstanceImportTask : public InstanceTask {
Q_OBJECT Q_OBJECT
public: public:
explicit InstanceImportTask(const QUrl& sourceUrl, QWidget* parent = nullptr, QMap<QString, QString>&& extra_info = {}); explicit InstanceImportTask(const QUrl& sourceUrl, QWidget* parent = nullptr, QMap<QString, QString>&& extra_info = {});
virtual ~InstanceImportTask() = default;
bool abort() override; bool abort() override;
const QVector<Flame::File>& getBlockedFiles() const { return m_blockedMods; }
protected: protected:
//! Entry point for tasks. //! Entry point for tasks.
virtual void executeTask() override; virtual void executeTask() override;
private: private:
void processZipPack();
void processMultiMC(); void processMultiMC();
void processTechnic(); void processTechnic();
void processFlame(); void processFlame();
void processModrinth(); void processModrinth();
QString getRootFromZip(QuaZip* zip, const QString& root = "");
private slots: private slots:
void processZipPack(); void downloadSucceeded();
void downloadFailed(QString reason);
void downloadProgressChanged(qint64 current, qint64 total);
void downloadAborted();
void extractFinished(); void extractFinished();
private: /* data */ private: /* data */
NetJob::Ptr m_filesNetJob;
QUrl m_sourceUrl; QUrl m_sourceUrl;
QString m_archivePath; QString m_archivePath;
Task::Ptr m_task; bool m_downloadRequired = false;
std::unique_ptr<QuaZip> m_packZip;
QFuture<std::optional<QStringList>> m_extractFuture;
QFutureWatcher<std::optional<QStringList>> m_extractFutureWatcher;
QVector<Flame::File> m_blockedMods;
enum class ModpackType { enum class ModpackType {
Unknown, Unknown,
MultiMC, MultiMC,

View File

@ -372,13 +372,13 @@ void InstanceList::undoTrashInstance()
auto top = m_trashHistory.pop(); auto top = m_trashHistory.pop();
while (QDir(top.path).exists()) { while (QDir(top.polyPath).exists()) {
top.id += "1"; top.id += "1";
top.path += "1"; top.polyPath += "1";
} }
qDebug() << "Moving" << top.trashPath << "back to" << top.path; qDebug() << "Moving" << top.trashPath << "back to" << top.polyPath;
QFile(top.trashPath).rename(top.path); QFile(top.trashPath).rename(top.polyPath);
m_instanceGroupIndex[top.id] = top.groupName; m_instanceGroupIndex[top.id] = top.groupName;
increaseGroupCount(top.groupName); increaseGroupCount(top.groupName);
@ -428,7 +428,7 @@ static QMap<InstanceId, InstanceLocator> getIdMapping(const QList<InstancePtr>&
QList<InstanceId> InstanceList::discoverInstances() QList<InstanceId> InstanceList::discoverInstances()
{ {
qInfo() << "Discovering instances in" << m_instDir; qDebug() << "Discovering instances in" << m_instDir;
QList<InstanceId> out; QList<InstanceId> out;
QDirIterator iter(m_instDir, QDir::Dirs | QDir::NoDot | QDir::NoDotDot | QDir::Readable | QDir::Hidden, QDirIterator::FollowSymlinks); QDirIterator iter(m_instDir, QDir::Dirs | QDir::NoDot | QDir::NoDotDot | QDir::Readable | QDir::Hidden, QDirIterator::FollowSymlinks);
while (iter.hasNext()) { while (iter.hasNext()) {
@ -447,9 +447,13 @@ QList<InstanceId> InstanceList::discoverInstances()
} }
auto id = dirInfo.fileName(); auto id = dirInfo.fileName();
out.append(id); out.append(id);
qInfo() << "Found instance ID" << id; qDebug() << "Found instance ID" << id;
} }
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
instanceSet = QSet<QString>(out.begin(), out.end()); instanceSet = QSet<QString>(out.begin(), out.end());
#else
instanceSet = out.toSet();
#endif
m_instancesProbed = true; m_instancesProbed = true;
return out; return out;
} }
@ -464,7 +468,7 @@ InstanceList::InstListError InstanceList::loadList()
if (existingIds.contains(id)) { if (existingIds.contains(id)) {
auto instPair = existingIds[id]; auto instPair = existingIds[id];
existingIds.remove(id); existingIds.remove(id);
qInfo() << "Should keep and soft-reload" << id; qDebug() << "Should keep and soft-reload" << id;
} else { } else {
InstancePtr instPtr = loadInstance(id); InstancePtr instPtr = loadInstance(id);
if (instPtr) { if (instPtr) {
@ -483,7 +487,7 @@ InstanceList::InstListError InstanceList::loadList()
int front_bookmark = -1; int front_bookmark = -1;
int back_bookmark = -1; int back_bookmark = -1;
int currentItem = -1; int currentItem = -1;
auto removeNow = [this, &front_bookmark, &back_bookmark, &currentItem]() { auto removeNow = [&]() {
beginRemoveRows(QModelIndex(), front_bookmark, back_bookmark); beginRemoveRows(QModelIndex(), front_bookmark, back_bookmark);
m_instances.erase(m_instances.begin() + front_bookmark, m_instances.begin() + back_bookmark + 1); m_instances.erase(m_instances.begin() + front_bookmark, m_instances.begin() + back_bookmark + 1);
endRemoveRows(); endRemoveRows();
@ -631,8 +635,8 @@ InstancePtr InstanceList::loadInstance(const InstanceId& id)
QString inst_type = instanceSettings->get("InstanceType").toString(); QString inst_type = instanceSettings->get("InstanceType").toString();
// NOTE: Some launcher versions didn't save the InstanceType properly. We will just bank on the probability that this is probably a // NOTE: Some PolyMC versions didn't save the InstanceType properly. We will just bank on the probability that this is probably a OneSix
// OneSix instance // instance
if (inst_type == "OneSix" || inst_type.isEmpty()) { if (inst_type == "OneSix" || inst_type.isEmpty()) {
inst.reset(new MinecraftInstance(m_globalSettings, instanceSettings, instanceRoot)); inst.reset(new MinecraftInstance(m_globalSettings, instanceSettings, instanceRoot));
} else { } else {
@ -706,12 +710,6 @@ void InstanceList::saveGroupList()
groupsArr.insert(name, groupObj); groupsArr.insert(name, groupObj);
} }
toplevel.insert("groups", groupsArr); toplevel.insert("groups", groupsArr);
// empty string represents ungrouped "group"
if (m_collapsedGroups.contains("")) {
QJsonObject ungrouped;
ungrouped.insert("hidden", QJsonValue(true));
toplevel.insert("ungrouped", ungrouped);
}
QJsonDocument doc(toplevel); QJsonDocument doc(toplevel);
try { try {
FS::write(groupFileName, doc.toJson()); FS::write(groupFileName, doc.toJson());
@ -807,16 +805,6 @@ void InstanceList::loadGroupList()
increaseGroupCount(groupName); increaseGroupCount(groupName);
} }
} }
bool ungroupedHidden = false;
if (rootObj.value("ungrouped").isObject()) {
QJsonObject ungrouped = rootObj.value("ungrouped").toObject();
ungroupedHidden = ungrouped.value("hidden").toBool(false);
}
if (ungroupedHidden) {
// empty string represents ungrouped "group"
m_collapsedGroups.insert("");
}
m_groupsLoaded = true; m_groupsLoaded = true;
qDebug() << "Group list loaded."; qDebug() << "Group list loaded.";
} }
@ -984,6 +972,7 @@ bool InstanceList::commitStagedInstance(const QString& path,
if (groupName.isEmpty() && !groupName.isNull()) if (groupName.isEmpty() && !groupName.isNull())
groupName = QString(); groupName = QString();
QDir dir;
QString instID; QString instID;
InstancePtr inst; InstancePtr inst;
@ -1007,7 +996,7 @@ bool InstanceList::commitStagedInstance(const QString& path,
return false; return false;
} }
} else { } else {
if (!FS::move(path, destination)) { if (!dir.rename(path, destination)) {
qWarning() << "Failed to move" << path << "to" << destination; qWarning() << "Failed to move" << path << "to" << destination;
return false; return false;
} }

View File

@ -58,7 +58,7 @@ enum class GroupsState { NotLoaded, Steady, Dirty };
struct TrashHistoryItem { struct TrashHistoryItem {
QString id; QString id;
QString path; QString polyPath;
QString trashPath; QString trashPath;
QString groupName; QString groupName;
}; };

View File

@ -22,7 +22,7 @@ class InstancePageProvider : protected QObject, public BasePageProvider {
public: public:
explicit InstancePageProvider(InstancePtr parent) { inst = parent; } explicit InstancePageProvider(InstancePtr parent) { inst = parent; }
virtual ~InstancePageProvider() = default; virtual ~InstancePageProvider(){};
virtual QList<BasePage*> getPages() override virtual QList<BasePage*> getPages() override
{ {
QList<BasePage*> values; QList<BasePage*> values;
@ -39,12 +39,15 @@ class InstancePageProvider : protected QObject, public BasePageProvider {
values.append(new TexturePackPage(onesix.get(), onesix->texturePackList())); values.append(new TexturePackPage(onesix.get(), onesix->texturePackList()));
values.append(new ShaderPackPage(onesix.get(), onesix->shaderPackList())); values.append(new ShaderPackPage(onesix.get(), onesix->shaderPackList()));
values.append(new NotesPage(onesix.get())); values.append(new NotesPage(onesix.get()));
values.append(new WorldListPage(onesix, onesix->worldList())); values.append(new WorldListPage(onesix.get(), onesix->worldList()));
values.append(new ServersPage(onesix)); values.append(new ServersPage(onesix));
// values.append(new GameOptionsPage(onesix.get())); // values.append(new GameOptionsPage(onesix.get()));
values.append(new ScreenshotsPage(FS::PathCombine(onesix->gameRoot(), "screenshots"))); values.append(new ScreenshotsPage(FS::PathCombine(onesix->gameRoot(), "screenshots")));
values.append(new InstanceSettingsPage(onesix)); values.append(new InstanceSettingsPage(onesix.get()));
values.append(new OtherLogsPage(inst)); auto logMatcher = inst->getLogFileMatcher();
if (logMatcher) {
values.append(new OtherLogsPage(inst->getLogFileRoot(), logMatcher));
}
return values; return values;
} }

View File

@ -1,7 +1,5 @@
#include "InstanceTask.h" #include "InstanceTask.h"
#include "Application.h"
#include "settings/SettingsObject.h"
#include "ui/dialogs/CustomMessageBox.h" #include "ui/dialogs/CustomMessageBox.h"
#include <QPushButton> #include <QPushButton>
@ -24,9 +22,6 @@ InstanceNameChange askForChangingInstanceName(QWidget* parent, const QString& ol
ShouldUpdate askIfShouldUpdate(QWidget* parent, QString original_version_name) ShouldUpdate askIfShouldUpdate(QWidget* parent, QString original_version_name)
{ {
if (APPLICATION->settings()->get("SkipModpackUpdatePrompt").toBool())
return ShouldUpdate::SkipUpdating;
auto info = CustomMessageBox::selectable( auto info = CustomMessageBox::selectable(
parent, QObject::tr("Similar modpack was found!"), parent, QObject::tr("Similar modpack was found!"),
QObject::tr( QObject::tr(

View File

@ -41,9 +41,7 @@
bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget* parent) bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget* parent)
{ {
static const QRegularExpression s_memRegex("-Xm[sx]"); if (jvmargs.contains("-XX:PermSize=") || jvmargs.contains(QRegularExpression("-Xm[sx]")) || jvmargs.contains("-XX-MaxHeapSize") ||
static const QRegularExpression s_versionRegex("-version:.*");
if (jvmargs.contains("-XX:PermSize=") || jvmargs.contains(s_memRegex) || jvmargs.contains("-XX-MaxHeapSize") ||
jvmargs.contains("-XX:InitialHeapSize")) { jvmargs.contains("-XX:InitialHeapSize")) {
auto warnStr = QObject::tr( auto warnStr = QObject::tr(
"You tried to manually set a JVM memory option (using \"-XX:PermSize\", \"-XX-MaxHeapSize\", \"-XX:InitialHeapSize\", \"-Xmx\" " "You tried to manually set a JVM memory option (using \"-XX:PermSize\", \"-XX-MaxHeapSize\", \"-XX:InitialHeapSize\", \"-Xmx\" "
@ -54,7 +52,7 @@ bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget* parent)
return false; return false;
} }
// block lunacy with passing required version to the JVM // block lunacy with passing required version to the JVM
if (jvmargs.contains(s_versionRegex)) { if (jvmargs.contains(QRegularExpression("-version:.*"))) {
auto warnStr = QObject::tr( auto warnStr = QObject::tr(
"You tried to pass required Java version argument to the JVM (using \"-version:xxx\"). This is not safe and will not be " "You tried to pass required Java version argument to the JVM (using \"-version:xxx\"). This is not safe and will not be "
"allowed.\n" "allowed.\n"
@ -65,7 +63,7 @@ bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget* parent)
return true; return true;
} }
void JavaCommon::javaWasOk(QWidget* parent, const JavaChecker::Result& result) void JavaCommon::javaWasOk(QWidget* parent, const JavaCheckResult& result)
{ {
QString text; QString text;
text += QObject::tr( text += QObject::tr(
@ -81,7 +79,7 @@ void JavaCommon::javaWasOk(QWidget* parent, const JavaChecker::Result& result)
CustomMessageBox::selectable(parent, QObject::tr("Java test success"), text, QMessageBox::Information)->show(); CustomMessageBox::selectable(parent, QObject::tr("Java test success"), text, QMessageBox::Information)->show();
} }
void JavaCommon::javaArgsWereBad(QWidget* parent, const JavaChecker::Result& result) void JavaCommon::javaArgsWereBad(QWidget* parent, const JavaCheckResult& result)
{ {
auto htmlError = result.errorLog; auto htmlError = result.errorLog;
QString text; QString text;
@ -91,7 +89,7 @@ void JavaCommon::javaArgsWereBad(QWidget* parent, const JavaChecker::Result& res
CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show(); CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
} }
void JavaCommon::javaBinaryWasBad(QWidget* parent, const JavaChecker::Result& result) void JavaCommon::javaBinaryWasBad(QWidget* parent, const JavaCheckResult& result)
{ {
QString text; QString text;
text += QObject::tr( text += QObject::tr(
@ -118,26 +116,34 @@ void JavaCommon::TestCheck::run()
emit finished(); emit finished();
return; return;
} }
checker.reset(new JavaChecker(m_path, "", 0, 0, 0, 0)); checker.reset(new JavaChecker());
connect(checker.get(), &JavaChecker::checkFinished, this, &JavaCommon::TestCheck::checkFinished); connect(checker.get(), &JavaChecker::checkFinished, this, &JavaCommon::TestCheck::checkFinished);
checker->start(); checker->m_path = m_path;
checker->performCheck();
} }
void JavaCommon::TestCheck::checkFinished(const JavaChecker::Result& result) void JavaCommon::TestCheck::checkFinished(JavaCheckResult result)
{ {
if (result.validity != JavaChecker::Result::Validity::Valid) { if (result.validity != JavaCheckResult::Validity::Valid) {
javaBinaryWasBad(m_parent, result); javaBinaryWasBad(m_parent, result);
emit finished(); emit finished();
return; return;
} }
checker.reset(new JavaChecker(m_path, m_args, m_maxMem, m_maxMem, result.javaVersion.requiresPermGen() ? m_permGen : 0, 0)); checker.reset(new JavaChecker());
connect(checker.get(), &JavaChecker::checkFinished, this, &JavaCommon::TestCheck::checkFinishedWithArgs); connect(checker.get(), &JavaChecker::checkFinished, this, &JavaCommon::TestCheck::checkFinishedWithArgs);
checker->start(); checker->m_path = m_path;
checker->m_args = m_args;
checker->m_minMem = m_minMem;
checker->m_maxMem = m_maxMem;
if (result.javaVersion.requiresPermGen()) {
checker->m_permGen = m_permGen;
}
checker->performCheck();
} }
void JavaCommon::TestCheck::checkFinishedWithArgs(const JavaChecker::Result& result) void JavaCommon::TestCheck::checkFinishedWithArgs(JavaCheckResult result)
{ {
if (result.validity == JavaChecker::Result::Validity::Valid) { if (result.validity == JavaCheckResult::Validity::Valid) {
javaWasOk(m_parent, result); javaWasOk(m_parent, result);
emit finished(); emit finished();
return; return;

View File

@ -10,11 +10,11 @@ namespace JavaCommon {
bool checkJVMArgs(QString args, QWidget* parent); bool checkJVMArgs(QString args, QWidget* parent);
// Show a dialog saying that the Java binary was usable // Show a dialog saying that the Java binary was usable
void javaWasOk(QWidget* parent, const JavaChecker::Result& result); void javaWasOk(QWidget* parent, const JavaCheckResult& result);
// Show a dialog saying that the Java binary was not usable because of bad options // Show a dialog saying that the Java binary was not usable because of bad options
void javaArgsWereBad(QWidget* parent, const JavaChecker::Result& result); void javaArgsWereBad(QWidget* parent, const JavaCheckResult& result);
// Show a dialog saying that the Java binary was not usable // Show a dialog saying that the Java binary was not usable
void javaBinaryWasBad(QWidget* parent, const JavaChecker::Result& result); void javaBinaryWasBad(QWidget* parent, const JavaCheckResult& result);
// Show a dialog if we couldn't find Java Checker // Show a dialog if we couldn't find Java Checker
void javaCheckNotFound(QWidget* parent); void javaCheckNotFound(QWidget* parent);
@ -24,7 +24,7 @@ class TestCheck : public QObject {
TestCheck(QWidget* parent, QString path, QString args, int minMem, int maxMem, int permGen) TestCheck(QWidget* parent, QString path, QString args, int minMem, int maxMem, int permGen)
: m_parent(parent), m_path(path), m_args(args), m_minMem(minMem), m_maxMem(maxMem), m_permGen(permGen) : m_parent(parent), m_path(path), m_args(args), m_minMem(minMem), m_maxMem(maxMem), m_permGen(permGen)
{} {}
virtual ~TestCheck() = default; virtual ~TestCheck(){};
void run(); void run();
@ -32,11 +32,11 @@ class TestCheck : public QObject {
void finished(); void finished();
private slots: private slots:
void checkFinished(const JavaChecker::Result& result); void checkFinished(JavaCheckResult result);
void checkFinishedWithArgs(const JavaChecker::Result& result); void checkFinishedWithArgs(JavaCheckResult result);
private: private:
JavaChecker::Ptr checker; std::shared_ptr<JavaChecker> checker;
QWidget* m_parent = nullptr; QWidget* m_parent = nullptr;
QString m_path; QString m_path;
QString m_args; QString m_args;

View File

@ -188,10 +188,10 @@ T ensureIsType(const QJsonObject& parent, const QString& key, const T default_ =
} }
template <typename T> template <typename T>
QList<T> requireIsArrayOf(const QJsonDocument& doc) QVector<T> requireIsArrayOf(const QJsonDocument& doc)
{ {
const QJsonArray array = requireArray(doc); const QJsonArray array = requireArray(doc);
QList<T> out; QVector<T> out;
for (const QJsonValue val : array) { for (const QJsonValue val : array) {
out.append(requireIsType<T>(val, "Document")); out.append(requireIsType<T>(val, "Document"));
} }
@ -199,10 +199,10 @@ QList<T> requireIsArrayOf(const QJsonDocument& doc)
} }
template <typename T> template <typename T>
QList<T> ensureIsArrayOf(const QJsonValue& value, const QString& what = "Value") QVector<T> ensureIsArrayOf(const QJsonValue& value, const QString& what = "Value")
{ {
const QJsonArray array = ensureIsType<QJsonArray>(value, QJsonArray(), what); const QJsonArray array = ensureIsType<QJsonArray>(value, QJsonArray(), what);
QList<T> out; QVector<T> out;
for (const QJsonValue val : array) { for (const QJsonValue val : array) {
out.append(requireIsType<T>(val, what)); out.append(requireIsType<T>(val, what));
} }
@ -210,7 +210,7 @@ QList<T> ensureIsArrayOf(const QJsonValue& value, const QString& what = "Value")
} }
template <typename T> template <typename T>
QList<T> ensureIsArrayOf(const QJsonValue& value, const QList<T> default_, const QString& what = "Value") QVector<T> ensureIsArrayOf(const QJsonValue& value, const QVector<T> default_, const QString& what = "Value")
{ {
if (value.isUndefined()) { if (value.isUndefined()) {
return default_; return default_;
@ -220,7 +220,7 @@ QList<T> ensureIsArrayOf(const QJsonValue& value, const QList<T> default_, const
/// @throw JsonException /// @throw JsonException
template <typename T> template <typename T>
QList<T> requireIsArrayOf(const QJsonObject& parent, const QString& key, const QString& what = "__placeholder__") QVector<T> requireIsArrayOf(const QJsonObject& parent, const QString& key, const QString& what = "__placeholder__")
{ {
const QString localWhat = QString(what).replace("__placeholder__", '\'' + key + '\''); const QString localWhat = QString(what).replace("__placeholder__", '\'' + key + '\'');
if (!parent.contains(key)) { if (!parent.contains(key)) {
@ -230,10 +230,10 @@ QList<T> requireIsArrayOf(const QJsonObject& parent, const QString& key, const Q
} }
template <typename T> template <typename T>
QList<T> ensureIsArrayOf(const QJsonObject& parent, QVector<T> ensureIsArrayOf(const QJsonObject& parent,
const QString& key, const QString& key,
const QList<T>& default_ = QList<T>(), const QVector<T>& default_ = QVector<T>(),
const QString& what = "__placeholder__") const QString& what = "__placeholder__")
{ {
const QString localWhat = QString(what).replace("__placeholder__", '\'' + key + '\''); const QString localWhat = QString(what).replace("__placeholder__", '\'' + key + '\'');
if (!parent.contains(key)) { if (!parent.contains(key)) {

View File

@ -36,14 +36,12 @@
#include "LaunchController.h" #include "LaunchController.h"
#include "Application.h" #include "Application.h"
#include "launch/steps/PrintServers.h"
#include "minecraft/auth/AccountData.h" #include "minecraft/auth/AccountData.h"
#include "minecraft/auth/AccountList.h" #include "minecraft/auth/AccountList.h"
#include "ui/InstanceWindow.h" #include "ui/InstanceWindow.h"
#include "ui/MainWindow.h" #include "ui/MainWindow.h"
#include "ui/dialogs/CustomMessageBox.h" #include "ui/dialogs/CustomMessageBox.h"
#include "ui/dialogs/MSALoginDialog.h"
#include "ui/dialogs/ProfileSelectDialog.h" #include "ui/dialogs/ProfileSelectDialog.h"
#include "ui/dialogs/ProfileSetupDialog.h" #include "ui/dialogs/ProfileSetupDialog.h"
#include "ui/dialogs/ProgressDialog.h" #include "ui/dialogs/ProgressDialog.h"
@ -54,15 +52,15 @@
#include <QLineEdit> #include <QLineEdit>
#include <QList> #include <QList>
#include <QPushButton> #include <QPushButton>
#include <QRegularExpression>
#include <QStringList> #include <QStringList>
#include "BuildConfig.h" #include "BuildConfig.h"
#include "JavaCommon.h" #include "JavaCommon.h"
#include "launch/steps/TextPrint.h" #include "launch/steps/TextPrint.h"
#include "minecraft/auth/AccountTask.h"
#include "tasks/Task.h" #include "tasks/Task.h"
LaunchController::LaunchController() : Task() {} LaunchController::LaunchController(QObject* parent) : Task(parent) {}
void LaunchController::executeTask() void LaunchController::executeTask()
{ {
@ -87,7 +85,7 @@ void LaunchController::decideAccount()
// Find an account to use. // Find an account to use.
auto accounts = APPLICATION->accounts(); auto accounts = APPLICATION->accounts();
if (accounts->count() <= 0 || !accounts->anyAccountIsValid()) { if (accounts->count() <= 0) {
// Tell the user they need to log in at least one account in order to play. // Tell the user they need to log in at least one account in order to play.
auto reply = CustomMessageBox::selectable(m_parentWidget, tr("No Accounts"), auto reply = CustomMessageBox::selectable(m_parentWidget, tr("No Accounts"),
tr("In order to play Minecraft, you must have at least one Microsoft " tr("In order to play Minecraft, you must have at least one Microsoft "
@ -131,64 +129,12 @@ void LaunchController::decideAccount()
} }
} }
bool LaunchController::askPlayDemo()
{
QMessageBox box(m_parentWidget);
box.setWindowTitle(tr("Play demo?"));
box.setText(
tr("This account does not own Minecraft.\nYou need to purchase the game first to play it.\n\nDo you want to play "
"the demo?"));
box.setIcon(QMessageBox::Warning);
auto demoButton = box.addButton(tr("Play Demo"), QMessageBox::ButtonRole::YesRole);
auto cancelButton = box.addButton(tr("Cancel"), QMessageBox::ButtonRole::NoRole);
box.setDefaultButton(cancelButton);
box.exec();
return box.clickedButton() == demoButton;
}
QString LaunchController::askOfflineName(QString playerName, bool demo, bool& ok)
{
// we ask the user for a player name
QString message = tr("Choose your offline mode player name.");
if (demo) {
message = tr("Choose your demo mode player name.");
}
QString lastOfflinePlayerName = APPLICATION->settings()->get("LastOfflinePlayerName").toString();
QString usedname = lastOfflinePlayerName.isEmpty() ? playerName : lastOfflinePlayerName;
QString name = QInputDialog::getText(m_parentWidget, tr("Player name"), message, QLineEdit::Normal, usedname, &ok);
if (!ok)
return {};
if (name.length()) {
usedname = name;
APPLICATION->settings()->set("LastOfflinePlayerName", usedname);
}
return usedname;
}
void LaunchController::login() void LaunchController::login()
{ {
decideAccount(); decideAccount();
// if no account is selected, we bail
if (!m_accountToUse) { if (!m_accountToUse) {
// if no account is selected, ask about demo
if (!m_demo) {
m_demo = askPlayDemo();
}
if (m_demo) {
// we ask the user for a player name
bool ok = false;
auto name = askOfflineName("Player", m_demo, ok);
if (ok) {
m_session = std::make_shared<AuthSession>();
static const QRegularExpression s_removeChars("[{}-]");
m_session->MakeDemo(name, MinecraftAccount::uuidFromUsername(name).toString().remove(s_removeChars));
launchInstance();
return;
}
}
// if no account is selected, we bail
emitFailed(tr("No account selected for launch.")); emitFailed(tr("No account selected for launch."));
return; return;
} }
@ -197,11 +143,11 @@ void LaunchController::login()
bool tryagain = true; bool tryagain = true;
unsigned int tries = 0; unsigned int tries = 0;
if ((m_accountToUse->accountType() != AccountType::Offline && m_accountToUse->accountState() == AccountState::Offline) || if (m_accountToUse->accountType() != AccountType::Offline && m_accountToUse->accountState() == AccountState::Offline) {
m_accountToUse->shouldRefresh()) {
// Force account refresh on the account used to launch the instance updating the AccountState // Force account refresh on the account used to launch the instance updating the AccountState
// only on first try and if it is not meant to be offline // only on first try and if it is not meant to be offline
m_accountToUse->refresh(); auto accounts = APPLICATION->accounts();
accounts->requestRefresh(m_accountToUse->internalId());
} }
while (tryagain) { while (tryagain) {
if (tries > 0 && tries % 3 == 0) { if (tries > 0 && tries % 3 == 0) {
@ -220,34 +166,13 @@ void LaunchController::login()
m_session->demo = m_demo; m_session->demo = m_demo;
m_accountToUse->fillSession(m_session); m_accountToUse->fillSession(m_session);
MinecraftAccountPtr accountToCheck; // Launch immediately in true offline mode
if (m_accountToUse->accountType() == AccountType::Offline) {
if (m_accountToUse->ownsMinecraft()) launchInstance();
accountToCheck = m_accountToUse;
else if (const MinecraftAccountPtr defaultAccount = APPLICATION->accounts()->defaultAccount();
defaultAccount != nullptr && defaultAccount->ownsMinecraft()) {
accountToCheck = defaultAccount;
} else {
for (int i = 0; i < APPLICATION->accounts()->count(); i++) {
MinecraftAccountPtr account = APPLICATION->accounts()->at(i);
if (account->ownsMinecraft())
accountToCheck = account;
}
}
if (accountToCheck == nullptr) {
if (!m_session->demo)
m_session->demo = askPlayDemo();
if (m_session->demo)
launchInstance();
else
emitFailed(tr("Launch cancelled - account does not own Minecraft."));
return; return;
} }
switch (accountToCheck->accountState()) { switch (m_accountToUse->accountState()) {
case AccountState::Offline: { case AccountState::Offline: {
m_session->wants_online = false; m_session->wants_online = false;
} }
@ -256,41 +181,68 @@ void LaunchController::login()
if (!m_session->wants_online) { if (!m_session->wants_online) {
// we ask the user for a player name // we ask the user for a player name
bool ok = false; bool ok = false;
QString name;
if (m_offlineName.isEmpty()) { QString message = tr("Choose your offline mode player name.");
name = askOfflineName(m_session->player_name, m_session->demo, ok); if (m_session->demo) {
if (!ok) { message = tr("Choose your demo mode player name.");
tryagain = false;
break;
}
} else {
name = m_offlineName;
} }
m_session->MakeOffline(name);
QString lastOfflinePlayerName = APPLICATION->settings()->get("LastOfflinePlayerName").toString();
QString usedname = lastOfflinePlayerName.isEmpty() ? m_session->player_name : lastOfflinePlayerName;
QString name = QInputDialog::getText(m_parentWidget, tr("Player name"), message, QLineEdit::Normal, usedname, &ok);
if (!ok) {
tryagain = false;
break;
}
if (name.length()) {
usedname = name;
APPLICATION->settings()->set("LastOfflinePlayerName", usedname);
}
m_session->MakeOffline(usedname);
// offline flavored game from here :3 // offline flavored game from here :3
} else if (m_accountToUse == accountToCheck && !m_accountToUse->hasProfile()) { }
// Now handle setting up a profile name here... if (m_accountToUse->ownsMinecraft()) {
ProfileSetupDialog dialog(m_accountToUse, m_parentWidget); if (!m_accountToUse->hasProfile()) {
if (dialog.exec() == QDialog::Accepted) { // Now handle setting up a profile name here...
tryagain = true; ProfileSetupDialog dialog(m_accountToUse, m_parentWidget);
continue; if (dialog.exec() == QDialog::Accepted) {
tryagain = true;
continue;
} else {
emitFailed(tr("Received undetermined session status during login."));
return;
}
}
// we own Minecraft, there is a profile, it's all ready to go!
launchInstance();
return;
} else {
// play demo ?
QMessageBox box(m_parentWidget);
box.setWindowTitle(tr("Play demo?"));
box.setText(
tr("This account does not own Minecraft.\nYou need to purchase the game first to play it.\n\nDo you want to play "
"the demo?"));
box.setIcon(QMessageBox::Warning);
auto demoButton = box.addButton(tr("Play Demo"), QMessageBox::ButtonRole::YesRole);
auto cancelButton = box.addButton(tr("Cancel"), QMessageBox::ButtonRole::NoRole);
box.setDefaultButton(cancelButton);
box.exec();
if (box.clickedButton() == demoButton) {
// play demo here
m_session->MakeDemo();
launchInstance();
} else { } else {
emitFailed(tr("Received undetermined session status during login.")); emitFailed(tr("Launch cancelled - account does not own Minecraft."));
return;
} }
} }
if (m_accountToUse->accountType() == AccountType::Offline)
m_session->wants_online = false;
// we own Minecraft, there is a profile, it's all ready to go!
launchInstance();
return; return;
} }
case AccountState::Errored: case AccountState::Errored:
// This means some sort of soft error that we can fix with a refresh ... so let's refresh. // This means some sort of soft error that we can fix with a refresh ... so let's refresh.
case AccountState::Unchecked: { case AccountState::Unchecked: {
accountToCheck->refresh(); m_accountToUse->refresh();
} }
/* fallthrough */ /* fallthrough */
case AccountState::Working: { case AccountState::Working: {
@ -299,19 +251,19 @@ void LaunchController::login()
if (m_online) { if (m_online) {
progDialog.setSkipButton(true, tr("Play Offline")); progDialog.setSkipButton(true, tr("Play Offline"));
} }
auto task = accountToCheck->currentTask(); auto task = m_accountToUse->currentTask();
progDialog.execWithTask(task.get()); progDialog.execWithTask(task.get());
continue; continue;
} }
case AccountState::Expired: { case AccountState::Expired: {
if (reauthenticateAccount(accountToCheck)) auto errorString = tr("The account has expired and needs to be logged into manually again.");
continue; QMessageBox::warning(m_parentWidget, tr("Account refresh failed"), errorString, QMessageBox::StandardButton::Ok,
QMessageBox::StandardButton::Ok);
emitFailed(errorString);
return; return;
} }
case AccountState::Disabled: { case AccountState::Disabled: {
auto errorString = tr("The launcher's client identification has changed. Please remove '%1' and try again.") auto errorString = tr("The launcher's client identification has changed. Please remove this account and add it again.");
.arg(accountToCheck->profileName());
QMessageBox::warning(m_parentWidget, tr("Client identification changed"), errorString, QMessageBox::StandardButton::Ok, QMessageBox::warning(m_parentWidget, tr("Client identification changed"), errorString, QMessageBox::StandardButton::Ok,
QMessageBox::StandardButton::Ok); QMessageBox::StandardButton::Ok);
emitFailed(errorString); emitFailed(errorString);
@ -319,9 +271,8 @@ void LaunchController::login()
} }
case AccountState::Gone: { case AccountState::Gone: {
auto errorString = auto errorString =
tr("'%1' no longer exists on the servers. It may have been migrated, in which case please add the new account " tr("The account no longer exists on the servers. It may have been migrated, in which case please add the new account "
"you migrated this one to.") "you migrated this one to.");
.arg(accountToCheck->profileName());
QMessageBox::warning(m_parentWidget, tr("Account gone"), errorString, QMessageBox::StandardButton::Ok, QMessageBox::warning(m_parentWidget, tr("Account gone"), errorString, QMessageBox::StandardButton::Ok,
QMessageBox::StandardButton::Ok); QMessageBox::StandardButton::Ok);
emitFailed(errorString); emitFailed(errorString);
@ -332,38 +283,6 @@ void LaunchController::login()
emitFailed(tr("Failed to launch.")); emitFailed(tr("Failed to launch."));
} }
bool LaunchController::reauthenticateAccount(MinecraftAccountPtr account)
{
auto button = QMessageBox::warning(
m_parentWidget, tr("Account refresh failed"),
tr("'%1' has expired and needs to be reauthenticated. Do you want to reauthenticate this account?").arg(account->profileName()),
QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No, QMessageBox::StandardButton::Yes);
if (button == QMessageBox::StandardButton::Yes) {
auto accounts = APPLICATION->accounts();
bool isDefault = accounts->defaultAccount() == account;
accounts->removeAccount(accounts->index(accounts->findAccountByProfileId(account->profileId())));
if (account->accountType() == AccountType::MSA) {
auto newAccount = MSALoginDialog::newAccount(m_parentWidget);
if (newAccount != nullptr) {
accounts->addAccount(newAccount);
if (isDefault)
accounts->setDefaultAccount(newAccount);
if (m_accountToUse == account) {
m_accountToUse = nullptr;
decideAccount();
}
return true;
}
}
}
emitFailed(tr("The account has expired and needs to be reauthenticated"));
return false;
}
void LaunchController::launchInstance() void LaunchController::launchInstance()
{ {
Q_ASSERT_X(m_instance != NULL, "launchInstance", "instance is NULL"); Q_ASSERT_X(m_instance != NULL, "launchInstance", "instance is NULL");
@ -375,7 +294,7 @@ void LaunchController::launchInstance()
return; return;
} }
m_launcher = m_instance->createLaunchTask(m_session, m_targetToJoin); m_launcher = m_instance->createLaunchTask(m_session, m_serverToJoin);
if (!m_launcher) { if (!m_launcher) {
emitFailed(tr("Couldn't instantiate a launcher.")); emitFailed(tr("Couldn't instantiate a launcher."));
return; return;
@ -397,9 +316,26 @@ void LaunchController::launchInstance()
online_mode = "online"; online_mode = "online";
// Prepend Server Status // Prepend Server Status
QStringList servers = { "login.microsoftonline.com", "session.minecraft.net", "textures.minecraft.net", "api.mojang.com" }; QStringList servers = { "authserver.mojang.com", "session.minecraft.net", "textures.minecraft.net", "api.mojang.com" };
QString resolved_servers = "";
QHostInfo host_info;
m_launcher->prependStep(makeShared<PrintServers>(m_launcher.get(), servers)); for (QString server : servers) {
host_info = QHostInfo::fromName(server);
resolved_servers = resolved_servers + server + " resolves to:\n [";
if (!host_info.addresses().isEmpty()) {
for (QHostAddress address : host_info.addresses()) {
resolved_servers = resolved_servers + address.toString();
if (!host_info.addresses().endsWith(address)) {
resolved_servers = resolved_servers + ", ";
}
}
} else {
resolved_servers = resolved_servers + "N/A";
}
resolved_servers = resolved_servers + "]\n\n";
}
m_launcher->prependStep(makeShared<TextPrint>(m_launcher.get(), resolved_servers, MessageLevel::Launcher));
} else { } else {
online_mode = m_demo ? "demo" : "offline"; online_mode = m_demo ? "demo" : "offline";
} }

View File

@ -39,7 +39,7 @@
#include <QObject> #include <QObject>
#include "minecraft/auth/MinecraftAccount.h" #include "minecraft/auth/MinecraftAccount.h"
#include "minecraft/launch/MinecraftTarget.h" #include "minecraft/launch/MinecraftServerTarget.h"
class InstanceWindow; class InstanceWindow;
class LaunchController : public Task { class LaunchController : public Task {
@ -47,8 +47,8 @@ class LaunchController : public Task {
public: public:
void executeTask() override; void executeTask() override;
LaunchController(); LaunchController(QObject* parent = nullptr);
virtual ~LaunchController() = default; virtual ~LaunchController(){};
void setInstance(InstancePtr instance) { m_instance = instance; } void setInstance(InstancePtr instance) { m_instance = instance; }
@ -56,15 +56,13 @@ class LaunchController : public Task {
void setOnline(bool online) { m_online = online; } void setOnline(bool online) { m_online = online; }
void setOfflineName(const QString& offlineName) { m_offlineName = offlineName; }
void setDemo(bool demo) { m_demo = demo; } void setDemo(bool demo) { m_demo = demo; }
void setProfiler(BaseProfilerFactory* profiler) { m_profiler = profiler; } void setProfiler(BaseProfilerFactory* profiler) { m_profiler = profiler; }
void setParentWidget(QWidget* widget) { m_parentWidget = widget; } void setParentWidget(QWidget* widget) { m_parentWidget = widget; }
void setTargetToJoin(MinecraftTarget::Ptr targetToJoin) { m_targetToJoin = std::move(targetToJoin); } void setServerToJoin(MinecraftServerTargetPtr serverToJoin) { m_serverToJoin = std::move(serverToJoin); }
void setAccountToUse(MinecraftAccountPtr accountToUse) { m_accountToUse = std::move(accountToUse); } void setAccountToUse(MinecraftAccountPtr accountToUse) { m_accountToUse = std::move(accountToUse); }
@ -76,9 +74,6 @@ class LaunchController : public Task {
void login(); void login();
void launchInstance(); void launchInstance();
void decideAccount(); void decideAccount();
bool askPlayDemo();
QString askOfflineName(QString playerName, bool demo, bool& ok);
bool reauthenticateAccount(MinecraftAccountPtr account);
private slots: private slots:
void readyForLaunch(); void readyForLaunch();
@ -90,7 +85,6 @@ class LaunchController : public Task {
private: private:
BaseProfilerFactory* m_profiler = nullptr; BaseProfilerFactory* m_profiler = nullptr;
bool m_online = true; bool m_online = true;
QString m_offlineName;
bool m_demo = false; bool m_demo = false;
InstancePtr m_instance; InstancePtr m_instance;
QWidget* m_parentWidget = nullptr; QWidget* m_parentWidget = nullptr;
@ -98,5 +92,5 @@ class LaunchController : public Task {
MinecraftAccountPtr m_accountToUse = nullptr; MinecraftAccountPtr m_accountToUse = nullptr;
AuthSessionPtr m_session; AuthSessionPtr m_session;
shared_qobject_ptr<LaunchTask> m_launcher; shared_qobject_ptr<LaunchTask> m_launcher;
MinecraftTarget::Ptr m_targetToJoin; MinecraftServerTargetPtr m_serverToJoin;
}; };

View File

@ -39,16 +39,8 @@ if [ "x$DEPS_LIST" = "x" ]; then
# Just to be sure... # Just to be sure...
chmod +x "${LAUNCHER_DIR}/bin/${LAUNCHER_NAME}" chmod +x "${LAUNCHER_DIR}/bin/${LAUNCHER_NAME}"
ARGS=("${LAUNCHER_DIR}/${LAUNCHER_NAME}" "${LAUNCHER_DIR}/bin/${LAUNCHER_NAME}")
if [ -f portable.txt ]; then
ARGS+=("-d" "${LAUNCHER_DIR}")
fi
ARGS+=("$@")
# Run the launcher # Run the launcher
exec -a "${ARGS[@]}" exec -a "${LAUNCHER_DIR}/${LAUNCHER_NAME}" "${LAUNCHER_DIR}/bin/${LAUNCHER_NAME}" -d "${LAUNCHER_DIR}" "$@"
# Run the launcher in valgrind # Run the launcher in valgrind
# valgrind --log-file="valgrind.log" --leak-check=full --track-origins=yes "${LAUNCHER_DIR}/bin/${LAUNCHER_NAME}" -d "${LAUNCHER_DIR}" "$@" # valgrind --log-file="valgrind.log" --leak-check=full --track-origins=yes "${LAUNCHER_DIR}/bin/${LAUNCHER_NAME}" -d "${LAUNCHER_DIR}" "$@"

View File

@ -39,8 +39,7 @@
#include <QTextDecoder> #include <QTextDecoder>
#include "MessageLevel.h" #include "MessageLevel.h"
LoggedProcess::LoggedProcess(const QTextCodec* output_codec, QObject* parent) LoggedProcess::LoggedProcess(QObject* parent) : QProcess(parent)
: QProcess(parent), m_err_decoder(output_codec), m_out_decoder(output_codec)
{ {
// QProcess has a strange interface... let's map a lot of those into a few. // QProcess has a strange interface... let's map a lot of those into a few.
connect(this, &QProcess::readyReadStandardOutput, this, &LoggedProcess::on_stdOut); connect(this, &QProcess::readyReadStandardOutput, this, &LoggedProcess::on_stdOut);

View File

@ -49,7 +49,7 @@ class LoggedProcess : public QProcess {
enum State { NotRunning, Starting, FailedToStart, Running, Finished, Crashed, Aborted }; enum State { NotRunning, Starting, FailedToStart, Running, Finished, Crashed, Aborted };
public: public:
explicit LoggedProcess(const QTextCodec* output_codec = QTextCodec::codecForLocale(), QObject* parent = 0); explicit LoggedProcess(QObject* parent = 0);
virtual ~LoggedProcess(); virtual ~LoggedProcess();
State state() const; State state() const;
@ -80,8 +80,8 @@ class LoggedProcess : public QProcess {
QStringList reprocess(const QByteArray& data, QTextDecoder& decoder); QStringList reprocess(const QByteArray& data, QTextDecoder& decoder);
private: private:
QTextDecoder m_err_decoder; QTextDecoder m_err_decoder = QTextDecoder(QTextCodec::codecForLocale());
QTextDecoder m_out_decoder; QTextDecoder m_out_decoder = QTextDecoder(QTextCodec::codecForLocale());
QString m_leftover_line; QString m_leftover_line;
bool m_killed = false; bool m_killed = false;
State m_state = NotRunning; State m_state = NotRunning;

View File

@ -2,7 +2,7 @@
/* /*
* Prism Launcher - Minecraft Launcher * Prism Launcher - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com> * Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -42,7 +42,6 @@
#include <QCoreApplication> #include <QCoreApplication>
#include <QDebug> #include <QDebug>
#include <QFileInfo>
#include <QUrl> #include <QUrl>
#if defined(LAUNCHER_APPLICATION) #if defined(LAUNCHER_APPLICATION)
@ -123,7 +122,7 @@ bool compressDirFiles(QString fileCompressed, QString dir, QFileInfoList files,
zip.setUtf8Enabled(true); zip.setUtf8Enabled(true);
QDir().mkpath(QFileInfo(fileCompressed).absolutePath()); QDir().mkpath(QFileInfo(fileCompressed).absolutePath());
if (!zip.open(QuaZip::mdCreate)) { if (!zip.open(QuaZip::mdCreate)) {
FS::deletePath(fileCompressed); QFile::remove(fileCompressed);
return false; return false;
} }
@ -131,7 +130,7 @@ bool compressDirFiles(QString fileCompressed, QString dir, QFileInfoList files,
zip.close(); zip.close();
if (zip.getZipError() != 0) { if (zip.getZipError() != 0) {
FS::deletePath(fileCompressed); QFile::remove(fileCompressed);
return false; return false;
} }
@ -145,7 +144,7 @@ bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<M
QuaZip zipOut(targetJarPath); QuaZip zipOut(targetJarPath);
zipOut.setUtf8Enabled(true); zipOut.setUtf8Enabled(true);
if (!zipOut.open(QuaZip::mdCreate)) { if (!zipOut.open(QuaZip::mdCreate)) {
FS::deletePath(targetJarPath); QFile::remove(targetJarPath);
qCritical() << "Failed to open the minecraft.jar for modding"; qCritical() << "Failed to open the minecraft.jar for modding";
return false; return false;
} }
@ -163,7 +162,7 @@ bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<M
if (mod->type() == ResourceType::ZIPFILE) { if (mod->type() == ResourceType::ZIPFILE) {
if (!mergeZipFiles(&zipOut, mod->fileinfo(), addedFiles)) { if (!mergeZipFiles(&zipOut, mod->fileinfo(), addedFiles)) {
zipOut.close(); zipOut.close();
FS::deletePath(targetJarPath); QFile::remove(targetJarPath);
qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar."; qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar.";
return false; return false;
} }
@ -172,7 +171,7 @@ bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<M
auto filename = mod->fileinfo(); auto filename = mod->fileinfo();
if (!JlCompress::compressFile(&zipOut, filename.absoluteFilePath(), filename.fileName())) { if (!JlCompress::compressFile(&zipOut, filename.absoluteFilePath(), filename.fileName())) {
zipOut.close(); zipOut.close();
FS::deletePath(targetJarPath); QFile::remove(targetJarPath);
qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar."; qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar.";
return false; return false;
} }
@ -195,7 +194,7 @@ bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<M
if (!compressDirFiles(&zipOut, parent_dir, files)) { if (!compressDirFiles(&zipOut, parent_dir, files)) {
zipOut.close(); zipOut.close();
FS::deletePath(targetJarPath); QFile::remove(targetJarPath);
qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar."; qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar.";
return false; return false;
} }
@ -203,7 +202,7 @@ bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<M
} else { } else {
// Make sure we do not continue launching when something is missing or undefined... // Make sure we do not continue launching when something is missing or undefined...
zipOut.close(); zipOut.close();
FS::deletePath(targetJarPath); QFile::remove(targetJarPath);
qCritical() << "Failed to add unknown mod type" << mod->fileinfo().fileName() << "to the jar."; qCritical() << "Failed to add unknown mod type" << mod->fileinfo().fileName() << "to the jar.";
return false; return false;
} }
@ -211,7 +210,7 @@ bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<M
if (!mergeZipFiles(&zipOut, QFileInfo(sourceJarPath), addedFiles, [](const QString key) { return !key.contains("META-INF"); })) { if (!mergeZipFiles(&zipOut, QFileInfo(sourceJarPath), addedFiles, [](const QString key) { return !key.contains("META-INF"); })) {
zipOut.close(); zipOut.close();
FS::deletePath(targetJarPath); QFile::remove(targetJarPath);
qCritical() << "Failed to insert minecraft.jar contents."; qCritical() << "Failed to insert minecraft.jar contents.";
return false; return false;
} }
@ -219,7 +218,7 @@ bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<M
// Recompress the jar // Recompress the jar
zipOut.close(); zipOut.close();
if (zipOut.getZipError() != 0) { if (zipOut.getZipError() != 0) {
FS::deletePath(targetJarPath); QFile::remove(targetJarPath);
qCritical() << "Failed to finalize minecraft.jar!"; qCritical() << "Failed to finalize minecraft.jar!";
return false; return false;
} }
@ -289,7 +288,9 @@ std::optional<QStringList> extractSubDir(QuaZip* zip, const QString& subdir, con
do { do {
QString file_name = zip->getCurrentFileName(); QString file_name = zip->getCurrentFileName();
#ifdef Q_OS_WIN
file_name = FS::RemoveInvalidPathChars(file_name); file_name = FS::RemoveInvalidPathChars(file_name);
#endif
if (!file_name.startsWith(subdir)) if (!file_name.startsWith(subdir))
continue; continue;
@ -331,31 +332,9 @@ std::optional<QStringList> extractSubDir(QuaZip* zip, const QString& subdir, con
} }
extracted.append(target_file_path); extracted.append(target_file_path);
auto fileInfo = QFileInfo(target_file_path); QFile::setPermissions(target_file_path,
if (fileInfo.isFile()) { QFileDevice::Permission::ReadUser | QFileDevice::Permission::WriteUser | QFileDevice::Permission::ExeUser);
auto permissions = fileInfo.permissions();
auto maxPermisions = QFileDevice::Permission::ReadUser | QFileDevice::Permission::WriteUser | QFileDevice::Permission::ExeUser |
QFileDevice::Permission::ReadGroup | QFileDevice::Permission::ReadOther;
auto minPermisions = QFileDevice::Permission::ReadUser | QFileDevice::Permission::WriteUser;
auto newPermisions = (permissions & maxPermisions) | minPermisions;
if (newPermisions != permissions) {
if (!QFile::setPermissions(target_file_path, newPermisions)) {
qWarning() << (QObject::tr("Could not fix permissions for %1").arg(target_file_path));
}
}
} else if (fileInfo.isDir()) {
// Ensure the folder has the minimal required permissions
QFile::Permissions minimalPermissions = QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner | QFile::ReadGroup |
QFile::ExeGroup | QFile::ReadOther | QFile::ExeOther;
QFile::Permissions currentPermissions = fileInfo.permissions();
if ((currentPermissions & minimalPermissions) != minimalPermissions) {
if (!QFile::setPermissions(target_file_path, minimalPermissions)) {
qWarning() << (QObject::tr("Could not fix permissions for %1").arg(target_file_path));
}
}
}
qDebug() << "Extracted file" << relative_file_name << "to" << target_file_path; qDebug() << "Extracted file" << relative_file_name << "to" << target_file_path;
} while (zip->goToNextFile()); } while (zip->goToNextFile());
@ -378,7 +357,7 @@ std::optional<QStringList> extractDir(QString fileCompressed, QString dir)
if (fileInfo.size() == 22) { if (fileInfo.size() == 22) {
return QStringList(); return QStringList();
} }
qWarning() << "Could not open archive for unpacking:" << fileCompressed << "Error:" << zip.getZipError(); qWarning() << "Could not open archive for unzipping:" << fileCompressed << "Error:" << zip.getZipError();
; ;
return std::nullopt; return std::nullopt;
} }
@ -395,7 +374,7 @@ std::optional<QStringList> extractDir(QString fileCompressed, QString subdir, QS
if (fileInfo.size() == 22) { if (fileInfo.size() == 22) {
return QStringList(); return QStringList();
} }
qWarning() << "Could not open archive for unpacking:" << fileCompressed << "Error:" << zip.getZipError(); qWarning() << "Could not open archive for unzipping:" << fileCompressed << "Error:" << zip.getZipError();
; ;
return std::nullopt; return std::nullopt;
} }
@ -412,13 +391,13 @@ bool extractFile(QString fileCompressed, QString file, QString target)
if (fileInfo.size() == 22) { if (fileInfo.size() == 22) {
return true; return true;
} }
qWarning() << "Could not open archive for unpacking:" << fileCompressed << "Error:" << zip.getZipError(); qWarning() << "Could not open archive for unzipping:" << fileCompressed << "Error:" << zip.getZipError();
return false; return false;
} }
return extractRelFile(&zip, file, target); return extractRelFile(&zip, file, target);
} }
bool collectFileListRecursively(const QString& rootDir, const QString& subDir, QFileInfoList* files, FilterFileFunction excludeFilter) bool collectFileListRecursively(const QString& rootDir, const QString& subDir, QFileInfoList* files, FilterFunction excludeFilter)
{ {
QDir rootDirectory(rootDir); QDir rootDirectory(rootDir);
if (!rootDirectory.exists()) if (!rootDirectory.exists())
@ -443,8 +422,8 @@ bool collectFileListRecursively(const QString& rootDir, const QString& subDir, Q
// collect files // collect files
entries = directory.entryInfoList(QDir::Files); entries = directory.entryInfoList(QDir::Files);
for (const auto& e : entries) { for (const auto& e : entries) {
if (excludeFilter && excludeFilter(e)) { QString relativeFilePath = rootDirectory.relativeFilePath(e.absoluteFilePath());
QString relativeFilePath = rootDirectory.relativeFilePath(e.absoluteFilePath()); if (excludeFilter && excludeFilter(relativeFilePath)) {
qDebug() << "Skipping file " << relativeFilePath; qDebug() << "Skipping file " << relativeFilePath;
continue; continue;
} }
@ -489,7 +468,7 @@ auto ExportToZipTask::exportZip() -> ZipResult
auto absolute = file.absoluteFilePath(); auto absolute = file.absoluteFilePath();
auto relative = m_dir.relativeFilePath(absolute); auto relative = m_dir.relativeFilePath(absolute);
setStatus("Compressing: " + relative); setStatus("Compresing: " + relative);
setProgress(m_progress + 1, m_progressTotal); setProgress(m_progress + 1, m_progressTotal);
if (m_follow_symlinks) { if (m_follow_symlinks) {
if (file.isSymLink()) if (file.isSymLink())
@ -513,10 +492,10 @@ auto ExportToZipTask::exportZip() -> ZipResult
void ExportToZipTask::finish() void ExportToZipTask::finish()
{ {
if (m_build_zip_future.isCanceled()) { if (m_build_zip_future.isCanceled()) {
FS::deletePath(m_output_path); QFile::remove(m_output_path);
emitAborted(); emitAborted();
} else if (auto result = m_build_zip_future.result(); result.has_value()) { } else if (auto result = m_build_zip_future.result(); result.has_value()) {
FS::deletePath(m_output_path); QFile::remove(m_output_path);
emitFailed(result.value()); emitFailed(result.value());
} else { } else {
emitSucceeded(); emitSucceeded();
@ -533,138 +512,6 @@ bool ExportToZipTask::abort()
} }
return false; return false;
} }
void ExtractZipTask::executeTask()
{
if (!m_input->isOpen() && !m_input->open(QuaZip::mdUnzip)) {
emitFailed(tr("Unable to open supplied zip file."));
return;
}
m_zip_future = QtConcurrent::run(QThreadPool::globalInstance(), [this]() { return extractZip(); });
connect(&m_zip_watcher, &QFutureWatcher<ZipResult>::finished, this, &ExtractZipTask::finish);
m_zip_watcher.setFuture(m_zip_future);
}
auto ExtractZipTask::extractZip() -> ZipResult
{
auto target = m_output_dir.absolutePath();
auto target_top_dir = QUrl::fromLocalFile(target);
QStringList extracted;
qDebug() << "Extracting subdir" << m_subdirectory << "from" << m_input->getZipName() << "to" << target;
auto numEntries = m_input->getEntriesCount();
if (numEntries < 0) {
return ZipResult(tr("Failed to enumerate files in archive"));
}
if (numEntries == 0) {
logWarning(tr("Extracting empty archives seems odd..."));
return ZipResult();
}
if (!m_input->goToFirstFile()) {
return ZipResult(tr("Failed to seek to first file in zip"));
}
setStatus("Extracting files...");
setProgress(0, numEntries);
do {
if (m_zip_future.isCanceled())
return ZipResult();
setProgress(m_progress + 1, m_progressTotal);
QString file_name = m_input->getCurrentFileName();
if (!file_name.startsWith(m_subdirectory))
continue;
auto relative_file_name = QDir::fromNativeSeparators(file_name.mid(m_subdirectory.size()));
auto original_name = relative_file_name;
setStatus("Unpacking: " + relative_file_name);
// Fix subdirs/files ending with a / getting transformed into absolute paths
if (relative_file_name.startsWith('/'))
relative_file_name = relative_file_name.mid(1);
// Fix weird "folders with a single file get squashed" thing
QString sub_path;
if (relative_file_name.contains('/') && !relative_file_name.endsWith('/')) {
sub_path = relative_file_name.section('/', 0, -2) + '/';
FS::ensureFolderPathExists(FS::PathCombine(target, sub_path));
relative_file_name = relative_file_name.split('/').last();
}
QString target_file_path;
if (relative_file_name.isEmpty()) {
target_file_path = target + '/';
} else {
target_file_path = FS::PathCombine(target_top_dir.toLocalFile(), sub_path, relative_file_name);
if (relative_file_name.endsWith('/') && !target_file_path.endsWith('/'))
target_file_path += '/';
}
if (!target_top_dir.isParentOf(QUrl::fromLocalFile(target_file_path))) {
return ZipResult(tr("Extracting %1 was cancelled, because it was effectively outside of the target path %2")
.arg(relative_file_name, target));
}
if (!JlCompress::extractFile(m_input.get(), "", target_file_path)) {
JlCompress::removeFile(extracted);
return ZipResult(tr("Failed to extract file %1 to %2").arg(original_name, target_file_path));
}
extracted.append(target_file_path);
auto fileInfo = QFileInfo(target_file_path);
if (fileInfo.isFile()) {
auto permissions = fileInfo.permissions();
auto maxPermisions = QFileDevice::Permission::ReadUser | QFileDevice::Permission::WriteUser | QFileDevice::Permission::ExeUser |
QFileDevice::Permission::ReadGroup | QFileDevice::Permission::ReadOther;
auto minPermisions = QFileDevice::Permission::ReadUser | QFileDevice::Permission::WriteUser;
auto newPermisions = (permissions & maxPermisions) | minPermisions;
if (newPermisions != permissions) {
if (!QFile::setPermissions(target_file_path, newPermisions)) {
logWarning(tr("Could not fix permissions for %1").arg(target_file_path));
}
}
} else if (fileInfo.isDir()) {
// Ensure the folder has the minimal required permissions
QFile::Permissions minimalPermissions = QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner | QFile::ReadGroup |
QFile::ExeGroup | QFile::ReadOther | QFile::ExeOther;
QFile::Permissions currentPermissions = fileInfo.permissions();
if ((currentPermissions & minimalPermissions) != minimalPermissions) {
if (!QFile::setPermissions(target_file_path, minimalPermissions)) {
logWarning(tr("Could not fix permissions for %1").arg(target_file_path));
}
}
}
qDebug() << "Extracted file" << relative_file_name << "to" << target_file_path;
} while (m_input->goToNextFile());
return ZipResult();
}
void ExtractZipTask::finish()
{
if (m_zip_future.isCanceled()) {
emitAborted();
} else if (auto result = m_zip_future.result(); result.has_value()) {
emitFailed(result.value());
} else {
emitSucceeded();
}
}
bool ExtractZipTask::abort()
{
if (m_zip_future.isRunning()) {
m_zip_future.cancel();
// NOTE: Here we don't do `emitAborted()` because it will be done when `m_build_zip_future` actually cancels, which may not occur
// immediately.
return true;
}
return false;
}
#endif #endif
} // namespace MMCZip } // namespace MMCZip

View File

@ -2,7 +2,7 @@
/* /*
* Prism Launcher - Minecraft Launcher * Prism Launcher - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com> * Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -56,7 +56,6 @@
namespace MMCZip { namespace MMCZip {
using FilterFunction = std::function<bool(const QString&)>; using FilterFunction = std::function<bool(const QString&)>;
using FilterFileFunction = std::function<bool(const QFileInfo&)>;
/** /**
* Merge two zip files, using a filter function * Merge two zip files, using a filter function
@ -150,18 +149,12 @@ bool extractFile(QString fileCompressed, QString file, QString dir);
* \param excludeFilter function to excludeFilter which files shouldn't be included (returning true means to excude) * \param excludeFilter function to excludeFilter which files shouldn't be included (returning true means to excude)
* \return true for success or false for failure * \return true for success or false for failure
*/ */
bool collectFileListRecursively(const QString& rootDir, const QString& subDir, QFileInfoList* files, FilterFileFunction excludeFilter); bool collectFileListRecursively(const QString& rootDir, const QString& subDir, QFileInfoList* files, FilterFunction excludeFilter);
#if defined(LAUNCHER_APPLICATION) #if defined(LAUNCHER_APPLICATION)
class ExportToZipTask : public Task { class ExportToZipTask : public Task {
Q_OBJECT
public: public:
ExportToZipTask(QString outputPath, ExportToZipTask(QString outputPath, QDir dir, QFileInfoList files, QString destinationPrefix = "", bool followSymlinks = false)
QDir dir,
QFileInfoList files,
QString destinationPrefix = "",
bool followSymlinks = false,
bool utf8Enabled = false)
: m_output_path(outputPath) : m_output_path(outputPath)
, m_output(outputPath) , m_output(outputPath)
, m_dir(dir) , m_dir(dir)
@ -170,15 +163,10 @@ class ExportToZipTask : public Task {
, m_follow_symlinks(followSymlinks) , m_follow_symlinks(followSymlinks)
{ {
setAbortable(true); setAbortable(true);
m_output.setUtf8Enabled(utf8Enabled); m_output.setUtf8Enabled(true);
}; };
ExportToZipTask(QString outputPath, ExportToZipTask(QString outputPath, QString dir, QFileInfoList files, QString destinationPrefix = "", bool followSymlinks = false)
QString dir, : ExportToZipTask(outputPath, QDir(dir), files, destinationPrefix, followSymlinks){};
QFileInfoList files,
QString destinationPrefix = "",
bool followSymlinks = false,
bool utf8Enabled = false)
: ExportToZipTask(outputPath, QDir(dir), files, destinationPrefix, followSymlinks, utf8Enabled) {};
virtual ~ExportToZipTask() = default; virtual ~ExportToZipTask() = default;
@ -207,34 +195,5 @@ class ExportToZipTask : public Task {
QFuture<ZipResult> m_build_zip_future; QFuture<ZipResult> m_build_zip_future;
QFutureWatcher<ZipResult> m_build_zip_watcher; QFutureWatcher<ZipResult> m_build_zip_watcher;
}; };
class ExtractZipTask : public Task {
Q_OBJECT
public:
ExtractZipTask(QString input, QDir outputDir, QString subdirectory = "")
: ExtractZipTask(std::make_shared<QuaZip>(input), outputDir, subdirectory)
{}
ExtractZipTask(std::shared_ptr<QuaZip> input, QDir outputDir, QString subdirectory = "")
: m_input(input), m_output_dir(outputDir), m_subdirectory(subdirectory)
{}
virtual ~ExtractZipTask() = default;
using ZipResult = std::optional<QString>;
protected:
virtual void executeTask() override;
bool abort() override;
ZipResult extractZip();
void finish();
private:
std::shared_ptr<QuaZip> m_input;
QDir m_output_dir;
QString m_subdirectory;
QFuture<ZipResult> m_zip_future;
QFutureWatcher<ZipResult> m_zip_watcher;
};
#endif #endif
} // namespace MMCZip } // namespace MMCZip

View File

@ -101,7 +101,7 @@ class PixmapCache final : public QObject {
*/ */
bool _markCacheMissByEviciton() bool _markCacheMissByEviciton()
{ {
static constexpr uint maxCache = static_cast<uint>(std::numeric_limits<int>::max()) / 4; static constexpr uint maxInt = static_cast<uint>(std::numeric_limits<int>::max());
static constexpr uint step = 10240; static constexpr uint step = 10240;
static constexpr int oneSecond = 1000; static constexpr int oneSecond = 1000;
@ -118,8 +118,8 @@ class PixmapCache final : public QObject {
if (m_consecutive_fast_evicitons >= m_consecutive_fast_evicitons_threshold) { if (m_consecutive_fast_evicitons >= m_consecutive_fast_evicitons_threshold) {
// increase the cache size // increase the cache size
uint newSize = _cacheLimit() + step; uint newSize = _cacheLimit() + step;
if (newSize >= maxCache) { // increase it until you overflow :D if (newSize >= maxInt) { // increase it until you overflow :D
newSize = maxCache; newSize = maxInt;
qDebug() << m_consecutive_fast_evicitons qDebug() << m_consecutive_fast_evicitons
<< tr("pixmap cache misses by eviction happened too fast, doing nothing as the cache size reached it's limit"); << tr("pixmap cache misses by eviction happened too fast, doing nothing as the cache size reached it's limit");
} else { } else {

View File

@ -40,8 +40,8 @@ namespace MangoHud {
QString getLibraryString() QString getLibraryString()
{ {
/** /*
* Guess MangoHud install location by searching for vulkan layers in this order: * Check for vulkan layers in this order:
* *
* $VK_LAYER_PATH * $VK_LAYER_PATH
* $XDG_DATA_DIRS (/usr/local/share/:/usr/share/) * $XDG_DATA_DIRS (/usr/local/share/:/usr/share/)
@ -49,9 +49,8 @@ QString getLibraryString()
* /etc * /etc
* $XDG_CONFIG_DIRS (/etc/xdg) * $XDG_CONFIG_DIRS (/etc/xdg)
* $XDG_CONFIG_HOME (~/.config) * $XDG_CONFIG_HOME (~/.config)
*
* @returns Absolute path of libMangoHud.so if found and empty QString otherwise.
*/ */
QStringList vkLayerList; QStringList vkLayerList;
{ {
QString home = QDir::homePath(); QString home = QDir::homePath();
@ -86,7 +85,7 @@ QString getLibraryString()
vkLayerList << FS::PathCombine(xdgConfigHome, "vulkan", "implicit_layer.d"); vkLayerList << FS::PathCombine(xdgConfigHome, "vulkan", "implicit_layer.d");
} }
for (const QString& vkLayer : vkLayerList) { for (QString vkLayer : vkLayerList) {
// prefer to use architecture specific vulkan layers // prefer to use architecture specific vulkan layers
QString currentArch = QSysInfo::currentCpuArchitecture(); QString currentArch = QSysInfo::currentCpuArchitecture();
@ -96,8 +95,8 @@ QString getLibraryString()
QStringList manifestNames = { QString("MangoHud.%1.json").arg(currentArch), "MangoHud.json" }; QStringList manifestNames = { QString("MangoHud.%1.json").arg(currentArch), "MangoHud.json" };
QString filePath{}; QString filePath = "";
for (const QString& manifestName : manifestNames) { for (QString manifestName : manifestNames) {
QString tryPath = FS::PathCombine(vkLayer, manifestName); QString tryPath = FS::PathCombine(vkLayer, manifestName);
if (QFile::exists(tryPath)) { if (QFile::exists(tryPath)) {
filePath = tryPath; filePath = tryPath;
@ -108,34 +107,14 @@ QString getLibraryString()
if (filePath.isEmpty()) { if (filePath.isEmpty()) {
continue; continue;
} }
try {
auto conf = Json::requireDocument(filePath, vkLayer);
auto confObject = Json::requireObject(conf, vkLayer);
auto layer = Json::ensureObject(confObject, "layer");
QString libraryName = Json::ensureString(layer, "library_path");
if (libraryName.isEmpty()) { auto conf = Json::requireDocument(filePath, vkLayer);
continue; auto confObject = Json::requireObject(conf, vkLayer);
} auto layer = Json::ensureObject(confObject, "layer");
if (QFileInfo(libraryName).isAbsolute()) { return Json::ensureString(layer, "library_path");
return libraryName;
}
#ifdef __GLIBC__
// Check whether mangohud is usable on a glibc based system
QString libraryPath = findLibrary(libraryName);
if (!libraryPath.isEmpty()) {
return libraryPath;
}
#else
// Without glibc return recorded shared library as-is.
return libraryName;
#endif
} catch (const Exception& e) {
}
} }
return {}; return QString();
} }
QString findLibrary(QString libName) QString findLibrary(QString libName)

View File

@ -2,22 +2,19 @@
MessageLevel::Enum MessageLevel::getLevel(const QString& levelName) MessageLevel::Enum MessageLevel::getLevel(const QString& levelName)
{ {
QString name = levelName.toUpper(); if (levelName == "Launcher")
if (name == "LAUNCHER")
return MessageLevel::Launcher; return MessageLevel::Launcher;
else if (name == "TRACE") else if (levelName == "Debug")
return MessageLevel::Trace;
else if (name == "DEBUG")
return MessageLevel::Debug; return MessageLevel::Debug;
else if (name == "INFO") else if (levelName == "Info")
return MessageLevel::Info; return MessageLevel::Info;
else if (name == "MESSAGE") else if (levelName == "Message")
return MessageLevel::Message; return MessageLevel::Message;
else if (name == "WARNING" || name == "WARN") else if (levelName == "Warning")
return MessageLevel::Warning; return MessageLevel::Warning;
else if (name == "ERROR") else if (levelName == "Error")
return MessageLevel::Error; return MessageLevel::Error;
else if (name == "FATAL") else if (levelName == "Fatal")
return MessageLevel::Fatal; return MessageLevel::Fatal;
// Skip PrePost, it's not exposed to !![]! // Skip PrePost, it's not exposed to !![]!
// Also skip StdErr and StdOut // Also skip StdErr and StdOut

View File

@ -12,7 +12,6 @@ enum Enum {
StdOut, /**< Undetermined stderr messages */ StdOut, /**< Undetermined stderr messages */
StdErr, /**< Undetermined stdout messages */ StdErr, /**< Undetermined stdout messages */
Launcher, /**< Launcher Messages */ Launcher, /**< Launcher Messages */
Trace, /**< Trace Messages */
Debug, /**< Debug Messages */ Debug, /**< Debug Messages */
Info, /**< Info Messages */ Info, /**< Info Messages */
Message, /**< Standard Messages */ Message, /**< Standard Messages */

View File

@ -46,24 +46,25 @@ class NullInstance : public BaseInstance {
{ {
setVersionBroken(true); setVersionBroken(true);
} }
virtual ~NullInstance() = default; virtual ~NullInstance(){};
void saveNow() override {} void saveNow() override {}
void loadSpecificSettings() override { setSpecificSettingsLoaded(true); } void loadSpecificSettings() override { setSpecificSettingsLoaded(true); }
QString getStatusbarDescription() override { return tr("Unknown instance type"); }; QString getStatusbarDescription() override { return tr("Unknown instance type"); };
QSet<QString> traits() const override { return {}; }; QSet<QString> traits() const override { return {}; };
QString instanceConfigFolder() const override { return instanceRoot(); }; QString instanceConfigFolder() const override { return instanceRoot(); };
shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr, MinecraftTarget::Ptr) override { return nullptr; } shared_qobject_ptr<LaunchTask> createLaunchTask(AuthSessionPtr, MinecraftServerTargetPtr) override { return nullptr; }
QList<Task::Ptr> createUpdateTask() override { return {}; } shared_qobject_ptr<Task> createUpdateTask([[maybe_unused]] Net::Mode mode) override { return nullptr; }
QProcessEnvironment createEnvironment() override { return QProcessEnvironment(); } QProcessEnvironment createEnvironment() override { return QProcessEnvironment(); }
QProcessEnvironment createLaunchEnvironment() override { return QProcessEnvironment(); } QProcessEnvironment createLaunchEnvironment() override { return QProcessEnvironment(); }
QMap<QString, QString> getVariables() override { return QMap<QString, QString>(); } QMap<QString, QString> getVariables() override { return QMap<QString, QString>(); }
QStringList getLogFileSearchPaths() override { return {}; } IPathMatcher::Ptr getLogFileMatcher() override { return nullptr; }
QString getLogFileRoot() override { return instanceRoot(); }
QString typeName() const override { return "Null"; } QString typeName() const override { return "Null"; }
bool canExport() const override { return false; } bool canExport() const override { return false; }
bool canEdit() const override { return false; } bool canEdit() const override { return false; }
bool canLaunch() const override { return false; } bool canLaunch() const override { return false; }
void populateLaunchMenu(QMenu* menu) override {} void populateLaunchMenu(QMenu* menu) override {}
QStringList verboseDescription(AuthSessionPtr session, MinecraftTarget::Ptr targetToJoin) override QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) override
{ {
QStringList out; QStringList out;
out << "Null instance - placeholder."; out << "Null instance - placeholder.";

View File

@ -1,71 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft Launcher
* Copyright (c) 2023-2024 Trial97 <alexandru.tripon97@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <QFileInfo>
#include <QSaveFile>
#include "Application.h"
#if defined(LAUNCHER_APPLICATION)
/* PSaveFile
* A class that mimics QSaveFile for Windows.
*
* When reading resources, we need to avoid accessing temporary files
* generated by QSaveFile. If we start reading such a file, we may
* inadvertently keep it open while QSaveFile is trying to remove it,
* or we might detect the file just before it is removed, leading to
* race conditions and errors.
*
* Unfortunately, QSaveFile doesn't provide a way to retrieve the
* temporary file name or to set a specific template for the temporary
* file name it uses. By default, QSaveFile appends a `.XXXXXX` suffix
* to the original file name, where the `XXXXXX` part is dynamically
* generated to ensure uniqueness.
*
* This class acts like a lock by adding and removing the target file
* name into/from a global string set, helping to manage access to
* files during critical operations.
*
* Note: Please do not use the `setFileName` function directly, as it
* is not virtual and cannot be overridden.
*/
class PSaveFile : public QSaveFile {
public:
PSaveFile(const QString& name) : QSaveFile(name) { addPath(name); }
PSaveFile(const QString& name, QObject* parent) : QSaveFile(name, parent) { addPath(name); }
virtual ~PSaveFile()
{
if (auto app = APPLICATION_DYN) {
app->removeQSavePath(m_absoluteFilePath);
}
}
private:
void addPath(const QString& path)
{
m_absoluteFilePath = QFileInfo(path).absoluteFilePath() + "."; // add dot for tmp files only
if (auto app = APPLICATION_DYN) {
app->addQSavePath(m_absoluteFilePath);
}
}
QString m_absoluteFilePath;
};
#else
#define PSaveFile QSaveFile
#endif

View File

@ -33,7 +33,7 @@ class shared_qobject_ptr : public QSharedPointer<T> {
{} {}
void reset() { QSharedPointer<T>::reset(); } void reset() { QSharedPointer<T>::reset(); }
void reset(T* other) void reset(T*&& other)
{ {
shared_qobject_ptr<T> t(other); shared_qobject_ptr<T> t(other);
this->swap(t); this->swap(t);

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