mirror of
https://github.com/PrismLauncher/PrismLauncher.git
synced 2026-06-29 09:59:59 +03:00
Compare commits
902 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2fa7cf7f7 | ||
|
|
585aa6e674 | ||
|
|
475ab8a208 | ||
|
|
62f537dd8d | ||
|
|
9c2c641531 | ||
|
|
402379a841 | ||
|
|
cb56c641d7 | ||
|
|
5b051e7d49 | ||
|
|
f181b5d0d7 | ||
|
|
4dc107b1fa | ||
|
|
34783c10fe | ||
|
|
a607373ced | ||
|
|
9752f9dfd7 | ||
|
|
0175653881 | ||
|
|
f654ce8212 | ||
|
|
a8643739f0 | ||
|
|
d8d2f383e9 | ||
|
|
2425d2f8a3 | ||
|
|
b387a1f793 | ||
|
|
d71cfc33a2 | ||
|
|
5f59aa5829 | ||
|
|
768d12259b | ||
|
|
0a3adb7912 | ||
|
|
a90e3d403d | ||
|
|
8de7aa2b17 | ||
|
|
022d2fe7cd | ||
|
|
803115cfde | ||
|
|
81159fd9d7 | ||
|
|
f99a0883af | ||
|
|
502a5175e2 | ||
|
|
6c15077731 | ||
|
|
6f3574f328 | ||
|
|
dd5261f7ad | ||
|
|
ad85dc3291 | ||
|
|
77f5f92634 | ||
|
|
5c1d783293 | ||
|
|
ea2d0d0644 | ||
|
|
f6d1b29b04 | ||
|
|
bf8d1ca1f8 | ||
|
|
cc466b44c3 | ||
|
|
99291186b2 | ||
|
|
2bf64efaf2 | ||
|
|
ccc23c8bc3 | ||
|
|
fa61e58cd9 | ||
|
|
f5d7e76ac4 | ||
|
|
f67a670bcf | ||
|
|
a80995ab7e | ||
|
|
64abd37e05 | ||
|
|
23c34f495f | ||
|
|
d7fc7fd855 | ||
|
|
22bfe0628f | ||
|
|
d4d032afea | ||
|
|
61cdabd40e | ||
|
|
43c11a8555 | ||
|
|
547b4c0d3a | ||
|
|
28eba8ed43 | ||
|
|
f4567bcc8c | ||
|
|
8ba5444c6b | ||
|
|
de60d804a1 | ||
|
|
8a7b17f958 | ||
|
|
558e5bc155 | ||
|
|
bc1f9db653 | ||
|
|
6699d3eca0 | ||
|
|
40824a187d | ||
|
|
323c25d83b | ||
|
|
8d8951475c | ||
|
|
d6db750797 | ||
|
|
ecc551b44e | ||
|
|
d741b403a9 | ||
|
|
0fee29559f | ||
|
|
d146972671 | ||
|
|
c9d07adbbe | ||
|
|
993eb40481 | ||
|
|
670f49309c | ||
|
|
b7381d8088 | ||
|
|
bac959bc6f | ||
|
|
4c9081a934 | ||
|
|
7fcadcd7a2 | ||
|
|
97d570b343 | ||
|
|
f9e007ca2b | ||
|
|
a63048d7e2 | ||
|
|
ca721f9d67 | ||
|
|
18924e43da | ||
|
|
5d3411f412 | ||
|
|
564fca8c9b | ||
|
|
d59b4b0ad7 | ||
|
|
49aef77f3f | ||
|
|
daa9e07e33 | ||
|
|
4cbfe7fb0e | ||
|
|
5f7aa2fbdb | ||
|
|
95a62a5dde | ||
|
|
d548cb2e44 | ||
|
|
813cff612c | ||
|
|
101127273c | ||
|
|
b174dec0d2 | ||
|
|
4463c21c98 | ||
|
|
e7dbdf3489 | ||
|
|
4f58197edb | ||
|
|
0a3f7da7e7 | ||
|
|
ac7c8adea2 | ||
|
|
692e0ec00d | ||
|
|
773285054d | ||
|
|
5d8cdb429b | ||
|
|
fb745777c3 | ||
|
|
7a94f6b4ae | ||
|
|
c4eb008d58 | ||
|
|
882b8e1bf8 | ||
|
|
a021c86871 | ||
|
|
bbd8c1e745 | ||
|
|
0c4c8703a3 | ||
|
|
74308fcaa5 | ||
|
|
87f7c812c7 | ||
|
|
2d920da737 | ||
|
|
0f9be64d6c | ||
|
|
ae33c82268 | ||
|
|
53dda7cd32 | ||
|
|
f6096d21db | ||
|
|
1f291a2d79 | ||
|
|
8b159bacd8 | ||
|
|
e449aae6c8 | ||
|
|
6b5615ece9 | ||
|
|
781e50cdbe | ||
|
|
e9cdef65e6 | ||
|
|
6e0d9b8ca0 | ||
|
|
031015b332 | ||
|
|
b4f34b87d6 | ||
|
|
de8ad56e60 | ||
|
|
b65f25fcfe | ||
|
|
5ad8372e16 | ||
|
|
92eeeaf14f | ||
|
|
f14701ffb7 | ||
|
|
672cd4d59c | ||
|
|
a7c91796b3 | ||
|
|
5a9fdffd7d | ||
|
|
e154413b1d | ||
|
|
541e5ca9fe | ||
|
|
418222cd6f | ||
|
|
48f240703f | ||
|
|
b595488487 | ||
|
|
e7322a4507 | ||
|
|
c67de94b3d | ||
|
|
9621b59573 | ||
|
|
e7a03d311c | ||
|
|
af8225e2da | ||
|
|
49e9f96327 | ||
|
|
cbaf45084e | ||
|
|
03799bf258 | ||
|
|
4344f5eef9 | ||
|
|
4872ec634c | ||
|
|
85613cfadc | ||
|
|
4a59e6012d | ||
|
|
ffded2ccac | ||
|
|
15b39af92e | ||
|
|
4ed3aa1f1c | ||
|
|
7d0d9a3827 | ||
|
|
b9fa4ffc00 | ||
|
|
f40cbf816e | ||
|
|
3ee45691ab | ||
|
|
8a68c625fb | ||
|
|
8eb9a9971b | ||
|
|
44e3ae59e4 | ||
|
|
8901da68c7 | ||
|
|
fa54329711 | ||
|
|
cddbb0e970 | ||
|
|
da50f0e9e3 | ||
|
|
28c42d04b6 | ||
|
|
5d9622db21 | ||
|
|
7e8db63882 | ||
|
|
519d8f7385 | ||
|
|
ece83eb637 | ||
|
|
06282c0363 | ||
|
|
a0c5893a98 | ||
|
|
fbec685eb5 | ||
|
|
0b578fa767 | ||
|
|
ae331cfc9a | ||
|
|
575be16d3e | ||
|
|
d5db0c6c1b | ||
|
|
1fec781251 | ||
|
|
08de904e21 | ||
|
|
7a1d2e41a1 | ||
|
|
1b650622ea | ||
|
|
88035b9815 | ||
|
|
ae7e143537 | ||
|
|
b230645d53 | ||
|
|
9b270f783e | ||
|
|
ac54df366b | ||
|
|
a17a45c748 | ||
|
|
a488eb6d5d | ||
|
|
f3ff0a730a | ||
|
|
966ecd00bd | ||
|
|
4b3aedd5d0 | ||
|
|
f2c5916205 | ||
|
|
2219c37d7f | ||
|
|
b7344af313 | ||
|
|
9bccda0a79 | ||
|
|
013bb5cac3 | ||
|
|
e8afd48c67 | ||
|
|
2ef22124cd | ||
|
|
6b9d2dbb64 | ||
|
|
658a1391f8 | ||
|
|
4cf8cf7d18 | ||
|
|
724c9a4a2c | ||
|
|
ec4484282c | ||
|
|
c044ed36af | ||
|
|
91616ae9b6 | ||
|
|
2fe0569bd6 | ||
|
|
364968a6b4 | ||
|
|
194b72f180 | ||
|
|
68efc9b9df | ||
|
|
fdd1a5dde8 | ||
|
|
4151db6c94 | ||
|
|
4706f894e3 | ||
|
|
bf75d50baf | ||
|
|
983bf34807 | ||
|
|
b0f7ae1223 | ||
|
|
447333c3f9 | ||
|
|
29c4f2f0e8 | ||
|
|
ad325960e7 | ||
|
|
c367cc1c59 | ||
|
|
35526b53f9 | ||
|
|
3656335666 | ||
|
|
16bd9c2743 | ||
|
|
a79cb5a9fc | ||
|
|
d2eae3b072 | ||
|
|
087ffb26ba | ||
|
|
8427626e56 | ||
|
|
5a0931d3cf | ||
|
|
156b7f365e | ||
|
|
66b5bd9618 | ||
|
|
67a1aee306 | ||
|
|
c58562a304 | ||
|
|
a3c5f1f6f2 | ||
|
|
9c81e74061 | ||
|
|
1f3403677c | ||
|
|
a4c9e294da | ||
|
|
0689e58ca2 | ||
|
|
1450ffca18 | ||
|
|
2b390a4ca3 | ||
|
|
3d1f495bd5 | ||
|
|
9b06c0699c | ||
|
|
fbc45699c1 | ||
|
|
83d82c2519 | ||
|
|
31be615f7b | ||
|
|
17048a586a | ||
|
|
071be5f700 | ||
|
|
01a4a6a528 | ||
|
|
2b9620b6a6 | ||
|
|
7ffec104dc | ||
|
|
f191947ad5 | ||
|
|
63a8b43119 | ||
|
|
40b7cab3ed | ||
|
|
eb44bdc3b3 | ||
|
|
75f951fec9 | ||
|
|
39bc1a72dc | ||
|
|
43c4223413 | ||
|
|
c7fd66cf97 | ||
|
|
1b05e33202 | ||
|
|
1ea0c7570f | ||
|
|
bf42cfdcf2 | ||
|
|
5ad45a4098 | ||
|
|
eed2facb66 | ||
|
|
47ad0703b2 | ||
|
|
d0ac15a275 | ||
|
|
9f5f1bcf10 | ||
|
|
64c78fadc1 | ||
|
|
3a48d13c07 | ||
|
|
7bb746dfab | ||
|
|
4bc72ccca4 | ||
|
|
e6d7e5cdae | ||
|
|
b3fa99dd2f | ||
|
|
69fe3e3b1a | ||
|
|
6674f1e803 | ||
|
|
c16a25faef | ||
|
|
19eba5c6bc | ||
|
|
f91accdce8 | ||
|
|
6c6dc55dc0 | ||
|
|
3a65ed4c25 | ||
|
|
e90ecdaeea | ||
|
|
5136c15833 | ||
|
|
f0f26bbfaf | ||
|
|
838687fb2e | ||
|
|
09823dbb4a | ||
|
|
0daf4669ad | ||
|
|
988ec79bc7 | ||
|
|
d43c2133b8 | ||
|
|
eed06a78f2 | ||
|
|
e9fab9ada3 | ||
|
|
03543a0cbb | ||
|
|
39bb912aab | ||
|
|
2f62b8ef06 | ||
|
|
731866c577 | ||
|
|
d0705a9406 | ||
|
|
26a2b35a3b | ||
|
|
2514c8b21f | ||
|
|
696039e1ce | ||
|
|
e524fa5b6b | ||
|
|
5d0eeae04c | ||
|
|
f945422246 | ||
|
|
348907f7d1 | ||
|
|
b7677c81d2 | ||
|
|
5cf20d935d | ||
|
|
24fea7b8a8 | ||
|
|
cd006d642b | ||
|
|
04786023b0 | ||
|
|
b00e5e3f64 | ||
|
|
109e453bf2 | ||
|
|
8e8bc5aa0f | ||
|
|
4c3a7c492b | ||
|
|
bc809d78d3 | ||
|
|
c61249d648 | ||
|
|
3f23985a97 | ||
|
|
06c29564cc | ||
|
|
3967fde405 | ||
|
|
cd06eee030 | ||
|
|
53385fdfea | ||
|
|
289a7e3859 | ||
|
|
1ce90fa6c0 | ||
|
|
cf1722110e | ||
|
|
877832c713 | ||
|
|
3d7d9b4e7c | ||
|
|
8477cc4cd6 | ||
|
|
a5a6da8a45 | ||
|
|
e8a7e2ebb5 | ||
|
|
067a992378 | ||
|
|
33056c913d | ||
|
|
4ae1296314 | ||
|
|
adf9d67030 | ||
|
|
0e732bf499 | ||
|
|
77e36c7d68 | ||
|
|
5dd90996b9 | ||
|
|
61d08d1870 | ||
|
|
9d5f4059bf | ||
|
|
085a3b0fab | ||
|
|
5979052337 | ||
|
|
7d62e72024 | ||
|
|
c7d43f1685 | ||
|
|
441fb4a891 | ||
|
|
662a448080 | ||
|
|
49cc358154 | ||
|
|
90a3769d33 | ||
|
|
c661322a36 | ||
|
|
d1252d4ea3 | ||
|
|
658c7e27d0 | ||
|
|
d97847e9ab | ||
|
|
720ea089b3 | ||
|
|
25387c5b6c | ||
|
|
6b90403550 | ||
|
|
d78ab048d4 | ||
|
|
d3f8dfe65c | ||
|
|
67fe365ae0 | ||
|
|
e16235c1ca | ||
|
|
6f7ba83168 | ||
|
|
0a5cca899e | ||
|
|
c301e3cbb4 | ||
|
|
98c3129424 | ||
|
|
90c4107199 | ||
|
|
ab72536248 | ||
|
|
ea67f17974 | ||
|
|
0434e16762 | ||
|
|
1c92ef83e5 | ||
|
|
81f9837e37 | ||
|
|
d221a0a449 | ||
|
|
de96b6ae87 | ||
|
|
cc22702ea5 | ||
|
|
5772a8ac93 | ||
|
|
47f4b85435 | ||
|
|
37590c8ffe | ||
|
|
3f97d65224 | ||
|
|
cf024e228f | ||
|
|
3cdb464feb | ||
|
|
13d9e0be4d | ||
|
|
764600704d | ||
|
|
14ca5f15f2 | ||
|
|
fac0ad7493 | ||
|
|
d510ad01c6 | ||
|
|
76bbd0f9ca | ||
|
|
ec874f7f21 | ||
|
|
14da23b06f | ||
|
|
a1e3a28666 | ||
|
|
31eb4c67ba | ||
|
|
9e3893fd62 | ||
|
|
8cb9262b09 | ||
|
|
d65b140d73 | ||
|
|
bf65a7385c | ||
|
|
faf23c053d | ||
|
|
8b33c6e06e | ||
|
|
0845218da8 | ||
|
|
18889939c2 | ||
|
|
7bef408598 | ||
|
|
d29912608d | ||
|
|
6d868f689c | ||
|
|
48eade763a | ||
|
|
464a04a2cb | ||
|
|
56936cf485 | ||
|
|
0b26d24c9b | ||
|
|
eb15897b1a | ||
|
|
5767479c21 | ||
|
|
d958a91ce9 | ||
|
|
367de94f31 | ||
|
|
7348cb9dc9 | ||
|
|
a46fb0df86 | ||
|
|
437242169d | ||
|
|
f47df1eebf | ||
|
|
6763a7fa39 | ||
|
|
1bc5f18b04 | ||
|
|
0068eef222 | ||
|
|
c24c4add50 | ||
|
|
4bba4aaebf | ||
|
|
9dcb5b7da4 | ||
|
|
3ab187a4fe | ||
|
|
6d5a3278cc | ||
|
|
ac8a51290b | ||
|
|
0a3953524a | ||
|
|
7c5d54f8aa | ||
|
|
b518259f57 | ||
|
|
7eb2c2a2f7 | ||
|
|
7472a2bb94 | ||
|
|
a4ea7839dc | ||
|
|
352b98db8e | ||
|
|
0aa2ceffec | ||
|
|
cd9efa2e42 | ||
|
|
3768d38b54 | ||
|
|
e71d0b082d | ||
|
|
068bbba570 | ||
|
|
07ddbb76f1 | ||
|
|
e3ea57c96b | ||
|
|
979973b313 | ||
|
|
314a7fc67d | ||
|
|
f7941b6431 | ||
|
|
b114d043f6 | ||
|
|
52e6e35fc9 | ||
|
|
8da890a1fc | ||
|
|
f61acde6de | ||
|
|
0dfb6c99e1 | ||
|
|
9cf9ec5341 | ||
|
|
f26a4f897c | ||
|
|
eda4592f19 | ||
|
|
110d1a8fcf | ||
|
|
ec4b36b299 | ||
|
|
94da1308ac | ||
|
|
eae13f705f | ||
|
|
83e0b93938 | ||
|
|
6b7f7a2477 | ||
|
|
dde1d21cbc | ||
|
|
1486e40f14 | ||
|
|
e8d0163aa4 | ||
|
|
c36fadee70 | ||
|
|
a3eba815dd | ||
|
|
69bf4d53e1 | ||
|
|
8855e16230 | ||
|
|
4ed77a940c | ||
|
|
eb26dcd516 | ||
|
|
a6c5a85639 | ||
|
|
92e9264230 | ||
|
|
6e09f01714 | ||
|
|
9d534d5a8f | ||
|
|
88d7bccd02 | ||
|
|
574b75fac0 | ||
|
|
a49ab221d9 | ||
|
|
f685aca18e | ||
|
|
ba9aed84aa | ||
|
|
d33a27656c | ||
|
|
f24b74f71b | ||
|
|
3422fa5c5a | ||
|
|
9d4bde7f96 | ||
|
|
d8a25f55e4 | ||
|
|
61c6eb0b4f | ||
|
|
dbe2770682 | ||
|
|
668cbf4ee0 | ||
|
|
3f11b185a8 | ||
|
|
0a4427f9c3 | ||
|
|
e0139185c8 | ||
|
|
eac55d849c | ||
|
|
61d55b4223 | ||
|
|
3c076bfcf6 | ||
|
|
1ac986b7c8 | ||
|
|
316121ba8f | ||
|
|
4a46726cc9 | ||
|
|
71abf3beec | ||
|
|
2b84053011 | ||
|
|
b20aa9a35c | ||
|
|
d81fa77d1f | ||
|
|
d7fc37cd42 | ||
|
|
9bf2792c7f | ||
|
|
6f0e053f4d | ||
|
|
9f94b00925 | ||
|
|
f7deeb0db4 | ||
|
|
5d0360ccec | ||
|
|
a9f3be9f45 | ||
|
|
ba325a6012 | ||
|
|
76e78d358f | ||
|
|
894787bdfd | ||
|
|
67101751c8 | ||
|
|
e59e6f463c | ||
|
|
996ab61dab | ||
|
|
c4b4d67d78 | ||
|
|
3576c2f101 | ||
|
|
f2cf982ea8 | ||
|
|
699df07613 | ||
|
|
44eb2dc290 | ||
|
|
e334a8c0f4 | ||
|
|
247e5fcc6c | ||
|
|
295a8493b8 | ||
|
|
4ba9c4b1a5 | ||
|
|
44056043b1 | ||
|
|
232e9fde09 | ||
|
|
4f12814893 | ||
|
|
00eb04db58 | ||
|
|
61c13655d3 | ||
|
|
a90c438655 | ||
|
|
e6f2d824ab | ||
|
|
71278ff7ea | ||
|
|
b664846030 | ||
|
|
6bbbfa06d1 | ||
|
|
1ad0628ca3 | ||
|
|
13b6aab7c1 | ||
|
|
67836213c5 | ||
|
|
43d2010960 | ||
|
|
c0c9185a09 | ||
|
|
9cb33b519f | ||
|
|
081d2f1e51 | ||
|
|
e2d503456f | ||
|
|
ca16d85258 | ||
|
|
157ae6fb72 | ||
|
|
e5fe2c100e | ||
|
|
fe5aee2619 | ||
|
|
f59e5b2df9 | ||
|
|
7cda5e738f | ||
|
|
45df360e4c | ||
|
|
0ba2c09787 | ||
|
|
ffd50e318a | ||
|
|
13c3111163 | ||
|
|
35121f26fd | ||
|
|
7ebc603963 | ||
|
|
68f98491d5 | ||
|
|
0229c0fd0c | ||
|
|
e8da9ee4fb | ||
|
|
b13f40df51 | ||
|
|
9ca3739465 | ||
|
|
8cbcadaca2 | ||
|
|
327a554d42 | ||
|
|
248eb13ab9 | ||
|
|
77ebf65c7d | ||
|
|
2f524c7a80 | ||
|
|
eba6ffb37b | ||
|
|
9171e2b2e1 | ||
|
|
620567e435 | ||
|
|
2c95df4271 | ||
|
|
2030b481bf | ||
|
|
f1a4721a6a | ||
|
|
a3c17034c0 | ||
|
|
d35155ca66 | ||
|
|
31971b2746 | ||
|
|
4afbd9da01 | ||
|
|
d464c1ea68 | ||
|
|
f085a0ef25 | ||
|
|
7bcd2dd768 | ||
|
|
625f0060a1 | ||
|
|
aa9896031d | ||
|
|
d888ecaf11 | ||
|
|
9e86c44f7c | ||
|
|
083671e4b3 | ||
|
|
131e8711aa | ||
|
|
12dfbb7255 | ||
|
|
8e992a324c | ||
|
|
9fac7065a7 | ||
|
|
8a53949f67 | ||
|
|
27172dd1bd | ||
|
|
fe81ad3fc8 | ||
|
|
bc6a6e959b | ||
|
|
0e06c57efe | ||
|
|
ed7101ba1e | ||
|
|
da019c8425 | ||
|
|
f476b2b726 | ||
|
|
add9e55493 | ||
|
|
e0ad6a2b3b | ||
|
|
f85e2ddb15 | ||
|
|
a770cc1128 | ||
|
|
3c6953845c | ||
|
|
02d1878a36 | ||
|
|
a58e3049b9 | ||
|
|
f007d90076 | ||
|
|
2338455076 | ||
|
|
e7382fd43d | ||
|
|
a884e36b96 | ||
|
|
2c6ce2fd8c | ||
|
|
baef2da03d | ||
|
|
2f9bc39eb6 | ||
|
|
5232ebe989 | ||
|
|
399c6c80ed | ||
|
|
f943331e39 | ||
|
|
76ba65a113 | ||
|
|
611b1b6911 | ||
|
|
ef1e35d585 | ||
|
|
e541e6dd80 | ||
|
|
fda9e74972 | ||
|
|
411b4b0649 | ||
|
|
cd993671cf | ||
|
|
3270288031 | ||
|
|
8781ac5f64 | ||
|
|
db7685259e | ||
|
|
9f745ec83e | ||
|
|
b1857508f7 | ||
|
|
204f9c5d8e | ||
|
|
6809d46ab6 | ||
|
|
7f9d5d07f8 | ||
|
|
3a1bbdbe3a | ||
|
|
27577e9d61 | ||
|
|
ffd1e7bc33 | ||
|
|
158a7bbc34 | ||
|
|
584dc47da5 | ||
|
|
193840b237 | ||
|
|
d4817a5669 | ||
|
|
5d9fc6091a | ||
|
|
b69dbc2224 | ||
|
|
665aa4c546 | ||
|
|
70cbbf5b07 | ||
|
|
301d978d9c | ||
|
|
81335aa1aa | ||
|
|
82b7c9786c | ||
|
|
cf63bccfd7 | ||
|
|
ec709e339b | ||
|
|
5de150b8dd | ||
|
|
915626de9d | ||
|
|
caec4ef96c | ||
|
|
f0a17d82d9 | ||
|
|
7945a7c626 | ||
|
|
e4a4d42bca | ||
|
|
4f3c778b4d | ||
|
|
9e4dc64fa9 | ||
|
|
abf3a65695 | ||
|
|
c6072ff434 | ||
|
|
9776fb8d68 | ||
|
|
70f9b88e45 | ||
|
|
1cdddd93ad | ||
|
|
3f0af19ed3 | ||
|
|
33deb1da3f | ||
|
|
1184a28a05 | ||
|
|
7baaa05683 | ||
|
|
3833b1e292 | ||
|
|
6348eafbda | ||
|
|
dd220e61be | ||
|
|
b4f892cf42 | ||
|
|
60a3745e50 | ||
|
|
1a135af7de | ||
|
|
79b76726db | ||
|
|
2554c37964 | ||
|
|
8abaea382d | ||
|
|
2c59b3342c | ||
|
|
87b3a2ef99 | ||
|
|
fa040fc959 | ||
|
|
29afecdbde | ||
|
|
6cb07e203b | ||
|
|
1cd78bf94a | ||
|
|
e27246c3f9 | ||
|
|
507de0fcbd | ||
|
|
490df18fd5 | ||
|
|
9ac0314d7a | ||
|
|
06d9079be1 | ||
|
|
b276ede6e5 | ||
|
|
19b9557c19 | ||
|
|
ca5e1e0f1b | ||
|
|
2842defe7f | ||
|
|
de4d8429be | ||
|
|
ef747055af | ||
|
|
4b72870d49 | ||
|
|
f60535dd68 | ||
|
|
14df798d78 | ||
|
|
70a6d11059 | ||
|
|
5fcd11bec3 | ||
|
|
fd91f87c21 | ||
|
|
686ad72e03 | ||
|
|
1c4d378fc4 | ||
|
|
e8b5d49154 | ||
|
|
d5da7c9bde | ||
|
|
a98ec194be | ||
|
|
479d5aff77 | ||
|
|
77f41a2a29 | ||
|
|
09f548f688 | ||
|
|
6a41932e65 | ||
|
|
e5aa5e298f | ||
|
|
0b81260cab | ||
|
|
38ac238cfa | ||
|
|
fcc557a79d | ||
|
|
3b3e246501 | ||
|
|
85071e8919 | ||
|
|
f3495bc4c0 | ||
|
|
67a724f990 | ||
|
|
35750ebada | ||
|
|
1735814d42 | ||
|
|
8c824ed3d6 | ||
|
|
c9426da64d | ||
|
|
1a82a83e36 | ||
|
|
36e540ed11 | ||
|
|
ba4d9cadc4 | ||
|
|
947656df0f | ||
|
|
66f0f95fd7 | ||
|
|
22539a4ff8 | ||
|
|
bacce134c0 | ||
|
|
8cf41be77f | ||
|
|
7ee4b35aee | ||
|
|
c27bc436da | ||
|
|
2e8256e322 | ||
|
|
ff34760868 | ||
|
|
d05b996c8a | ||
|
|
78bc6657f4 | ||
|
|
edf1840225 | ||
|
|
3496b7b3a0 | ||
|
|
6848d60cad | ||
|
|
267e8f1d33 | ||
|
|
70de524c3a | ||
|
|
3ce765fba0 | ||
|
|
5f89187719 | ||
|
|
07100658a8 | ||
|
|
d283726494 | ||
|
|
40c6f79b5f | ||
|
|
90e3c59bd8 | ||
|
|
3a16cf3081 | ||
|
|
9ced66e990 | ||
|
|
2f1ab0162b | ||
|
|
5a9382d29b | ||
|
|
35e64ae2c6 | ||
|
|
a6d6ff9926 | ||
|
|
1b15643fcd | ||
|
|
c2fc0a30b7 | ||
|
|
eafce5d5f6 | ||
|
|
92a2e3b894 | ||
|
|
6cbedbe184 | ||
|
|
809e766aec | ||
|
|
7f0f90fcce | ||
|
|
6cddc28e9b | ||
|
|
8aba994312 | ||
|
|
6321db5942 | ||
|
|
6ac9de7a11 | ||
|
|
9a93696915 | ||
|
|
5a6f94fe79 | ||
|
|
b7e508870d | ||
|
|
73dc92cedd | ||
|
|
508a66aedd | ||
|
|
01c1840531 | ||
|
|
c24fd2f570 | ||
|
|
3937819305 | ||
|
|
549405ab2f | ||
|
|
f0813b578e | ||
|
|
c64d871a28 | ||
|
|
136ad59fad | ||
|
|
2b04da0c36 | ||
|
|
7f3790bf73 | ||
|
|
62e17cd19e | ||
|
|
cbe77872fa | ||
|
|
100b2aa6da | ||
|
|
01228cc0b7 | ||
|
|
53acc60983 | ||
|
|
133842d6a8 | ||
|
|
99c5c7b990 | ||
|
|
1d659b5c68 | ||
|
|
c7501b747e | ||
|
|
e856f60804 | ||
|
|
3f53670cc2 | ||
|
|
3e7ef5ee17 | ||
|
|
a97c15d0fb | ||
|
|
7f952d9fdf | ||
|
|
398689637d | ||
|
|
3b1a5dd3c0 | ||
|
|
ada0401137 | ||
|
|
3e5990f8ec | ||
|
|
e91d05922a | ||
|
|
fa88edf8c3 | ||
|
|
9be292b845 | ||
|
|
fc1e29111b | ||
|
|
d191f83a62 | ||
|
|
6ae06249cb | ||
|
|
39e283169e | ||
|
|
2e6efab913 | ||
|
|
c3bcfec5e4 | ||
|
|
4037446051 | ||
|
|
40af45bb1c | ||
|
|
20055aa2fa | ||
|
|
44bf3aad29 | ||
|
|
31da9f51f0 | ||
|
|
3b967ee195 | ||
|
|
3a7366a998 | ||
|
|
e4991d81d7 | ||
|
|
398305eb66 | ||
|
|
ea7122b641 | ||
|
|
d625a28112 | ||
|
|
1cf48dfd85 | ||
|
|
639268798b | ||
|
|
db0bdc6bed | ||
|
|
318a12cee6 | ||
|
|
9b7630485f | ||
|
|
681c635f0e | ||
|
|
abd482db4a | ||
|
|
c46eaec046 | ||
|
|
d6942089cd | ||
|
|
009b65cc1d | ||
|
|
56392a20ed | ||
|
|
7b0896a0b9 | ||
|
|
b32bc08b34 | ||
|
|
939093d648 | ||
|
|
55102d4113 | ||
|
|
094425552b | ||
|
|
fe2e171fa1 | ||
|
|
36ffd6b4ee | ||
|
|
015ee05311 | ||
|
|
20f9784881 | ||
|
|
840bed0666 | ||
|
|
7e4e1de68e | ||
|
|
3aab71ea3d | ||
|
|
b9e8ddac2b | ||
|
|
c059e812a0 | ||
|
|
d4230349e3 | ||
|
|
abe0c8e687 | ||
|
|
698e1dd7cf | ||
|
|
df1573abfd | ||
|
|
99d00957b7 | ||
|
|
44e927a69e | ||
|
|
d1313cbd2d | ||
|
|
16635ca9fc | ||
|
|
57c4b71c61 | ||
|
|
31dd8cd9f8 | ||
|
|
993da92199 | ||
|
|
e3c79b3427 | ||
|
|
91bd74198e | ||
|
|
de092922d7 | ||
|
|
1fdc33669b | ||
|
|
a4b142681d | ||
|
|
8e3be68c65 | ||
|
|
e0c2fbbcde | ||
|
|
76d1cd1b4e | ||
|
|
072eaa32ec | ||
|
|
7f68f2fe3b | ||
|
|
c59db39e06 | ||
|
|
d18a6909c1 | ||
|
|
8e96beeda0 | ||
|
|
9504ed500a | ||
|
|
b1408775b3 | ||
|
|
8a84f5fc1d | ||
|
|
c723b3abe8 | ||
|
|
4b96c5736c | ||
|
|
c7bf324e64 | ||
|
|
5ee33814b6 | ||
|
|
ea84621d2f | ||
|
|
d85ff94f03 | ||
|
|
39c4e7c79b | ||
|
|
586364e3b6 | ||
|
|
85849fea41 | ||
|
|
ee21ad836f | ||
|
|
d7745d97f2 | ||
|
|
49b66d8a54 | ||
|
|
52240cc64c | ||
|
|
6732d7f99c | ||
|
|
08c45684de | ||
|
|
f4b22dae90 | ||
|
|
d3f59a8a43 | ||
|
|
5c6c92f286 | ||
|
|
fcf201755c | ||
|
|
42b72d676c | ||
|
|
877b824c3b | ||
|
|
2f540ffc61 | ||
|
|
53fbc39ad1 | ||
|
|
d1df515bcc | ||
|
|
e360a95c23 | ||
|
|
624d506fac | ||
|
|
53e090f035 | ||
|
|
51b47050f9 | ||
|
|
9c7fe72f9c | ||
|
|
e1eee6e3ca | ||
|
|
43fce3ae46 | ||
|
|
018ff600f6 | ||
|
|
5d5f22e672 | ||
|
|
e39e59acb6 | ||
|
|
1d8bf82ef8 | ||
|
|
06e99e2990 | ||
|
|
f7111b6ec1 | ||
|
|
3c570f9e9c | ||
|
|
1dd8c9606f | ||
|
|
5ebd386797 | ||
|
|
177e7b272b | ||
|
|
8cfed54399 | ||
|
|
9aa1a4d11b | ||
|
|
92a12b5617 | ||
|
|
981b3fc48e | ||
|
|
e53093c4b4 | ||
|
|
e7f801c4c4 | ||
|
|
e46b0335ab | ||
|
|
e125f4767f | ||
|
|
7f740e4ad6 | ||
|
|
7cb623e800 | ||
|
|
d53b785a1c | ||
|
|
a7dd3aeaab | ||
|
|
283d49ba35 | ||
|
|
19aab36a4d | ||
|
|
5465f17916 | ||
|
|
efe302b197 | ||
|
|
d0a296208a | ||
|
|
11a2ba63b3 | ||
|
|
55dc9e6a84 | ||
|
|
7f7649f13d | ||
|
|
c4971479f8 | ||
|
|
b0594dbb06 | ||
|
|
d0737eecc5 |
642 changed files with 19933 additions and 8816 deletions
|
|
@ -16,3 +16,4 @@ BraceWrapping:
|
||||||
BreakBeforeBraces: Custom
|
BreakBeforeBraces: Custom
|
||||||
BreakConstructorInitializers: BeforeComma
|
BreakConstructorInitializers: BeforeComma
|
||||||
Cpp11BracedListStyle: false
|
Cpp11BracedListStyle: false
|
||||||
|
QualifierAlignment: Left
|
||||||
|
|
|
||||||
49
.clang-tidy
49
.clang-tidy
|
|
@ -1,23 +1,32 @@
|
||||||
Checks:
|
FormatStyle: file
|
||||||
- modernize-use-using
|
|
||||||
- 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.
|
Checks:
|
||||||
|
"bugprone-*,clang-analyzer-*,cppcoreguidelines-*,hicpp-*,misc-*,modernize-*,performance-*,portability-*,readability-*,
|
||||||
|
-*-magic-numbers,
|
||||||
|
-*-non-private-member-variables-in-classes,
|
||||||
|
-*-special-member-functions,
|
||||||
|
-bugprone-easily-swappable-parameters,
|
||||||
|
-cppcoreguidelines-owning-memory,
|
||||||
|
-cppcoreguidelines-pro-type-static-cast-downcast,
|
||||||
|
-modernize-use-nodiscard,
|
||||||
|
-modernize-use-trailing-return-type,
|
||||||
|
-portability-avoid-pragma-once,
|
||||||
|
-readability-avoid-unconditional-preprocessor-if,
|
||||||
|
-readability-function-cognitive-complexity,
|
||||||
|
-readability-identifier-length,
|
||||||
|
-readability-redundant-access-specifiers"
|
||||||
|
|
||||||
CheckOptions:
|
CheckOptions:
|
||||||
- { key: readability-identifier-naming.ClassCase, value: PascalCase }
|
misc-include-cleaner.MissingIncludes: false
|
||||||
- { key: readability-identifier-naming.EnumCase, value: PascalCase }
|
readability-identifier-naming.DefaultCase: "camelBack"
|
||||||
- { key: readability-identifier-naming.FunctionCase, value: camelCase }
|
readability-identifier-naming.NamespaceCase: "CamelCase"
|
||||||
- { key: readability-identifier-naming.GlobalVariableCase, value: camelCase }
|
readability-identifier-naming.ClassCase: "CamelCase"
|
||||||
- { key: readability-identifier-naming.GlobalFunctionCase, value: camelCase }
|
readability-identifier-naming.ClassConstantCase: "CamelCase"
|
||||||
- { key: readability-identifier-naming.GlobalConstantCase, value: SCREAMING_SNAKE_CASE }
|
readability-identifier-naming.EnumCase: "CamelCase"
|
||||||
- { key: readability-identifier-naming.MacroDefinitionCase, value: SCREAMING_SNAKE_CASE }
|
readability-identifier-naming.EnumConstantCase: "CamelCase"
|
||||||
- { key: readability-identifier-naming.ClassMemberCase, value: camelCase }
|
readability-identifier-naming.MacroDefinitionCase: "UPPER_CASE"
|
||||||
- { key: readability-identifier-naming.PrivateMemberPrefix, value: m_ }
|
readability-identifier-naming.ClassMemberPrefix: "m_"
|
||||||
- { key: readability-identifier-naming.ProtectedMemberPrefix, value: m_ }
|
readability-identifier-naming.StaticConstantPrefix: "s_"
|
||||||
- { key: readability-identifier-naming.PrivateStaticMemberPrefix, value: s_ }
|
readability-identifier-naming.StaticVariablePrefix: "s_"
|
||||||
- { key: readability-identifier-naming.ProtectedStaticMemberPrefix, value: s_ }
|
readability-identifier-naming.GlobalConstantPrefix: "g_"
|
||||||
- { key: readability-identifier-naming.PublicStaticConstantCase, value: SCREAMING_SNAKE_CASE }
|
readability-implicit-bool-conversion.AllowPointerConditions: true
|
||||||
- { key: readability-identifier-naming.EnumConstantCase, value: SCREAMING_SNAKE_CASE }
|
|
||||||
|
|
|
||||||
6
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
6
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
|
|
@ -1,6 +1,6 @@
|
||||||
name: Bug Report
|
name: Bug Report
|
||||||
description: File a bug report
|
description: File a bug report
|
||||||
labels: [bug]
|
labels: ["bug: unconfirmed", "status: needs triage"]
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
|
|
@ -23,14 +23,14 @@ body:
|
||||||
- macOS
|
- macOS
|
||||||
- Linux
|
- Linux
|
||||||
- Other
|
- Other
|
||||||
- type: textarea
|
- type: input
|
||||||
attributes:
|
attributes:
|
||||||
label: Version of Prism Launcher
|
label: Version of Prism Launcher
|
||||||
description: The version of Prism Launcher used in the bug report.
|
description: The version of Prism Launcher used in the bug report.
|
||||||
placeholder: Prism Launcher 5.0
|
placeholder: Prism Launcher 5.0
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: input
|
||||||
attributes:
|
attributes:
|
||||||
label: Version of Qt
|
label: Version of Qt
|
||||||
description: The version of Qt used in the bug report. You can find it in Help -> About Prism Launcher -> About Qt.
|
description: The version of Qt used in the bug report. You can find it in Help -> About Prism Launcher -> About Qt.
|
||||||
|
|
|
||||||
6
.github/ISSUE_TEMPLATE/rfc.yml
vendored
6
.github/ISSUE_TEMPLATE/rfc.yml
vendored
|
|
@ -1,7 +1,7 @@
|
||||||
# Template based on https://gitlab.archlinux.org/archlinux/rfcs/-/blob/0ba3b61e987e197f8d1901709409b8564958f78a/rfcs/0000-template.rst
|
# Template based on https://gitlab.archlinux.org/archlinux/rfcs/-/blob/0ba3b61e987e197f8d1901709409b8564958f78a/rfcs/0000-template.rst
|
||||||
name: Request for Comment (RFC)
|
name: Request for Comment (RFC)
|
||||||
description: Propose a larger change and start a discussion.
|
description: Propose a larger change and start a discussion.
|
||||||
labels: [rfc]
|
labels: ["type: enhancement", "status: needs discussion", "status: needs triage"]
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
|
|
@ -44,8 +44,8 @@ body:
|
||||||
attributes:
|
attributes:
|
||||||
label: Unresolved Questions
|
label: Unresolved Questions
|
||||||
description: |
|
description: |
|
||||||
Are there any portions of your proposal which need to be discussed with the community before the RFC can proceed?
|
Are there any portions of your proposal which need to be discussed with the community before the RFC can proceed?
|
||||||
Be careful here -- an RFC with a lot of remaining questions is likely to be stalled.
|
Be careful here -- an RFC with a lot of remaining questions is likely to be stalled.
|
||||||
If your RFC is mostly unresolved questions and not too much substance, it may not be ready.
|
If your RFC is mostly unresolved questions and not too much substance, it may not be ready.
|
||||||
placeholder: Do a lot of users care about the cat?
|
placeholder: Do a lot of users care about the cat?
|
||||||
validations:
|
validations:
|
||||||
|
|
|
||||||
2
.github/ISSUE_TEMPLATE/suggestion.yml
vendored
2
.github/ISSUE_TEMPLATE/suggestion.yml
vendored
|
|
@ -1,6 +1,6 @@
|
||||||
name: Suggestion
|
name: Suggestion
|
||||||
description: Make a suggestion
|
description: Make a suggestion
|
||||||
labels: [enhancement]
|
labels: ["type: enhancement", "status: needs triage"]
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
|
|
|
||||||
75
.github/actions/package/linux/action.yml
vendored
75
.github/actions/package/linux/action.yml
vendored
|
|
@ -27,6 +27,18 @@ runs:
|
||||||
using: composite
|
using: composite
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
- name: Cleanup Qt installation on Linux
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
rm -rf "$QT_PLUGIN_PATH"/printsupport
|
||||||
|
rm -rf "$QT_PLUGIN_PATH"/sqldrivers
|
||||||
|
rm -rf "$QT_PLUGIN_PATH"/help
|
||||||
|
rm -rf "$QT_PLUGIN_PATH"/designer
|
||||||
|
rm -rf "$QT_PLUGIN_PATH"/qmltooling
|
||||||
|
rm -rf "$QT_PLUGIN_PATH"/qmlls
|
||||||
|
rm -rf "$QT_PLUGIN_PATH"/qmllint
|
||||||
|
rm -rf "$QT_PLUGIN_PATH"/platformthemes/libqgtk3.so
|
||||||
|
|
||||||
- name: Setup build variables
|
- name: Setup build variables
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
|
|
@ -52,32 +64,52 @@ runs:
|
||||||
- name: Package AppImage
|
- name: Package AppImage
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
VERSION: ${{ inputs.version }}
|
VERSION: ${{ github.ref_type == 'tag' && github.ref_name || inputs.version }}
|
||||||
BUILD_DIR: build
|
BUILD_DIR: build
|
||||||
INSTALL_APPIMAGE_DIR: install-appdir
|
INSTALL_APPIMAGE_DIR: install-appdir
|
||||||
|
|
||||||
GPG_PRIVATE_KEY: ${{ inputs.gpg-private-key }}
|
GPG_PRIVATE_KEY: ${{ inputs.gpg-private-key }}
|
||||||
run: |
|
run: |
|
||||||
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }} --prefix ${{ env.INSTALL_APPIMAGE_DIR }}/usr
|
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }} --prefix ${{ env.INSTALL_APPIMAGE_DIR }}
|
||||||
|
|
||||||
cp ${{ env.INSTALL_APPIMAGE_DIR }}/usr/share/metainfo/org.prismlauncher.PrismLauncher.{metainfo,appdata}.xml
|
|
||||||
|
|
||||||
if [ '${{ inputs.gpg-private-key-id }}' != '' ]; then
|
if [ '${{ inputs.gpg-private-key-id }}' != '' ]; then
|
||||||
echo "$GPG_PRIVATE_KEY" > privkey.asc
|
echo "$GPG_PRIVATE_KEY" > privkey.asc
|
||||||
gpg --import privkey.asc
|
gpg --import privkey.asc
|
||||||
gpg --export --armor 9C7A2C9B62603299 > pubkey.asc
|
gpg --export --armor ${{ inputs.gpg-private-key-id }} > pubkey.asc
|
||||||
else
|
else
|
||||||
echo ":warning: Skipped code signing for Linux AppImage, as gpg key was not present." >> $GITHUB_STEP_SUMMARY
|
echo ":warning: Skipped code signing for Linux AppImage, as gpg key was not present." >> $GITHUB_STEP_SUMMARY
|
||||||
fi
|
fi
|
||||||
|
|
||||||
appimagetool -s deploy "$INSTALL_APPIMAGE_DIR"/usr/share/applications/*.desktop
|
sharun lib4bin \
|
||||||
cp ~/bin/AppImageUpdate.AppImage "$INSTALL_APPIMAGE_DIR"/usr/bin/
|
--hard-links \
|
||||||
# FIXME(@getchoo): Validate AppStream information when https://github.com/probonopd/go-appimage/pull/379 is merged
|
--with-hooks \
|
||||||
|
--dst-dir "$INSTALL_APPIMAGE_DIR" \
|
||||||
|
"$INSTALL_APPIMAGE_DIR"/bin/* "$QT_PLUGIN_PATH"/*/*.so
|
||||||
|
|
||||||
|
cp ~/bin/AppImageUpdate.AppImage "$INSTALL_APPIMAGE_DIR"/bin/
|
||||||
|
# FIXME(@getchoo): gamemode doesn't seem to be very portable with DBus. Find a way to make it work!
|
||||||
|
find "$INSTALL_APPIMAGE_DIR" -name '*gamemode*' -exec rm {} +
|
||||||
|
|
||||||
|
#disable OpenGL and Vulkan launcher features until https://github.com/VHSgunzo/sharun/issues/35
|
||||||
|
echo "PRISMLAUNCHER_DISABLE_GLVULKAN=1" >> "$INSTALL_APPIMAGE_DIR"/.env
|
||||||
|
#makes the launcher use portals for file picking
|
||||||
|
echo "QT_QPA_PLATFORMTHEME=xdgdesktopportal" >> "$INSTALL_APPIMAGE_DIR"/.env
|
||||||
|
ln -s org.prismlauncher.PrismLauncher.metainfo.xml "$INSTALL_APPIMAGE_DIR"/share/metainfo/org.prismlauncher.PrismLauncher.appdata.xml
|
||||||
|
ln -s share/applications/org.prismlauncher.PrismLauncher.desktop "$INSTALL_APPIMAGE_DIR"
|
||||||
|
ln -s share/icons/hicolor/256x256/apps/org.prismlauncher.PrismLauncher.png "$INSTALL_APPIMAGE_DIR"
|
||||||
|
mv "$INSTALL_APPIMAGE_DIR"/{sharun,AppRun}
|
||||||
|
ls -la "$INSTALL_APPIMAGE_DIR"
|
||||||
|
|
||||||
|
if [[ "${{ github.ref_type }}" == "tag" ]]; then
|
||||||
|
APPIMAGE_DEST="PrismLauncher-Linux-$APPIMAGE_ARCH.AppImage"
|
||||||
|
else
|
||||||
|
APPIMAGE_DEST="PrismLauncher-Linux-$VERSION-${{ inputs.build-type }}-$APPIMAGE_ARCH.AppImage"
|
||||||
|
fi
|
||||||
|
|
||||||
mkappimage \
|
mkappimage \
|
||||||
--no-appstream \
|
|
||||||
--updateinformation "gh-releases-zsync|${{ github.repository_owner }}|${{ github.event.repository.name }}|latest|PrismLauncher-Linux-$APPIMAGE_ARCH.AppImage.zsync" \
|
--updateinformation "gh-releases-zsync|${{ github.repository_owner }}|${{ github.event.repository.name }}|latest|PrismLauncher-Linux-$APPIMAGE_ARCH.AppImage.zsync" \
|
||||||
"$INSTALL_APPIMAGE_DIR" \
|
"$INSTALL_APPIMAGE_DIR" \
|
||||||
"PrismLauncher-Linux-$VERSION-${{ inputs.build-type }}-$APPIMAGE_ARCH.AppImage"
|
"$APPIMAGE_DEST"
|
||||||
|
|
||||||
- name: Package portable tarball
|
- name: Package portable tarball
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
@ -89,28 +121,33 @@ runs:
|
||||||
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }} --prefix ${{ env.INSTALL_PORTABLE_DIR }}
|
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }} --prefix ${{ env.INSTALL_PORTABLE_DIR }}
|
||||||
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable
|
cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable
|
||||||
|
|
||||||
#the linked cmark .so is of the version that ubuntu uses, so without this it breaks on most updated distros
|
sharun lib4bin \
|
||||||
mkdir ${{ env.INSTALL_PORTABLE_DIR }}/lib
|
--with-hooks \
|
||||||
cp /lib/$APPIMAGE_ARCH-linux-gnu/libcmark.so.0.* ${{ env.INSTALL_PORTABLE_DIR }}/lib
|
--hard-links \
|
||||||
|
--dst-dir "$INSTALL_PORTABLE_DIR" \
|
||||||
|
"$INSTALL_PORTABLE_DIR"/bin/* "$QT_PLUGIN_PATH"/*/*.so
|
||||||
|
|
||||||
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
|
# FIXME(@getchoo): gamemode doesn't seem to be very portable with DBus. Find a way to make it work!
|
||||||
|
find "$INSTALL_PORTABLE_DIR" -name '*gamemode*' -exec rm {} +
|
||||||
|
|
||||||
|
for l in $(find ${{ env.INSTALL_PORTABLE_DIR }} -type f -o -type l); do l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_PORTABLE_DIR }}/}; l=${l#./}; echo $l; done > ${{ env.INSTALL_PORTABLE_DIR }}/manifest.txt
|
||||||
cd ${{ env.INSTALL_PORTABLE_DIR }}
|
cd ${{ env.INSTALL_PORTABLE_DIR }}
|
||||||
tar -czf ../PrismLauncher-portable.tar.gz *
|
tar -czf ../PrismLauncher-portable.tar.gz *
|
||||||
|
|
||||||
- name: Upload binary tarball
|
- name: Upload binary tarball
|
||||||
uses: actions/upload-artifact@v6
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ inputs.artifact-name }}-Qt6-Portable-${{ inputs.version }}-${{ inputs.build-type }}
|
name: PrismLauncher-${{ inputs.artifact-name }}-Qt6-Portable-${{ inputs.version }}-${{ inputs.build-type }}
|
||||||
path: PrismLauncher-portable.tar.gz
|
path: PrismLauncher-portable.tar.gz
|
||||||
|
|
||||||
- name: Upload AppImage
|
- name: Upload AppImage
|
||||||
uses: actions/upload-artifact@v6
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ runner.os }}-${{ inputs.version }}-${{ inputs.build-type }}-${{ env.APPIMAGE_ARCH }}.AppImage
|
name: PrismLauncher-${{ runner.os }}-${{ inputs.version }}-${{ inputs.build-type }}-${{ env.APPIMAGE_ARCH }}.AppImage
|
||||||
path: PrismLauncher-${{ runner.os }}-${{ inputs.version }}-${{ inputs.build-type }}-${{ env.APPIMAGE_ARCH }}.AppImage
|
path: PrismLauncher-${{ runner.os }}-*${{ env.APPIMAGE_ARCH }}.AppImage
|
||||||
|
|
||||||
- name: Upload AppImage Zsync
|
- name: Upload AppImage Zsync
|
||||||
uses: actions/upload-artifact@v6
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ runner.os }}-${{ inputs.version }}-${{ inputs.build-type }}-${{ env.APPIMAGE_ARCH }}.AppImage.zsync
|
name: PrismLauncher-${{ runner.os }}-${{ inputs.version }}-${{ inputs.build-type }}-${{ env.APPIMAGE_ARCH }}.AppImage.zsync
|
||||||
path: PrismLauncher-${{ runner.os }}-${{ inputs.version }}-${{ inputs.build-type }}-${{ env.APPIMAGE_ARCH }}.AppImage.zsync
|
path: PrismLauncher-${{ runner.os }}-*${{ env.APPIMAGE_ARCH }}.AppImage.zsync
|
||||||
|
|
|
||||||
32
.github/actions/package/macos/action.yml
vendored
32
.github/actions/package/macos/action.yml
vendored
|
|
@ -96,16 +96,36 @@ runs:
|
||||||
fi
|
fi
|
||||||
ditto -c -k --sequesterRsrc --keepParent "Prism Launcher.app" ../PrismLauncher.zip
|
ditto -c -k --sequesterRsrc --keepParent "Prism Launcher.app" ../PrismLauncher.zip
|
||||||
|
|
||||||
|
- name: Create DMG
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
INSTALL_DIR: install
|
||||||
|
run: |
|
||||||
|
cd ${{ env.INSTALL_DIR }}
|
||||||
|
|
||||||
|
mkdir -p src
|
||||||
|
cp -R "Prism Launcher.app" src/
|
||||||
|
|
||||||
|
ln -s /Applications src/
|
||||||
|
|
||||||
|
hdiutil create \
|
||||||
|
-volname "Prism Launcher ${{ inputs.version }}" \
|
||||||
|
-srcfolder src \
|
||||||
|
-ov -format ULMO \
|
||||||
|
"../PrismLauncher.dmg"
|
||||||
|
|
||||||
- name: Make Sparkle signature
|
- name: Make Sparkle signature
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
if [ '${{ inputs.sparkle-ed25519-key }}' != '' ]; then
|
if [ '${{ inputs.sparkle-ed25519-key }}' != '' ]; then
|
||||||
echo '${{ inputs.sparkle-ed25519-key }}' > ed25519-priv.pem
|
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)
|
signature_zip=$(/opt/homebrew/opt/openssl@3/bin/openssl pkeyutl -sign -rawin -in ${{ github.workspace }}/PrismLauncher.zip -inkey ed25519-priv.pem | openssl base64 | tr -d \\n)
|
||||||
|
signature_dmg=$(/opt/homebrew/opt/openssl@3/bin/openssl pkeyutl -sign -rawin -in ${{ github.workspace }}/PrismLauncher.dmg -inkey ed25519-priv.pem | openssl base64 | tr -d \\n)
|
||||||
rm ed25519-priv.pem
|
rm ed25519-priv.pem
|
||||||
cat >> $GITHUB_STEP_SUMMARY << EOF
|
cat >> $GITHUB_STEP_SUMMARY << EOF
|
||||||
### Artifact Information :information_source:
|
### Artifact Information :information_source:
|
||||||
- :memo: Sparkle Signature (ed25519): \`$signature\`
|
- :memo: Sparkle Signature (ed25519): \`$signature_zip\` (ZIP)
|
||||||
|
- :memo: Sparkle Signature (ed25519): \`$signature_dmg\` (DMG)
|
||||||
EOF
|
EOF
|
||||||
else
|
else
|
||||||
cat >> $GITHUB_STEP_SUMMARY << EOF
|
cat >> $GITHUB_STEP_SUMMARY << EOF
|
||||||
|
|
@ -115,7 +135,13 @@ runs:
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Upload binary tarball
|
- name: Upload binary tarball
|
||||||
uses: actions/upload-artifact@v6
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ inputs.artifact-name }}-${{ inputs.version }}-${{ inputs.build-type }}
|
name: PrismLauncher-${{ inputs.artifact-name }}-${{ inputs.version }}-${{ inputs.build-type }}
|
||||||
path: PrismLauncher.zip
|
path: PrismLauncher.zip
|
||||||
|
|
||||||
|
- name: Upload disk image
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: PrismLauncher-${{ inputs.artifact-name }}-${{ inputs.version }}-${{ inputs.build-type }}.dmg
|
||||||
|
path: PrismLauncher.dmg
|
||||||
|
|
|
||||||
36
.github/actions/package/windows/action.yml
vendored
36
.github/actions/package/windows/action.yml
vendored
|
|
@ -54,32 +54,33 @@ runs:
|
||||||
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
|
Get-ChildItem ${{ env.INSTALL_DIR }} -Recurse | ForEach FullName | Resolve-Path -Relative | %{ $_.TrimStart('.\') } | %{ $_.TrimStart('${{ env.INSTALL_DIR }}') } | %{ $_.TrimStart('\') } | Out-File -FilePath ${{ env.INSTALL_DIR }}/manifest.txt
|
||||||
|
|
||||||
- name: Emit warning for unsigned builds
|
- name: Emit warning for unsigned builds
|
||||||
if: ${{ github.ref_name != 'develop' || inputs.azure-client-id == '' }}
|
if: ${{ env.CI_HAS_ACCESS_TO_AZURE == '' || inputs.azure-client-id == '' }}
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
run: |
|
run: |
|
||||||
":warning: Skipped code signing for Windows, as certificate was not present." >> $env:GITHUB_STEP_SUMMARY
|
":warning: Skipped code signing for Windows, as certificate was not present." >> $env:GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
- name: Login to Azure
|
- name: Login to Azure
|
||||||
if: ${{ github.ref_name == 'develop' && inputs.azure-client-id != '' }}
|
if: ${{ env.CI_HAS_ACCESS_TO_AZURE != '' && inputs.azure-client-id != '' }}
|
||||||
uses: azure/login@v2
|
uses: azure/login@v3
|
||||||
with:
|
with:
|
||||||
client-id: ${{ inputs.azure-client-id }}
|
client-id: ${{ inputs.azure-client-id }}
|
||||||
tenant-id: ${{ inputs.azure-tenant-id }}
|
tenant-id: ${{ inputs.azure-tenant-id }}
|
||||||
subscription-id: ${{ inputs.azure-subscription-id }}
|
subscription-id: ${{ inputs.azure-subscription-id }}
|
||||||
|
|
||||||
- name: Sign executables
|
- name: Sign executables
|
||||||
if: ${{ github.ref_name == 'develop' && inputs.azure-client-id != '' }}
|
if: ${{ env.CI_HAS_ACCESS_TO_AZURE != '' && inputs.azure-client-id != '' }}
|
||||||
uses: azure/trusted-signing-action@v0
|
uses: azure/artifact-signing-action@v2
|
||||||
with:
|
with:
|
||||||
endpoint: https://eus.codesigning.azure.net/
|
endpoint: https://eus.codesigning.azure.net/
|
||||||
trusted-signing-account-name: PrismLauncher
|
trusted-signing-account-name: PrismLauncher
|
||||||
certificate-profile-name: PrismLauncher
|
certificate-profile-name: PrismLauncher
|
||||||
|
files-folder: ${{ github.workspace }}\install\
|
||||||
files: |
|
files-folder-filter: dll,exe
|
||||||
${{ github.workspace }}\install\prismlauncher.exe
|
files-folder-recurse: true
|
||||||
${{ github.workspace }}\install\prismlauncher_filelink.exe
|
files-folder-depth: 2
|
||||||
${{ github.workspace }}\install\prismlauncher_updater.exe
|
# recommended in https://github.com/Azure/artifact-signing-action#timestamping-1
|
||||||
|
timestamp-rfc3161: 'http://timestamp.acs.microsoft.com'
|
||||||
|
timestamp-digest: 'SHA256'
|
||||||
# TODO(@getchoo): Is this all really needed???
|
# TODO(@getchoo): Is this all really needed???
|
||||||
# https://github.com/Azure/trusted-signing-action/blob/fc390cf8ed0f14e248a542af1d838388a47c7a7c/docs/OIDC.md
|
# https://github.com/Azure/trusted-signing-action/blob/fc390cf8ed0f14e248a542af1d838388a47c7a7c/docs/OIDC.md
|
||||||
exclude-environment-credential: true
|
exclude-environment-credential: true
|
||||||
|
|
@ -140,8 +141,8 @@ runs:
|
||||||
makensis -NOCD "${{ github.workspace }}/${{ env.BUILD_DIR }}/program_info/win_install.nsi"
|
makensis -NOCD "${{ github.workspace }}/${{ env.BUILD_DIR }}/program_info/win_install.nsi"
|
||||||
|
|
||||||
- name: Sign installer
|
- name: Sign installer
|
||||||
if: ${{ github.ref_name == 'develop' && inputs.azure-client-id != '' }}
|
if: ${{ env.CI_HAS_ACCESS_TO_AZURE != '' && inputs.azure-client-id != '' }}
|
||||||
uses: azure/trusted-signing-action@v0
|
uses: azure/artifact-signing-action@v2
|
||||||
with:
|
with:
|
||||||
endpoint: https://eus.codesigning.azure.net/
|
endpoint: https://eus.codesigning.azure.net/
|
||||||
trusted-signing-account-name: PrismLauncher
|
trusted-signing-account-name: PrismLauncher
|
||||||
|
|
@ -150,6 +151,9 @@ runs:
|
||||||
files: |
|
files: |
|
||||||
${{ github.workspace }}\PrismLauncher-Setup.exe
|
${{ github.workspace }}\PrismLauncher-Setup.exe
|
||||||
|
|
||||||
|
# recommended in https://github.com/Azure/artifact-signing-action#timestamping-1
|
||||||
|
timestamp-rfc3161: 'http://timestamp.acs.microsoft.com'
|
||||||
|
timestamp-digest: 'SHA256'
|
||||||
# TODO(@getchoo): Is this all really needed???
|
# TODO(@getchoo): Is this all really needed???
|
||||||
# https://github.com/Azure/trusted-signing-action/blob/fc390cf8ed0f14e248a542af1d838388a47c7a7c/docs/OIDC.md
|
# https://github.com/Azure/trusted-signing-action/blob/fc390cf8ed0f14e248a542af1d838388a47c7a7c/docs/OIDC.md
|
||||||
exclude-environment-credential: true
|
exclude-environment-credential: true
|
||||||
|
|
@ -164,19 +168,19 @@ runs:
|
||||||
exclude-interactive-browser-credential: true
|
exclude-interactive-browser-credential: true
|
||||||
|
|
||||||
- name: Upload binary zip
|
- name: Upload binary zip
|
||||||
uses: actions/upload-artifact@v6
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ inputs.artifact-name }}-${{ inputs.version }}-${{ inputs.build-type }}
|
name: PrismLauncher-${{ inputs.artifact-name }}-${{ inputs.version }}-${{ inputs.build-type }}
|
||||||
path: install/**
|
path: install/**
|
||||||
|
|
||||||
- name: Upload portable zip
|
- name: Upload portable zip
|
||||||
uses: actions/upload-artifact@v6
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ inputs.artifact-name }}-Portable-${{ inputs.version }}-${{ inputs.build-type }}
|
name: PrismLauncher-${{ inputs.artifact-name }}-Portable-${{ inputs.version }}-${{ inputs.build-type }}
|
||||||
path: install-portable/**
|
path: install-portable/**
|
||||||
|
|
||||||
- name: Upload installer
|
- name: Upload installer
|
||||||
uses: actions/upload-artifact@v6
|
uses: actions/upload-artifact@v7
|
||||||
with:
|
with:
|
||||||
name: PrismLauncher-${{ inputs.artifact-name }}-Setup-${{ inputs.version }}-${{ inputs.build-type }}
|
name: PrismLauncher-${{ inputs.artifact-name }}-Setup-${{ inputs.version }}-${{ inputs.build-type }}
|
||||||
path: PrismLauncher-Setup.exe
|
path: PrismLauncher-Setup.exe
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ inputs:
|
||||||
qt-version:
|
qt-version:
|
||||||
description: Version of Qt to use
|
description: Version of Qt to use
|
||||||
required: true
|
required: true
|
||||||
default: 6.9.3
|
|
||||||
|
|
||||||
outputs:
|
outputs:
|
||||||
build-type:
|
build-type:
|
||||||
|
|
@ -56,7 +55,7 @@ runs:
|
||||||
# TODO(@getchoo): Get this working on MSYS2!
|
# TODO(@getchoo): Get this working on MSYS2!
|
||||||
- name: Setup ccache
|
- name: Setup ccache
|
||||||
if: ${{ (runner.os != 'Windows' || inputs.msystem == '') && inputs.build-type == 'Debug' }}
|
if: ${{ (runner.os != 'Windows' || inputs.msystem == '') && inputs.build-type == 'Debug' }}
|
||||||
uses: hendrikmuhs/ccache-action@v1.2.20
|
uses: hendrikmuhs/ccache-action@v1.2.23
|
||||||
with:
|
with:
|
||||||
variant: sccache
|
variant: sccache
|
||||||
create-symlink: ${{ runner.os != 'Windows' }}
|
create-symlink: ${{ runner.os != 'Windows' }}
|
||||||
|
|
@ -78,6 +77,5 @@ runs:
|
||||||
with:
|
with:
|
||||||
aqtversion: "==3.1.*"
|
aqtversion: "==3.1.*"
|
||||||
version: ${{ inputs.qt-version }}
|
version: ${{ inputs.qt-version }}
|
||||||
arch: ${{ inputs.qt-architecture }}
|
|
||||||
modules: qtimageformats qtnetworkauth
|
modules: qtimageformats qtnetworkauth
|
||||||
cache: ${{ inputs.build-type == 'Debug' }}
|
cache: ${{ inputs.build-type == 'Debug' }}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
name: Setup Linux dependencies
|
name: Setup Linux dependencies
|
||||||
|
description: Install and setup dependencies for building Prism Launcher
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: composite
|
using: composite
|
||||||
|
|
@ -12,29 +13,7 @@ runs:
|
||||||
dpkg-dev \
|
dpkg-dev \
|
||||||
ninja-build extra-cmake-modules pkg-config scdoc \
|
ninja-build extra-cmake-modules pkg-config scdoc \
|
||||||
cmark gamemode-dev libarchive-dev libcmark-dev libqrencode-dev zlib1g-dev \
|
cmark gamemode-dev libarchive-dev libcmark-dev libqrencode-dev zlib1g-dev \
|
||||||
libxcb-cursor-dev
|
libxcb-cursor-dev libtomlplusplus-dev
|
||||||
|
|
||||||
# TODO(@getchoo): Install with the above when all targets use Ubuntu 24.04
|
|
||||||
- name: Install tomlplusplus
|
|
||||||
if: ${{ runner.arch == 'ARM64' }}
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
sudo apt-get -y install libtomlplusplus-dev
|
|
||||||
|
|
||||||
# FIXME(@getchoo): THIS IS HORRIBLE TO DO!
|
|
||||||
# Install tomlplusplus from Ubuntu 24.04, since it never got backported to 22.04
|
|
||||||
# I've done too much to continue keeping this as a submodule....
|
|
||||||
- name: Install tomlplusplus from 24.04
|
|
||||||
if: ${{ runner.arch != 'ARM64' }}
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
deb_arch="$(dpkg-architecture -q DEB_HOST_ARCH)"
|
|
||||||
curl -Lo libtomlplusplus-dev.deb http://mirrors.kernel.org/ubuntu/pool/universe/t/tomlplusplus/libtomlplusplus-dev_3.4.0+ds-0.2build1_"$deb_arch".deb
|
|
||||||
curl -Lo libtomlplusplus3t64.deb http://mirrors.kernel.org/ubuntu/pool/universe/t/tomlplusplus/libtomlplusplus3t64_3.4.0+ds-0.2build1_"$deb_arch".deb
|
|
||||||
sudo dpkg -i libtomlplusplus3t64.deb
|
|
||||||
sudo dpkg -i libtomlplusplus-dev.deb
|
|
||||||
rm *.deb
|
|
||||||
sudo apt-get install -f
|
|
||||||
|
|
||||||
- name: Setup AppImage tooling
|
- name: Setup AppImage tooling
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
@ -56,19 +35,20 @@ runs:
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
gh release download \
|
||||||
|
--repo VHSgunzo/sharun \
|
||||||
|
--pattern "sharun-$APPIMAGE_ARCH-aio" \
|
||||||
|
--output ~/bin/sharun
|
||||||
|
|
||||||
|
# FIXME!: revert this to probonopd/go-appimage once https://github.com/probonopd/go-appimage/pull/377 is merged!
|
||||||
gh release download continuous \
|
gh release download continuous \
|
||||||
--repo probonopd/go-appimage \
|
--repo DioEgizio/go-appimage \
|
||||||
--pattern "appimagetool-*-$APPIMAGE_ARCH.AppImage" \
|
|
||||||
--output ~/bin/appimagetool
|
|
||||||
gh release download continuous \
|
|
||||||
--repo probonopd/go-appimage \
|
|
||||||
--pattern "mkappimage-*-$APPIMAGE_ARCH.AppImage" \
|
--pattern "mkappimage-*-$APPIMAGE_ARCH.AppImage" \
|
||||||
--output ~/bin/mkappimage
|
--output ~/bin/mkappimage
|
||||||
chmod +x ~/bin/appimagetool ~/bin/mkappimage
|
|
||||||
echo "$HOME/bin" >> "$GITHUB_PATH"
|
|
||||||
|
|
||||||
gh release download \
|
gh release download \
|
||||||
--repo AppImageCommunity/AppImageUpdate \
|
--repo AppImageCommunity/AppImageUpdate \
|
||||||
--pattern "AppImageUpdate-$APPIMAGE_ARCH.AppImage" \
|
--pattern "AppImageUpdate-$APPIMAGE_ARCH.AppImage" \
|
||||||
--output ~/bin/AppImageUpdate.AppImage
|
--output ~/bin/AppImageUpdate.AppImage
|
||||||
chmod +x ~/bin/AppImageUpdate.AppImage
|
chmod +x ~/bin/*
|
||||||
|
echo "$HOME/bin" >> "$GITHUB_PATH"
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ runs:
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
brew update
|
brew update
|
||||||
brew install ninja extra-cmake-modules temurin@17
|
brew install ninja extra-cmake-modules temurin@17 mono
|
||||||
|
|
||||||
- name: Set JAVA_HOME
|
- name: Set JAVA_HOME
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
@ -44,4 +44,4 @@ runs:
|
||||||
- name: Setup vcpkg environment
|
- name: Setup vcpkg environment
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
echo "CMAKE_TOOLCHAIN_FILE=$VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake" >> "$GITHUB_ENV"
|
echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> "$GITHUB_ENV"
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
name: Setup Windows Dependencies
|
name: Setup Windows Dependencies
|
||||||
|
description: Install and setup dependencies for building Prism Launcher
|
||||||
|
|
||||||
inputs:
|
inputs:
|
||||||
build-type:
|
build-type:
|
||||||
|
|
@ -57,7 +58,7 @@ runs:
|
||||||
if: ${{ inputs.msystem == '' }}
|
if: ${{ inputs.msystem == '' }}
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
echo "CMAKE_TOOLCHAIN_FILE=$VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake" >> "$GITHUB_ENV"
|
echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
- name: Setup MSYS2 (MinGW)
|
- name: Setup MSYS2 (MinGW)
|
||||||
if: ${{ inputs.msystem != '' }}
|
if: ${{ inputs.msystem != '' }}
|
||||||
|
|
@ -90,7 +91,7 @@ runs:
|
||||||
|
|
||||||
- name: Retrieve ccache cache (MinGW)
|
- name: Retrieve ccache cache (MinGW)
|
||||||
if: ${{ inputs.msystem != '' && inputs.build-type == 'Debug' }}
|
if: ${{ inputs.msystem != '' && inputs.build-type == 'Debug' }}
|
||||||
uses: actions/cache@v5.0.1
|
uses: actions/cache@v5.0.5
|
||||||
with:
|
with:
|
||||||
path: '${{ github.workspace }}\.ccache'
|
path: '${{ github.workspace }}\.ccache'
|
||||||
key: ${{ runner.os }}-mingw-w64-ccache-${{ github.run_id }}
|
key: ${{ runner.os }}-mingw-w64-ccache-${{ github.run_id }}
|
||||||
|
|
|
||||||
7
.github/workflows/backport.yml
vendored
7
.github/workflows/backport.yml
vendored
|
|
@ -8,8 +8,7 @@ on:
|
||||||
# the GitHub repository. This means that it should not evaluate user input in a
|
# the GitHub repository. This means that it should not evaluate user input in a
|
||||||
# way that allows code injection.
|
# way that allows code injection.
|
||||||
|
|
||||||
permissions:
|
permissions: {}
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
backport:
|
backport:
|
||||||
|
|
@ -19,13 +18,13 @@ jobs:
|
||||||
actions: write # for korthout/backport-action to create PR with workflow changes
|
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-slim
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
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@v4.0.0
|
uses: korthout/backport-action@v4.5
|
||||||
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: |-
|
||||||
|
|
|
||||||
36
.github/workflows/blocked-prs.yml
vendored
36
.github/workflows/blocked-prs.yml
vendored
|
|
@ -14,15 +14,17 @@ on:
|
||||||
required: true
|
required: true
|
||||||
type: number
|
type: number
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
blocked_status:
|
blocked_status:
|
||||||
name: Check Blocked Status
|
name: Check Blocked Status
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-slim
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Generate token
|
- name: Generate token
|
||||||
id: generate-token
|
id: generate-token
|
||||||
uses: actions/create-github-app-token@v2
|
uses: actions/create-github-app-token@v3
|
||||||
with:
|
with:
|
||||||
app-id: ${{ vars.PULL_REQUEST_APP_ID }}
|
app-id: ${{ vars.PULL_REQUEST_APP_ID }}
|
||||||
private-key: ${{ secrets.PULL_REQUEST_APP_PRIVATE_KEY }}
|
private-key: ${{ secrets.PULL_REQUEST_APP_PRIVATE_KEY }}
|
||||||
|
|
@ -76,11 +78,11 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
prs=$(
|
prs=$(
|
||||||
jq -c '
|
jq -c '
|
||||||
.prBody as $body
|
.prBody as $body
|
||||||
| (
|
| (
|
||||||
$body |
|
$body |
|
||||||
reduce (
|
reduce (
|
||||||
. | scan("blocked (?:by|on):? #([0-9]+)")
|
. | scan("[Bb]locked (?:[Bb]y|[Oo]n):? #([0-9]+)")
|
||||||
| map({
|
| map({
|
||||||
"type": "Blocked on",
|
"type": "Blocked on",
|
||||||
"number": ( . | tonumber )
|
"number": ( . | tonumber )
|
||||||
|
|
@ -88,17 +90,17 @@ jobs:
|
||||||
) as $i ([]; . + [$i[]])
|
) as $i ([]; . + [$i[]])
|
||||||
) as $bprs
|
) as $bprs
|
||||||
| (
|
| (
|
||||||
$body |
|
$body |
|
||||||
reduce (
|
reduce (
|
||||||
. | scan("stacked on:? #([0-9]+)")
|
. | scan("[Ss]tacked [Oo]n:? #([0-9]+)")
|
||||||
| map({
|
| map({
|
||||||
"type": "Stacked on",
|
"type": "Stacked on",
|
||||||
"number": ( . | tonumber )
|
"number": ( . | tonumber )
|
||||||
})
|
})
|
||||||
) as $i ([]; . + [$i[]])
|
) as $i ([]; . + [$i[]])
|
||||||
) as $sprs
|
) as $sprs
|
||||||
| ($bprs + $sprs) as $prs
|
| ($bprs + $sprs) as $prs
|
||||||
| {
|
| {
|
||||||
"blocking": $prs,
|
"blocking": $prs,
|
||||||
"numBlocking": ( $prs | length),
|
"numBlocking": ( $prs | length),
|
||||||
}
|
}
|
||||||
|
|
@ -126,7 +128,7 @@ jobs:
|
||||||
"number": .number,
|
"number": .number,
|
||||||
"merged": .merged,
|
"merged": .merged,
|
||||||
"state": (if .state == "open" then "Open" elif .merged then "Merged" else "Closed" end),
|
"state": (if .state == "open" then "Open" elif .merged then "Merged" else "Closed" end),
|
||||||
"labels": (reduce .labels[].name as $l ([]; . + [$l])),
|
"labels": (reduce .labels[].name as $l ([]; . + [$l])),
|
||||||
"basePrUrl": .html_url,
|
"basePrUrl": .html_url,
|
||||||
"baseRepoName": .head.repo.name,
|
"baseRepoName": .head.repo.name,
|
||||||
"baseRepoOwner": .head.repo.owner.login,
|
"baseRepoOwner": .head.repo.owner.login,
|
||||||
|
|
@ -143,19 +145,19 @@ jobs:
|
||||||
echo "current_blocking=$(jq -c 'map(
|
echo "current_blocking=$(jq -c 'map(
|
||||||
select(
|
select(
|
||||||
(.type == "Stacked on" and (.merged | not)) or
|
(.type == "Stacked on" and (.merged | not)) or
|
||||||
(.type == "Blocked on" and (.state == "Open"))
|
(.type == "Blocked on" and (.state == "Open"))
|
||||||
) | .number
|
) | .number
|
||||||
)' <<< "$blocked_pr_data" )";
|
)' <<< "$blocked_pr_data" )";
|
||||||
} >> "$GITHUB_OUTPUT"
|
} >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Add 'blocked' Label if Missing
|
- name: Add 'blocked' Label if Missing
|
||||||
id: label_blocked
|
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)
|
if: "(fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0) && !contains(fromJSON(env.JOB_DATA).prLabels, 'status: blocked') && !fromJSON(steps.blocking_data.outputs.all_merged)"
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
||||||
run: |
|
run: |
|
||||||
gh -R ${{ github.repository }} issue edit --add-label 'blocked' "$PR_NUMBER"
|
gh -R ${{ github.repository }} issue edit --add-label 'status: blocked' "$PR_NUMBER"
|
||||||
|
|
||||||
- name: Remove 'blocked' Label if All Dependencies Are Merged
|
- name: Remove 'blocked' Label if All Dependencies Are Merged
|
||||||
id: unlabel_blocked
|
id: unlabel_blocked
|
||||||
|
|
@ -164,7 +166,7 @@ jobs:
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
||||||
run: |
|
run: |
|
||||||
gh -R ${{ github.repository }} issue edit --remove-label 'blocked' "$PR_NUMBER"
|
gh -R ${{ github.repository }} issue edit --remove-label 'status: blocked' "$PR_NUMBER"
|
||||||
|
|
||||||
- name: Apply 'blocking' Label to Unmerged Dependencies
|
- name: Apply 'blocking' Label to Unmerged Dependencies
|
||||||
id: label_blocking
|
id: label_blocking
|
||||||
|
|
@ -175,7 +177,7 @@ jobs:
|
||||||
BLOCKING_ISSUES: ${{ steps.blocking_data.outputs.current_blocking }}
|
BLOCKING_ISSUES: ${{ steps.blocking_data.outputs.current_blocking }}
|
||||||
run: |
|
run: |
|
||||||
while read -r pr ; do
|
while read -r pr ; do
|
||||||
gh -R ${{ github.repository }} issue edit --add-label 'blocking' "$pr" || true
|
gh -R ${{ github.repository }} issue edit --add-label 'status: blocking' "$pr" || true
|
||||||
done < <(jq -c '.[]' <<< "$BLOCKING_ISSUES")
|
done < <(jq -c '.[]' <<< "$BLOCKING_ISSUES")
|
||||||
|
|
||||||
- name: Apply Blocking PR Status Check
|
- name: Apply Blocking PR Status Check
|
||||||
|
|
|
||||||
77
.github/workflows/build.yml
vendored
77
.github/workflows/build.yml
vendored
|
|
@ -5,63 +5,18 @@ concurrency:
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
merge_group:
|
||||||
branches:
|
types: [checks_requested]
|
||||||
- "develop"
|
|
||||||
- "release-*"
|
|
||||||
paths:
|
|
||||||
# File types
|
|
||||||
- "**.cpp"
|
|
||||||
- "**.h"
|
|
||||||
- "**.java"
|
|
||||||
- "**.ui"
|
|
||||||
|
|
||||||
# Directories
|
|
||||||
- "buildconfig/**"
|
|
||||||
- "cmake/**"
|
|
||||||
- "launcher/**"
|
|
||||||
- "libraries/**"
|
|
||||||
- "program_info/**"
|
|
||||||
- "tests/**"
|
|
||||||
|
|
||||||
# Files
|
|
||||||
- "CMakeLists.txt"
|
|
||||||
- "COPYING.md"
|
|
||||||
|
|
||||||
# Workflows
|
|
||||||
- ".github/workflows/build.yml"
|
|
||||||
- ".github/actions/package/**"
|
|
||||||
- ".github/actions/setup-dependencies/**"
|
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
|
||||||
# File types
|
|
||||||
- "**.cpp"
|
|
||||||
- "**.h"
|
|
||||||
- "**.java"
|
|
||||||
- "**.ui"
|
|
||||||
|
|
||||||
# Directories
|
|
||||||
- "buildconfig/**"
|
|
||||||
- "cmake/**"
|
|
||||||
- "launcher/**"
|
|
||||||
- "libraries/**"
|
|
||||||
- "program_info/**"
|
|
||||||
- "tests/**"
|
|
||||||
|
|
||||||
# Files
|
|
||||||
- "CMakeLists.txt"
|
|
||||||
- "COPYING.md"
|
|
||||||
|
|
||||||
# Workflows
|
|
||||||
- ".github/workflows/build.yml"
|
|
||||||
- ".github/actions/package/**"
|
|
||||||
- ".github/actions/setup-dependencies/**"
|
|
||||||
workflow_call:
|
workflow_call:
|
||||||
inputs:
|
inputs:
|
||||||
build-type:
|
build-type:
|
||||||
description: Type of build (Debug or Release)
|
description: Type of build (Debug or Release)
|
||||||
type: string
|
type: string
|
||||||
default: Debug
|
default: Debug
|
||||||
|
environment:
|
||||||
|
description: Deployment environment to run under
|
||||||
|
type: string
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
build-type:
|
build-type:
|
||||||
|
|
@ -69,11 +24,16 @@ on:
|
||||||
type: string
|
type: string
|
||||||
default: Debug
|
default: Debug
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
name: Build (${{ matrix.artifact-name }})
|
name: Build (${{ matrix.artifact-name }})
|
||||||
|
|
||||||
|
environment: ${{ inputs.environment || '' }}
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
|
contents: read
|
||||||
# Required for Azure Trusted Signing
|
# Required for Azure Trusted Signing
|
||||||
id-token: write
|
id-token: write
|
||||||
# Required for vcpkg binary cache
|
# Required for vcpkg binary cache
|
||||||
|
|
@ -83,17 +43,15 @@ jobs:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- os: ubuntu-22.04
|
- os: ubuntu-24.04
|
||||||
artifact-name: Linux
|
artifact-name: Linux
|
||||||
cmake-preset: linux
|
cmake-preset: linux
|
||||||
|
qt-version: 6.10.2
|
||||||
|
|
||||||
# NOTE(@getchoo): Yes, we're intentionally using 24.04 here!!!
|
|
||||||
#
|
|
||||||
# It's not really documented anywhere AFAICT, but upstream Qt binaries
|
|
||||||
# *for the same version* are compiled against 24.04 on ARM, and *not* 22.04 like x64
|
|
||||||
- os: ubuntu-24.04-arm
|
- os: ubuntu-24.04-arm
|
||||||
artifact-name: Linux-aarch64
|
artifact-name: Linux-aarch64
|
||||||
cmake-preset: linux
|
cmake-preset: linux
|
||||||
|
qt-version: 6.10.2
|
||||||
|
|
||||||
- os: windows-2022
|
- os: windows-2022
|
||||||
artifact-name: Windows-MinGW-w64
|
artifact-name: Windows-MinGW-w64
|
||||||
|
|
@ -112,16 +70,19 @@ jobs:
|
||||||
cmake-preset: windows_msvc
|
cmake-preset: windows_msvc
|
||||||
# TODO(@getchoo): This is the default in setup-dependencies/windows. Why isn't it working?!?!
|
# TODO(@getchoo): This is the default in setup-dependencies/windows. Why isn't it working?!?!
|
||||||
vcvars-arch: amd64
|
vcvars-arch: amd64
|
||||||
|
qt-version: 6.10.2
|
||||||
|
|
||||||
- os: windows-11-arm
|
- os: windows-11-arm
|
||||||
artifact-name: Windows-MSVC-arm64
|
artifact-name: Windows-MSVC-arm64
|
||||||
cmake-preset: windows_msvc
|
cmake-preset: windows_msvc
|
||||||
vcvars-arch: arm64
|
vcvars-arch: arm64
|
||||||
|
qt-version: 6.10.2
|
||||||
|
|
||||||
- os: macos-14
|
- os: macos-26
|
||||||
artifact-name: macOS
|
artifact-name: macOS
|
||||||
cmake-preset: macos_universal
|
cmake-preset: macos_universal
|
||||||
macosx-deployment-target: 12.0
|
macosx-deployment-target: 12.0
|
||||||
|
qt-version: 6.9.3
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
|
@ -155,7 +116,7 @@ jobs:
|
||||||
artifact-name: ${{ matrix.artifact-name }}
|
artifact-name: ${{ matrix.artifact-name }}
|
||||||
msystem: ${{ matrix.msystem }}
|
msystem: ${{ matrix.msystem }}
|
||||||
vcvars-arch: ${{ matrix.vcvars-arch }}
|
vcvars-arch: ${{ matrix.vcvars-arch }}
|
||||||
qt-architecture: ${{ matrix.qt-architecture }}
|
qt-version: ${{ matrix.qt-version }}
|
||||||
|
|
||||||
##
|
##
|
||||||
# BUILD
|
# BUILD
|
||||||
|
|
@ -214,6 +175,8 @@ jobs:
|
||||||
- name: Package (Windows)
|
- name: Package (Windows)
|
||||||
if: ${{ runner.os == 'Windows' }}
|
if: ${{ runner.os == 'Windows' }}
|
||||||
uses: ./.github/actions/package/windows
|
uses: ./.github/actions/package/windows
|
||||||
|
env:
|
||||||
|
CI_HAS_ACCESS_TO_AZURE: ${{ vars.CI_HAS_ACCESS_TO_AZURE || '' }}
|
||||||
with:
|
with:
|
||||||
version: ${{ steps.short-version.outputs.version }}
|
version: ${{ steps.short-version.outputs.version }}
|
||||||
build-type: ${{ steps.setup-dependencies.outputs.build-type }}
|
build-type: ${{ steps.setup-dependencies.outputs.build-type }}
|
||||||
|
|
|
||||||
48
.github/workflows/clang-tidy.yml
vendored
Normal file
48
.github/workflows/clang-tidy.yml
vendored
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
name: Clang-Tidy Code Scanning
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
on:
|
||||||
|
merge_group:
|
||||||
|
types: [checks_requested]
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
clang-tidy:
|
||||||
|
name: Run Clang-Tidy
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
security-events: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # Required for diffing later on
|
||||||
|
submodules: "true"
|
||||||
|
|
||||||
|
- name: Install Nix
|
||||||
|
uses: cachix/install-nix-action@v31
|
||||||
|
|
||||||
|
- name: Run source generators
|
||||||
|
# TODO(@getchoo): Figure out how to make this work with PCH
|
||||||
|
run: |
|
||||||
|
nix develop --command bash -c '
|
||||||
|
cmake -B build -D Launcher_USE_PCH=OFF && cmake --build build --target autogen autorcc
|
||||||
|
'
|
||||||
|
|
||||||
|
# TODO: Use SARIF after https://github.com/psastras/sarif-rs/issues/638 is fixed
|
||||||
|
- name: Run clang-tidy-diff
|
||||||
|
env:
|
||||||
|
BASE_REF: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha }}
|
||||||
|
run: |
|
||||||
|
nix develop --command bash -c '
|
||||||
|
clang-tidy -verify-config && git diff -U0 --no-color "$BASE_REF" | clang-tidy-diff.py -p1 -quiet -only-check-in-db
|
||||||
|
'
|
||||||
65
.github/workflows/codeql.yml
vendored
65
.github/workflows/codeql.yml
vendored
|
|
@ -5,63 +5,21 @@ concurrency:
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
merge_group:
|
||||||
branches:
|
types: [checks_requested]
|
||||||
- "develop"
|
|
||||||
- "release-*"
|
|
||||||
paths:
|
|
||||||
# File types
|
|
||||||
- "**.cpp"
|
|
||||||
- "**.h"
|
|
||||||
- "**.java"
|
|
||||||
- "**.ui"
|
|
||||||
|
|
||||||
# Directories
|
|
||||||
- "buildconfig/**"
|
|
||||||
- "cmake/**"
|
|
||||||
- "launcher/**"
|
|
||||||
- "libraries/**"
|
|
||||||
- "program_info/**"
|
|
||||||
- "tests/**"
|
|
||||||
|
|
||||||
# Files
|
|
||||||
- "CMakeLists.txt"
|
|
||||||
- "COPYING.md"
|
|
||||||
|
|
||||||
# Workflows
|
|
||||||
- ".github/codeql/**"
|
|
||||||
- ".github/workflows/codeql.yml"
|
|
||||||
- ".github/actions/setup-dependencies/**"
|
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
|
||||||
# File types
|
|
||||||
- "**.cpp"
|
|
||||||
- "**.h"
|
|
||||||
- "**.java"
|
|
||||||
- "**.ui"
|
|
||||||
|
|
||||||
# Directories
|
|
||||||
- "buildconfig/**"
|
|
||||||
- "cmake/**"
|
|
||||||
- "launcher/**"
|
|
||||||
- "libraries/**"
|
|
||||||
- "program_info/**"
|
|
||||||
- "tests/**"
|
|
||||||
|
|
||||||
# Files
|
|
||||||
- "CMakeLists.txt"
|
|
||||||
- "COPYING.md"
|
|
||||||
|
|
||||||
# Workflows
|
|
||||||
- ".github/codeql/**"
|
|
||||||
- ".github/workflows/codeql.yml"
|
|
||||||
- ".github/actions/setup-dependencies/**"
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
CodeQL:
|
CodeQL:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
security-events: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v6
|
||||||
|
|
@ -79,11 +37,16 @@ jobs:
|
||||||
uses: ./.github/actions/setup-dependencies
|
uses: ./.github/actions/setup-dependencies
|
||||||
with:
|
with:
|
||||||
build-type: Debug
|
build-type: Debug
|
||||||
|
qt-version: 6.4.3
|
||||||
|
|
||||||
- name: Configure and Build
|
- name: Configure and Build
|
||||||
run: |
|
run: |
|
||||||
cmake --preset linux
|
cmake --preset linux -DLauncher_USE_PCH=OFF
|
||||||
cmake --build --preset linux --config Debug
|
cmake --build --preset linux --config Debug
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: |
|
||||||
|
ctest --preset linux --build-config Debug --extra-verbose --output-on-failure
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v4
|
uses: github/codeql-action/analyze@v4
|
||||||
|
|
|
||||||
174
.github/workflows/container.yml
vendored
Normal file
174
.github/workflows/container.yml
vendored
Normal file
|
|
@ -0,0 +1,174 @@
|
||||||
|
name: Development Container
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
on:
|
||||||
|
merge_group:
|
||||||
|
types: [checks_requested]
|
||||||
|
pull_request:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
env:
|
||||||
|
REGISTRY: ghcr.io
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build (${{ matrix.arch }})
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
|
||||||
|
outputs:
|
||||||
|
image-name: ${{ steps.image-name.outputs.image-name }}
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- arch: arm64
|
||||||
|
os: ubuntu-24.04-arm
|
||||||
|
- arch: amd64
|
||||||
|
os: ubuntu-24.04
|
||||||
|
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Set image name
|
||||||
|
id: image-name
|
||||||
|
run: |
|
||||||
|
echo "image-name=${REGISTRY}/${GITHUB_REPOSITORY_OWNER,,}/devcontainer" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Install Podman
|
||||||
|
uses: redhat-actions/podman-install@main
|
||||||
|
# TODO(@getchoo): Always use this when the action properly supports ARM
|
||||||
|
if: ${{ runner.arch == 'X64' || runner.arch == 'X86' }}
|
||||||
|
with:
|
||||||
|
github-token: ${{ github.token }}
|
||||||
|
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Determine metadata for image
|
||||||
|
id: image-metadata
|
||||||
|
uses: docker/metadata-action@v6
|
||||||
|
with:
|
||||||
|
images: |
|
||||||
|
${{ steps.image-name.outputs.image-name }}
|
||||||
|
flavor: |
|
||||||
|
latest=false
|
||||||
|
tags: |
|
||||||
|
type=raw,value=latest,enable=${{ github.event.merge_group.base_ref == 'refs/heads/develop' }}
|
||||||
|
|
||||||
|
type=sha
|
||||||
|
type=sha,format=long
|
||||||
|
type=ref,event=branch
|
||||||
|
type=ref,event=tag
|
||||||
|
|
||||||
|
- name: Build image
|
||||||
|
id: build-image
|
||||||
|
uses: redhat-actions/buildah-build@v2
|
||||||
|
with:
|
||||||
|
containerfiles: |
|
||||||
|
./Containerfile
|
||||||
|
tags: ${{ steps.image-metadata.outputs.tags }}
|
||||||
|
labels: ${{ steps.image-metadata.outputs.labels }}
|
||||||
|
|
||||||
|
- name: Push image
|
||||||
|
id: push-image
|
||||||
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
|
uses: redhat-actions/push-to-registry@v2
|
||||||
|
with:
|
||||||
|
tags: ${{ steps.build-image.outputs.tags }}
|
||||||
|
username: ${{ github.repository_owner }}
|
||||||
|
password: ${{ github.token }}
|
||||||
|
tls-verify: true
|
||||||
|
|
||||||
|
- name: Export image digest
|
||||||
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
|
env:
|
||||||
|
DIGEST: ${{ steps.push-image.outputs.digest }}
|
||||||
|
run: |
|
||||||
|
mkdir -p "$RUNNER_TEMP"/digests
|
||||||
|
touch "$RUNNER_TEMP"/digests/"${DIGEST#sha256:}"
|
||||||
|
|
||||||
|
- name: Upload digest artifact
|
||||||
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: digests-${{ matrix.arch }}
|
||||||
|
path: ${{ runner.temp }}/digests/*
|
||||||
|
if-no-files-found: error
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
manifest:
|
||||||
|
name: Create manifest
|
||||||
|
|
||||||
|
needs: [ build ]
|
||||||
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Download digests
|
||||||
|
uses: actions/download-artifact@v8
|
||||||
|
with:
|
||||||
|
path: ${{ runner.temp }}/digests
|
||||||
|
pattern: digests-*
|
||||||
|
merge-multiple: true
|
||||||
|
|
||||||
|
- name: Install Podman
|
||||||
|
# TODO(@getchoo): Always use this when the action properly supports ARM
|
||||||
|
if: ${{ runner.arch == 'X64' || runner.arch == 'X86' }}
|
||||||
|
uses: redhat-actions/podman-install@main
|
||||||
|
with:
|
||||||
|
github-token: ${{ github.token }}
|
||||||
|
|
||||||
|
- name: Login to registry
|
||||||
|
uses: redhat-actions/podman-login@v1
|
||||||
|
with:
|
||||||
|
registry: ${{ env.REGISTRY }}
|
||||||
|
username: ${{ github.repository_owner }}
|
||||||
|
password: ${{ github.token }}
|
||||||
|
|
||||||
|
- name: Determine metadata for manifest
|
||||||
|
id: manifest-metadata
|
||||||
|
uses: docker/metadata-action@v6
|
||||||
|
with:
|
||||||
|
images: |
|
||||||
|
${{ needs.build.outputs.image-name }}
|
||||||
|
flavor: |
|
||||||
|
latest=false
|
||||||
|
tags: |
|
||||||
|
type=raw,value=latest,enable=${{ github.event.merge_group.base_ref == 'refs/heads/develop' }}
|
||||||
|
|
||||||
|
type=sha
|
||||||
|
type=sha,format=long
|
||||||
|
type=ref,event=branch
|
||||||
|
type=ref,event=tag
|
||||||
|
|
||||||
|
- name: Create manifest list
|
||||||
|
working-directory: ${{ runner.temp }}/digests
|
||||||
|
env:
|
||||||
|
IMAGE_NAME: ${{ needs.build.outputs.image-name }}
|
||||||
|
run: |
|
||||||
|
while read -r tag; do
|
||||||
|
podman manifest create "$tag" \
|
||||||
|
$(printf "$IMAGE_NAME@sha256:%s " *)
|
||||||
|
done <<< "$DOCKER_METADATA_OUTPUT_TAGS"
|
||||||
|
|
||||||
|
- name: Push manifest
|
||||||
|
uses: redhat-actions/push-to-registry@v2
|
||||||
|
with:
|
||||||
|
tags: ${{ steps.manifest-metadata.outputs.tags }}
|
||||||
|
username: ${{ github.repository_owner }}
|
||||||
|
password: ${{ github.token }}
|
||||||
|
tls-verify: true
|
||||||
105
.github/workflows/flatpak.yml
vendored
105
.github/workflows/flatpak.yml
vendored
|
|
@ -1,105 +0,0 @@
|
||||||
name: Flatpak
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- "develop"
|
|
||||||
- "release-*"
|
|
||||||
# We don't do anything with these artifacts on releases. They go to Flathub
|
|
||||||
tags-ignore:
|
|
||||||
- "*"
|
|
||||||
paths:
|
|
||||||
# File types
|
|
||||||
- "**.cpp"
|
|
||||||
- "**.h"
|
|
||||||
- "**.java"
|
|
||||||
- "**.ui"
|
|
||||||
|
|
||||||
# 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"
|
|
||||||
- "**.java"
|
|
||||||
- "**.ui"
|
|
||||||
|
|
||||||
# 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.10
|
|
||||||
options: --privileged
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
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 }}
|
|
||||||
14
.github/workflows/merge-blocking-pr.yml
vendored
14
.github/workflows/merge-blocking-pr.yml
vendored
|
|
@ -11,19 +11,21 @@ on:
|
||||||
required: true
|
required: true
|
||||||
type: number
|
type: number
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
update-blocked-status:
|
update-blocked-status:
|
||||||
name: Update Blocked Status
|
name: Update Blocked Status
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-slim
|
||||||
|
|
||||||
# a pr that was a `blocking:<id>` label was merged.
|
# 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
|
# 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') }}
|
if: "${{ github.event_name == 'workflow_dispatch' || github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'status: blocking') }}"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Generate token
|
- name: Generate token
|
||||||
id: generate-token
|
id: generate-token
|
||||||
uses: actions/create-github-app-token@v2
|
uses: actions/create-github-app-token@v3
|
||||||
with:
|
with:
|
||||||
app-id: ${{ vars.PULL_REQUEST_APP_ID }}
|
app-id: ${{ vars.PULL_REQUEST_APP_ID }}
|
||||||
private-key: ${{ secrets.PULL_REQUEST_APP_PRIVATE_KEY }}
|
private-key: ${{ secrets.PULL_REQUEST_APP_PRIVATE_KEY }}
|
||||||
|
|
@ -35,10 +37,10 @@ jobs:
|
||||||
PR_NUMBER: ${{ inputs.pr_id || github.event.pull_request.number }}
|
PR_NUMBER: ${{ inputs.pr_id || github.event.pull_request.number }}
|
||||||
run: |
|
run: |
|
||||||
blocked_prs=$(
|
blocked_prs=$(
|
||||||
gh -R ${{ github.repository }} pr list --label 'blocked' --json 'number,body' \
|
gh -R ${{ github.repository }} pr list --label 'status: blocked' --json 'number,body' \
|
||||||
| jq -c --argjson pr "$PR_NUMBER" '
|
| jq -c --argjson pr "$PR_NUMBER" '
|
||||||
reduce ( .[] | select(
|
reduce ( .[] | select(
|
||||||
.body |
|
.body |
|
||||||
scan("(?:blocked (?:by|on)|stacked on):? #([0-9]+)") |
|
scan("(?:blocked (?:by|on)|stacked on):? #([0-9]+)") |
|
||||||
map(tonumber) |
|
map(tonumber) |
|
||||||
any(.[]; . == $pr)
|
any(.[]; . == $pr)
|
||||||
|
|
@ -47,7 +49,7 @@ jobs:
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
echo "deps=$blocked_prs"
|
echo "deps=$blocked_prs"
|
||||||
echo "numdeps=$(jq -r '. | length' <<< "$blocked_prs")"
|
echo "numdeps=$(jq -r '. | length' <<< "$blocked_prs")"
|
||||||
} >> "$GITHUB_OUTPUT"
|
} >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Trigger Blocked PR Workflows for Dependants
|
- name: Trigger Blocked PR Workflows for Dependants
|
||||||
|
|
|
||||||
19
.github/workflows/nix.yml
vendored
19
.github/workflows/nix.yml
vendored
|
|
@ -17,6 +17,7 @@ on:
|
||||||
- "**.h"
|
- "**.h"
|
||||||
- "**.java"
|
- "**.java"
|
||||||
- "**.ui"
|
- "**.ui"
|
||||||
|
- "**.md"
|
||||||
|
|
||||||
# Build files
|
# Build files
|
||||||
- "**.nix"
|
- "**.nix"
|
||||||
|
|
@ -33,7 +34,6 @@ on:
|
||||||
|
|
||||||
# Files
|
# Files
|
||||||
- "CMakeLists.txt"
|
- "CMakeLists.txt"
|
||||||
- "COPYING.md"
|
|
||||||
|
|
||||||
# Workflows
|
# Workflows
|
||||||
- ".github/workflows/nix.yml"
|
- ".github/workflows/nix.yml"
|
||||||
|
|
@ -44,6 +44,7 @@ on:
|
||||||
- "**.h"
|
- "**.h"
|
||||||
- "**.java"
|
- "**.java"
|
||||||
- "**.ui"
|
- "**.ui"
|
||||||
|
- "**.md"
|
||||||
|
|
||||||
# Build files
|
# Build files
|
||||||
- "**.nix"
|
- "**.nix"
|
||||||
|
|
@ -60,14 +61,12 @@ on:
|
||||||
|
|
||||||
# Files
|
# Files
|
||||||
- "CMakeLists.txt"
|
- "CMakeLists.txt"
|
||||||
- "COPYING.md"
|
|
||||||
|
|
||||||
# Workflows
|
# Workflows
|
||||||
- ".github/workflows/nix.yml"
|
- ".github/workflows/nix.yml"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
permissions: {}
|
||||||
contents: read
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
DEBUG: ${{ github.ref_type != 'tag' }}
|
DEBUG: ${{ github.ref_type != 'tag' }}
|
||||||
|
|
@ -76,6 +75,9 @@ jobs:
|
||||||
build:
|
build:
|
||||||
name: Build (${{ matrix.system }})
|
name: Build (${{ matrix.system }})
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
|
|
@ -86,10 +88,7 @@ jobs:
|
||||||
- os: ubuntu-22.04-arm
|
- os: ubuntu-22.04-arm
|
||||||
system: aarch64-linux
|
system: aarch64-linux
|
||||||
|
|
||||||
- os: macos-15-intel
|
- os: macos-26
|
||||||
system: x86_64-darwin
|
|
||||||
|
|
||||||
- os: macos-14
|
|
||||||
system: aarch64-darwin
|
system: aarch64-darwin
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
@ -104,7 +103,7 @@ jobs:
|
||||||
# For PRs
|
# For PRs
|
||||||
- name: Setup Nix Magic Cache
|
- name: Setup Nix Magic Cache
|
||||||
if: ${{ github.event_name == 'pull_request' }}
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
uses: DeterminateSystems/magic-nix-cache-action@v13
|
uses: DeterminateSystems/magic-nix-cache-action@v14
|
||||||
with:
|
with:
|
||||||
diagnostic-endpoint: ""
|
diagnostic-endpoint: ""
|
||||||
use-flakehub: false
|
use-flakehub: false
|
||||||
|
|
@ -112,7 +111,7 @@ jobs:
|
||||||
# For in-tree builds
|
# For in-tree builds
|
||||||
- name: Setup Cachix
|
- name: Setup Cachix
|
||||||
if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }}
|
if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }}
|
||||||
uses: cachix/cachix-action@v16
|
uses: cachix/cachix-action@v17
|
||||||
with:
|
with:
|
||||||
name: prismlauncher
|
name: prismlauncher
|
||||||
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
|
||||||
|
|
|
||||||
8
.github/workflows/publish.yml
vendored
8
.github/workflows/publish.yml
vendored
|
|
@ -4,14 +4,16 @@ on:
|
||||||
release:
|
release:
|
||||||
types: [ released ]
|
types: [ released ]
|
||||||
|
|
||||||
permissions:
|
permissions: {}
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
winget:
|
winget:
|
||||||
name: Winget
|
name: Winget
|
||||||
|
|
||||||
runs-on: windows-latest
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
runs-on: ubuntu-slim
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Publish on Winget
|
- name: Publish on Winget
|
||||||
|
|
|
||||||
21
.github/workflows/release.yml
vendored
21
.github/workflows/release.yml
vendored
|
|
@ -5,17 +5,28 @@ on:
|
||||||
tags:
|
tags:
|
||||||
- "*"
|
- "*"
|
||||||
|
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build_release:
|
build_release:
|
||||||
name: Build Release
|
name: Build Release
|
||||||
uses: ./.github/workflows/build.yml
|
uses: ./.github/workflows/build.yml
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
# Required for Azure Trusted Signing
|
||||||
|
id-token: write
|
||||||
|
# Required for vcpkg binary cache
|
||||||
|
packages: write
|
||||||
with:
|
with:
|
||||||
build-type: Release
|
build-type: Release
|
||||||
|
environment: Release
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
create_release:
|
create_release:
|
||||||
needs: build_release
|
needs: build_release
|
||||||
runs-on: ubuntu-latest
|
permissions:
|
||||||
|
contents: write
|
||||||
|
runs-on: ubuntu-slim
|
||||||
outputs:
|
outputs:
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
steps:
|
steps:
|
||||||
|
|
@ -25,7 +36,7 @@ jobs:
|
||||||
submodules: "true"
|
submodules: "true"
|
||||||
path: "PrismLauncher-source"
|
path: "PrismLauncher-source"
|
||||||
- name: Download artifacts
|
- name: Download artifacts
|
||||||
uses: actions/download-artifact@v7
|
uses: actions/download-artifact@v8
|
||||||
- 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,11 +45,13 @@ 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-aarch64-Qt6-Portable*/PrismLauncher-portable.tar.gz PrismLauncher-Linux-aarch64-Qt6-Portable-${{ env.VERSION }}.tar.gz
|
||||||
mv PrismLauncher-*.AppImage/PrismLauncher-*-x86_64.AppImage PrismLauncher-Linux-x86_64.AppImage
|
mv PrismLauncher-*.AppImage/PrismLauncher-*-x86_64.AppImage PrismLauncher-Linux-x86_64.AppImage
|
||||||
mv PrismLauncher-*.AppImage.zsync/PrismLauncher-*-x86_64.AppImage.zsync PrismLauncher-Linux-x86_64.AppImage.zsync
|
mv PrismLauncher-*.AppImage.zsync/PrismLauncher-*-x86_64.AppImage.zsync PrismLauncher-Linux-x86_64.AppImage.zsync
|
||||||
mv PrismLauncher-*.AppImage/PrismLauncher-*-aarch64.AppImage PrismLauncher-Linux-aarch64.AppImage
|
mv PrismLauncher-*.AppImage/PrismLauncher-*-aarch64.AppImage PrismLauncher-Linux-aarch64.AppImage
|
||||||
mv PrismLauncher-*.AppImage.zsync/PrismLauncher-*-aarch64.AppImage.zsync PrismLauncher-Linux-aarch64.AppImage.zsync
|
mv PrismLauncher-*.AppImage.zsync/PrismLauncher-*-aarch64.AppImage.zsync PrismLauncher-Linux-aarch64.AppImage.zsync
|
||||||
mv PrismLauncher-macOS*/PrismLauncher.zip PrismLauncher-macOS-${{ env.VERSION }}.zip
|
mv PrismLauncher-macOS*/PrismLauncher.zip PrismLauncher-macOS-${{ env.VERSION }}.zip
|
||||||
|
mv PrismLauncher-macOS*/PrismLauncher.dmg PrismLauncher-macOS-${{ env.VERSION }}.dmg
|
||||||
|
|
||||||
tar --exclude='.git' -czf PrismLauncher-${{ env.VERSION }}.tar.gz PrismLauncher-${{ env.VERSION }}
|
tar --exclude='.git' -czf PrismLauncher-${{ env.VERSION }}.tar.gz PrismLauncher-${{ env.VERSION }}
|
||||||
|
|
||||||
|
|
@ -81,13 +94,14 @@ jobs:
|
||||||
|
|
||||||
- name: Create release
|
- name: Create release
|
||||||
id: create_release
|
id: create_release
|
||||||
uses: softprops/action-gh-release@v2
|
uses: softprops/action-gh-release@v3
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
tag_name: ${{ github.ref }}
|
tag_name: ${{ github.ref }}
|
||||||
name: Prism Launcher ${{ env.VERSION }}
|
name: Prism Launcher ${{ env.VERSION }}
|
||||||
draft: true
|
draft: true
|
||||||
prerelease: false
|
prerelease: false
|
||||||
|
fail_on_unmatched_files: true
|
||||||
files: |
|
files: |
|
||||||
PrismLauncher-Linux-x86_64.AppImage
|
PrismLauncher-Linux-x86_64.AppImage
|
||||||
PrismLauncher-Linux-x86_64.AppImage.zsync
|
PrismLauncher-Linux-x86_64.AppImage.zsync
|
||||||
|
|
@ -108,4 +122,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-${{ env.VERSION }}.dmg
|
||||||
PrismLauncher-${{ env.VERSION }}.tar.gz
|
PrismLauncher-${{ env.VERSION }}.tar.gz
|
||||||
|
|
|
||||||
29
.github/workflows/stale.yml
vendored
29
.github/workflows/stale.yml
vendored
|
|
@ -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@v10
|
|
||||||
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
|
|
||||||
21
.github/workflows/update-flake.yml
vendored
21
.github/workflows/update-flake.yml
vendored
|
|
@ -6,25 +6,30 @@ on:
|
||||||
- cron: "0 0 * * 0"
|
- cron: "0 0 * * 0"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
permissions: {}
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
update-flake:
|
update-flake:
|
||||||
if: github.repository == 'PrismLauncher/PrismLauncher'
|
if: github.repository == 'PrismLauncher/PrismLauncher'
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
runs-on: ubuntu-slim
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
- uses: cachix/install-nix-action@4e002c8ec80594ecd40e759629461e26c8abed15 # v31
|
- uses: cachix/install-nix-action@8aa03977d8d733052d78f4e008a241fd1dbf36b3 # v31
|
||||||
|
|
||||||
- uses: DeterminateSystems/update-flake-lock@v28
|
- uses: DeterminateSystems/update-flake-lock@v28
|
||||||
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"
|
||||||
pr-labels: |
|
pr-labels: |
|
||||||
Linux
|
platform: Linux
|
||||||
packaging
|
area: packaging
|
||||||
simple change
|
complexity: low
|
||||||
|
priority: low
|
||||||
|
type: robot
|
||||||
changelog:omit
|
changelog:omit
|
||||||
|
|
|
||||||
3
.gitmodules
vendored
3
.gitmodules
vendored
|
|
@ -1,6 +1,3 @@
|
||||||
[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
|
||||||
[submodule "flatpak/shared-modules"]
|
|
||||||
path = flatpak/shared-modules
|
|
||||||
url = https://github.com/flathub/shared-modules.git
|
|
||||||
|
|
|
||||||
226
CMakeLists.txt
226
CMakeLists.txt
|
|
@ -1,6 +1,9 @@
|
||||||
cmake_minimum_required(VERSION 3.22) # minimum version required by Qt
|
cmake_minimum_required(VERSION 3.25) # Required for features like `CMAKE_MSVC_DEBUG_INFORMATION_FORMAT`
|
||||||
|
|
||||||
project(Launcher)
|
project(Launcher LANGUAGES C CXX)
|
||||||
|
if(APPLE)
|
||||||
|
enable_language(OBJC OBJCXX)
|
||||||
|
endif()
|
||||||
|
|
||||||
string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BUILD_DIR}" IS_IN_SOURCE_BUILD)
|
string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BUILD_DIR}" IS_IN_SOURCE_BUILD)
|
||||||
if(IS_IN_SOURCE_BUILD)
|
if(IS_IN_SOURCE_BUILD)
|
||||||
|
|
@ -10,6 +13,10 @@ endif()
|
||||||
##################################### Set CMake options #####################################
|
##################################### Set CMake options #####################################
|
||||||
set(CMAKE_AUTOMOC ON)
|
set(CMAKE_AUTOMOC ON)
|
||||||
set(CMAKE_AUTORCC ON)
|
set(CMAKE_AUTORCC ON)
|
||||||
|
set(CMAKE_AUTOUIC ON)
|
||||||
|
set(CMAKE_AUTOGEN_ORIGIN_DEPENDS OFF)
|
||||||
|
set(CMAKE_GLOBAL_AUTOGEN_TARGET ON)
|
||||||
|
set(CMAKE_GLOBAL_AUTORCC_TARGET ON)
|
||||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
|
|
||||||
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/")
|
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/")
|
||||||
|
|
@ -27,119 +34,103 @@ set(CMAKE_C_STANDARD_REQUIRED true)
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
set(CMAKE_C_STANDARD 11)
|
set(CMAKE_C_STANDARD 11)
|
||||||
include(GenerateExportHeader)
|
include(GenerateExportHeader)
|
||||||
if(MSVC)
|
|
||||||
# /GS Adds buffer security checks, default on but incuded anyway to mirror gcc's fstack-protector flag
|
|
||||||
# /permissive- specify standards-conforming compiler behavior, also enabled by Qt6, default on with std:c++20
|
|
||||||
# Use /W4 as /Wall includes unnesserey warnings such as added padding to structs
|
|
||||||
set(CMAKE_CXX_FLAGS "/GS /permissive- /W4 ${CMAKE_CXX_FLAGS}")
|
|
||||||
|
|
||||||
# /EHs Enables stack unwind semantics for standard C++ exceptions to ensure stackframes are unwound
|
add_compile_definitions($<$<NOT:$<CONFIG:Debug>>:QT_NO_DEBUG>)
|
||||||
# and object deconstructors are called when an exception is caught.
|
add_compile_definitions(QT_WARN_DEPRECATED_UP_TO=0x060400)
|
||||||
# without it memory leaks and a warning is printed
|
add_compile_definitions(QT_DISABLE_DEPRECATED_UP_TO=0x060400)
|
||||||
# /EHc tells the compiler to assume that functions declared as extern "C" never throw a C++ exception
|
|
||||||
# This appears to not always be a defualt compiler option in CMAKE
|
|
||||||
set(CMAKE_CXX_FLAGS "/EHsc ${CMAKE_CXX_FLAGS}")
|
|
||||||
|
|
||||||
# LINK accepts /SUBSYSTEM whics sets if we are a WINDOWS (gui) or a CONSOLE programs
|
if(CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
|
||||||
# This implicitly selects an entrypoint specific to the subsystem selected
|
add_compile_options(
|
||||||
# qtmain/QtEntryPointLib provides the correct entrypoint (wWinMain) for gui programs
|
# /GS Adds buffer security checks, default on but included anyway to mirror gcc's fstack-protector flag
|
||||||
# Additinaly LINK autodetects we use a GUI so we can omit /SUBSYSTEM
|
"$<$<COMPILE_LANGUAGE:C,CXX>:/GS>"
|
||||||
# This allows tests to still use have console without using seperate linker flags
|
|
||||||
# /LTCG allows for linking wholy optimizated programs
|
# /Gw helps reduce binary size
|
||||||
# /MANIFEST:NO disables generating a manifest file, we instead provide our own
|
# /Gy allows the compiler to package individual functions
|
||||||
# /STACK sets the stack reserve size, ATL's pack list needs 3-4 MiB as of November 2022, provide 8 MiB
|
# /guard:cf enables control flow guard
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "/LTCG /MANIFEST:NO /STACK:8388608 ${CMAKE_EXE_LINKER_FLAGS}")
|
"$<$<AND:$<CONFIG:Release,RelWithDebInfo>,$<COMPILE_LANGUAGE:C,CXX>>:/Gw;/Gy;/guard:cf>"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_link_options(
|
||||||
|
# /LTCG allows for linking wholy optimizated programs
|
||||||
|
# /MANIFEST:NO disables generating a manifest file, we instead provide our own
|
||||||
|
# /STACK sets the stack reserve size, ATL's pack list needs 3-4 MiB as of November 2022, provide 8 MiB
|
||||||
|
"$<$<COMPILE_LANGUAGE:C,CXX>:/LTCG;/MANIFEST:NO;/STACK:8388608>"
|
||||||
|
)
|
||||||
|
|
||||||
# /GL enables whole program optimizations
|
# /GL enables whole program optimizations
|
||||||
# /Gw helps reduce binary size
|
# NOTE: With Clang, this is implemented as regular LTO and only used during linking
|
||||||
# /Gy allows the compiler to package individual functions
|
if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||||
# /guard:cf enables control flow guard
|
add_compile_options("$<$<AND:$<CONFIG:Release,RelWithDebInfo>,$<COMPILE_LANGUAGE:C,CXX>>:/GL>")
|
||||||
foreach(lang C CXX)
|
endif()
|
||||||
set("CMAKE_${lang}_FLAGS_RELEASE" "/GL /Gw /Gy /guard:cf")
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
# See https://github.com/ccache/ccache/issues/1040
|
# See https://github.com/ccache/ccache/issues/1040
|
||||||
# Note, CMake 3.25 replaces this with CMAKE_MSVC_DEBUG_INFORMATION_FORMAT
|
# TODO(@getchoo): Is sccache affected by this? Would be nice to use `ProgramDatabase`....
|
||||||
# See https://cmake.org/cmake/help/v3.25/variable/CMAKE_MSVC_DEBUG_INFORMATION_FORMAT.html
|
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<$<CONFIG:Debug,RelWithDebInfo>:Embedded>")
|
||||||
foreach(config DEBUG RELWITHDEBINFO)
|
|
||||||
foreach(lang C CXX)
|
|
||||||
set(flags_var "CMAKE_${lang}_FLAGS_${config}")
|
|
||||||
string(REGEX REPLACE "/Z[Ii]" "/Z7" ${flags_var} "${${flags_var}}")
|
|
||||||
endforeach()
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
if(CMAKE_MSVC_RUNTIME_LIBRARY STREQUAL "MultiThreadedDLL")
|
if(CMAKE_MSVC_RUNTIME_LIBRARY STREQUAL "MultiThreadedDLL")
|
||||||
set(CMAKE_MAP_IMPORTED_CONFIG_DEBUG Release "")
|
set(CMAKE_MAP_IMPORTED_CONFIG_DEBUG Release "")
|
||||||
set(CMAKE_MAP_IMPORTED_CONFIG_RELWITHDEBINFO Release "")
|
set(CMAKE_MAP_IMPORTED_CONFIG_RELWITHDEBINFO Release "")
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
set(CMAKE_CXX_FLAGS "-Wall -pedantic -fstack-protector-strong --param=ssp-buffer-size=4 ${CMAKE_CXX_FLAGS}")
|
add_compile_options("$<$<COMPILE_LANGUAGE:C,CXX>:-fstack-protector-strong;--param=ssp-buffer-size=4>")
|
||||||
|
|
||||||
|
# Avoid re-defining _FORTIFY_SOURCE, as it can cause redefinition errors in setups that use it by default (i.e., package builds)
|
||||||
|
if(NOT (CMAKE_C_FLAGS MATCHES "-D_FORTIFY_SOURCE" OR CMAKE_CXX_FLAGS MATCHES "-D_FORTIFY_SOURCE"))
|
||||||
|
# NOTE: _FORTIFY_SOURCE requires optimizations in most newer versions of glibc
|
||||||
|
add_compile_options("$<$<AND:$<COMPILE_LANGUAGE:C,CXX>,$<CONFIG:Release,RelWithDebInfo>>:-D_FORTIFY_SOURCE=2>")
|
||||||
|
endif()
|
||||||
|
|
||||||
# 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(CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "-Wl,--stack,8388608 ${CMAKE_EXE_LINKER_FLAGS}")
|
add_link_options("$<$<COMPILE_LANGUAGE:C,CXX>:-Wl,--stack,8388608>")
|
||||||
|
|
||||||
# Emit PDBs for WinDbg, etc.
|
|
||||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
|
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "-Wl,--pdb= ${CMAKE_EXE_LINKER_FLAGS}")
|
|
||||||
|
|
||||||
foreach(lang C CXX)
|
|
||||||
set("CMAKE_${lang}_FLAGS" "-gcodeview ${CMAKE_${lang}_FLAGS}")
|
|
||||||
|
|
||||||
# Force-enabling this to use generator expressions like TARGET_PDB_FILE
|
|
||||||
# (and because we can actually emit PDBs)
|
|
||||||
set("CMAKE_${lang}_LINKER_SUPPORTS_PDB" ON)
|
|
||||||
endforeach()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# -ffunction-sections and -fdata-sections help reduce binary size
|
# -ffunction-sections and -fdata-sections help reduce binary size
|
||||||
# -mguard=cf enables Control Flow Guard
|
# -mguard=cf enables Control Flow Guard
|
||||||
# TODO: Look into -gc-sections to further reduce binary size
|
# TODO: Look into -gc-sections to further reduce binary size
|
||||||
foreach(lang C CXX)
|
add_compile_options("$<$<AND:$<CONFIG:Release,RelWithDebInfo>,$<COMPILE_LANGUAGE:C,CXX>>:-ffunction-sections;-fdata-sections;-mguard=cf>")
|
||||||
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")
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_DISABLE_DEPRECATED_UP_TO=0x060000")
|
|
||||||
|
|
||||||
# set CXXFLAGS for build targets
|
|
||||||
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)
|
# 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
|
# https://cmake.org/cmake/help/v3.31/variable/CMAKE_EXPORT_COMPILE_COMMANDS.html
|
||||||
if(CMAKE_GENERATOR STREQUAL "Unix Makefiles" OR CMAKE_GENERATOR MATCHES "^Ninja")
|
if(CMAKE_GENERATOR STREQUAL "Unix Makefiles" OR CMAKE_GENERATOR MATCHES "^Ninja")
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
option(USE_CLANG_TIDY "Enable the use of clang-tidy during compilation" OFF)
|
||||||
|
|
||||||
|
if(USE_CLANG_TIDY)
|
||||||
|
find_program(CLANG_TIDY clang-tidy OPTIONAL)
|
||||||
|
if(CLANG_TIDY)
|
||||||
|
message(STATUS "Using clang-tidy during compilation")
|
||||||
|
set(CLANG_TIDY_COMMAND "${CLANG_TIDY}" "--config-file=${CMAKE_SOURCE_DIR}/.clang-tidy")
|
||||||
|
set(CMAKE_CXX_CLANG_TIDY ${CLANG_TIDY_COMMAND})
|
||||||
|
else()
|
||||||
|
message(WARNING "Unable to find `clang-tidy`. Not using during compilation")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
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
|
||||||
if ((CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") AND DEBUG_ADDRESS_SANITIZER)
|
if (DEBUG_ADDRESS_SANITIZER)
|
||||||
message(STATUS "Address Sanitizer enabled for Debug builds, Turn it off with -DDEBUG_ADDRESS_SANITIZER=off")
|
message(STATUS "Address Sanitizer enabled for Debug builds, Turn it off with -DDEBUG_ADDRESS_SANITIZER=off")
|
||||||
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
|
||||||
if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
|
set(USE_ASAN_COMPILE_OPTIONS $<AND:$<CONFIG:Debug,RelWithDebInfo>,$<COMPILE_LANGUAGE:C,CXX>>)
|
||||||
# using clang with clang-cl front end
|
if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
|
||||||
message(STATUS "Address Sanitizer available on Clang MSVC frontend")
|
message(STATUS "Using Address Sanitizer compile options for MSVC frontend")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fsanitize=address /Oy-")
|
add_compile_options(
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fsanitize=address /Oy-")
|
$<${USE_ASAN_COMPILE_OPTIONS}:/fsanitize=address>
|
||||||
else()
|
$<${USE_ASAN_COMPILE_OPTIONS}:/Oy->
|
||||||
# AppleClang and Clang
|
)
|
||||||
message(STATUS "Address Sanitizer available on Clang")
|
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined -fno-sanitize-recover=null")
|
message(STATUS "Using Address Sanitizer compile options for GCC/Clang")
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined -fno-sanitize-recover=null")
|
add_compile_options(
|
||||||
endif()
|
$<${USE_ASAN_COMPILE_OPTIONS}:-fsanitize=address,undefined>
|
||||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
$<${USE_ASAN_COMPILE_OPTIONS}:-fno-omit-frame-pointer>
|
||||||
# GCC
|
$<${USE_ASAN_COMPILE_OPTIONS}:-fno-sanitize-recover=null>
|
||||||
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")
|
link_libraries("asan" "ubsan")
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined -fno-sanitize-recover")
|
|
||||||
link_libraries("asan")
|
|
||||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
|
||||||
message(STATUS "Address Sanitizer available on MSVC")
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /fsanitize=address /Oy-")
|
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /fsanitize=address /Oy-")
|
|
||||||
else()
|
else()
|
||||||
message(STATUS "Address Sanitizer not available on compiler ${CMAKE_CXX_COMPILER_ID}")
|
message(STATUS "Address Sanitizer not available on compiler ${CMAKE_CXX_COMPILER_ID}")
|
||||||
endif()
|
endif()
|
||||||
|
|
@ -155,8 +146,9 @@ if(ENABLE_LTO)
|
||||||
if(ipo_supported)
|
if(ipo_supported)
|
||||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE)
|
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE)
|
||||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_MINSIZEREL TRUE)
|
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_MINSIZEREL TRUE)
|
||||||
|
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE)
|
||||||
if(CMAKE_BUILD_TYPE)
|
if(CMAKE_BUILD_TYPE)
|
||||||
if(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
|
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||||
message(STATUS "IPO / LTO enabled")
|
message(STATUS "IPO / LTO enabled")
|
||||||
else()
|
else()
|
||||||
message(STATUS "Not enabling IPO / LTO on debug builds")
|
message(STATUS "Not enabling IPO / LTO on debug builds")
|
||||||
|
|
@ -185,12 +177,13 @@ endif()
|
||||||
######## Set URLs ########
|
######## Set URLs ########
|
||||||
set(Launcher_NEWS_RSS_URL "https://prismlauncher.org/feed/feed.xml" CACHE STRING "URL to fetch Prism Launcher's news RSS feed from.")
|
set(Launcher_NEWS_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_WIKI_URL "https://prismlauncher.org/wiki/" CACHE STRING "URL that gets opened when the user clicks 'Launcher Help'")
|
||||||
|
set(Launcher_HELP_URL "https://prismlauncher.org/wiki/help-pages/%1" CACHE STRING "URL (with arg %1 to be substituted with page-id) that gets opened when the user requests help in a dialog window")
|
||||||
set(Launcher_LOGIN_CALLBACK_URL "https://prismlauncher.org/successful-login" CACHE STRING "URL that gets opened when the user successfully logins.")
|
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(Launcher_LEGACY_FMLLIBS_BASE_URL "https://files.prismlauncher.org/fmllibs/" CACHE STRING "URL for legacy (<=1.5.2) FML Libraries.")
|
||||||
|
|
||||||
######## Set version numbers ########
|
######## Set version numbers ########
|
||||||
set(Launcher_VERSION_MAJOR 10)
|
set(Launcher_VERSION_MAJOR 12)
|
||||||
set(Launcher_VERSION_MINOR 0)
|
set(Launcher_VERSION_MINOR 0)
|
||||||
set(Launcher_VERSION_PATCH 0)
|
set(Launcher_VERSION_PATCH 0)
|
||||||
|
|
||||||
|
|
@ -232,6 +225,8 @@ set(Launcher_SUBREDDIT_URL "https://prismlauncher.org/reddit" CACHE STRING "URL
|
||||||
# Builds
|
# Builds
|
||||||
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")
|
||||||
|
|
||||||
|
option(Launcher_USE_PCH "Use precompiled headers where possible" ON)
|
||||||
|
|
||||||
# Java downloader
|
# Java downloader
|
||||||
set(Launcher_ENABLE_JAVA_DOWNLOADER_DEFAULT ON)
|
set(Launcher_ENABLE_JAVA_DOWNLOADER_DEFAULT ON)
|
||||||
|
|
||||||
|
|
@ -297,7 +292,7 @@ set(Launcher_BUILD_TIMESTAMP "${TODAY}")
|
||||||
# Find the required Qt parts
|
# Find the required Qt parts
|
||||||
if(Launcher_QT_VERSION_MAJOR EQUAL 6)
|
if(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 NetworkAuth OpenGL)
|
find_package(Qt6 6.4 REQUIRED COMPONENTS Core CoreTools Widgets Concurrent Network Test Xml NetworkAuth OpenGL)
|
||||||
find_package(Qt6 COMPONENTS DBus)
|
find_package(Qt6 COMPONENTS DBus)
|
||||||
list(APPEND Launcher_QT_DBUS Qt6::DBus)
|
list(APPEND Launcher_QT_DBUS Qt6::DBus)
|
||||||
else()
|
else()
|
||||||
|
|
@ -337,7 +332,7 @@ if(NOT LibArchive_FOUND)
|
||||||
pkg_check_modules(libarchive REQUIRED IMPORTED_TARGET libarchive)
|
pkg_check_modules(libarchive REQUIRED IMPORTED_TARGET libarchive)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(tomlplusplus 3.2.0 REQUIRED)
|
find_package(tomlplusplus 3.2.0)
|
||||||
# fallback to pkgconfig, important especially as many distros package toml++ built with meson
|
# fallback to pkgconfig, important especially as many distros package toml++ built with meson
|
||||||
if(NOT tomlplusplus_FOUND)
|
if(NOT tomlplusplus_FOUND)
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
|
|
@ -379,7 +374,7 @@ if(UNIX AND APPLE)
|
||||||
# Mac bundle settings
|
# Mac bundle settings
|
||||||
set(MACOSX_BUNDLE_BUNDLE_NAME "${Launcher_DisplayName}")
|
set(MACOSX_BUNDLE_BUNDLE_NAME "${Launcher_DisplayName}")
|
||||||
set(MACOSX_BUNDLE_INFO_STRING "${Launcher_DisplayName}: A custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once.")
|
set(MACOSX_BUNDLE_INFO_STRING "${Launcher_DisplayName}: A custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once.")
|
||||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER "org.prismlauncher.${Launcher_Name}")
|
set(MACOSX_BUNDLE_GUI_IDENTIFIER "${Launcher_AppID}")
|
||||||
set(MACOSX_BUNDLE_BUNDLE_VERSION "${Launcher_VERSION_NAME}")
|
set(MACOSX_BUNDLE_BUNDLE_VERSION "${Launcher_VERSION_NAME}")
|
||||||
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${Launcher_VERSION_NAME}")
|
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${Launcher_VERSION_NAME}")
|
||||||
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${Launcher_VERSION_NAME}")
|
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${Launcher_VERSION_NAME}")
|
||||||
|
|
@ -399,6 +394,52 @@ if(UNIX AND APPLE)
|
||||||
# Add the icon
|
# Add the icon
|
||||||
install(FILES ${Launcher_Branding_ICNS} DESTINATION ${RESOURCES_DEST_DIR} RENAME ${Launcher_Name}.icns)
|
install(FILES ${Launcher_Branding_ICNS} DESTINATION ${RESOURCES_DEST_DIR} RENAME ${Launcher_Name}.icns)
|
||||||
|
|
||||||
|
find_program(ACTOOL_EXE actool DOC "Path to the apple asset catalog compiler")
|
||||||
|
if(ACTOOL_EXE)
|
||||||
|
execute_process(
|
||||||
|
COMMAND xcodebuild -version
|
||||||
|
OUTPUT_VARIABLE XCODE_VERSION_OUTPUT
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
)
|
||||||
|
|
||||||
|
string(REGEX MATCH "Xcode ([0-9]+\.[0-9]+)" XCODE_VERSION_MATCH "${XCODE_VERSION_OUTPUT}")
|
||||||
|
if(XCODE_VERSION_MATCH)
|
||||||
|
set(XCODE_VERSION ${CMAKE_MATCH_1})
|
||||||
|
else()
|
||||||
|
set(XCODE_VERSION 0.0)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(XCODE_VERSION VERSION_GREATER_EQUAL 26.0)
|
||||||
|
set(ASSETS_OUT_DIR "${CMAKE_BINARY_DIR}/program_info")
|
||||||
|
set(GENERATED_ASSETS_CAR "${ASSETS_OUT_DIR}/Assets.car")
|
||||||
|
set(ICON_SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_Branding_MAC_ICON}")
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT "${GENERATED_ASSETS_CAR}"
|
||||||
|
COMMAND ${ACTOOL_EXE} "${ICON_SOURCE}"
|
||||||
|
--compile "${ASSETS_OUT_DIR}"
|
||||||
|
--output-partial-info-plist /dev/null
|
||||||
|
--app-icon ${Launcher_Name}
|
||||||
|
--enable-on-demand-resources NO
|
||||||
|
--target-device mac
|
||||||
|
--minimum-deployment-target ${CMAKE_OSX_DEPLOYMENT_TARGET}
|
||||||
|
--platform macosx
|
||||||
|
DEPENDS "${ICON_SOURCE}"
|
||||||
|
COMMENT "Compiling asset catalog (${ICON_SOURCE})"
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
add_custom_target(compile_assets ALL DEPENDS "${GENERATED_ASSETS_CAR}")
|
||||||
|
install(FILES "${GENERATED_ASSETS_CAR}" DESTINATION "${RESOURCES_DEST_DIR}")
|
||||||
|
else()
|
||||||
|
message(WARNING "Xcode ${XCODE_VERSION} is too old. Minimum required version is 26.0. Not compiling liquid glass icons.")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
else()
|
||||||
|
message(WARNING "actool not found. Cannot compile macOS app icons.\n"
|
||||||
|
"Install Xcode command line tools: 'xcode-select --install'")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
elseif(UNIX)
|
elseif(UNIX)
|
||||||
include(KDEInstallDirs)
|
include(KDEInstallDirs)
|
||||||
|
|
||||||
|
|
@ -413,7 +454,7 @@ elseif(UNIX)
|
||||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_MetaInfo} DESTINATION ${KDE_INSTALL_METAINFODIR})
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_MetaInfo} DESTINATION ${KDE_INSTALL_METAINFODIR})
|
||||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_SVG} DESTINATION "${KDE_INSTALL_ICONDIR}/hicolor/scalable/apps")
|
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_SVG} DESTINATION "${KDE_INSTALL_ICONDIR}/hicolor/scalable/apps")
|
||||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_PNG_256} DESTINATION "${KDE_INSTALL_ICONDIR}/hicolor/256x256/apps" RENAME "${Launcher_AppID}.png")
|
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_PNG_256} DESTINATION "${KDE_INSTALL_ICONDIR}/hicolor/256x256/apps" RENAME "${Launcher_AppID}.png")
|
||||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_mrpack_MIMEInfo} DESTINATION ${KDE_INSTALL_MIMEDIR})
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_MIMEInfo} DESTINATION ${KDE_INSTALL_MIMEDIR})
|
||||||
|
|
||||||
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}")
|
||||||
|
|
||||||
|
|
@ -451,7 +492,6 @@ option(NBT_USE_ZLIB "Build NBT library with zlib support" OFF)
|
||||||
option(NBT_BUILD_TESTS "Build NBT library tests" OFF) #FIXME: fix unit tests.
|
option(NBT_BUILD_TESTS "Build NBT library tests" OFF) #FIXME: fix unit tests.
|
||||||
add_subdirectory(libraries/libnbtplusplus)
|
add_subdirectory(libraries/libnbtplusplus)
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,214 +1,222 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://cmake.org/cmake/help/latest/_downloads/3e2d73bff478d88a7de0de736ba5e361/schema.json",
|
"$schema": "https://cmake.org/cmake/help/latest/_downloads/3e2d73bff478d88a7de0de736ba5e361/schema.json",
|
||||||
"version": 8,
|
"version": 8,
|
||||||
"cmakeMinimumRequired": {
|
"cmakeMinimumRequired": {
|
||||||
"major": 3,
|
"major": 3,
|
||||||
"minor": 28
|
"minor": 28
|
||||||
},
|
},
|
||||||
"configurePresets": [
|
"configurePresets": [
|
||||||
{
|
{
|
||||||
"name": "base",
|
"name": "base",
|
||||||
"hidden": true,
|
"hidden": true,
|
||||||
"binaryDir": "build",
|
"binaryDir": "build",
|
||||||
"installDir": "install",
|
"installDir": "install",
|
||||||
"generator": "Ninja Multi-Config",
|
"generator": "Ninja Multi-Config",
|
||||||
"cacheVariables": {
|
"cacheVariables": {
|
||||||
"Launcher_BUILD_ARTIFACT": "$penv{ARTIFACT_NAME}",
|
"Launcher_BUILD_ARTIFACT": "$penv{ARTIFACT_NAME}",
|
||||||
"Launcher_BUILD_PLATFORM": "$penv{BUILD_PLATFORM}",
|
"Launcher_BUILD_PLATFORM": "$penv{BUILD_PLATFORM}",
|
||||||
"Launcher_ENABLE_JAVA_DOWNLOADER": "ON",
|
"Launcher_ENABLE_JAVA_DOWNLOADER": "ON",
|
||||||
"ENABLE_LTO": "ON"
|
"ENABLE_LTO": "ON"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "linux",
|
"name": "linux",
|
||||||
"displayName": "Linux",
|
"displayName": "Linux",
|
||||||
"inherits": [
|
"inherits": [
|
||||||
"base"
|
"base"
|
||||||
],
|
],
|
||||||
"condition": {
|
"condition": {
|
||||||
"type": "equals",
|
"type": "equals",
|
||||||
"lhs": "${hostSystemName}",
|
"lhs": "${hostSystemName}",
|
||||||
"rhs": "Linux"
|
"rhs": "Linux"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "macos",
|
"name": "macos",
|
||||||
"displayName": "macOS",
|
"displayName": "macOS",
|
||||||
"inherits": [
|
"inherits": [
|
||||||
"base"
|
"base"
|
||||||
],
|
],
|
||||||
"condition": {
|
"condition": {
|
||||||
"type": "equals",
|
"type": "equals",
|
||||||
"lhs": "${hostSystemName}",
|
"lhs": "${hostSystemName}",
|
||||||
"rhs": "Darwin"
|
"rhs": "Darwin"
|
||||||
}
|
},
|
||||||
},
|
"cacheVariables": {
|
||||||
{
|
"CMAKE_TOOLCHAIN_FILE": "$penv{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
|
||||||
"name": "macos_universal",
|
}
|
||||||
"displayName": "macOS (Universal Binary)",
|
},
|
||||||
"inherits": [
|
{
|
||||||
"macos"
|
"name": "macos_universal",
|
||||||
],
|
"displayName": "macOS (Universal Binary)",
|
||||||
"cacheVariables": {
|
"inherits": [
|
||||||
"CMAKE_OSX_ARCHITECTURES": "x86_64;arm64",
|
"macos"
|
||||||
"VCPKG_TARGET_TRIPLET": "universal-osx"
|
],
|
||||||
}
|
"cacheVariables": {
|
||||||
},
|
"CMAKE_TOOLCHAIN_FILE": "$penv{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake",
|
||||||
{
|
"CMAKE_OSX_ARCHITECTURES": "x86_64;arm64",
|
||||||
"name": "windows_mingw",
|
"VCPKG_TARGET_TRIPLET": "universal-osx"
|
||||||
"displayName": "Windows (MinGW)",
|
}
|
||||||
"inherits": [
|
},
|
||||||
"base"
|
{
|
||||||
],
|
"name": "windows_mingw",
|
||||||
"condition": {
|
"displayName": "Windows (MinGW)",
|
||||||
"type": "equals",
|
"inherits": [
|
||||||
"lhs": "${hostSystemName}",
|
"base"
|
||||||
"rhs": "Windows"
|
],
|
||||||
}
|
"condition": {
|
||||||
},
|
"type": "equals",
|
||||||
{
|
"lhs": "${hostSystemName}",
|
||||||
"name": "windows_msvc",
|
"rhs": "Windows"
|
||||||
"displayName": "Windows (MSVC)",
|
}
|
||||||
"inherits": [
|
},
|
||||||
"base"
|
{
|
||||||
],
|
"name": "windows_msvc",
|
||||||
"condition": {
|
"displayName": "Windows (MSVC)",
|
||||||
"type": "equals",
|
"inherits": [
|
||||||
"lhs": "${hostSystemName}",
|
"base"
|
||||||
"rhs": "Windows"
|
],
|
||||||
}
|
"condition": {
|
||||||
}
|
"type": "equals",
|
||||||
],
|
"lhs": "${hostSystemName}",
|
||||||
"buildPresets": [
|
"rhs": "Windows"
|
||||||
{
|
},
|
||||||
"name": "linux",
|
"cacheVariables": {
|
||||||
"displayName": "Linux",
|
"CMAKE_TOOLCHAIN_FILE": "$penv{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
|
||||||
"condition": {
|
}
|
||||||
"type": "equals",
|
}
|
||||||
"lhs": "${hostSystemName}",
|
],
|
||||||
"rhs": "Linux"
|
"buildPresets": [
|
||||||
},
|
{
|
||||||
"configurePreset": "linux"
|
"name": "linux",
|
||||||
},
|
"displayName": "Linux",
|
||||||
{
|
"condition": {
|
||||||
"name": "macos",
|
"type": "equals",
|
||||||
"displayName": "macOS",
|
"lhs": "${hostSystemName}",
|
||||||
"condition": {
|
"rhs": "Linux"
|
||||||
"type": "equals",
|
},
|
||||||
"lhs": "${hostSystemName}",
|
"configurePreset": "linux"
|
||||||
"rhs": "Darwin"
|
},
|
||||||
},
|
{
|
||||||
"configurePreset": "macos"
|
"name": "macos",
|
||||||
},
|
"displayName": "macOS",
|
||||||
{
|
"condition": {
|
||||||
"name": "macos_universal",
|
"type": "equals",
|
||||||
"displayName": "macOS (Universal Binary)",
|
"lhs": "${hostSystemName}",
|
||||||
"inherits": [
|
"rhs": "Darwin"
|
||||||
"macos"
|
},
|
||||||
],
|
"configurePreset": "macos"
|
||||||
"configurePreset": "macos_universal"
|
},
|
||||||
},
|
{
|
||||||
{
|
"name": "macos_universal",
|
||||||
"name": "windows_mingw",
|
"displayName": "macOS (Universal Binary)",
|
||||||
"displayName": "Windows (MinGW)",
|
"inherits": [
|
||||||
"condition": {
|
"macos"
|
||||||
"type": "equals",
|
],
|
||||||
"lhs": "${hostSystemName}",
|
"configurePreset": "macos_universal"
|
||||||
"rhs": "Windows"
|
},
|
||||||
},
|
{
|
||||||
"configurePreset": "windows_mingw"
|
"name": "windows_mingw",
|
||||||
},
|
"displayName": "Windows (MinGW)",
|
||||||
{
|
"condition": {
|
||||||
"name": "windows_msvc",
|
"type": "equals",
|
||||||
"displayName": "Windows (MSVC)",
|
"lhs": "${hostSystemName}",
|
||||||
"condition": {
|
"rhs": "Windows"
|
||||||
"type": "equals",
|
},
|
||||||
"lhs": "${hostSystemName}",
|
"configurePreset": "windows_mingw"
|
||||||
"rhs": "Windows"
|
},
|
||||||
},
|
{
|
||||||
"configurePreset": "windows_msvc"
|
"name": "windows_msvc",
|
||||||
}
|
"displayName": "Windows (MSVC)",
|
||||||
],
|
"condition": {
|
||||||
"testPresets": [
|
"type": "equals",
|
||||||
{
|
"lhs": "${hostSystemName}",
|
||||||
"name": "base",
|
"rhs": "Windows"
|
||||||
"hidden": true,
|
},
|
||||||
"output": {
|
"configurePreset": "windows_msvc"
|
||||||
"outputOnFailure": true
|
}
|
||||||
},
|
],
|
||||||
"execution": {
|
"testPresets": [
|
||||||
"noTestsAction": "error"
|
{
|
||||||
},
|
"name": "base",
|
||||||
"filter": {
|
"hidden": true,
|
||||||
"exclude": {
|
"output": {
|
||||||
"name": "^example64|example$"
|
"outputOnFailure": true,
|
||||||
}
|
"verbosity": "extra"
|
||||||
}
|
},
|
||||||
},
|
"execution": {
|
||||||
{
|
"noTestsAction": "error"
|
||||||
"name": "linux",
|
},
|
||||||
"displayName": "Linux",
|
"filter": {
|
||||||
"inherits": [
|
"exclude": {
|
||||||
"base"
|
"name": "^example64|example$"
|
||||||
],
|
}
|
||||||
"condition": {
|
}
|
||||||
"type": "equals",
|
},
|
||||||
"lhs": "${hostSystemName}",
|
{
|
||||||
"rhs": "Linux"
|
"name": "linux",
|
||||||
},
|
"displayName": "Linux",
|
||||||
"configurePreset": "linux"
|
"inherits": [
|
||||||
},
|
"base"
|
||||||
{
|
],
|
||||||
"name": "macos",
|
"condition": {
|
||||||
"displayName": "macOS",
|
"type": "equals",
|
||||||
"inherits": [
|
"lhs": "${hostSystemName}",
|
||||||
"base"
|
"rhs": "Linux"
|
||||||
],
|
},
|
||||||
"condition": {
|
"configurePreset": "linux"
|
||||||
"type": "equals",
|
},
|
||||||
"lhs": "${hostSystemName}",
|
{
|
||||||
"rhs": "Darwin"
|
"name": "macos",
|
||||||
},
|
"displayName": "macOS",
|
||||||
"configurePreset": "macos"
|
"inherits": [
|
||||||
},
|
"base"
|
||||||
{
|
],
|
||||||
"name": "macos_universal",
|
"condition": {
|
||||||
"displayName": "macOS (Universal Binary)",
|
"type": "equals",
|
||||||
"inherits": [
|
"lhs": "${hostSystemName}",
|
||||||
"base"
|
"rhs": "Darwin"
|
||||||
],
|
},
|
||||||
"condition": {
|
"configurePreset": "macos"
|
||||||
"type": "equals",
|
},
|
||||||
"lhs": "${hostSystemName}",
|
{
|
||||||
"rhs": "Darwin"
|
"name": "macos_universal",
|
||||||
},
|
"displayName": "macOS (Universal Binary)",
|
||||||
"configurePreset": "macos_universal"
|
"inherits": [
|
||||||
},
|
"base"
|
||||||
{
|
],
|
||||||
"name": "windows_mingw",
|
"condition": {
|
||||||
"displayName": "Windows (MinGW)",
|
"type": "equals",
|
||||||
"inherits": [
|
"lhs": "${hostSystemName}",
|
||||||
"base"
|
"rhs": "Darwin"
|
||||||
],
|
},
|
||||||
"condition": {
|
"configurePreset": "macos_universal"
|
||||||
"type": "equals",
|
},
|
||||||
"lhs": "${hostSystemName}",
|
{
|
||||||
"rhs": "Windows"
|
"name": "windows_mingw",
|
||||||
},
|
"displayName": "Windows (MinGW)",
|
||||||
"configurePreset": "windows_mingw"
|
"inherits": [
|
||||||
},
|
"base"
|
||||||
{
|
],
|
||||||
"name": "windows_msvc",
|
"condition": {
|
||||||
"displayName": "Windows (MSVC)",
|
"type": "equals",
|
||||||
"inherits": [
|
"lhs": "${hostSystemName}",
|
||||||
"base"
|
"rhs": "Windows"
|
||||||
],
|
},
|
||||||
"condition": {
|
"configurePreset": "windows_mingw"
|
||||||
"type": "equals",
|
},
|
||||||
"lhs": "${hostSystemName}",
|
{
|
||||||
"rhs": "Windows"
|
"name": "windows_msvc",
|
||||||
},
|
"displayName": "Windows (MSVC)",
|
||||||
"configurePreset": "windows_msvc"
|
"inherits": [
|
||||||
}
|
"base"
|
||||||
]
|
],
|
||||||
|
"condition": {
|
||||||
|
"type": "equals",
|
||||||
|
"lhs": "${hostSystemName}",
|
||||||
|
"rhs": "Windows"
|
||||||
|
},
|
||||||
|
"configurePreset": "windows_msvc"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,52 @@
|
||||||
# Contributions Guidelines
|
# Contributions Guidelines
|
||||||
|
|
||||||
|
## Restrictions on Generative AI Usage (AI Policy)
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> The following is adapted from [matplotlib's contributing guide](https://matplotlib.org/devdocs/devel/contribute.html#generative-ai) and the [Linux Kernel policy guide](https://www.kernel.org/doc./html/next/process/coding-assistants.html)
|
||||||
|
|
||||||
|
We expect authentic engagement in our community.
|
||||||
|
|
||||||
|
- Do not post output from Large Language Models or similar generative AI as comments on GitHub or our discord server, as such comments tend to be formulaic and low-quality content.
|
||||||
|
- If you use generative AI tools as an aid in developing code or documentation changes, ensure that you fully understand the proposed changes and can explain why they are the correct approach.
|
||||||
|
|
||||||
|
Make sure you have added value based on your personal competency to your contributions.
|
||||||
|
Just taking some input, feeding it to an AI and posting the result is not of value to the project.
|
||||||
|
To preserve precious core developer capacity, we reserve the right to rigorously reject seemingly AI generated low-value contributions.
|
||||||
|
|
||||||
|
### Signed-off-by and Developer Certificate of Origin
|
||||||
|
|
||||||
|
AI agents MUST NOT add Signed-off-by tags. Only humans can legally certify the Developer Certificate of Origin (DCO). The human submitter is responsible for:
|
||||||
|
|
||||||
|
- Reviewing all AI-generated code
|
||||||
|
- Ensuring compliance with licensing requirements
|
||||||
|
- Adding their own Signed-off-by tag to certify the DCO
|
||||||
|
- Taking full responsibility for the contribution
|
||||||
|
|
||||||
|
See [Signing your work](#signing-your-work) for more information.
|
||||||
|
|
||||||
|
### Attribution
|
||||||
|
|
||||||
|
When AI tools contribute to development, proper attribution helps track the evolving role of AI in the development process. Contributions should include an Assisted-by tag in the commit message with the following format:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Assisted-by: AGENT_NAME:MODEL_VERSION [TOOL1] [TOOL2]
|
||||||
|
```
|
||||||
|
|
||||||
|
Where:
|
||||||
|
|
||||||
|
- `AGENT_NAME` is the name of the AI tool or framework
|
||||||
|
- `MODEL_VERSION` is the specific model version used
|
||||||
|
- `[TOOL1] [TOOL2]` are optional specialized analysis tools used (e.g., coccinelle, sparse, smatch, clang-tidy)
|
||||||
|
|
||||||
|
Basic development tools (git, gcc, make, editors) should not be listed.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Assisted-by: Claude:claude-3-opus coccinelle sparse
|
||||||
|
```
|
||||||
|
|
||||||
## Code style
|
## Code style
|
||||||
|
|
||||||
All files are formatted with `clang-format` using the configuration in `.clang-format`. Ensure it is run on changed files before committing!
|
All files are formatted with `clang-format` using the configuration in `.clang-format`. Ensure it is run on changed files before committing!
|
||||||
|
|
@ -13,7 +60,8 @@ Please also follow the project's conventions for C++:
|
||||||
- Public, private or protected `static const` class data members should be formatted as `SCREAMING_SNAKE_CASE`: `MAX_VALUE`.
|
- Public, private or protected `static const` class data members should be formatted as `SCREAMING_SNAKE_CASE`: `MAX_VALUE`.
|
||||||
- Class function members should be formatted as `camelCase` without a prefix: `incrementCounter`.
|
- 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`.
|
- 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`.
|
- `const` global variables and macros should be formatted as `SCREAMING_SNAKE_CASE`: `LIGHT_GRAY`.
|
||||||
|
- enum constants should be formatted as `PascalCase`: `CamelusBactrianus`
|
||||||
- Avoid inventing acronyms or abbreviations especially for a name of multiple words - like `tp` for `texturePack`.
|
- Avoid inventing acronyms or abbreviations especially for a name of multiple words - like `tp` for `texturePack`.
|
||||||
- Avoid using `[[nodiscard]]` unless ignoring the return value is likely to cause a bug in cases such as:
|
- Avoid using `[[nodiscard]]` unless ignoring the return value is likely to cause a bug in cases such as:
|
||||||
- A function allocates memory or another resource and the caller needs to clean it up.
|
- A function allocates memory or another resource and the caller needs to clean it up.
|
||||||
|
|
@ -30,7 +78,7 @@ Here is what these conventions with the formatting configuration look like:
|
||||||
|
|
||||||
constexpr double PI = 3.14159;
|
constexpr double PI = 3.14159;
|
||||||
|
|
||||||
enum class PizzaToppings { HAM_AND_PINEAPPLE, OREO_AND_KETCHUP };
|
enum class PizzaToppings { HamAndPineapple, OreoAndKetchup };
|
||||||
|
|
||||||
struct Person {
|
struct Person {
|
||||||
QString name;
|
QString name;
|
||||||
|
|
|
||||||
|
|
@ -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-2026 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
|
||||||
|
|
|
||||||
74
Containerfile
Normal file
74
Containerfile
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
ARG DEBIAN_VERSION=stable-slim
|
||||||
|
|
||||||
|
FROM docker.io/library/debian:${DEBIAN_VERSION}
|
||||||
|
|
||||||
|
ARG QT_ABI=gcc_64
|
||||||
|
ARG QT_ARCH=
|
||||||
|
ARG QT_HOST=linux
|
||||||
|
ARG QT_TARGET=desktop
|
||||||
|
ARG QT_VERSION=6.10.2
|
||||||
|
|
||||||
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get --assume-yes upgrade \
|
||||||
|
&& apt-get --assume-yes autopurge
|
||||||
|
|
||||||
|
# Use Adoptium for Java 17
|
||||||
|
RUN apt-get --assume-yes --no-install-recommends install \
|
||||||
|
apt-transport-https ca-certificates curl gpg
|
||||||
|
RUN curl -L https://packages.adoptium.net/artifactory/api/gpg/key/public | gpg --dearmor | tee /etc/apt/trusted.gpg.d/adoptium.gpg
|
||||||
|
RUN echo "deb https://packages.adoptium.net/artifactory/deb $(awk -F= '/^VERSION_CODENAME/{print$2}' /etc/os-release) main" | tee /etc/apt/sources.list.d/adoptium.list
|
||||||
|
RUN apt-get update
|
||||||
|
|
||||||
|
# Install base dependencies
|
||||||
|
RUN apt-get --assume-yes --no-install-recommends install \
|
||||||
|
# Compilers
|
||||||
|
clang lld llvm temurin-17-jdk \
|
||||||
|
# Build system
|
||||||
|
cmake ninja-build extra-cmake-modules pkg-config \
|
||||||
|
# Dependencies
|
||||||
|
cmark gamemode-dev libarchive-dev libcmark-dev libgamemode0 libgl1-mesa-dev libqrencode-dev libtomlplusplus-dev scdoc zlib1g-dev \
|
||||||
|
# Tooling
|
||||||
|
clang-format clang-tidy git
|
||||||
|
|
||||||
|
# Use LLD by default for faster linking
|
||||||
|
ENV CMAKE_LINKER_TYPE=lld
|
||||||
|
|
||||||
|
# Prepare and install Qt
|
||||||
|
## Setup UTF-8 locale (required, apparently)
|
||||||
|
RUN apt-get --assume-yes --no-install-recommends install locales
|
||||||
|
RUN echo "C.UTF-8 UTF-8" > /etc/locale.gen
|
||||||
|
RUN locale-gen
|
||||||
|
ENV LC_ALL=C.UTF-8
|
||||||
|
|
||||||
|
## Some libraries are required for the official binaries
|
||||||
|
RUN apt-get --assume-yes --no-install-recommends install \
|
||||||
|
libglib2.0-0t64 libxkbcommon0 python3-pip
|
||||||
|
|
||||||
|
RUN pip3 install --break-system-packages aqtinstall
|
||||||
|
RUN aqt install-qt \
|
||||||
|
${QT_HOST} ${QT_TARGET} ${QT_VERSION} ${QT_ARCH} \
|
||||||
|
--outputdir /opt/qt \
|
||||||
|
--modules qtimageformats qtnetworkauth
|
||||||
|
|
||||||
|
ENV PATH=/opt/qt/${QT_VERSION}/${QT_ABI}/bin:$PATH
|
||||||
|
ENV QT_PLUGIN_PATH=/opt/qt/${QT_VERSION}/${QT_ABI}/plugins/
|
||||||
|
|
||||||
|
## We don't use these. Nuke them
|
||||||
|
RUN rm -rf \
|
||||||
|
"$QT_PLUGIN_PATH"/designer \
|
||||||
|
"$QT_PLUGIN_PATH"/help \
|
||||||
|
# "$QT_PLUGIN_PATH"/platformthemes/libqgtk3.so \
|
||||||
|
"$QT_PLUGIN_PATH"/printsupport \
|
||||||
|
"$QT_PLUGIN_PATH"/qmllint \
|
||||||
|
"$QT_PLUGIN_PATH"/qmlls \
|
||||||
|
"$QT_PLUGIN_PATH"/qmltooling \
|
||||||
|
"$QT_PLUGIN_PATH"/sqldrivers
|
||||||
|
|
||||||
|
# Setup workspace
|
||||||
|
RUN mkdir /work
|
||||||
|
WORKDIR /work
|
||||||
|
|
||||||
|
ENTRYPOINT ["bash"]
|
||||||
|
CMD ["-i"]
|
||||||
15
README.md
15
README.md
|
|
@ -27,17 +27,13 @@ Please understand that these builds are not intended for most users. There may b
|
||||||
There are development builds available through:
|
There are development builds available through:
|
||||||
|
|
||||||
- [GitHub Actions](https://github.com/PrismLauncher/PrismLauncher/actions) (includes builds from pull requests opened by contributors)
|
- [GitHub Actions](https://github.com/PrismLauncher/PrismLauncher/actions) (includes builds from pull requests opened by contributors)
|
||||||
- [nightly.link](https://nightly.link/PrismLauncher/PrismLauncher/workflows/build/develop) (this will always point only to the latest version of develop)
|
- [nightly.link](https://prismlauncher.org/nightly) (this will always point only to the latest version of develop)
|
||||||
|
|
||||||
These have debug information in the binaries, so their file sizes are relatively larger.
|
These have debug information in the binaries, so their file sizes are relatively larger.
|
||||||
|
|
||||||
Prebuilt Development builds are provided for **Linux**, **Windows** and **macOS**.
|
Prebuilt Development builds are provided for **Linux**, **Windows** and **macOS**.
|
||||||
|
|
||||||
For **Arch**, **Debian**, **Fedora**, **OpenSUSE (Tumbleweed)** and **Gentoo**, respectively, you can use these packages for the latest development versions:
|
On Linux, we also offer our own [Flatpak nightly repository](https://github.com/PrismLauncher/flatpak). Most software centers are able to install it by opening [this link](https://flatpak.prismlauncher.org/prismlauncher-nightly.flatpakref).
|
||||||
|
|
||||||
[](https://aur.archlinux.org/packages/prismlauncher-git) [](https://aur.archlinux.org/packages/prismlauncher-qt5-git) [](https://mpr.makedeb.org/packages/prismlauncher-git)<br />[](https://copr.fedorainfracloud.org/coprs/g3tchoo/prismlauncher/) [](https://build.opensuse.org/project/show/home:getchoo) [](https://packages.gentoo.org/packages/games-action/prismlauncher)
|
|
||||||
|
|
||||||
These packages are also available to all the distributions based on the ones mentioned above.
|
|
||||||
|
|
||||||
## Community & Support
|
## Community & Support
|
||||||
|
|
||||||
|
|
@ -61,12 +57,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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,6 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <qstringliteral.h>
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include "BuildConfig.h"
|
#include "BuildConfig.h"
|
||||||
|
|
||||||
|
|
@ -51,6 +50,7 @@ Config::Config()
|
||||||
LAUNCHER_GIT = "@Launcher_Git@";
|
LAUNCHER_GIT = "@Launcher_Git@";
|
||||||
LAUNCHER_APPID = "@Launcher_AppID@";
|
LAUNCHER_APPID = "@Launcher_AppID@";
|
||||||
LAUNCHER_SVGFILENAME = "@Launcher_SVGFileName@";
|
LAUNCHER_SVGFILENAME = "@Launcher_SVGFileName@";
|
||||||
|
LAUNCHER_ENVNAME = "@Launcher_ENVName@";
|
||||||
|
|
||||||
USER_AGENT = "@Launcher_UserAgent@";
|
USER_AGENT = "@Launcher_UserAgent@";
|
||||||
|
|
||||||
|
|
@ -106,13 +106,14 @@ Config::Config()
|
||||||
|
|
||||||
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@";
|
||||||
|
WIKI_URL = "@Launcher_WIKI_URL@";
|
||||||
HELP_URL = "@Launcher_HELP_URL@";
|
HELP_URL = "@Launcher_HELP_URL@";
|
||||||
LOGIN_CALLBACK_URL = "@Launcher_LOGIN_CALLBACK_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@";
|
LEGACY_FMLLIBS_BASE_URL = "@Launcher_LEGACY_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@";
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ class Config {
|
||||||
QString LAUNCHER_GIT;
|
QString LAUNCHER_GIT;
|
||||||
QString LAUNCHER_APPID;
|
QString LAUNCHER_APPID;
|
||||||
QString LAUNCHER_SVGFILENAME;
|
QString LAUNCHER_SVGFILENAME;
|
||||||
|
QString LAUNCHER_ENVNAME;
|
||||||
|
|
||||||
/// The major version number.
|
/// The major version number.
|
||||||
int VERSION_MAJOR;
|
int VERSION_MAJOR;
|
||||||
|
|
@ -128,7 +129,12 @@ class Config {
|
||||||
QString NEWS_OPEN_URL;
|
QString NEWS_OPEN_URL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* URL (with arg %1 to be substituted with page-id) that gets opened when the user requests help
|
* URL that gets opened when the user clicks 'Launcher Help'
|
||||||
|
*/
|
||||||
|
QString WIKI_URL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL (with arg %1 to be substituted with page-id) that gets opened when the user requests help in a dialog window
|
||||||
*/
|
*/
|
||||||
QString HELP_URL;
|
QString HELP_URL;
|
||||||
|
|
||||||
|
|
@ -169,10 +175,10 @@ class Config {
|
||||||
QString DEFAULT_RESOURCE_BASE = "https://resources.download.minecraft.net/";
|
QString DEFAULT_RESOURCE_BASE = "https://resources.download.minecraft.net/";
|
||||||
QString LIBRARY_BASE = "https://libraries.minecraft.net/";
|
QString LIBRARY_BASE = "https://libraries.minecraft.net/";
|
||||||
QString IMGUR_BASE_URL = "https://api.imgur.com/3/";
|
QString IMGUR_BASE_URL = "https://api.imgur.com/3/";
|
||||||
QString FMLLIBS_BASE_URL;
|
QString LEGACY_FMLLIBS_BASE_URL;
|
||||||
QString TRANSLATION_FILES_URL;
|
QString TRANSLATION_FILES_URL;
|
||||||
|
|
||||||
QString MODPACKSCH_API_BASE_URL = "https://api.modpacks.ch/";
|
QString FTB_API_BASE_URL = "https://api.feed-the-beast.com/v1/modpacks/public";
|
||||||
|
|
||||||
QString LEGACY_FTB_CDN_BASE_URL = "https://dist.creeper.host/FTB2/";
|
QString LEGACY_FTB_CDN_BASE_URL = "https://dist.creeper.host/FTB2/";
|
||||||
|
|
||||||
|
|
@ -188,8 +194,10 @@ class Config {
|
||||||
QString MODRINTH_STAGING_URL = "https://staging-api.modrinth.com/v2";
|
QString MODRINTH_STAGING_URL = "https://staging-api.modrinth.com/v2";
|
||||||
QString MODRINTH_PROD_URL = "https://api.modrinth.com/v2";
|
QString MODRINTH_PROD_URL = "https://api.modrinth.com/v2";
|
||||||
QStringList MODRINTH_MRPACK_HOSTS{ "cdn.modrinth.com", "github.com", "raw.githubusercontent.com", "gitlab.com" };
|
QStringList MODRINTH_MRPACK_HOSTS{ "cdn.modrinth.com", "github.com", "raw.githubusercontent.com", "gitlab.com" };
|
||||||
|
QString MODRINTH_DOWNLOAD_HOST = "cdn.modrinth.com";
|
||||||
|
|
||||||
QString FLAME_BASE_URL = "https://api.curseforge.com/v1";
|
QString FLAME_BASE_URL = "https://api.curseforge.com/v1";
|
||||||
|
QString FLAME_DOWNLOAD_HOST = "edge.forgecdn.net";
|
||||||
|
|
||||||
QString versionString() const;
|
QString versionString() const;
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,163 +0,0 @@
|
||||||
#
|
|
||||||
# Function to set compiler warnings with reasonable defaults at the project level.
|
|
||||||
# Taken from https://github.com/aminya/project_options/blob/main/src/CompilerWarnings.cmake
|
|
||||||
# under the folowing license:
|
|
||||||
#
|
|
||||||
# MIT License
|
|
||||||
#
|
|
||||||
# Copyright (c) 2022-2100 Amin Yahyaabadi
|
|
||||||
#
|
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
# of this software and associated documentation files (the "Software"), to deal
|
|
||||||
# in the Software without restriction, including without limitation the rights
|
|
||||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
# copies of the Software, and to permit persons to whom the Software is
|
|
||||||
# furnished to do so, subject to the following conditions:
|
|
||||||
#
|
|
||||||
# The above copyright notice and this permission notice shall be included in all
|
|
||||||
# copies or substantial portions of the Software.
|
|
||||||
#
|
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
# SOFTWARE.
|
|
||||||
#
|
|
||||||
|
|
||||||
include_guard()
|
|
||||||
|
|
||||||
function(_set_project_warnings_add_target_link_option TARGET OPTIONS)
|
|
||||||
target_link_options(${_project_name} INTERFACE ${OPTIONS})
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
# Set the compiler warnings
|
|
||||||
#
|
|
||||||
# https://clang.llvm.org/docs/DiagnosticsReference.html
|
|
||||||
# https://github.com/lefticus/cppbestpractices/blob/master/02-Use_the_Tools_Available.md
|
|
||||||
function(
|
|
||||||
set_project_warnings
|
|
||||||
_project_name
|
|
||||||
MSVC_WARNINGS
|
|
||||||
CLANG_WARNINGS
|
|
||||||
GCC_WARNINGS
|
|
||||||
)
|
|
||||||
if("${MSVC_WARNINGS}" STREQUAL "")
|
|
||||||
set(MSVC_WARNINGS
|
|
||||||
/W4 # Baseline reasonable warnings
|
|
||||||
/w14242 # 'identifier': conversion from 'type1' to 'type1', possible loss of data
|
|
||||||
/w14254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
|
|
||||||
/w14263 # 'function': member function does not override any base class virtual member function
|
|
||||||
/w14265 # 'classname': class has virtual functions, but destructor is not virtual instances of this class may not
|
|
||||||
# be destructed correctly
|
|
||||||
/w14287 # 'operator': unsigned/negative constant mismatch
|
|
||||||
/we4289 # nonstandard extension used: 'variable': loop control variable declared in the for-loop is used outside
|
|
||||||
# the for-loop scope
|
|
||||||
/w14296 # 'operator': expression is always 'boolean_value'
|
|
||||||
/w14311 # 'variable': pointer truncation from 'type1' to 'type2'
|
|
||||||
/w14545 # expression before comma evaluates to a function which is missing an argument list
|
|
||||||
/w14546 # function call before comma missing argument list
|
|
||||||
/w14547 # 'operator': operator before comma has no effect; expected operator with side-effect
|
|
||||||
/w14549 # 'operator': operator before comma has no effect; did you intend 'operator'?
|
|
||||||
/w14555 # expression has no effect; expected expression with side- effect
|
|
||||||
/w14619 # pragma warning: there is no warning number 'number'
|
|
||||||
/w14640 # Enable warning on thread un-safe static member initialization
|
|
||||||
/w14826 # Conversion from 'type1' to 'type_2' is sign-extended. This may cause unexpected runtime behavior.
|
|
||||||
/w14905 # wide string literal cast to 'LPSTR'
|
|
||||||
/w14906 # string literal cast to 'LPWSTR'
|
|
||||||
/w14928 # illegal copy-initialization; more than one user-defined conversion has been implicitly applied
|
|
||||||
/permissive- # standards conformance mode for MSVC compiler.
|
|
||||||
|
|
||||||
/we4062 # forbid omitting a possible value of an enum in a switch statement
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if("${CLANG_WARNINGS}" STREQUAL "")
|
|
||||||
set(CLANG_WARNINGS
|
|
||||||
-Wall
|
|
||||||
-Wextra # reasonable and standard
|
|
||||||
-Wshadow # warn the user if a variable declaration shadows one from a parent context
|
|
||||||
-Wnon-virtual-dtor # warn the user if a class with virtual functions has a non-virtual destructor. This helps
|
|
||||||
# catch hard to track down memory errors
|
|
||||||
-Wold-style-cast # warn for c-style casts
|
|
||||||
-Wcast-align # warn for potential performance problem casts
|
|
||||||
-Wunused # warn on anything being unused
|
|
||||||
-Woverloaded-virtual # warn if you overload (not override) a virtual function
|
|
||||||
-Wpedantic # warn if non-standard C++ is used
|
|
||||||
-Wconversion # warn on type conversions that may lose data
|
|
||||||
-Wsign-conversion # warn on sign conversions
|
|
||||||
-Wnull-dereference # warn if a null dereference is detected
|
|
||||||
-Wdouble-promotion # warn if float is implicit promoted to double
|
|
||||||
-Wformat=2 # warn on security issues around functions that format output (ie printf)
|
|
||||||
-Wimplicit-fallthrough # warn on statements that fallthrough without an explicit annotation
|
|
||||||
# -Wgnu-zero-variadic-macro-arguments (part of -pedantic) is triggered by every qCDebug() call and therefore results
|
|
||||||
# in a lot of noise. This warning is only notifying us that clang is emulating the GCC behaviour
|
|
||||||
# instead of the exact standard wording so we can safely ignore it
|
|
||||||
-Wno-gnu-zero-variadic-macro-arguments
|
|
||||||
|
|
||||||
-Werror=switch # forbid omitting a possible value of an enum in a switch statement
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if("${GCC_WARNINGS}" STREQUAL "")
|
|
||||||
set(GCC_WARNINGS
|
|
||||||
${CLANG_WARNINGS}
|
|
||||||
-Wmisleading-indentation # warn if indentation implies blocks where blocks do not exist
|
|
||||||
-Wduplicated-cond # warn if if / else chain has duplicated conditions
|
|
||||||
-Wduplicated-branches # warn if if / else branches have duplicated code
|
|
||||||
-Wlogical-op # warn about logical operations being used where bitwise were probably wanted
|
|
||||||
-Wuseless-cast # warn if you perform a cast to the same type
|
|
||||||
|
|
||||||
-Werror=switch # forbid omitting a possible value of an enum in a switch statement
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(MSVC)
|
|
||||||
set(PROJECT_WARNINGS_CXX ${MSVC_WARNINGS})
|
|
||||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang")
|
|
||||||
set(PROJECT_WARNINGS_CXX ${CLANG_WARNINGS})
|
|
||||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
|
||||||
set(PROJECT_WARNINGS_CXX ${GCC_WARNINGS})
|
|
||||||
else()
|
|
||||||
message(AUTHOR_WARNING "No compiler warnings set for CXX compiler: '${CMAKE_CXX_COMPILER_ID}'")
|
|
||||||
# TODO support Intel compiler
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Add C warnings
|
|
||||||
set(PROJECT_WARNINGS_C "${PROJECT_WARNINGS_CXX}")
|
|
||||||
list(
|
|
||||||
REMOVE_ITEM
|
|
||||||
PROJECT_WARNINGS_C
|
|
||||||
-Wnon-virtual-dtor
|
|
||||||
-Wold-style-cast
|
|
||||||
-Woverloaded-virtual
|
|
||||||
-Wuseless-cast
|
|
||||||
-Wextra-semi
|
|
||||||
|
|
||||||
-Werror=switch # forbid omitting a possible value of an enum in a switch statement
|
|
||||||
)
|
|
||||||
|
|
||||||
target_compile_options(
|
|
||||||
${_project_name}
|
|
||||||
INTERFACE # C++ warnings
|
|
||||||
$<$<COMPILE_LANGUAGE:CXX>:${PROJECT_WARNINGS_CXX}>
|
|
||||||
# C warnings
|
|
||||||
$<$<COMPILE_LANGUAGE:C>:${PROJECT_WARNINGS_C}>
|
|
||||||
)
|
|
||||||
|
|
||||||
# If we are using the compiler as a linker driver pass the warnings to it
|
|
||||||
# (most useful when using LTO or warnings as errors)
|
|
||||||
if(CMAKE_CXX_LINK_EXECUTABLE MATCHES "^<CMAKE_CXX_COMPILER>")
|
|
||||||
_set_project_warnings_add_target_link_option(
|
|
||||||
${_project_name} "$<$<COMPILE_LANGUAGE:CXX>:${PROJECT_WARNINGS_CXX}>"
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(CMAKE_C_LINK_EXECUTABLE MATCHES "^<CMAKE_C_COMPILER>")
|
|
||||||
_set_project_warnings_add_target_link_option(
|
|
||||||
${_project_name} "$<$<COMPILE_LANGUAGE:C>:${PROJECT_WARNINGS_C}>"
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
endfunction()
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
<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>
|
<key>NSDownloadsFolderUsageDescription</key>
|
||||||
<string>Prism uses access to your Downloads folder to help you more quickly add mods that can't be automatically downloaded to your instance. You can change where Prism scans for downloaded mods in Settings or the prompt that appears.</string>
|
<string>${Launcher_DisplayName} uses access to your Downloads folder to help you more quickly add mods that can't be automatically downloaded to your instance. You can change where ${Launcher_DisplayName} scans for downloaded mods in Settings or the prompt that appears.</string>
|
||||||
<key>NSLocalNetworkUsageDescription</key>
|
<key>NSLocalNetworkUsageDescription</key>
|
||||||
<string>Minecraft uses the local network to find and connect to LAN servers.</string>
|
<string>Minecraft uses the local network to find and connect to LAN servers.</string>
|
||||||
<key>NSPrincipalClass</key>
|
<key>NSPrincipalClass</key>
|
||||||
|
|
@ -21,7 +21,9 @@
|
||||||
<key>CFBundleGetInfoString</key>
|
<key>CFBundleGetInfoString</key>
|
||||||
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
|
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
|
||||||
<key>CFBundleIconFile</key>
|
<key>CFBundleIconFile</key>
|
||||||
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
|
<string>${Launcher_Name}</string>
|
||||||
|
<key>CFBundleIconName</key>
|
||||||
|
<string>${Launcher_Name}</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
|
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
|
@ -42,6 +44,8 @@
|
||||||
<true/>
|
<true/>
|
||||||
<key>LSRequiresCarbon</key>
|
<key>LSRequiresCarbon</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>LSApplicationCategoryType</key>
|
||||||
|
<string>public.app-category.games</string>
|
||||||
<key>NSHumanReadableCopyright</key>
|
<key>NSHumanReadableCopyright</key>
|
||||||
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
|
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
|
||||||
<key>SUPublicEDKey</key>
|
<key>SUPublicEDKey</key>
|
||||||
|
|
@ -57,7 +61,7 @@
|
||||||
<string>mrpack</string>
|
<string>mrpack</string>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleTypeName</key>
|
<key>CFBundleTypeName</key>
|
||||||
<string>Prism Launcher instance</string>
|
<string>${Launcher_DisplayName} instance</string>
|
||||||
<key>CFBundleTypeOSTypes</key>
|
<key>CFBundleTypeOSTypes</key>
|
||||||
<array>
|
<array>
|
||||||
<string>TEXT</string>
|
<string>TEXT</string>
|
||||||
|
|
@ -83,10 +87,11 @@
|
||||||
</dict>
|
</dict>
|
||||||
<dict>
|
<dict>
|
||||||
<key>CFBundleURLName</key>
|
<key>CFBundleURLName</key>
|
||||||
<string>Prismlauncher</string>
|
<string>${Launcher_Name}</string>
|
||||||
<key>CFBundleURLSchemes</key>
|
<key>CFBundleURLSchemes</key>
|
||||||
<array>
|
<array>
|
||||||
<string>prismlauncher</string>
|
<string>prismlauncher</string>
|
||||||
|
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
|
|
|
||||||
23
flake.lock
generated
23
flake.lock
generated
|
|
@ -3,11 +3,11 @@
|
||||||
"libnbtplusplus": {
|
"libnbtplusplus": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1744811532,
|
"lastModified": 1772016279,
|
||||||
"narHash": "sha256-qhmjaRkt+O7A+gu6HjUkl7QzOEb4r8y8vWZMG2R/C6o=",
|
"narHash": "sha256-7itkptyjoRcXfGLwg1/jxajetZ3a4mDc66+w4X6yW8s=",
|
||||||
"owner": "PrismLauncher",
|
"owner": "PrismLauncher",
|
||||||
"repo": "libnbtplusplus",
|
"repo": "libnbtplusplus",
|
||||||
"rev": "531449ba1c930c98e0bcf5d332b237a8566f9d78",
|
"rev": "687e43031df0dc641984b4256bcca50d5b3f7de3",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -18,18 +18,15 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1765472234,
|
"lastModified": 1778443072,
|
||||||
"narHash": "sha256-9VvC20PJPsleGMewwcWYKGzDIyjckEz8uWmT0vCDYK0=",
|
"narHash": "sha256-rNDJzV2JTV5SUTwv1cgKZYMdyoUYU9/YfegSaUf3QfY=",
|
||||||
"owner": "NixOS",
|
"rev": "da5ad661ba4e5ef59ba743f0d112cbc30e474f32",
|
||||||
"repo": "nixpkgs",
|
"type": "tarball",
|
||||||
"rev": "2fbfb1d73d239d2402a8fe03963e37aab15abe8b",
|
"url": "https://releases.nixos.org/nixos/unstable/nixos-26.05pre995699.da5ad661ba4e/nixexprs.tar.xz"
|
||||||
"type": "github"
|
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"type": "tarball",
|
||||||
"ref": "nixos-unstable",
|
"url": "https://channels.nixos.org/nixos-unstable/nixexprs.tar.xz"
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": {
|
"root": {
|
||||||
|
|
|
||||||
60
flake.nix
60
flake.nix
|
|
@ -9,7 +9,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
nixpkgs.url = "https://channels.nixos.org/nixos-unstable/nixexprs.tar.xz";
|
||||||
|
|
||||||
libnbtplusplus = {
|
libnbtplusplus = {
|
||||||
url = "github:PrismLauncher/libnbtplusplus";
|
url = "github:PrismLauncher/libnbtplusplus";
|
||||||
|
|
@ -42,7 +42,7 @@
|
||||||
|
|
||||||
let
|
let
|
||||||
pkgs = nixpkgsFor.${system};
|
pkgs = nixpkgsFor.${system};
|
||||||
llvm = pkgs.llvmPackages_19;
|
llvm = pkgs.llvmPackages_22;
|
||||||
in
|
in
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
@ -85,7 +85,9 @@
|
||||||
|
|
||||||
let
|
let
|
||||||
pkgs = nixpkgsFor.${system};
|
pkgs = nixpkgsFor.${system};
|
||||||
llvm = pkgs.llvmPackages_19;
|
llvm = pkgs.llvmPackages_22;
|
||||||
|
python = pkgs.python3;
|
||||||
|
mkShell = pkgs.mkShell.override { inherit (llvm) stdenv; };
|
||||||
|
|
||||||
packages' = self.packages.${system};
|
packages' = self.packages.${system};
|
||||||
|
|
||||||
|
|
@ -131,18 +133,36 @@
|
||||||
in
|
in
|
||||||
|
|
||||||
{
|
{
|
||||||
default = pkgs.mkShell {
|
default = mkShell {
|
||||||
name = "prism-launcher";
|
name = "prism-launcher";
|
||||||
|
|
||||||
inputsFrom = [ packages'.prismlauncher-unwrapped ];
|
inputsFrom = [ packages'.prismlauncher-unwrapped ];
|
||||||
|
|
||||||
packages = with pkgs; [
|
packages = [
|
||||||
ccache
|
pkgs.ccache
|
||||||
llvm.clang-tools
|
llvm.clang-tools
|
||||||
|
python # NOTE(@getchoo): Required for run-clang-tidy, etc.
|
||||||
|
|
||||||
|
(pkgs.stdenvNoCC.mkDerivation {
|
||||||
|
pname = "clang-tidy-diff";
|
||||||
|
inherit (llvm.clang) version;
|
||||||
|
|
||||||
|
nativeBuildInputs = [
|
||||||
|
pkgs.installShellFiles
|
||||||
|
python.pkgs.wrapPython
|
||||||
|
];
|
||||||
|
|
||||||
|
dontUnpack = true;
|
||||||
|
dontConfigure = true;
|
||||||
|
dontBuild = true;
|
||||||
|
|
||||||
|
postInstall = "installBin ${llvm.libclang.python}/share/clang/clang-tidy-diff.py";
|
||||||
|
postFixup = "wrapPythonPrograms";
|
||||||
|
})
|
||||||
];
|
];
|
||||||
|
|
||||||
cmakeBuildType = "Debug";
|
cmakeBuildType = "Debug";
|
||||||
cmakeFlags = [ "-GNinja" ] ++ packages'.prismlauncher.cmakeFlags;
|
cmakeFlags = [ "-GNinja" ] ++ packages'.prismlauncher-unwrapped.cmakeFlags;
|
||||||
dontFixCmake = true;
|
dontFixCmake = true;
|
||||||
|
|
||||||
shellHook = ''
|
shellHook = ''
|
||||||
|
|
@ -165,16 +185,24 @@
|
||||||
|
|
||||||
formatter = forAllSystems (system: nixpkgsFor.${system}.nixfmt-rfc-style);
|
formatter = forAllSystems (system: nixpkgsFor.${system}.nixfmt-rfc-style);
|
||||||
|
|
||||||
overlays.default = final: prev: {
|
overlays.default =
|
||||||
prismlauncher-unwrapped = prev.callPackage ./nix/unwrapped.nix {
|
final: prev:
|
||||||
inherit
|
|
||||||
libnbtplusplus
|
|
||||||
self
|
|
||||||
;
|
|
||||||
};
|
|
||||||
|
|
||||||
prismlauncher = final.callPackage ./nix/wrapper.nix { };
|
let
|
||||||
};
|
llvm = final.llvmPackages_22 or prev.llvmPackages_22;
|
||||||
|
in
|
||||||
|
|
||||||
|
{
|
||||||
|
prismlauncher-unwrapped = prev.callPackage ./nix/unwrapped.nix {
|
||||||
|
inherit (llvm) stdenv;
|
||||||
|
inherit
|
||||||
|
libnbtplusplus
|
||||||
|
self
|
||||||
|
;
|
||||||
|
};
|
||||||
|
|
||||||
|
prismlauncher = final.callPackage ./nix/wrapper.nix { };
|
||||||
|
};
|
||||||
|
|
||||||
packages = forAllSystems (
|
packages = forAllSystems (
|
||||||
system:
|
system:
|
||||||
|
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
name: cmark
|
|
||||||
buildsystem: cmake-ninja
|
|
||||||
builddir: true
|
|
||||||
config-opts:
|
|
||||||
- -DCMAKE_TESTS=OFF
|
|
||||||
sources:
|
|
||||||
- type: archive
|
|
||||||
url: https://github.com/commonmark/cmark/archive/0.31.1.tar.gz
|
|
||||||
sha256: 3da93db5469c30588cfeb283d9d62edfc6ded9eb0edc10a4f5bbfb7d722ea802
|
|
||||||
x-checker-data:
|
|
||||||
type: anitya
|
|
||||||
project-id: 9159
|
|
||||||
stable-only: true
|
|
||||||
url-template: https://github.com/commonmark/cmark/archive/$version.tar.gz
|
|
||||||
|
|
@ -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.]+)$"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
{
|
|
||||||
"name": "libdecor",
|
|
||||||
"buildsystem": "meson",
|
|
||||||
"config-opts": [
|
|
||||||
"-Ddemo=false"
|
|
||||||
],
|
|
||||||
"sources": [
|
|
||||||
{
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://gitlab.freedesktop.org/libdecor/libdecor.git",
|
|
||||||
"commit": "c2bd8ad6fa42c0cb17553ce77ad8a87d1f543b1f"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"cleanup": [
|
|
||||||
"/include",
|
|
||||||
"/lib/pkgconfig"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
@ -1,154 +0,0 @@
|
||||||
id: org.prismlauncher.PrismLauncher
|
|
||||||
runtime: org.kde.Platform
|
|
||||||
runtime-version: '6.10'
|
|
||||||
sdk: org.kde.Sdk
|
|
||||||
sdk-extensions:
|
|
||||||
- org.freedesktop.Sdk.Extension.openjdk17
|
|
||||||
|
|
||||||
command: prismlauncher
|
|
||||||
finish-args:
|
|
||||||
- --share=ipc
|
|
||||||
- --socket=x11
|
|
||||||
- --socket=wayland
|
|
||||||
- --device=all
|
|
||||||
- --share=network
|
|
||||||
- --socket=pulseaudio
|
|
||||||
# for Discord RPC mods
|
|
||||||
- --filesystem=xdg-run/app/com.discordapp.Discord:create
|
|
||||||
# Mod drag&drop
|
|
||||||
- --filesystem=xdg-download:ro
|
|
||||||
# FTBApp import
|
|
||||||
- --filesystem=~/.ftba:ro
|
|
||||||
# Userspace visibility for manual hugepages configuration
|
|
||||||
# Required for -XX:+UseLargePages
|
|
||||||
- --filesystem=/sys/kernel/mm/hugepages:ro
|
|
||||||
# Userspace visibility for transparent hugepages configuration
|
|
||||||
# Required for -XX:+UseTransparentHugePages
|
|
||||||
- --filesystem=/sys/kernel/mm/transparent_hugepage:ro
|
|
||||||
|
|
||||||
modules:
|
|
||||||
- cmark.yml
|
|
||||||
- tomlplusplus.yml
|
|
||||||
|
|
||||||
# Might be needed by some Controller mods (see https://github.com/isXander/Controlify/issues/31)
|
|
||||||
- shared-modules/libusb/libusb.json
|
|
||||||
|
|
||||||
# Needed for proper Wayland support
|
|
||||||
- libdecor.json
|
|
||||||
|
|
||||||
# Text to Speech in the game
|
|
||||||
- flite.json
|
|
||||||
|
|
||||||
- name: prismlauncher
|
|
||||||
buildsystem: cmake-ninja
|
|
||||||
builddir: true
|
|
||||||
config-opts:
|
|
||||||
- -DLauncher_BUILD_PLATFORM=flatpak
|
|
||||||
# This allows us to manage and update Java independently of this Flatpak
|
|
||||||
- -DLauncher_ENABLE_JAVA_DOWNLOADER=ON
|
|
||||||
- -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
|
||||||
build-options:
|
|
||||||
env:
|
|
||||||
JAVA_HOME: /usr/lib/sdk/openjdk17/jvm/openjdk-17
|
|
||||||
JAVA_COMPILER: /usr/lib/sdk/openjdk17/jvm/openjdk-17/bin/javac
|
|
||||||
run-tests: true
|
|
||||||
sources:
|
|
||||||
- type: dir
|
|
||||||
path: ../
|
|
||||||
|
|
||||||
- name: glfw
|
|
||||||
buildsystem: cmake-ninja
|
|
||||||
config-opts:
|
|
||||||
- -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
|
||||||
- -DBUILD_SHARED_LIBS:BOOL=ON
|
|
||||||
- -DGLFW_BUILD_WAYLAND:BOOL=ON
|
|
||||||
- -DGLFW_BUILD_DOCS:BOOL=OFF
|
|
||||||
sources:
|
|
||||||
- type: git
|
|
||||||
url: https://github.com/glfw/glfw.git
|
|
||||||
commit: 7b6aead9fb88b3623e3b3725ebb42670cbe4c579 # 3.4
|
|
||||||
- type: patch
|
|
||||||
path: patches/0009-Defer-setting-cursor-position-until-the-cursor-is-lo.patch
|
|
||||||
cleanup:
|
|
||||||
- /include
|
|
||||||
- /lib/cmake
|
|
||||||
- /lib/pkgconfig
|
|
||||||
|
|
||||||
- name: xrandr
|
|
||||||
buildsystem: autotools
|
|
||||||
sources:
|
|
||||||
- type: archive
|
|
||||||
url: https://xorg.freedesktop.org/archive/individual/app/xrandr-1.5.3.tar.xz
|
|
||||||
sha256: f8dd7566adb74147fab9964680b6bbadee87cf406a7fcff51718a5e6949b841c
|
|
||||||
x-checker-data:
|
|
||||||
type: anitya
|
|
||||||
project-id: 14957
|
|
||||||
stable-only: true
|
|
||||||
url-template: https://xorg.freedesktop.org/archive/individual/app/xrandr-$version.tar.xz
|
|
||||||
cleanup:
|
|
||||||
- /share/man
|
|
||||||
- /bin/xkeystone
|
|
||||||
|
|
||||||
- name: gamemode
|
|
||||||
buildsystem: meson
|
|
||||||
config-opts:
|
|
||||||
- -Dwith-sd-bus-provider=no-daemon
|
|
||||||
- -Dwith-examples=false
|
|
||||||
post-install:
|
|
||||||
# gamemoderun is installed for users who want to use wrapper commands
|
|
||||||
# post-install is running inside the build dir, we need it from the source though
|
|
||||||
- install -Dm755 ../data/gamemoderun -t /app/bin
|
|
||||||
sources:
|
|
||||||
- type: archive
|
|
||||||
dest-filename: gamemode.tar.gz
|
|
||||||
url: https://api.github.com/repos/FeralInteractive/gamemode/tarball/1.8.2
|
|
||||||
sha256: 2886d4ce543c78bd2a364316d5e7fd59ef06b71de63f896b37c6d3dc97658f60
|
|
||||||
x-checker-data:
|
|
||||||
type: json
|
|
||||||
url: https://api.github.com/repos/FeralInteractive/gamemode/releases/latest
|
|
||||||
version-query: .tag_name
|
|
||||||
url-query: .tarball_url
|
|
||||||
timestamp-query: .published_at
|
|
||||||
cleanup:
|
|
||||||
- /include
|
|
||||||
- /lib/pkgconfig
|
|
||||||
- /lib/libgamemodeauto.a
|
|
||||||
|
|
||||||
- name: glxinfo
|
|
||||||
buildsystem: meson
|
|
||||||
config-opts:
|
|
||||||
- --bindir=/app/mesa-demos
|
|
||||||
- -Degl=disabled
|
|
||||||
- -Dglut=disabled
|
|
||||||
- -Dosmesa=disabled
|
|
||||||
- -Dvulkan=disabled
|
|
||||||
- -Dwayland=disabled
|
|
||||||
post-install:
|
|
||||||
- mv -v /app/mesa-demos/glxinfo /app/bin
|
|
||||||
sources:
|
|
||||||
- type: archive
|
|
||||||
url: https://archive.mesa3d.org/demos/mesa-demos-9.0.0.tar.xz
|
|
||||||
sha256: 3046a3d26a7b051af7ebdd257a5f23bfeb160cad6ed952329cdff1e9f1ed496b
|
|
||||||
x-checker-data:
|
|
||||||
type: anitya
|
|
||||||
project-id: 16781
|
|
||||||
stable-only: true
|
|
||||||
url-template: https://archive.mesa3d.org/demos/mesa-demos-$version.tar.xz
|
|
||||||
cleanup:
|
|
||||||
- /include
|
|
||||||
- /mesa-demos
|
|
||||||
- /share
|
|
||||||
modules:
|
|
||||||
- shared-modules/glu/glu-9.json
|
|
||||||
|
|
||||||
- name: enhance
|
|
||||||
buildsystem: simple
|
|
||||||
build-commands:
|
|
||||||
- install -Dm755 prime-run /app/bin/prime-run
|
|
||||||
- mv /app/bin/prismlauncher /app/bin/prismrun
|
|
||||||
- install -Dm755 prismlauncher /app/bin/prismlauncher
|
|
||||||
sources:
|
|
||||||
- type: file
|
|
||||||
path: prime-run
|
|
||||||
- type: file
|
|
||||||
path: prismlauncher
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
export __NV_PRIME_RENDER_OFFLOAD=1 __VK_LAYER_NV_optimus=NVIDIA_only __GLX_VENDOR_LIBRARY_NAME=nvidia
|
|
||||||
exec "$@"
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# discord RPC
|
|
||||||
for i in {0..9}; do
|
|
||||||
test -S "$XDG_RUNTIME_DIR"/discord-ipc-"$i" || ln -sf {app/com.discordapp.Discord,"$XDG_RUNTIME_DIR"}/discord-ipc-"$i";
|
|
||||||
done
|
|
||||||
|
|
||||||
export PATH="${PATH}${PATH:+:}/usr/lib/extensions/vulkan/gamescope/bin:/usr/lib/extensions/vulkan/MangoHud/bin"
|
|
||||||
export VK_LAYER_PATH="/usr/lib/extensions/vulkan/share/vulkan/implicit_layer.d/"
|
|
||||||
|
|
||||||
exec /app/bin/prismrun "$@"
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit 73f08ed2c3187f6648ca04ebef030930a6c9f0be
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
name: tomlplusplus
|
|
||||||
buildsystem: cmake-ninja
|
|
||||||
sources:
|
|
||||||
- type: archive
|
|
||||||
url: https://github.com/marzer/tomlplusplus/archive/v3.4.0.tar.gz
|
|
||||||
sha256: 8517f65938a4faae9ccf8ebb36631a38c1cadfb5efa85d9a72e15b9e97d25155
|
|
||||||
|
|
@ -50,6 +50,7 @@
|
||||||
#include "tools/GenericProfiler.h"
|
#include "tools/GenericProfiler.h"
|
||||||
#include "ui/InstanceWindow.h"
|
#include "ui/InstanceWindow.h"
|
||||||
#include "ui/MainWindow.h"
|
#include "ui/MainWindow.h"
|
||||||
|
#include "ui/ToolTipFilter.h"
|
||||||
#include "ui/ViewLogWindow.h"
|
#include "ui/ViewLogWindow.h"
|
||||||
|
|
||||||
#include "ui/dialogs/ProgressDialog.h"
|
#include "ui/dialogs/ProgressDialog.h"
|
||||||
|
|
@ -125,12 +126,11 @@
|
||||||
#include <LocalPeer.h>
|
#include <LocalPeer.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys.h>
|
|
||||||
#include "SysInfo.h"
|
#include "SysInfo.h"
|
||||||
|
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include "MangoHud.h"
|
#include "LibraryUtils.h"
|
||||||
#include "gamemode_client.h"
|
#include "gamemode_client.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -157,7 +157,6 @@
|
||||||
#endif
|
#endif
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <QStyleHints>
|
#include <QStyleHints>
|
||||||
#include "console/WindowsConsole.h"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "console/Console.h"
|
#include "console/Console.h"
|
||||||
|
|
@ -291,21 +290,9 @@ std::tuple<QDateTime, QString, QString, QString, QString> read_lock_File(const Q
|
||||||
|
|
||||||
Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
||||||
{
|
{
|
||||||
#if defined Q_OS_WIN32
|
|
||||||
// attach the parent console if stdout not already captured
|
|
||||||
if (AttachWindowsConsole()) {
|
|
||||||
consoleAttached = true;
|
|
||||||
if (auto err = EnableAnsiSupport(); !err) {
|
|
||||||
isANSIColorConsole = true;
|
|
||||||
} else {
|
|
||||||
std::cout << "Error setting up ansi console" << err.message() << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (console::isConsole()) {
|
if (console::isConsole()) {
|
||||||
isANSIColorConsole = true;
|
isANSIColorConsole = true;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
setOrganizationName(BuildConfig.LAUNCHER_NAME);
|
setOrganizationName(BuildConfig.LAUNCHER_NAME);
|
||||||
setOrganizationDomain(BuildConfig.LAUNCHER_DOMAIN);
|
setOrganizationDomain(BuildConfig.LAUNCHER_DOMAIN);
|
||||||
|
|
@ -331,6 +318,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
||||||
{ { "a", "profile" }, "Use the account specified by its profile name (only valid in combination with --launch)", "profile" },
|
{ { "a", "profile" }, "Use the account specified by its profile name (only valid in combination with --launch)", "profile" },
|
||||||
{ { "o", "offline" }, "Launch offline, with given player name (only valid in combination with --launch)", "offline" },
|
{ { "o", "offline" }, "Launch offline, with given player name (only valid in combination with --launch)", "offline" },
|
||||||
{ "alive", "Write a small '" + liveCheckFile + "' file after the launcher starts" },
|
{ "alive", "Write a small '" + liveCheckFile + "' file after the launcher starts" },
|
||||||
|
{ "show-window", "Show the main launcher window (useful in combination with --launch)" },
|
||||||
{ { "I", "import" }, "Import instance or resource from specified local path or URL", "url" },
|
{ { "I", "import" }, "Import instance or resource from specified local path or URL", "url" },
|
||||||
{ "show", "Opens the window for the specified instance (by instance ID)", "show" } });
|
{ "show", "Opens the window for the specified instance (by instance ID)", "show" } });
|
||||||
// Has to be positional for some OS to handle that properly
|
// Has to be positional for some OS to handle that properly
|
||||||
|
|
@ -346,12 +334,13 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
||||||
m_worldToJoin = parser.value("world");
|
m_worldToJoin = parser.value("world");
|
||||||
m_profileToUse = parser.value("profile");
|
m_profileToUse = parser.value("profile");
|
||||||
if (parser.isSet("offline")) {
|
if (parser.isSet("offline")) {
|
||||||
m_offline = true;
|
m_launchOffline = true;
|
||||||
m_offlineName = parser.value("offline");
|
m_offlineName = parser.value("offline");
|
||||||
}
|
}
|
||||||
m_liveCheck = parser.isSet("alive");
|
m_liveCheck = parser.isSet("alive");
|
||||||
|
|
||||||
m_instanceIdToShowWindowOf = parser.value("show");
|
m_instanceIdToShowWindowOf = parser.value("show");
|
||||||
|
m_showMainWindow = parser.isSet("show-window");
|
||||||
|
|
||||||
for (auto url : parser.values("import")) {
|
for (auto url : parser.values("import")) {
|
||||||
m_urlsToImport.append(normalizeImportUrl(url));
|
m_urlsToImport.append(normalizeImportUrl(url));
|
||||||
|
|
@ -363,7 +352,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
// error if --launch is missing with --server or --profile
|
// error if --launch is missing with --server or --profile
|
||||||
if ((!m_serverToJoin.isEmpty() || !m_worldToJoin.isEmpty() || !m_profileToUse.isEmpty() || m_offline) &&
|
if ((!m_serverToJoin.isEmpty() || !m_worldToJoin.isEmpty() || !m_profileToUse.isEmpty() || m_launchOffline) &&
|
||||||
m_instanceIdToLaunch.isEmpty()) {
|
m_instanceIdToLaunch.isEmpty()) {
|
||||||
std::cerr << "--server, --profile and --offline can only be used in combination with --launch!" << std::endl;
|
std::cerr << "--server, --profile and --offline can only be used in combination with --launch!" << std::endl;
|
||||||
m_status = Application::Failed;
|
m_status = Application::Failed;
|
||||||
|
|
@ -371,25 +360,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
QString origcwdPath = QDir::currentPath();
|
QString origcwdPath = QDir::currentPath();
|
||||||
#if defined(Q_OS_LINUX)
|
|
||||||
const QString binFilePath = applicationFilePath();
|
|
||||||
const bool isAppImage = binFilePath.startsWith("/tmp/.mount_");
|
|
||||||
// Yes, this can technically trigger the logic below if someone makes an AppImage with an actual launcher exe named "ld-linux"
|
|
||||||
// Please don't :)
|
|
||||||
const bool executedFromLinker = QFileInfo(binFilePath).fileName().startsWith("ld-linux");
|
|
||||||
|
|
||||||
// NOTE(@getchoo): In order for `go-appimage` to generate self-contained AppImages, it executes apps from a bundled linker at
|
|
||||||
// <root>/lib64
|
|
||||||
// This is not the path to our actual binary, which we want
|
|
||||||
QString binPath;
|
|
||||||
if (isAppImage && executedFromLinker) {
|
|
||||||
binPath = FS::PathCombine(applicationDirPath(), "../usr/bin");
|
|
||||||
} else {
|
|
||||||
binPath = applicationDirPath();
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
QString binPath = applicationDirPath();
|
QString binPath = applicationDirPath();
|
||||||
#endif
|
|
||||||
|
|
||||||
{
|
{
|
||||||
// Root path is used for updates and portable data
|
// Root path is used for updates and portable data
|
||||||
|
|
@ -423,7 +394,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
||||||
} else {
|
} else {
|
||||||
QDir foo;
|
QDir foo;
|
||||||
if (DesktopServices::isSnap()) {
|
if (DesktopServices::isSnap()) {
|
||||||
foo = QDir(getenv("SNAP_USER_COMMON"));
|
foo = QDir(qEnvironmentVariable("SNAP_USER_COMMON"));
|
||||||
} else {
|
} else {
|
||||||
foo = QDir(FS::PathCombine(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation), ".."));
|
foo = QDir(FS::PathCombine(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation), ".."));
|
||||||
}
|
}
|
||||||
|
|
@ -509,7 +480,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
||||||
if (!m_profileToUse.isEmpty()) {
|
if (!m_profileToUse.isEmpty()) {
|
||||||
launch.args["profile"] = m_profileToUse;
|
launch.args["profile"] = m_profileToUse;
|
||||||
}
|
}
|
||||||
if (m_offline) {
|
if (m_launchOffline) {
|
||||||
launch.args["offline_enabled"] = "true";
|
launch.args["offline_enabled"] = "true";
|
||||||
launch.args["offline_name"] = m_offlineName;
|
launch.args["offline_name"] = m_offlineName;
|
||||||
}
|
}
|
||||||
|
|
@ -543,12 +514,13 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
||||||
logFile = std::unique_ptr<QFile>(new QFile(logBase.arg(0)));
|
logFile = std::unique_ptr<QFile>(new QFile(logBase.arg(0)));
|
||||||
if (!logFile->open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
|
if (!logFile->open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
|
||||||
showFatalErrorMessage("The launcher data folder is not writable!",
|
showFatalErrorMessage("The launcher data folder is not writable!",
|
||||||
QString("The launcher couldn't create a log file - the data folder is not writable.\n"
|
QString("The launcher couldn't create a log file - %1.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Make sure you have write permissions to the data folder.\n"
|
"Make sure you have write permissions to the data folder.\n"
|
||||||
"(%1)\n"
|
"(%2)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"The launcher cannot continue until you fix this problem.")
|
"The launcher cannot continue until you fix this problem.")
|
||||||
|
.arg(logFile->errorString())
|
||||||
.arg(dataPath));
|
.arg(dataPath));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -606,39 +578,37 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
bool migrated = false;
|
auto migrated = handleDataMigration(
|
||||||
|
dataPath, FS::PathCombine(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation), "../../PolyMC"), "PolyMC",
|
||||||
if (!migrated)
|
"polymc.cfg");
|
||||||
migrated = handleDataMigration(
|
if (!migrated) {
|
||||||
dataPath, FS::PathCombine(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation), "../../PolyMC"), "PolyMC",
|
handleDataMigration(dataPath,
|
||||||
"polymc.cfg");
|
FS::PathCombine(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation), "../../multimc"),
|
||||||
if (!migrated)
|
"MultiMC", "multimc.cfg");
|
||||||
migrated = handleDataMigration(
|
}
|
||||||
dataPath, FS::PathCombine(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation), "../../multimc"), "MultiMC",
|
|
||||||
"multimc.cfg");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
qInfo() << qPrintable(BuildConfig.LAUNCHER_DISPLAYNAME + ", " + QString(BuildConfig.LAUNCHER_COPYRIGHT).replace("\n", ", "));
|
qInfo() << qPrintable(BuildConfig.LAUNCHER_DISPLAYNAME + ", " + QString(BuildConfig.LAUNCHER_COPYRIGHT).replace("\n", ", "));
|
||||||
qInfo() << "Version : " << BuildConfig.printableVersionString();
|
qInfo() << "Version :" << BuildConfig.printableVersionString();
|
||||||
qInfo() << "Platform : " << BuildConfig.BUILD_PLATFORM;
|
qInfo() << "Platform :" << BuildConfig.BUILD_PLATFORM;
|
||||||
qInfo() << "Git commit : " << BuildConfig.GIT_COMMIT;
|
qInfo() << "Git commit :" << BuildConfig.GIT_COMMIT;
|
||||||
qInfo() << "Git refspec : " << BuildConfig.GIT_REFSPEC;
|
qInfo() << "Git refspec :" << BuildConfig.GIT_REFSPEC;
|
||||||
qInfo() << "Compiled for : " << BuildConfig.systemID();
|
qInfo() << "Compiled for :" << BuildConfig.systemID();
|
||||||
qInfo() << "Compiled by : " << BuildConfig.compilerID();
|
qInfo() << "Compiled by :" << BuildConfig.compilerID();
|
||||||
qInfo() << "Build Artifact : " << BuildConfig.BUILD_ARTIFACT;
|
qInfo() << "Build Artifact :" << BuildConfig.BUILD_ARTIFACT;
|
||||||
qInfo() << "Updates Enabled : " << (updaterEnabled() ? "Yes" : "No");
|
qInfo() << "Updates Enabled :" << (updaterEnabled() ? "Yes" : "No");
|
||||||
if (adjustedBy.size()) {
|
if (adjustedBy.size()) {
|
||||||
qInfo() << "Work dir before adjustment : " << origcwdPath;
|
qInfo() << "Work dir before adjustment :" << origcwdPath;
|
||||||
qInfo() << "Work dir after adjustment : " << QDir::currentPath();
|
qInfo() << "Work dir after adjustment :" << QDir::currentPath();
|
||||||
qInfo() << "Adjusted by : " << adjustedBy;
|
qInfo() << "Adjusted by :" << adjustedBy;
|
||||||
} else {
|
} else {
|
||||||
qInfo() << "Work dir : " << QDir::currentPath();
|
qInfo() << "Work dir :" << QDir::currentPath();
|
||||||
}
|
}
|
||||||
qInfo() << "Binary path : " << binPath;
|
qInfo() << "Binary path :" << binPath;
|
||||||
qInfo() << "Application root path : " << m_rootPath;
|
qInfo() << "Application root path :" << m_rootPath;
|
||||||
if (!m_instanceIdToLaunch.isEmpty()) {
|
if (!m_instanceIdToLaunch.isEmpty()) {
|
||||||
qInfo() << "ID of instance to launch : " << m_instanceIdToLaunch;
|
qInfo() << "ID of instance to launch :" << m_instanceIdToLaunch;
|
||||||
}
|
}
|
||||||
if (!m_serverToJoin.isEmpty()) {
|
if (!m_serverToJoin.isEmpty()) {
|
||||||
qInfo() << "Address of server to join :" << m_serverToJoin;
|
qInfo() << "Address of server to join :" << m_serverToJoin;
|
||||||
|
|
@ -655,11 +625,11 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
||||||
if (check.write(payload) == payload.size()) {
|
if (check.write(payload) == payload.size()) {
|
||||||
check.close();
|
check.close();
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "Could not write into" << liveCheckFile << "!";
|
qWarning() << "Could not write into" << liveCheckFile << "error:" << check.errorString();
|
||||||
check.remove(); // also closes file!
|
check.remove(); // also closes file!
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "Could not open" << liveCheckFile << "for writing!";
|
qWarning() << "Could not open" << liveCheckFile << "for writing:" << check.errorString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -702,8 +672,8 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
||||||
QFontInfo consoleFontInfo(consoleFont);
|
QFontInfo consoleFontInfo(consoleFont);
|
||||||
QString resolvedDefaultMonospace = consoleFontInfo.family();
|
QString resolvedDefaultMonospace = consoleFontInfo.family();
|
||||||
QFont resolvedFont(resolvedDefaultMonospace);
|
QFont resolvedFont(resolvedDefaultMonospace);
|
||||||
qDebug() << "Detected default console font:" << resolvedDefaultMonospace
|
qDebug().nospace() << "Detected default console font: " << resolvedDefaultMonospace
|
||||||
<< ", substitutions:" << resolvedFont.substitutions().join(',');
|
<< ", substitutions: " << resolvedFont.substitutions().join(',');
|
||||||
|
|
||||||
m_settings->registerSetting("ConsoleFont", resolvedDefaultMonospace);
|
m_settings->registerSetting("ConsoleFont", resolvedDefaultMonospace);
|
||||||
m_settings->registerSetting("ConsoleFontSize", defaultSize);
|
m_settings->registerSetting("ConsoleFontSize", defaultSize);
|
||||||
|
|
@ -761,8 +731,9 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
||||||
|
|
||||||
// Memory
|
// Memory
|
||||||
m_settings->registerSetting({ "MinMemAlloc", "MinMemoryAlloc" }, 512);
|
m_settings->registerSetting({ "MinMemAlloc", "MinMemoryAlloc" }, 512);
|
||||||
m_settings->registerSetting({ "MaxMemAlloc", "MaxMemoryAlloc" }, SysInfo::suitableMaxMem());
|
m_settings->registerSetting({ "MaxMemAlloc", "MaxMemoryAlloc" }, SysInfo::defaultMaxJvmMem());
|
||||||
m_settings->registerSetting("PermGen", 128);
|
m_settings->registerSetting("PermGen", 128);
|
||||||
|
m_settings->registerSetting("LowMemWarning", true);
|
||||||
|
|
||||||
// Java Settings
|
// Java Settings
|
||||||
m_settings->registerSetting("JavaPath", "");
|
m_settings->registerSetting("JavaPath", "");
|
||||||
|
|
@ -805,6 +776,8 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
||||||
m_settings->registerSetting("ModMetadataDisabled", false);
|
m_settings->registerSetting("ModMetadataDisabled", false);
|
||||||
m_settings->registerSetting("ModDependenciesDisabled", false);
|
m_settings->registerSetting("ModDependenciesDisabled", false);
|
||||||
m_settings->registerSetting("SkipModpackUpdatePrompt", false);
|
m_settings->registerSetting("SkipModpackUpdatePrompt", false);
|
||||||
|
m_settings->registerSetting("ShowModIncompat", false);
|
||||||
|
m_settings->registerSetting("DownloadGameFilesDuringInstanceCreation", true);
|
||||||
|
|
||||||
// Minecraft offline player name
|
// Minecraft offline player name
|
||||||
m_settings->registerSetting("LastOfflinePlayerName", "");
|
m_settings->registerSetting("LastOfflinePlayerName", "");
|
||||||
|
|
@ -845,6 +818,8 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
||||||
|
|
||||||
m_settings->registerSetting("UpdateDialogGeometry", "");
|
m_settings->registerSetting("UpdateDialogGeometry", "");
|
||||||
|
|
||||||
|
m_settings->registerSetting("NewsGeometry", "");
|
||||||
|
|
||||||
m_settings->registerSetting("ModDownloadGeometry", "");
|
m_settings->registerSetting("ModDownloadGeometry", "");
|
||||||
m_settings->registerSetting("RPDownloadGeometry", "");
|
m_settings->registerSetting("RPDownloadGeometry", "");
|
||||||
m_settings->registerSetting("TPDownloadGeometry", "");
|
m_settings->registerSetting("TPDownloadGeometry", "");
|
||||||
|
|
@ -879,25 +854,23 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
auto resetIfInvalid = [this](const Setting* setting) {
|
||||||
|
if (const QUrl url(setting->get().toString()); !url.isValid() || (url.scheme() != "http" && url.scheme() != "https")) {
|
||||||
|
m_settings->reset(setting->id());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Meta URL
|
// Meta URL
|
||||||
m_settings->registerSetting("MetaURLOverride", "");
|
resetIfInvalid(m_settings->registerSetting("MetaURLOverride", "").get());
|
||||||
|
|
||||||
QUrl metaUrl(m_settings->get("MetaURLOverride").toString());
|
|
||||||
|
|
||||||
// get rid of invalid meta urls
|
|
||||||
if (!metaUrl.isValid() || (metaUrl.scheme() != "http" && metaUrl.scheme() != "https"))
|
|
||||||
m_settings->reset("MetaURLOverride");
|
|
||||||
|
|
||||||
// Resource URL
|
// Resource URL
|
||||||
m_settings->registerSetting("ResourceURL", BuildConfig.DEFAULT_RESOURCE_BASE);
|
resetIfInvalid(m_settings->registerSetting({ "ResourceURLOverride", "ResourceURL" }, "").get());
|
||||||
|
|
||||||
QUrl resourceUrl(m_settings->get("ResourceURL").toString());
|
// Legacy FML libs URL
|
||||||
|
resetIfInvalid(m_settings->registerSetting("LegacyFMLLibsURLOverride", "").get());
|
||||||
// get rid of invalid resource urls
|
|
||||||
if (!resourceUrl.isValid() || (resourceUrl.scheme() != "http" && resourceUrl.scheme() != "https"))
|
|
||||||
m_settings->reset("ResourceURL");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_settings->registerSetting("MetaRefreshOnLaunch", true);
|
||||||
m_settings->registerSetting("CloseAfterLaunch", false);
|
m_settings->registerSetting("CloseAfterLaunch", false);
|
||||||
m_settings->registerSetting("QuitAfterGameStop", false);
|
m_settings->registerSetting("QuitAfterGameStop", false);
|
||||||
|
|
||||||
|
|
@ -917,6 +890,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
||||||
m_settings->set("FlameKeyOverride", flameKey);
|
m_settings->set("FlameKeyOverride", flameKey);
|
||||||
m_settings->reset("CFKeyOverride");
|
m_settings->reset("CFKeyOverride");
|
||||||
}
|
}
|
||||||
|
m_settings->registerSetting("FallbackMRBlockedMods", true);
|
||||||
m_settings->registerSetting("ModrinthToken", "");
|
m_settings->registerSetting("ModrinthToken", "");
|
||||||
m_settings->registerSetting("UserAgentOverride", "");
|
m_settings->registerSetting("UserAgentOverride", "");
|
||||||
|
|
||||||
|
|
@ -928,7 +902,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
||||||
|
|
||||||
// Init page provider
|
// Init page provider
|
||||||
{
|
{
|
||||||
m_globalSettingsProvider = std::make_shared<GenericPageProvider>(tr("Settings"));
|
m_globalSettingsProvider = std::make_unique<GenericPageProvider>(tr("Settings"));
|
||||||
m_globalSettingsProvider->addPage<LauncherPage>();
|
m_globalSettingsProvider->addPage<LauncherPage>();
|
||||||
m_globalSettingsProvider->addPage<LanguagePage>();
|
m_globalSettingsProvider->addPage<LanguagePage>();
|
||||||
m_globalSettingsProvider->addPage<AppearancePage>();
|
m_globalSettingsProvider->addPage<AppearancePage>();
|
||||||
|
|
@ -961,15 +935,6 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
||||||
qInfo() << "<> Network done.";
|
qInfo() << "<> Network done.";
|
||||||
}
|
}
|
||||||
|
|
||||||
// load translations
|
|
||||||
{
|
|
||||||
m_translations.reset(new TranslationsModel("translations"));
|
|
||||||
auto bcp47Name = m_settings->get("Language").toString();
|
|
||||||
m_translations->selectLanguage(bcp47Name);
|
|
||||||
qInfo() << "Your language is" << bcp47Name;
|
|
||||||
qInfo() << "<> Translations loaded.";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Instance icons
|
// Instance icons
|
||||||
{
|
{
|
||||||
auto setting = APPLICATION->settings()->getSetting("IconsDir");
|
auto setting = APPLICATION->settings()->getSetting("IconsDir");
|
||||||
|
|
@ -1005,11 +970,11 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
||||||
// instance path: check for problems with '!' in instance path and warn the user in the log
|
// instance path: check for problems with '!' in instance path and warn the user in the log
|
||||||
// and remember that we have to show him a dialog when the gui starts (if it does so)
|
// and remember that we have to show him a dialog when the gui starts (if it does so)
|
||||||
QString instDir = m_settings->get("InstanceDir").toString();
|
QString instDir = m_settings->get("InstanceDir").toString();
|
||||||
qInfo() << "Instance path : " << instDir;
|
qInfo() << "Instance path :" << instDir;
|
||||||
if (FS::checkProblemticPathJava(QDir(instDir))) {
|
if (FS::checkProblemticPathJava(QDir(instDir))) {
|
||||||
qWarning() << "Your instance path contains \'!\' and this is known to cause java problems!";
|
qWarning() << "Your instance path contains \'!\' and this is known to cause java problems!";
|
||||||
}
|
}
|
||||||
m_instances.reset(new InstanceList(m_settings, instDir, this));
|
m_instances.reset(new InstanceList(m_settings.get(), instDir, this));
|
||||||
connect(InstDirSetting.get(), &Setting::SettingChanged, m_instances.get(), &InstanceList::on_InstFolderChanged);
|
connect(InstDirSetting.get(), &Setting::SettingChanged, m_instances.get(), &InstanceList::on_InstFolderChanged);
|
||||||
qInfo() << "Loading Instances...";
|
qInfo() << "Loading Instances...";
|
||||||
m_instances->loadList();
|
m_instances->loadList();
|
||||||
|
|
@ -1043,24 +1008,30 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
||||||
m_metacache->addBase("translations", QDir("translations").absolutePath());
|
m_metacache->addBase("translations", QDir("translations").absolutePath());
|
||||||
m_metacache->addBase("meta", QDir("meta").absolutePath());
|
m_metacache->addBase("meta", QDir("meta").absolutePath());
|
||||||
m_metacache->addBase("java", QDir("cache/java").absolutePath());
|
m_metacache->addBase("java", QDir("cache/java").absolutePath());
|
||||||
|
m_metacache->addBase("feed", QDir("cache/feed").absolutePath());
|
||||||
m_metacache->Load();
|
m_metacache->Load();
|
||||||
qInfo() << "<> Cache initialized.";
|
qInfo() << "<> Cache initialized.";
|
||||||
}
|
}
|
||||||
|
|
||||||
// now we have network, download translation updates
|
// load translations
|
||||||
m_translations->downloadIndex();
|
{
|
||||||
|
m_translations.reset(new TranslationsModel("translations"));
|
||||||
|
m_translations->downloadIndex();
|
||||||
|
qInfo() << "Your language is" << m_translations->selectedLanguage();
|
||||||
|
qInfo() << "<> Translations loaded.";
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: what to do with these?
|
// FIXME: what to do with these?
|
||||||
m_profilers.insert("jprofiler", std::shared_ptr<BaseProfilerFactory>(new JProfilerFactory()));
|
m_profilers.insert("jprofiler", std::shared_ptr<BaseProfilerFactory>(new JProfilerFactory()));
|
||||||
m_profilers.insert("jvisualvm", std::shared_ptr<BaseProfilerFactory>(new JVisualVMFactory()));
|
m_profilers.insert("jvisualvm", std::shared_ptr<BaseProfilerFactory>(new JVisualVMFactory()));
|
||||||
m_profilers.insert("generic", std::shared_ptr<BaseProfilerFactory>(new GenericProfilerFactory()));
|
m_profilers.insert("generic", std::shared_ptr<BaseProfilerFactory>(new GenericProfilerFactory()));
|
||||||
for (auto profiler : m_profilers.values()) {
|
for (auto profiler : m_profilers.values()) {
|
||||||
profiler->registerSettings(m_settings);
|
profiler->registerSettings(m_settings.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the MCEdit thing... why is this here?
|
// Create the MCEdit thing... why is this here?
|
||||||
{
|
{
|
||||||
m_mcedit.reset(new MCEditTool(m_settings));
|
m_mcedit.reset(new MCEditTool(m_settings.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef Q_OS_MACOS
|
#ifdef Q_OS_MACOS
|
||||||
|
|
@ -1217,6 +1188,10 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (qgetenv("XDG_CURRENT_DESKTOP") == "gamescope") {
|
||||||
|
installEventFilter(new ToolTipFilter);
|
||||||
|
}
|
||||||
|
|
||||||
if (createSetupWizard()) {
|
if (createSetupWizard()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -1377,8 +1352,11 @@ void Application::performMainStartupAction()
|
||||||
qDebug() << " Launching with account" << m_profileToUse;
|
qDebug() << " Launching with account" << m_profileToUse;
|
||||||
}
|
}
|
||||||
|
|
||||||
launch(inst, !m_offline, false, targetToJoin, accountToUse, m_offlineName);
|
launch(inst, m_launchOffline ? LaunchMode::Offline : LaunchMode::Normal, targetToJoin, accountToUse, m_offlineName);
|
||||||
return;
|
|
||||||
|
if (!m_showMainWindow) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!m_instanceIdToShowWindowOf.isEmpty()) {
|
if (!m_instanceIdToShowWindowOf.isEmpty()) {
|
||||||
|
|
@ -1431,16 +1409,6 @@ Application::~Application()
|
||||||
{
|
{
|
||||||
// Shut down logger by setting the logger function to nothing
|
// Shut down logger by setting the logger function to nothing
|
||||||
qInstallMessageHandler(nullptr);
|
qInstallMessageHandler(nullptr);
|
||||||
|
|
||||||
#if defined Q_OS_WIN32
|
|
||||||
// Detach from Windows console
|
|
||||||
if (consoleAttached) {
|
|
||||||
fclose(stdout);
|
|
||||||
fclose(stdin);
|
|
||||||
fclose(stderr);
|
|
||||||
FreeConsole();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::messageReceived(const QByteArray& message)
|
void Application::messageReceived(const QByteArray& message)
|
||||||
|
|
@ -1482,7 +1450,7 @@ void Application::messageReceived(const QByteArray& message)
|
||||||
bool offline = received.args["offline_enabled"] == "true";
|
bool offline = received.args["offline_enabled"] == "true";
|
||||||
QString offlineName = received.args["offline_name"];
|
QString offlineName = received.args["offline_name"];
|
||||||
|
|
||||||
InstancePtr instance;
|
BaseInstance* instance;
|
||||||
if (!id.isEmpty()) {
|
if (!id.isEmpty()) {
|
||||||
instance = instances()->getInstanceById(id);
|
instance = instances()->getInstanceById(id);
|
||||||
if (!instance) {
|
if (!instance) {
|
||||||
|
|
@ -1510,23 +1478,23 @@ void Application::messageReceived(const QByteArray& message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
launch(instance, !offline, false, serverObject, accountObject, offlineName);
|
launch(instance, offline ? LaunchMode::Offline : LaunchMode::Normal, serverObject, accountObject, offlineName);
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "Received invalid message" << message;
|
qWarning() << "Received invalid message" << message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<TranslationsModel> Application::translations()
|
TranslationsModel* Application::translations()
|
||||||
{
|
{
|
||||||
return m_translations;
|
return m_translations.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<JavaInstallList> Application::javalist()
|
JavaInstallList* Application::javalist()
|
||||||
{
|
{
|
||||||
if (!m_javalist) {
|
if (!m_javalist) {
|
||||||
m_javalist.reset(new JavaInstallList());
|
m_javalist.reset(new JavaInstallList());
|
||||||
}
|
}
|
||||||
return m_javalist;
|
return m_javalist.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
QIcon Application::logo()
|
QIcon Application::logo()
|
||||||
|
|
@ -1545,9 +1513,8 @@ bool Application::openJsonEditor(const QString& filename)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Application::launch(InstancePtr instance,
|
bool Application::launch(BaseInstance* instance,
|
||||||
bool online,
|
LaunchMode mode,
|
||||||
bool demo,
|
|
||||||
MinecraftTarget::Ptr targetToJoin,
|
MinecraftTarget::Ptr targetToJoin,
|
||||||
MinecraftAccountPtr accountToUse,
|
MinecraftAccountPtr accountToUse,
|
||||||
const QString& offlineName)
|
const QString& offlineName)
|
||||||
|
|
@ -1566,8 +1533,7 @@ bool Application::launch(InstancePtr instance,
|
||||||
auto& controller = extras.controller;
|
auto& controller = extras.controller;
|
||||||
controller.reset(new LaunchController());
|
controller.reset(new LaunchController());
|
||||||
controller->setInstance(instance);
|
controller->setInstance(instance);
|
||||||
controller->setOnline(online);
|
controller->setLaunchMode(mode);
|
||||||
controller->setDemo(demo);
|
|
||||||
controller->setProfiler(profilers().value(instance->settings()->get("Profiler").toString(), nullptr).get());
|
controller->setProfiler(profilers().value(instance->settings()->get("Profiler").toString(), nullptr).get());
|
||||||
controller->setTargetToJoin(targetToJoin);
|
controller->setTargetToJoin(targetToJoin);
|
||||||
controller->setAccountToUse(accountToUse);
|
controller->setAccountToUse(accountToUse);
|
||||||
|
|
@ -1577,9 +1543,7 @@ bool Application::launch(InstancePtr instance,
|
||||||
} else if (m_mainWindow) {
|
} else if (m_mainWindow) {
|
||||||
controller->setParentWidget(m_mainWindow);
|
controller->setParentWidget(m_mainWindow);
|
||||||
}
|
}
|
||||||
connect(controller.get(), &LaunchController::succeeded, this, &Application::controllerSucceeded);
|
connect(controller.get(), &LaunchController::finished, this, &Application::controllerFinished);
|
||||||
connect(controller.get(), &LaunchController::failed, this, &Application::controllerFailed);
|
|
||||||
connect(controller.get(), &LaunchController::aborted, this, [this] { controllerFailed(tr("Aborted")); });
|
|
||||||
addRunningInstance();
|
addRunningInstance();
|
||||||
QMetaObject::invokeMethod(controller.get(), &Task::start, Qt::QueuedConnection);
|
QMetaObject::invokeMethod(controller.get(), &Task::start, Qt::QueuedConnection);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -1593,7 +1557,7 @@ bool Application::launch(InstancePtr instance,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Application::kill(InstancePtr instance)
|
bool Application::kill(BaseInstance* instance)
|
||||||
{
|
{
|
||||||
if (!instance->isRunning()) {
|
if (!instance->isRunning()) {
|
||||||
qWarning() << "Attempted to kill instance" << instance->id() << ", which isn't running.";
|
qWarning() << "Attempted to kill instance" << instance->id() << ", which isn't running.";
|
||||||
|
|
@ -1602,7 +1566,7 @@ bool Application::kill(InstancePtr instance)
|
||||||
QMutexLocker locker(&m_instanceExtrasMutex);
|
QMutexLocker locker(&m_instanceExtrasMutex);
|
||||||
auto& extras = m_instanceExtras[instance->id()];
|
auto& extras = m_instanceExtras[instance->id()];
|
||||||
// NOTE: copy of the shared pointer keeps it alive
|
// NOTE: copy of the shared pointer keeps it alive
|
||||||
auto controller = extras.controller;
|
auto& controller = extras.controller;
|
||||||
locker.unlock();
|
locker.unlock();
|
||||||
if (controller) {
|
if (controller) {
|
||||||
return controller->abort();
|
return controller->abort();
|
||||||
|
|
@ -1651,7 +1615,7 @@ void Application::updateIsRunning(bool running)
|
||||||
m_updateRunning = running;
|
m_updateRunning = running;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::controllerSucceeded()
|
void Application::controllerFinished()
|
||||||
{
|
{
|
||||||
auto controller = qobject_cast<LaunchController*>(sender());
|
auto controller = qobject_cast<LaunchController*>(sender());
|
||||||
if (!controller)
|
if (!controller)
|
||||||
|
|
@ -1659,10 +1623,11 @@ void Application::controllerSucceeded()
|
||||||
auto id = controller->id();
|
auto id = controller->id();
|
||||||
|
|
||||||
QMutexLocker locker(&m_instanceExtrasMutex);
|
QMutexLocker locker(&m_instanceExtrasMutex);
|
||||||
auto& extras = m_instanceExtras[id];
|
auto& extras = m_instanceExtras.at(id);
|
||||||
|
|
||||||
|
const bool wasSuccessful = controller->wasSuccessful();
|
||||||
// on success, do...
|
// on success, do...
|
||||||
if (controller->instance()->settings()->get("AutoCloseConsole").toBool()) {
|
if (wasSuccessful && controller->instance()->settings()->get("AutoCloseConsole").toBool()) {
|
||||||
if (extras.window) {
|
if (extras.window) {
|
||||||
QMetaObject::invokeMethod(extras.window, &QWidget::close, Qt::QueuedConnection);
|
QMetaObject::invokeMethod(extras.window, &QWidget::close, Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
|
|
@ -1672,29 +1637,8 @@ void Application::controllerSucceeded()
|
||||||
|
|
||||||
// quit when there are no more windows.
|
// quit when there are no more windows.
|
||||||
if (shouldExitNow()) {
|
if (shouldExitNow()) {
|
||||||
m_status = Status::Succeeded;
|
m_status = wasSuccessful ? Succeeded : Failed;
|
||||||
exit(0);
|
exit(wasSuccessful ? 0 : 1);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::controllerFailed(const QString& error)
|
|
||||||
{
|
|
||||||
Q_UNUSED(error);
|
|
||||||
auto controller = qobject_cast<LaunchController*>(sender());
|
|
||||||
if (!controller)
|
|
||||||
return;
|
|
||||||
auto id = controller->id();
|
|
||||||
QMutexLocker locker(&m_instanceExtrasMutex);
|
|
||||||
auto& extras = m_instanceExtras[id];
|
|
||||||
|
|
||||||
// on failure, do... nothing
|
|
||||||
extras.controller.reset();
|
|
||||||
subRunningInstance();
|
|
||||||
|
|
||||||
// quit when there are no more windows.
|
|
||||||
if (shouldExitNow()) {
|
|
||||||
m_status = Status::Failed;
|
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1751,7 +1695,7 @@ ViewLogWindow* Application::showLogWindow()
|
||||||
return m_viewLogWindow;
|
return m_viewLogWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
InstanceWindow* Application::showInstanceWindow(InstancePtr instance, QString page)
|
InstanceWindow* Application::showInstanceWindow(BaseInstance* instance, QString page)
|
||||||
{
|
{
|
||||||
if (!instance)
|
if (!instance)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
@ -1863,22 +1807,22 @@ void Application::updateProxySettings(QString proxyTypeStr, QString addr, int po
|
||||||
qDebug() << proxyDesc;
|
qDebug() << proxyDesc;
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_qobject_ptr<HttpMetaCache> Application::metacache()
|
HttpMetaCache* Application::metacache()
|
||||||
{
|
{
|
||||||
return m_metacache;
|
return m_metacache.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_qobject_ptr<QNetworkAccessManager> Application::network()
|
QNetworkAccessManager* Application::network()
|
||||||
{
|
{
|
||||||
return m_network;
|
return m_network.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_qobject_ptr<Meta::Index> Application::metadataIndex()
|
Meta::Index* Application::metadataIndex()
|
||||||
{
|
{
|
||||||
if (!m_metadataIndex) {
|
if (!m_metadataIndex) {
|
||||||
m_metadataIndex.reset(new Meta::Index());
|
m_metadataIndex.reset(new Meta::Index());
|
||||||
}
|
}
|
||||||
return m_metadataIndex;
|
return m_metadataIndex.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::updateCapabilities()
|
void Application::updateCapabilities()
|
||||||
|
|
@ -1893,7 +1837,7 @@ void Application::updateCapabilities()
|
||||||
if (gamemode_query_status() >= 0)
|
if (gamemode_query_status() >= 0)
|
||||||
m_capabilities |= SupportsGameMode;
|
m_capabilities |= SupportsGameMode;
|
||||||
|
|
||||||
if (!MangoHud::getLibraryString().isEmpty())
|
if (!LibraryUtils::findMangoHud().isEmpty())
|
||||||
m_capabilities |= SupportsMangoHud;
|
m_capabilities |= SupportsMangoHud;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
@ -1901,8 +1845,8 @@ void Application::updateCapabilities()
|
||||||
void Application::detectLibraries()
|
void Application::detectLibraries()
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
m_detectedGLFWPath = MangoHud::findLibrary(BuildConfig.GLFW_LIBRARY_NAME);
|
m_detectedGLFWPath = LibraryUtils::find(BuildConfig.GLFW_LIBRARY_NAME);
|
||||||
m_detectedOpenALPath = MangoHud::findLibrary(BuildConfig.OPENAL_LIBRARY_NAME);
|
m_detectedOpenALPath = LibraryUtils::find(BuildConfig.OPENAL_LIBRARY_NAME);
|
||||||
qDebug() << "Detected native libraries:" << m_detectedGLFWPath << m_detectedOpenALPath;
|
qDebug() << "Detected native libraries:" << m_detectedGLFWPath << m_detectedOpenALPath;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
@ -2009,7 +1953,7 @@ bool Application::handleDataMigration(const QString& currentData,
|
||||||
auto setDoNotMigrate = [&nomigratePath] {
|
auto setDoNotMigrate = [&nomigratePath] {
|
||||||
QFile file(nomigratePath);
|
QFile file(nomigratePath);
|
||||||
if (!file.open(QIODevice::WriteOnly)) {
|
if (!file.open(QIODevice::WriteOnly)) {
|
||||||
qWarning() << "setDoNotMigrate failed; Failed to open file '" << file.fileName() << "' for writing!";
|
qWarning() << "setDoNotMigrate failed; Failed to open file" << file.fileName() << "for writing:" << file.errorString();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -2063,7 +2007,7 @@ void Application::triggerUpdateCheck()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QUrl Application::normalizeImportUrl(QString const& url)
|
QUrl Application::normalizeImportUrl(const QString& url)
|
||||||
{
|
{
|
||||||
auto local_file = QFileInfo(url);
|
auto local_file = QFileInfo(url);
|
||||||
if (local_file.exists()) {
|
if (local_file.exists()) {
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
@ -44,12 +46,10 @@
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include <BaseInstance.h>
|
#include "QObjectPtr.h"
|
||||||
|
|
||||||
#include "launch/LogModel.h"
|
#include "minecraft/auth/MinecraftAccount.h"
|
||||||
#include "minecraft/launch/MinecraftTarget.h"
|
|
||||||
|
|
||||||
class LaunchController;
|
class LaunchController;
|
||||||
class LocalPeer;
|
class LocalPeer;
|
||||||
|
|
@ -74,6 +74,12 @@ class ITheme;
|
||||||
class MCEditTool;
|
class MCEditTool;
|
||||||
class ThemeManager;
|
class ThemeManager;
|
||||||
class IconTheme;
|
class IconTheme;
|
||||||
|
class BaseInstance;
|
||||||
|
|
||||||
|
class LogModel;
|
||||||
|
|
||||||
|
struct MinecraftTarget;
|
||||||
|
class MinecraftAccount;
|
||||||
|
|
||||||
namespace Meta {
|
namespace Meta {
|
||||||
class Index;
|
class Index;
|
||||||
|
|
@ -91,7 +97,6 @@ class Index;
|
||||||
#define APPLICATION_DYN (dynamic_cast<Application*>(QCoreApplication::instance()))
|
#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
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
enum Status { StartingUp, Failed, Succeeded, Initialized };
|
enum Status { StartingUp, Failed, Succeeded, Initialized };
|
||||||
|
|
@ -112,7 +117,7 @@ class Application : public QApplication {
|
||||||
|
|
||||||
bool event(QEvent* event) override;
|
bool event(QEvent* event) override;
|
||||||
|
|
||||||
std::shared_ptr<SettingsObject> settings() const { return m_settings; }
|
SettingsObject* settings() const { return m_settings.get(); }
|
||||||
|
|
||||||
qint64 timeSinceStart() const { return m_startTime.msecsTo(QDateTime::currentDateTime()); }
|
qint64 timeSinceStart() const { return m_startTime.msecsTo(QDateTime::currentDateTime()); }
|
||||||
|
|
||||||
|
|
@ -120,21 +125,21 @@ class Application : public QApplication {
|
||||||
|
|
||||||
ThemeManager* themeManager() { return m_themeManager.get(); }
|
ThemeManager* themeManager() { return m_themeManager.get(); }
|
||||||
|
|
||||||
shared_qobject_ptr<ExternalUpdater> updater() { return m_updater; }
|
ExternalUpdater* updater() { return m_updater.get(); }
|
||||||
|
|
||||||
void triggerUpdateCheck();
|
void triggerUpdateCheck();
|
||||||
|
|
||||||
std::shared_ptr<TranslationsModel> translations();
|
TranslationsModel* translations();
|
||||||
|
|
||||||
std::shared_ptr<JavaInstallList> javalist();
|
JavaInstallList* javalist();
|
||||||
|
|
||||||
std::shared_ptr<InstanceList> instances() const { return m_instances; }
|
InstanceList* instances() const { return m_instances.get(); }
|
||||||
|
|
||||||
std::shared_ptr<IconList> icons() const { return m_icons; }
|
IconList* icons() const { return m_icons.get(); }
|
||||||
|
|
||||||
MCEditTool* mcedit() const { return m_mcedit.get(); }
|
MCEditTool* mcedit() const { return m_mcedit.get(); }
|
||||||
|
|
||||||
shared_qobject_ptr<AccountList> accounts() const { return m_accounts; }
|
AccountList* accounts() const { return m_accounts.get(); }
|
||||||
|
|
||||||
Status status() const { return m_status; }
|
Status status() const { return m_status; }
|
||||||
|
|
||||||
|
|
@ -142,11 +147,11 @@ class Application : public QApplication {
|
||||||
|
|
||||||
void updateProxySettings(QString proxyTypeStr, QString addr, int port, QString user, QString password);
|
void updateProxySettings(QString proxyTypeStr, QString addr, int port, QString user, QString password);
|
||||||
|
|
||||||
shared_qobject_ptr<QNetworkAccessManager> network();
|
QNetworkAccessManager* network();
|
||||||
|
|
||||||
shared_qobject_ptr<HttpMetaCache> metacache();
|
HttpMetaCache* metacache();
|
||||||
|
|
||||||
shared_qobject_ptr<Meta::Index> metadataIndex();
|
Meta::Index* metadataIndex();
|
||||||
|
|
||||||
void updateCapabilities();
|
void updateCapabilities();
|
||||||
|
|
||||||
|
|
@ -182,7 +187,7 @@ class Application : public QApplication {
|
||||||
*/
|
*/
|
||||||
bool openJsonEditor(const QString& filename);
|
bool openJsonEditor(const QString& filename);
|
||||||
|
|
||||||
InstanceWindow* showInstanceWindow(InstancePtr instance, QString page = QString());
|
InstanceWindow* showInstanceWindow(BaseInstance* instance, QString page = QString());
|
||||||
MainWindow* showMainWindow(bool minimized = false);
|
MainWindow* showMainWindow(bool minimized = false);
|
||||||
ViewLogWindow* showLogWindow();
|
ViewLogWindow* showLogWindow();
|
||||||
|
|
||||||
|
|
@ -194,7 +199,7 @@ class Application : public QApplication {
|
||||||
bool updaterEnabled();
|
bool updaterEnabled();
|
||||||
QString updaterBinaryName();
|
QString updaterBinaryName();
|
||||||
|
|
||||||
QUrl normalizeImportUrl(QString const& url);
|
QUrl normalizeImportUrl(const QString& url);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void updateAllowedChanged(bool status);
|
void updateAllowedChanged(bool status);
|
||||||
|
|
@ -209,20 +214,18 @@ class Application : public QApplication {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
bool launch(InstancePtr instance,
|
bool launch(BaseInstance* instance,
|
||||||
bool online = true,
|
LaunchMode mode = LaunchMode::Normal,
|
||||||
bool demo = false,
|
std::shared_ptr<MinecraftTarget> targetToJoin = nullptr,
|
||||||
MinecraftTarget::Ptr targetToJoin = nullptr,
|
shared_qobject_ptr<MinecraftAccount> accountToUse = nullptr,
|
||||||
MinecraftAccountPtr accountToUse = nullptr,
|
|
||||||
const QString& offlineName = QString());
|
const QString& offlineName = QString());
|
||||||
bool kill(InstancePtr instance);
|
bool kill(BaseInstance* instance);
|
||||||
void closeCurrentWindow();
|
void closeCurrentWindow();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_windowClose();
|
void on_windowClose();
|
||||||
void messageReceived(const QByteArray& message);
|
void messageReceived(const QByteArray& message);
|
||||||
void controllerSucceeded();
|
void controllerFinished();
|
||||||
void controllerFailed(const QString& error);
|
|
||||||
void setupWizardFinished(int status);
|
void setupWizardFinished(int status);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -238,23 +241,27 @@ class Application : public QApplication {
|
||||||
void subRunningInstance();
|
void subRunningInstance();
|
||||||
bool shouldExitNow() const;
|
bool shouldExitNow() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QHash<QString, int> m_qsaveResources;
|
||||||
|
mutable QMutex m_qsaveResourcesMutex;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QDateTime m_startTime;
|
QDateTime m_startTime;
|
||||||
|
|
||||||
shared_qobject_ptr<QNetworkAccessManager> m_network;
|
std::unique_ptr<QNetworkAccessManager> m_network;
|
||||||
|
|
||||||
shared_qobject_ptr<ExternalUpdater> m_updater;
|
std::unique_ptr<ExternalUpdater> m_updater;
|
||||||
shared_qobject_ptr<AccountList> m_accounts;
|
std::unique_ptr<AccountList> m_accounts;
|
||||||
|
|
||||||
shared_qobject_ptr<HttpMetaCache> m_metacache;
|
std::unique_ptr<HttpMetaCache> m_metacache;
|
||||||
shared_qobject_ptr<Meta::Index> m_metadataIndex;
|
std::unique_ptr<Meta::Index> m_metadataIndex;
|
||||||
|
|
||||||
std::shared_ptr<SettingsObject> m_settings;
|
std::unique_ptr<SettingsObject> m_settings;
|
||||||
std::shared_ptr<InstanceList> m_instances;
|
std::unique_ptr<InstanceList> m_instances;
|
||||||
std::shared_ptr<IconList> m_icons;
|
std::unique_ptr<IconList> m_icons;
|
||||||
std::shared_ptr<JavaInstallList> m_javalist;
|
std::unique_ptr<JavaInstallList> m_javalist;
|
||||||
std::shared_ptr<TranslationsModel> m_translations;
|
std::unique_ptr<TranslationsModel> m_translations;
|
||||||
std::shared_ptr<GenericPageProvider> m_globalSettingsProvider;
|
std::unique_ptr<GenericPageProvider> m_globalSettingsProvider;
|
||||||
std::unique_ptr<MCEditTool> m_mcedit;
|
std::unique_ptr<MCEditTool> m_mcedit;
|
||||||
QSet<QString> m_features;
|
QSet<QString> m_features;
|
||||||
std::unique_ptr<ThemeManager> m_themeManager;
|
std::unique_ptr<ThemeManager> m_themeManager;
|
||||||
|
|
@ -271,15 +278,10 @@ class Application : public QApplication {
|
||||||
Qt::ApplicationState m_prevAppState = Qt::ApplicationInactive;
|
Qt::ApplicationState m_prevAppState = Qt::ApplicationInactive;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined Q_OS_WIN32
|
|
||||||
// used on Windows to attach the standard IO streams
|
|
||||||
bool consoleAttached = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// FIXME: attach to instances instead.
|
// FIXME: attach to instances instead.
|
||||||
struct InstanceXtras {
|
struct InstanceXtras {
|
||||||
InstanceWindow* window = nullptr;
|
InstanceWindow* window = nullptr;
|
||||||
shared_qobject_ptr<LaunchController> controller;
|
std::unique_ptr<LaunchController> controller;
|
||||||
};
|
};
|
||||||
std::map<QString, InstanceXtras> m_instanceExtras;
|
std::map<QString, InstanceXtras> m_instanceExtras;
|
||||||
mutable QMutex m_instanceExtrasMutex;
|
mutable QMutex m_instanceExtrasMutex;
|
||||||
|
|
@ -307,20 +309,17 @@ class Application : public QApplication {
|
||||||
QString m_serverToJoin;
|
QString m_serverToJoin;
|
||||||
QString m_worldToJoin;
|
QString m_worldToJoin;
|
||||||
QString m_profileToUse;
|
QString m_profileToUse;
|
||||||
bool m_offline = false;
|
bool m_launchOffline = false;
|
||||||
QString m_offlineName;
|
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;
|
||||||
|
bool m_showMainWindow = false;
|
||||||
std::unique_ptr<QFile> logFile;
|
std::unique_ptr<QFile> logFile;
|
||||||
shared_qobject_ptr<LogModel> logModel;
|
std::unique_ptr<LogModel> logModel;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void addQSavePath(QString);
|
void addQSavePath(QString);
|
||||||
void removeQSavePath(QString);
|
void removeQSavePath(QString);
|
||||||
bool checkQSavePath(QString);
|
bool checkQSavePath(QString);
|
||||||
|
|
||||||
private:
|
|
||||||
QHash<QString, int> m_qsaveResources;
|
|
||||||
mutable QMutex m_qsaveResourcesMutex;
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
25
launcher/AssertHelpers.h
Normal file
25
launcher/AssertHelpers.h
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (C) 2025 Octol1ttle <l1ttleofficial@outlook.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if defined(ASSERT_NEVER)
|
||||||
|
#error ASSERT_NEVER already defined
|
||||||
|
#else
|
||||||
|
#define ASSERT_NEVER(cond) (Q_ASSERT((cond) == false), (cond))
|
||||||
|
#endif
|
||||||
|
|
@ -45,6 +45,7 @@
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "Json.h"
|
#include "Json.h"
|
||||||
|
#include "launch/LaunchTask.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"
|
||||||
|
|
@ -53,7 +54,7 @@
|
||||||
#include "Commandline.h"
|
#include "Commandline.h"
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
|
|
||||||
int getConsoleMaxLines(SettingsObjectPtr settings)
|
int getConsoleMaxLines(SettingsObject* settings)
|
||||||
{
|
{
|
||||||
auto lineSetting = settings->getSetting("ConsoleMaxLines");
|
auto lineSetting = settings->getSetting("ConsoleMaxLines");
|
||||||
bool conversionOk = false;
|
bool conversionOk = false;
|
||||||
|
|
@ -65,14 +66,14 @@ int getConsoleMaxLines(SettingsObjectPtr settings)
|
||||||
return maxLines;
|
return maxLines;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool shouldStopOnConsoleOverflow(SettingsObjectPtr settings)
|
bool shouldStopOnConsoleOverflow(SettingsObject* settings)
|
||||||
{
|
{
|
||||||
return settings->get("ConsoleOverflowStop").toBool();
|
return settings->get("ConsoleOverflowStop").toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString& rootDir) : QObject()
|
BaseInstance::BaseInstance(SettingsObject* globalSettings, std::unique_ptr<SettingsObject> settings, const QString& rootDir) : QObject()
|
||||||
{
|
{
|
||||||
m_settings = settings;
|
m_settings = std::move(settings);
|
||||||
m_global_settings = globalSettings;
|
m_global_settings = globalSettings;
|
||||||
m_rootDir = rootDir;
|
m_rootDir = rootDir;
|
||||||
|
|
||||||
|
|
@ -122,10 +123,13 @@ BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr s
|
||||||
m_settings->registerSetting("ManagedPackName", "");
|
m_settings->registerSetting("ManagedPackName", "");
|
||||||
m_settings->registerSetting("ManagedPackVersionID", "");
|
m_settings->registerSetting("ManagedPackVersionID", "");
|
||||||
m_settings->registerSetting("ManagedPackVersionName", "");
|
m_settings->registerSetting("ManagedPackVersionName", "");
|
||||||
|
m_settings->registerSetting("ManagedPackURL", "");
|
||||||
|
|
||||||
m_settings->registerSetting("Profiler", "");
|
m_settings->registerSetting("Profiler", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BaseInstance::~BaseInstance() {}
|
||||||
|
|
||||||
QString BaseInstance::getPreLaunchCommand()
|
QString BaseInstance::getPreLaunchCommand()
|
||||||
{
|
{
|
||||||
return settings()->get("PreLaunchCommand").toString();
|
return settings()->get("PreLaunchCommand").toString();
|
||||||
|
|
@ -335,11 +339,11 @@ QString BaseInstance::instanceRoot() const
|
||||||
return m_rootDir;
|
return m_rootDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsObjectPtr BaseInstance::settings()
|
SettingsObject* BaseInstance::settings()
|
||||||
{
|
{
|
||||||
loadSpecificSettings();
|
loadSpecificSettings();
|
||||||
|
|
||||||
return m_settings;
|
return m_settings.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseInstance::canLaunch() const
|
bool BaseInstance::canLaunch() const
|
||||||
|
|
@ -467,9 +471,9 @@ QStringList BaseInstance::extraArguments()
|
||||||
return Commandline::splitArgs(settings()->get("JvmArgs").toString());
|
return Commandline::splitArgs(settings()->get("JvmArgs").toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_qobject_ptr<LaunchTask> BaseInstance::getLaunchTask()
|
LaunchTask* BaseInstance::getLaunchTask()
|
||||||
{
|
{
|
||||||
return m_launchProcess;
|
return m_launchProcess.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseInstance::updateRuntimeContext()
|
void BaseInstance::updateRuntimeContext()
|
||||||
|
|
|
||||||
|
|
@ -64,9 +64,6 @@ class Task;
|
||||||
class LaunchTask;
|
class LaunchTask;
|
||||||
class BaseInstance;
|
class BaseInstance;
|
||||||
|
|
||||||
// pointer for lazy people
|
|
||||||
using InstancePtr = std::shared_ptr<BaseInstance>;
|
|
||||||
|
|
||||||
/// Shortcut saving target representations
|
/// Shortcut saving target representations
|
||||||
enum class ShortcutTarget { Desktop, Applications, Other };
|
enum class ShortcutTarget { Desktop, Applications, Other };
|
||||||
|
|
||||||
|
|
@ -78,8 +75,8 @@ struct ShortcutData {
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Console settings
|
/// Console settings
|
||||||
int getConsoleMaxLines(SettingsObjectPtr settings);
|
int getConsoleMaxLines(SettingsObject* settings);
|
||||||
bool shouldStopOnConsoleOverflow(SettingsObjectPtr settings);
|
bool shouldStopOnConsoleOverflow(SettingsObject* settings);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Base class for instances.
|
* \brief Base class for instances.
|
||||||
|
|
@ -89,11 +86,11 @@ bool shouldStopOnConsoleOverflow(SettingsObjectPtr settings);
|
||||||
* To create a new instance type, create a new class inheriting from this class
|
* To create a new instance type, create a new class inheriting from this class
|
||||||
* and implement the pure virtual functions.
|
* and implement the pure virtual functions.
|
||||||
*/
|
*/
|
||||||
class BaseInstance : public QObject, public std::enable_shared_from_this<BaseInstance> {
|
class BaseInstance : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
protected:
|
protected:
|
||||||
/// no-touchy!
|
/// no-touchy!
|
||||||
BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString& rootDir);
|
BaseInstance(SettingsObject* globalSettings, std::unique_ptr<SettingsObject> settings, const QString& rootDir);
|
||||||
|
|
||||||
public: /* types */
|
public: /* types */
|
||||||
enum class Status {
|
enum class Status {
|
||||||
|
|
@ -103,7 +100,7 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// virtual destructor to make sure the destruction is COMPLETE
|
/// virtual destructor to make sure the destruction is COMPLETE
|
||||||
virtual ~BaseInstance() {}
|
virtual ~BaseInstance();
|
||||||
|
|
||||||
virtual void saveNow() = 0;
|
virtual void saveNow() = 0;
|
||||||
|
|
||||||
|
|
@ -193,7 +190,7 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
|
||||||
*
|
*
|
||||||
* \return A pointer to this instance's settings object.
|
* \return A pointer to this instance's settings object.
|
||||||
*/
|
*/
|
||||||
virtual SettingsObjectPtr settings();
|
virtual SettingsObject* settings();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Loads settings specific to an instance type if they're not already loaded.
|
* \brief Loads settings specific to an instance type if they're not already loaded.
|
||||||
|
|
@ -204,10 +201,10 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
|
||||||
virtual QList<Task::Ptr> createUpdateTask() = 0;
|
virtual QList<Task::Ptr> createUpdateTask() = 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 LaunchTask* createLaunchTask(AuthSessionPtr account, MinecraftTarget::Ptr targetToJoin) = 0;
|
||||||
|
|
||||||
/// returns the current launch task (if any)
|
/// returns the current launch task (if any)
|
||||||
shared_qobject_ptr<LaunchTask> getLaunchTask();
|
LaunchTask* getLaunchTask();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Create envrironment variables for running the instance
|
* Create envrironment variables for running the instance
|
||||||
|
|
@ -286,7 +283,7 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
|
||||||
protected:
|
protected:
|
||||||
void changeStatus(Status newStatus);
|
void changeStatus(Status newStatus);
|
||||||
|
|
||||||
SettingsObjectPtr globalSettings() const { return m_global_settings.lock(); }
|
SettingsObject* globalSettings() const { return m_global_settings; }
|
||||||
|
|
||||||
bool isSpecificSettingsLoaded() const { return m_specific_settings_loaded; }
|
bool isSpecificSettingsLoaded() const { return m_specific_settings_loaded; }
|
||||||
void setSpecificSettingsLoaded(bool loaded) { m_specific_settings_loaded = loaded; }
|
void setSpecificSettingsLoaded(bool loaded) { m_specific_settings_loaded = loaded; }
|
||||||
|
|
@ -297,7 +294,7 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
|
||||||
*/
|
*/
|
||||||
void propertiesChanged(BaseInstance* inst);
|
void propertiesChanged(BaseInstance* inst);
|
||||||
|
|
||||||
void launchTaskChanged(shared_qobject_ptr<LaunchTask>);
|
void launchTaskChanged(LaunchTask*);
|
||||||
|
|
||||||
void runningStatusChanged(bool running);
|
void runningStatusChanged(bool running);
|
||||||
|
|
||||||
|
|
@ -310,10 +307,10 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
|
||||||
|
|
||||||
protected: /* data */
|
protected: /* data */
|
||||||
QString m_rootDir;
|
QString m_rootDir;
|
||||||
SettingsObjectPtr m_settings;
|
std::unique_ptr<SettingsObject> m_settings;
|
||||||
// InstanceFlags m_flags;
|
// InstanceFlags m_flags;
|
||||||
bool m_isRunning = false;
|
bool m_isRunning = false;
|
||||||
shared_qobject_ptr<LaunchTask> m_launchProcess;
|
std::unique_ptr<LaunchTask> m_launchProcess;
|
||||||
QDateTime m_timeStarted;
|
QDateTime m_timeStarted;
|
||||||
RuntimeContext m_runtimeContext;
|
RuntimeContext m_runtimeContext;
|
||||||
|
|
||||||
|
|
@ -323,7 +320,7 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
|
||||||
bool m_hasUpdate = false;
|
bool m_hasUpdate = false;
|
||||||
bool m_hasBrokenVersion = false;
|
bool m_hasBrokenVersion = false;
|
||||||
|
|
||||||
SettingsObjectWeakPtr m_global_settings;
|
SettingsObject* m_global_settings;
|
||||||
bool m_specific_settings_loaded = false;
|
bool m_specific_settings_loaded = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
*/
|
*/
|
||||||
class BaseVersion {
|
class BaseVersion {
|
||||||
public:
|
public:
|
||||||
|
// TODO: delete
|
||||||
using Ptr = std::shared_ptr<BaseVersion>;
|
using Ptr = std::shared_ptr<BaseVersion>;
|
||||||
virtual ~BaseVersion() {}
|
virtual ~BaseVersion() {}
|
||||||
/*!
|
/*!
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ class BaseVersionList : public QAbstractListModel {
|
||||||
* The task returned by this function should reset the model when it's done.
|
* The task returned by this function should reset the model when it's done.
|
||||||
* \return A pointer to a task that reloads the version list.
|
* \return A pointer to a task that reloads the version list.
|
||||||
*/
|
*/
|
||||||
virtual Task::Ptr getLoadTask() = 0;
|
virtual Task::Ptr getLoadTask(bool forceReload = false) = 0;
|
||||||
|
|
||||||
//! Checks whether or not the list is loaded. If this returns false, the list should be
|
//! Checks whether or not the list is loaded. If this returns false, the list should be
|
||||||
// loaded.
|
// loaded.
|
||||||
|
|
|
||||||
|
|
@ -26,13 +26,13 @@ set(CORE_SOURCES
|
||||||
NullInstance.h
|
NullInstance.h
|
||||||
MMCZip.h
|
MMCZip.h
|
||||||
MMCZip.cpp
|
MMCZip.cpp
|
||||||
archive/ArchiveReader.cpp
|
archive/ArchiveReader.cpp
|
||||||
archive/ArchiveReader.h
|
archive/ArchiveReader.h
|
||||||
archive/ArchiveWriter.cpp
|
archive/ArchiveWriter.cpp
|
||||||
archive/ArchiveWriter.h
|
archive/ArchiveWriter.h
|
||||||
archive/ExportToZipTask.cpp
|
archive/ExportToZipTask.cpp
|
||||||
archive/ExportToZipTask.h
|
archive/ExportToZipTask.h
|
||||||
archive/ExtractZipTask.cpp
|
archive/ExtractZipTask.cpp
|
||||||
archive/ExtractZipTask.h
|
archive/ExtractZipTask.h
|
||||||
StringUtils.h
|
StringUtils.h
|
||||||
StringUtils.cpp
|
StringUtils.cpp
|
||||||
|
|
@ -75,9 +75,6 @@ set(CORE_SOURCES
|
||||||
# RW lock protected map
|
# RW lock protected map
|
||||||
RWStorage.h
|
RWStorage.h
|
||||||
|
|
||||||
# A variable that has an implicit default value and keeps track of changes
|
|
||||||
DefaultVariable.h
|
|
||||||
|
|
||||||
# a smart pointer wrapper intended for safer use with Qt signal/slot mechanisms
|
# a smart pointer wrapper intended for safer use with Qt signal/slot mechanisms
|
||||||
QObjectPtr.h
|
QObjectPtr.h
|
||||||
|
|
||||||
|
|
@ -102,14 +99,17 @@ set(CORE_SOURCES
|
||||||
MMCTime.cpp
|
MMCTime.cpp
|
||||||
|
|
||||||
MTPixmapCache.h
|
MTPixmapCache.h
|
||||||
|
|
||||||
|
# Assertion helper
|
||||||
|
AssertHelpers.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
|
# LibraryUtils
|
||||||
MangoHud.h
|
LibraryUtils.h
|
||||||
MangoHud.cpp
|
LibraryUtils.cpp
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
@ -119,6 +119,7 @@ set(NET_SOURCES
|
||||||
net/ChecksumValidator.h
|
net/ChecksumValidator.h
|
||||||
net/Download.cpp
|
net/Download.cpp
|
||||||
net/Download.h
|
net/Download.h
|
||||||
|
net/DummySink.h
|
||||||
net/FileSink.cpp
|
net/FileSink.cpp
|
||||||
net/FileSink.h
|
net/FileSink.h
|
||||||
net/HttpMetaCache.cpp
|
net/HttpMetaCache.cpp
|
||||||
|
|
@ -243,15 +244,13 @@ set(MINECRAFT_SOURCES
|
||||||
minecraft/auth/steps/MSAStep.h
|
minecraft/auth/steps/MSAStep.h
|
||||||
minecraft/auth/steps/XboxAuthorizationStep.cpp
|
minecraft/auth/steps/XboxAuthorizationStep.cpp
|
||||||
minecraft/auth/steps/XboxAuthorizationStep.h
|
minecraft/auth/steps/XboxAuthorizationStep.h
|
||||||
minecraft/auth/steps/XboxProfileStep.cpp
|
|
||||||
minecraft/auth/steps/XboxProfileStep.h
|
|
||||||
minecraft/auth/steps/XboxUserStep.cpp
|
minecraft/auth/steps/XboxUserStep.cpp
|
||||||
minecraft/auth/steps/XboxUserStep.h
|
minecraft/auth/steps/XboxUserStep.h
|
||||||
|
|
||||||
minecraft/update/AssetUpdateTask.h
|
minecraft/update/AssetUpdateTask.h
|
||||||
minecraft/update/AssetUpdateTask.cpp
|
minecraft/update/AssetUpdateTask.cpp
|
||||||
minecraft/update/FMLLibrariesTask.cpp
|
minecraft/update/LegacyFMLLibrariesTask.cpp
|
||||||
minecraft/update/FMLLibrariesTask.h
|
minecraft/update/LegacyFMLLibrariesTask.h
|
||||||
minecraft/update/FoldersTask.cpp
|
minecraft/update/FoldersTask.cpp
|
||||||
minecraft/update/FoldersTask.h
|
minecraft/update/FoldersTask.h
|
||||||
minecraft/update/LibrariesTask.cpp
|
minecraft/update/LibrariesTask.cpp
|
||||||
|
|
@ -261,6 +260,10 @@ set(MINECRAFT_SOURCES
|
||||||
minecraft/launch/ClaimAccount.h
|
minecraft/launch/ClaimAccount.h
|
||||||
minecraft/launch/CreateGameFolders.cpp
|
minecraft/launch/CreateGameFolders.cpp
|
||||||
minecraft/launch/CreateGameFolders.h
|
minecraft/launch/CreateGameFolders.h
|
||||||
|
minecraft/launch/EnsureAvailableMemory.cpp
|
||||||
|
minecraft/launch/EnsureAvailableMemory.h
|
||||||
|
minecraft/launch/EnsureOfflineLibraries.cpp
|
||||||
|
minecraft/launch/EnsureOfflineLibraries.h
|
||||||
minecraft/launch/ModMinecraftJar.cpp
|
minecraft/launch/ModMinecraftJar.cpp
|
||||||
minecraft/launch/ModMinecraftJar.h
|
minecraft/launch/ModMinecraftJar.h
|
||||||
minecraft/launch/ExtractNatives.cpp
|
minecraft/launch/ExtractNatives.cpp
|
||||||
|
|
@ -346,6 +349,7 @@ 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/ShaderPackFolderModel.cpp
|
||||||
minecraft/mod/tasks/ResourceFolderLoadTask.h
|
minecraft/mod/tasks/ResourceFolderLoadTask.h
|
||||||
minecraft/mod/tasks/ResourceFolderLoadTask.cpp
|
minecraft/mod/tasks/ResourceFolderLoadTask.cpp
|
||||||
minecraft/mod/tasks/LocalModParseTask.h
|
minecraft/mod/tasks/LocalModParseTask.h
|
||||||
|
|
@ -525,6 +529,11 @@ set(FTB_SOURCES
|
||||||
modplatform/import_ftb/PackInstallTask.cpp
|
modplatform/import_ftb/PackInstallTask.cpp
|
||||||
modplatform/import_ftb/PackHelpers.h
|
modplatform/import_ftb/PackHelpers.h
|
||||||
modplatform/import_ftb/PackHelpers.cpp
|
modplatform/import_ftb/PackHelpers.cpp
|
||||||
|
|
||||||
|
modplatform/ftb/FTBPackInstallTask.h
|
||||||
|
modplatform/ftb/FTBPackInstallTask.cpp
|
||||||
|
modplatform/ftb/FTBPackManifest.h
|
||||||
|
modplatform/ftb/FTBPackManifest.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(FLAME_SOURCES
|
set(FLAME_SOURCES
|
||||||
|
|
@ -621,10 +630,10 @@ set(PRISMUPDATER_SOURCES
|
||||||
# Zip
|
# Zip
|
||||||
MMCZip.h
|
MMCZip.h
|
||||||
MMCZip.cpp
|
MMCZip.cpp
|
||||||
archive/ArchiveReader.cpp
|
archive/ArchiveReader.cpp
|
||||||
archive/ArchiveReader.h
|
archive/ArchiveReader.h
|
||||||
archive/ArchiveWriter.cpp
|
archive/ArchiveWriter.cpp
|
||||||
archive/ArchiveWriter.h
|
archive/ArchiveWriter.h
|
||||||
|
|
||||||
# Time
|
# Time
|
||||||
MMCTime.h
|
MMCTime.h
|
||||||
|
|
@ -790,6 +799,8 @@ SET(LAUNCHER_SOURCES
|
||||||
ApplicationMessage.cpp
|
ApplicationMessage.cpp
|
||||||
SysInfo.h
|
SysInfo.h
|
||||||
SysInfo.cpp
|
SysInfo.cpp
|
||||||
|
HardwareInfo.cpp
|
||||||
|
HardwareInfo.h
|
||||||
|
|
||||||
# console utils
|
# console utils
|
||||||
console/Console.h
|
console/Console.h
|
||||||
|
|
@ -806,23 +817,6 @@ SET(LAUNCHER_SOURCES
|
||||||
KonamiCode.h
|
KonamiCode.h
|
||||||
KonamiCode.cpp
|
KonamiCode.cpp
|
||||||
|
|
||||||
# Bundled resources
|
|
||||||
resources/backgrounds/backgrounds.qrc
|
|
||||||
resources/multimc/multimc.qrc
|
|
||||||
resources/pe_dark/pe_dark.qrc
|
|
||||||
resources/pe_light/pe_light.qrc
|
|
||||||
resources/pe_colored/pe_colored.qrc
|
|
||||||
resources/pe_blue/pe_blue.qrc
|
|
||||||
resources/breeze_dark/breeze_dark.qrc
|
|
||||||
resources/breeze_light/breeze_light.qrc
|
|
||||||
resources/OSX/OSX.qrc
|
|
||||||
resources/iOS/iOS.qrc
|
|
||||||
resources/flat/flat.qrc
|
|
||||||
resources/flat_white/flat_white.qrc
|
|
||||||
resources/documents/documents.qrc
|
|
||||||
resources/shaders/shaders.qrc
|
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/../${Launcher_Branding_LogoQRC}"
|
|
||||||
|
|
||||||
# Icons
|
# Icons
|
||||||
icons/MMCIcon.h
|
icons/MMCIcon.h
|
||||||
icons/MMCIcon.cpp
|
icons/MMCIcon.cpp
|
||||||
|
|
@ -842,6 +836,8 @@ SET(LAUNCHER_SOURCES
|
||||||
ui/InstanceWindow.cpp
|
ui/InstanceWindow.cpp
|
||||||
ui/ViewLogWindow.h
|
ui/ViewLogWindow.h
|
||||||
ui/ViewLogWindow.cpp
|
ui/ViewLogWindow.cpp
|
||||||
|
ui/ToolTipFilter.h
|
||||||
|
ui/ToolTipFilter.cpp
|
||||||
|
|
||||||
# FIXME: maybe find a better home for this.
|
# FIXME: maybe find a better home for this.
|
||||||
FileIgnoreProxy.cpp
|
FileIgnoreProxy.cpp
|
||||||
|
|
@ -890,6 +886,7 @@ SET(LAUNCHER_SOURCES
|
||||||
ui/themes/CatPainter.h
|
ui/themes/CatPainter.h
|
||||||
|
|
||||||
# Processes
|
# Processes
|
||||||
|
LaunchMode.h
|
||||||
LaunchController.h
|
LaunchController.h
|
||||||
LaunchController.cpp
|
LaunchController.cpp
|
||||||
|
|
||||||
|
|
@ -1000,6 +997,13 @@ SET(LAUNCHER_SOURCES
|
||||||
ui/pages/modplatform/atlauncher/AtlUserInteractionSupportImpl.cpp
|
ui/pages/modplatform/atlauncher/AtlUserInteractionSupportImpl.cpp
|
||||||
ui/pages/modplatform/atlauncher/AtlUserInteractionSupportImpl.h
|
ui/pages/modplatform/atlauncher/AtlUserInteractionSupportImpl.h
|
||||||
|
|
||||||
|
ui/pages/modplatform/ftb/FtbFilterModel.cpp
|
||||||
|
ui/pages/modplatform/ftb/FtbFilterModel.h
|
||||||
|
ui/pages/modplatform/ftb/FtbListModel.cpp
|
||||||
|
ui/pages/modplatform/ftb/FtbListModel.h
|
||||||
|
ui/pages/modplatform/ftb/FtbPage.cpp
|
||||||
|
ui/pages/modplatform/ftb/FtbPage.h
|
||||||
|
|
||||||
ui/pages/modplatform/legacy_ftb/Page.cpp
|
ui/pages/modplatform/legacy_ftb/Page.cpp
|
||||||
ui/pages/modplatform/legacy_ftb/Page.h
|
ui/pages/modplatform/legacy_ftb/Page.h
|
||||||
ui/pages/modplatform/legacy_ftb/ListModel.h
|
ui/pages/modplatform/legacy_ftb/ListModel.h
|
||||||
|
|
@ -1063,6 +1067,8 @@ SET(LAUNCHER_SOURCES
|
||||||
ui/dialogs/ImportResourceDialog.h
|
ui/dialogs/ImportResourceDialog.h
|
||||||
ui/dialogs/MSALoginDialog.cpp
|
ui/dialogs/MSALoginDialog.cpp
|
||||||
ui/dialogs/MSALoginDialog.h
|
ui/dialogs/MSALoginDialog.h
|
||||||
|
ui/dialogs/NetworkJobFailedDialog.cpp
|
||||||
|
ui/dialogs/NetworkJobFailedDialog.h
|
||||||
ui/dialogs/NewComponentDialog.cpp
|
ui/dialogs/NewComponentDialog.cpp
|
||||||
ui/dialogs/NewComponentDialog.h
|
ui/dialogs/NewComponentDialog.h
|
||||||
ui/dialogs/NewInstanceDialog.cpp
|
ui/dialogs/NewInstanceDialog.cpp
|
||||||
|
|
@ -1200,76 +1206,6 @@ if(WIN32)
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
qt_wrap_ui(LAUNCHER_UI
|
|
||||||
ui/MainWindow.ui
|
|
||||||
ui/setupwizard/PasteWizardPage.ui
|
|
||||||
ui/setupwizard/AutoJavaWizardPage.ui
|
|
||||||
ui/setupwizard/LoginWizardPage.ui
|
|
||||||
ui/pages/global/AccountListPage.ui
|
|
||||||
ui/pages/global/JavaPage.ui
|
|
||||||
ui/pages/global/LauncherPage.ui
|
|
||||||
ui/pages/global/APIPage.ui
|
|
||||||
ui/pages/global/ProxyPage.ui
|
|
||||||
ui/pages/global/ExternalToolsPage.ui
|
|
||||||
ui/pages/instance/ExternalResourcesPage.ui
|
|
||||||
ui/pages/instance/NotesPage.ui
|
|
||||||
ui/pages/instance/LogPage.ui
|
|
||||||
ui/pages/instance/ServersPage.ui
|
|
||||||
ui/pages/instance/OtherLogsPage.ui
|
|
||||||
ui/pages/instance/VersionPage.ui
|
|
||||||
ui/pages/instance/ManagedPackPage.ui
|
|
||||||
ui/pages/instance/WorldListPage.ui
|
|
||||||
ui/pages/instance/ScreenshotsPage.ui
|
|
||||||
ui/pages/modplatform/atlauncher/AtlOptionalModDialog.ui
|
|
||||||
ui/pages/modplatform/atlauncher/AtlPage.ui
|
|
||||||
ui/pages/modplatform/CustomPage.ui
|
|
||||||
ui/pages/modplatform/ResourcePage.ui
|
|
||||||
ui/pages/modplatform/flame/FlamePage.ui
|
|
||||||
ui/pages/modplatform/legacy_ftb/Page.ui
|
|
||||||
ui/pages/modplatform/import_ftb/ImportFTBPage.ui
|
|
||||||
ui/pages/modplatform/ImportPage.ui
|
|
||||||
ui/pages/modplatform/OptionalModDialog.ui
|
|
||||||
ui/pages/modplatform/modrinth/ModrinthPage.ui
|
|
||||||
ui/pages/modplatform/technic/TechnicPage.ui
|
|
||||||
ui/widgets/CustomCommands.ui
|
|
||||||
ui/widgets/EnvironmentVariables.ui
|
|
||||||
ui/widgets/InfoFrame.ui
|
|
||||||
ui/widgets/ModFilterWidget.ui
|
|
||||||
ui/widgets/SubTaskProgressBar.ui
|
|
||||||
ui/widgets/AppearanceWidget.ui
|
|
||||||
ui/widgets/MinecraftSettingsWidget.ui
|
|
||||||
ui/widgets/JavaSettingsWidget.ui
|
|
||||||
ui/dialogs/CopyInstanceDialog.ui
|
|
||||||
ui/dialogs/CreateShortcutDialog.ui
|
|
||||||
ui/dialogs/ProfileSetupDialog.ui
|
|
||||||
ui/dialogs/ProgressDialog.ui
|
|
||||||
ui/dialogs/NewInstanceDialog.ui
|
|
||||||
ui/dialogs/NewComponentDialog.ui
|
|
||||||
ui/dialogs/NewsDialog.ui
|
|
||||||
ui/dialogs/ProfileSelectDialog.ui
|
|
||||||
ui/dialogs/ExportInstanceDialog.ui
|
|
||||||
ui/dialogs/ExportPackDialog.ui
|
|
||||||
ui/dialogs/ExportToModListDialog.ui
|
|
||||||
ui/dialogs/IconPickerDialog.ui
|
|
||||||
ui/dialogs/ImportResourceDialog.ui
|
|
||||||
ui/dialogs/MSALoginDialog.ui
|
|
||||||
ui/dialogs/AboutDialog.ui
|
|
||||||
ui/dialogs/ReviewMessageBox.ui
|
|
||||||
ui/dialogs/ScrollMessageBox.ui
|
|
||||||
ui/dialogs/BlockedModsDialog.ui
|
|
||||||
ui/dialogs/ChooseProviderDialog.ui
|
|
||||||
ui/dialogs/skins/SkinManageDialog.ui
|
|
||||||
ui/dialogs/ChooseOfflineNameDialog.ui
|
|
||||||
)
|
|
||||||
|
|
||||||
qt_wrap_ui(PRISM_UPDATE_UI
|
|
||||||
ui/dialogs/UpdateAvailableDialog.ui
|
|
||||||
)
|
|
||||||
|
|
||||||
if (NOT Apple)
|
|
||||||
set (LAUNCHER_UI ${LAUNCHER_UI} ${PRISM_UPDATE_UI})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
qt_add_resources(LAUNCHER_RESOURCES
|
qt_add_resources(LAUNCHER_RESOURCES
|
||||||
resources/backgrounds/backgrounds.qrc
|
resources/backgrounds/backgrounds.qrc
|
||||||
resources/multimc/multimc.qrc
|
resources/multimc/multimc.qrc
|
||||||
|
|
@ -1282,34 +1218,40 @@ qt_add_resources(LAUNCHER_RESOURCES
|
||||||
resources/OSX/OSX.qrc
|
resources/OSX/OSX.qrc
|
||||||
resources/iOS/iOS.qrc
|
resources/iOS/iOS.qrc
|
||||||
resources/flat/flat.qrc
|
resources/flat/flat.qrc
|
||||||
|
resources/flat_white/flat_white.qrc
|
||||||
resources/documents/documents.qrc
|
resources/documents/documents.qrc
|
||||||
resources/shaders/shaders.qrc
|
resources/shaders/shaders.qrc
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/../${Launcher_Branding_LogoQRC}"
|
"${CMAKE_CURRENT_BINARY_DIR}/../${Launcher_Branding_LogoQRC}"
|
||||||
)
|
)
|
||||||
|
|
||||||
qt_wrap_ui(PRISMUPDATER_UI
|
|
||||||
updater/prismupdater/SelectReleaseDialog.ui
|
|
||||||
ui/widgets/SubTaskProgressBar.ui
|
|
||||||
ui/dialogs/ProgressDialog.ui
|
|
||||||
)
|
|
||||||
|
|
||||||
######## Windows resource files ########
|
######## Windows resource files ########
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
set(LAUNCHER_RCS ${CMAKE_CURRENT_BINARY_DIR}/../${Launcher_Branding_WindowsRC})
|
set(LAUNCHER_RCS ${CMAKE_CURRENT_BINARY_DIR}/../${Launcher_Branding_WindowsRC})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include(CompilerWarnings)
|
######## Precompiled Headers ###########
|
||||||
|
|
||||||
|
if(${Launcher_USE_PCH})
|
||||||
|
message(STATUS "Using precompiled headers for applicable launcher targets")
|
||||||
|
set(PRECOMPILED_HEADERS
|
||||||
|
include/base.pch.hpp
|
||||||
|
include/qtcore.pch.hpp
|
||||||
|
include/qtgui.pch.hpp
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
####### Targets ########
|
||||||
|
|
||||||
# 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_RESOURCES})
|
||||||
set_project_warnings(Launcher_logic
|
|
||||||
"${Launcher_MSVC_WARNINGS}"
|
|
||||||
"${Launcher_CLANG_WARNINGS}"
|
|
||||||
"${Launcher_GCC_WARNINGS}")
|
|
||||||
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)
|
||||||
|
|
||||||
|
if(${Launcher_USE_PCH})
|
||||||
|
target_precompile_headers(Launcher_logic PRIVATE ${PRECOMPILED_HEADERS})
|
||||||
|
endif()
|
||||||
|
|
||||||
target_link_libraries(Launcher_logic
|
target_link_libraries(Launcher_logic
|
||||||
systeminfo
|
|
||||||
Launcher_murmur2
|
Launcher_murmur2
|
||||||
nbt++
|
nbt++
|
||||||
${ZLIB_LIBRARIES}
|
${ZLIB_LIBRARIES}
|
||||||
|
|
@ -1386,9 +1328,12 @@ if(APPLE)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_libraries(Launcher_logic)
|
|
||||||
|
|
||||||
add_executable(${Launcher_Name} MACOSX_BUNDLE WIN32 main.cpp ${LAUNCHER_RCS})
|
add_executable(${Launcher_Name} MACOSX_BUNDLE WIN32 main.cpp ${LAUNCHER_RCS})
|
||||||
|
|
||||||
|
if(${Launcher_USE_PCH})
|
||||||
|
target_precompile_headers(${Launcher_Name} REUSE_FROM Launcher_logic)
|
||||||
|
endif()
|
||||||
|
|
||||||
target_link_libraries(${Launcher_Name} Launcher_logic)
|
target_link_libraries(${Launcher_Name} Launcher_logic)
|
||||||
|
|
||||||
if(DEFINED Launcher_APP_BINARY_NAME)
|
if(DEFINED Launcher_APP_BINARY_NAME)
|
||||||
|
|
@ -1412,17 +1357,21 @@ install(TARGETS ${Launcher_Name}
|
||||||
)
|
)
|
||||||
|
|
||||||
# Deploy PDBs
|
# Deploy PDBs
|
||||||
if(WIN32 AND (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo"))
|
if(CMAKE_CXX_LINKER_SUPPORTS_PDB)
|
||||||
install(FILES $<TARGET_PDB_FILE:${Launcher_Name}> DESTINATION ${BINARY_DEST_DIR})
|
install(FILES $<TARGET_PDB_FILE:${Launcher_Name}> DESTINATION ${BINARY_DEST_DIR} OPTIONAL)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(Launcher_BUILD_UPDATER)
|
if(Launcher_BUILD_UPDATER)
|
||||||
# Updater
|
# Updater
|
||||||
add_library(prism_updater_logic STATIC ${PRISMUPDATER_SOURCES} ${TASKS_SOURCES} ${PRISMUPDATER_UI})
|
add_library(prism_updater_logic STATIC ${PRISMUPDATER_SOURCES} ${TASKS_SOURCES})
|
||||||
target_include_directories(prism_updater_logic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(prism_updater_logic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
|
if(${Launcher_USE_PCH})
|
||||||
|
target_precompile_headers(prism_updater_logic PRIVATE ${PRECOMPILED_HEADERS})
|
||||||
|
endif()
|
||||||
|
|
||||||
target_link_libraries(prism_updater_logic
|
target_link_libraries(prism_updater_logic
|
||||||
${ZLIB_LIBRARIES}
|
${ZLIB_LIBRARIES}
|
||||||
systeminfo
|
|
||||||
BuildConfig
|
BuildConfig
|
||||||
Qt${QT_VERSION_MAJOR}::Widgets
|
Qt${QT_VERSION_MAJOR}::Widgets
|
||||||
Qt${QT_VERSION_MAJOR}::Core
|
Qt${QT_VERSION_MAJOR}::Core
|
||||||
|
|
@ -1440,6 +1389,10 @@ if(Launcher_BUILD_UPDATER)
|
||||||
target_sources("${Launcher_Name}_updater" PRIVATE updater/prismupdater/updater.exe.manifest)
|
target_sources("${Launcher_Name}_updater" PRIVATE updater/prismupdater/updater.exe.manifest)
|
||||||
target_link_libraries("${Launcher_Name}_updater" prism_updater_logic)
|
target_link_libraries("${Launcher_Name}_updater" prism_updater_logic)
|
||||||
|
|
||||||
|
if(${Launcher_USE_PCH})
|
||||||
|
target_precompile_headers("${Launcher_Name}_updater" REUSE_FROM prism_updater_logic)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(DEFINED Launcher_APP_BINARY_NAME)
|
if(DEFINED Launcher_APP_BINARY_NAME)
|
||||||
set_target_properties("${Launcher_Name}_updater" PROPERTIES OUTPUT_NAME "${Launcher_APP_BINARY_NAME}_updater")
|
set_target_properties("${Launcher_Name}_updater" PROPERTIES OUTPUT_NAME "${Launcher_APP_BINARY_NAME}_updater")
|
||||||
endif()
|
endif()
|
||||||
|
|
@ -1455,22 +1408,22 @@ if(Launcher_BUILD_UPDATER)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Deploy PDBs
|
# Deploy PDBs
|
||||||
if(WIN32 AND (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo"))
|
if(CMAKE_CXX_LINKER_SUPPORTS_PDB)
|
||||||
install(FILES $<TARGET_PDB_FILE:${Launcher_Name}_updater> DESTINATION ${BINARY_DEST_DIR})
|
install(FILES $<TARGET_PDB_FILE:${Launcher_Name}_updater> DESTINATION ${BINARY_DEST_DIR} OPTIONAL)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WIN32 OR (DEFINED Launcher_BUILD_FILELINKER AND Launcher_BUILD_FILELINKER))
|
if(WIN32 OR (DEFINED Launcher_BUILD_FILELINKER AND Launcher_BUILD_FILELINKER))
|
||||||
# File link
|
# File link
|
||||||
add_library(filelink_logic STATIC ${LINKEXE_SOURCES})
|
add_library(filelink_logic STATIC ${LINKEXE_SOURCES})
|
||||||
set_project_warnings(filelink_logic
|
|
||||||
"${Launcher_MSVC_WARNINGS}"
|
|
||||||
"${Launcher_CLANG_WARNINGS}"
|
|
||||||
"${Launcher_GCC_WARNINGS}")
|
|
||||||
|
|
||||||
target_include_directories(filelink_logic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(filelink_logic PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
|
if(${Launcher_USE_PCH})
|
||||||
|
target_precompile_headers(filelink_logic PRIVATE ${PRECOMPILED_HEADERS})
|
||||||
|
endif()
|
||||||
|
|
||||||
target_link_libraries(filelink_logic
|
target_link_libraries(filelink_logic
|
||||||
systeminfo
|
|
||||||
BuildConfig
|
BuildConfig
|
||||||
Qt${QT_VERSION_MAJOR}::Widgets
|
Qt${QT_VERSION_MAJOR}::Widgets
|
||||||
Qt${QT_VERSION_MAJOR}::Core
|
Qt${QT_VERSION_MAJOR}::Core
|
||||||
|
|
@ -1480,8 +1433,12 @@ if(WIN32 OR (DEFINED Launcher_BUILD_FILELINKER AND Launcher_BUILD_FILELINKER))
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable("${Launcher_Name}_filelink" WIN32 filelink/filelink_main.cpp)
|
add_executable("${Launcher_Name}_filelink" WIN32 filelink/filelink_main.cpp)
|
||||||
|
|
||||||
target_sources("${Launcher_Name}_filelink" PRIVATE filelink/filelink.exe.manifest)
|
target_sources("${Launcher_Name}_filelink" PRIVATE filelink/filelink.exe.manifest)
|
||||||
|
|
||||||
|
if(${Launcher_USE_PCH})
|
||||||
|
target_precompile_headers("${Launcher_Name}_filelink" REUSE_FROM filelink_logic)
|
||||||
|
endif()
|
||||||
|
|
||||||
# HACK: Fix manifest issues with Ninja in release mode (and only release mode) and MSVC
|
# HACK: Fix manifest issues with Ninja in release mode (and only release mode) and MSVC
|
||||||
# I have no idea why this works or why it's needed. UPDATE THIS IF YOU EDIT THE MANIFEST!!! -@getchoo
|
# I have no idea why this works or why it's needed. UPDATE THIS IF YOU EDIT THE MANIFEST!!! -@getchoo
|
||||||
# Thank you 2018 CMake mailing list thread https://cmake.cmake.narkive.com/LnotZXus/conflicting-msvc-manifests
|
# Thank you 2018 CMake mailing list thread https://cmake.cmake.narkive.com/LnotZXus/conflicting-msvc-manifests
|
||||||
|
|
@ -1506,8 +1463,8 @@ if(WIN32 OR (DEFINED Launcher_BUILD_FILELINKER AND Launcher_BUILD_FILELINKER))
|
||||||
)
|
)
|
||||||
|
|
||||||
# Deploy PDBs
|
# Deploy PDBs
|
||||||
if(WIN32 AND (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo"))
|
if(CMAKE_CXX_LINKER_SUPPORTS_PDB)
|
||||||
install(FILES $<TARGET_PDB_FILE:${Launcher_Name}_filelink> DESTINATION ${BINARY_DEST_DIR})
|
install(FILES $<TARGET_PDB_FILE:${Launcher_Name}_filelink> DESTINATION ${BINARY_DEST_DIR} OPTIONAL)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
@ -1518,6 +1475,28 @@ if (UNIX AND APPLE AND Launcher_ENABLE_UPDATER)
|
||||||
install(DIRECTORY ${MACOSX_SPARKLE_DIR}/Sparkle.framework DESTINATION ${FRAMEWORK_DEST_DIR} USE_SOURCE_PERMISSIONS)
|
install(DIRECTORY ${MACOSX_SPARKLE_DIR}/Sparkle.framework DESTINATION ${FRAMEWORK_DEST_DIR} USE_SOURCE_PERMISSIONS)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Set basic compiler warning/error flags for all targets
|
||||||
|
get_property(Launcher_TARGETS DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY BUILDSYSTEM_TARGETS)
|
||||||
|
foreach(target ${Launcher_TARGETS})
|
||||||
|
message(STATUS "Enabling all warnings as errors for target '${target}'")
|
||||||
|
if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
|
||||||
|
target_compile_options(${target} PRIVATE /W4 /WX /permissive-)
|
||||||
|
else()
|
||||||
|
target_compile_options(${target} PRIVATE -Wall -Wextra -Wpedantic -Werror)
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Disable some warnings in main launcher target due to being present in a lot of places. TODO: Fix them.
|
||||||
|
if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
|
||||||
|
target_compile_options(Launcher_logic PRIVATE /wd4100) # C4100 - unused parameter
|
||||||
|
target_compile_options(${Launcher_Name} PRIVATE /wd4100) # C4100 - unused parameter
|
||||||
|
else()
|
||||||
|
# sfinae-incomplete is a new GCC warning and triggers in Qt headers
|
||||||
|
# no-unknown-warning-option so that compilers that don't have sfinae-incomplete don't error
|
||||||
|
target_compile_options(Launcher_logic PRIVATE -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unknown-warning-option -Wno-sfinae-incomplete)
|
||||||
|
target_compile_options(${Launcher_Name} PRIVATE -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unknown-warning-option -Wno-sfinae-incomplete)
|
||||||
|
endif()
|
||||||
|
|
||||||
#### The bundle mess! ####
|
#### The bundle mess! ####
|
||||||
# Bundle utilities are used to complete packages for different platforms - they add all the libraries that would otherwise be missing on the target system.
|
# Bundle utilities are used to complete packages for different platforms - they add all the libraries that would otherwise be missing on the target system.
|
||||||
# NOTE: it seems that this absolutely has to be here, and nowhere else.
|
# NOTE: it seems that this absolutely has to be here, and nowhere else.
|
||||||
|
|
@ -1567,6 +1546,49 @@ if(WIN32 OR (UNIX AND APPLE))
|
||||||
SCRIPT ${QT_DEPLOY_SCRIPT}
|
SCRIPT ${QT_DEPLOY_SCRIPT}
|
||||||
COMPONENT bundle
|
COMPONENT bundle
|
||||||
)
|
)
|
||||||
|
# FIXME: remove this crap once we stop using msys2
|
||||||
|
if(MINGW)
|
||||||
|
# i've not found a solution better than injecting the config vars like this...
|
||||||
|
# with install(CODE" for everything everything just breaks
|
||||||
|
install(CODE "
|
||||||
|
set(QT_PLUGINS_DIR \"${QT_PLUGINS_DIR}\")
|
||||||
|
set(QT_LIBS_DIR \"${QT_LIBS_DIR}\")
|
||||||
|
set(QT_LIBEXECS_DIR \"${QT_LIBEXECS_DIR}\")
|
||||||
|
set(CMAKE_SYSTEM_LIBRARY_PATH \"${CMAKE_SYSTEM_LIBRARY_PATH}\")
|
||||||
|
set(CMAKE_INSTALL_PREFIX \"${CMAKE_INSTALL_PREFIX}\")
|
||||||
|
"
|
||||||
|
COMPONENT bundle)
|
||||||
|
|
||||||
|
install(CODE [[
|
||||||
|
file(GLOB QT_IMAGEFORMAT_DLLS "${QT_PLUGINS_DIR}/imageformats/*.dll")
|
||||||
|
set(CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL objdump)
|
||||||
|
file(GET_RUNTIME_DEPENDENCIES
|
||||||
|
RESOLVED_DEPENDENCIES_VAR imageformatdeps
|
||||||
|
LIBRARIES ${QT_IMAGEFORMAT_DLLS}
|
||||||
|
DIRECTORIES
|
||||||
|
${CMAKE_SYSTEM_LIBRARY_PATH}
|
||||||
|
${QT_PLUGINS_DIR}
|
||||||
|
${QT_LIBS_DIR}
|
||||||
|
${QT_LIBEXECS_DIR}
|
||||||
|
PRE_EXCLUDE_REGEXES
|
||||||
|
"^(api-ms-win|ext-ms)-.*\\.dll$"
|
||||||
|
# FIXME: Why aren't these caught by the below regex???
|
||||||
|
"^azure.*\\.dll$"
|
||||||
|
"^vcruntime.*\\.dll$"
|
||||||
|
POST_EXCLUDE_REGEXES
|
||||||
|
"system32"
|
||||||
|
)
|
||||||
|
foreach(_lib ${imageformatdeps})
|
||||||
|
file(INSTALL
|
||||||
|
DESTINATION ${CMAKE_INSTALL_PREFIX}
|
||||||
|
TYPE SHARED_LIBRARY
|
||||||
|
FOLLOW_SYMLINK_CHAIN
|
||||||
|
FILES ${_lib}
|
||||||
|
)
|
||||||
|
endforeach()
|
||||||
|
]]
|
||||||
|
COMPONENT bundle)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Add qt.conf - this makes Qt stop looking for things outside the bundle
|
# Add qt.conf - this makes Qt stop looking for things outside the bundle
|
||||||
install(
|
install(
|
||||||
|
|
@ -1580,3 +1602,15 @@ if(WIN32 OR (UNIX AND APPLE))
|
||||||
COMPONENT bundle
|
COMPONENT bundle
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
find_program(CLANG_FORMAT clang-format OPTIONAL)
|
||||||
|
if(CLANG_FORMAT)
|
||||||
|
message(STATUS "Creating clang-format target")
|
||||||
|
add_custom_target(
|
||||||
|
clang-format
|
||||||
|
COMMAND ${CLANG_FORMAT} -i --style=file:${CMAKE_SOURCE_DIR}/.clang-format ${LOGIC_SOURCES} ${LAUNCHER_SOURCES} ${PRISMUPDATER_SOURCES} ${LINKEXE_SOURCES} ${PRECOMPILED_HEADERS}
|
||||||
|
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
message(WARNING "Unable to find `clang-format`. Not creating custom target")
|
||||||
|
endif()
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ void DataMigrationTask::dryRunFinished()
|
||||||
|
|
||||||
void DataMigrationTask::dryRunAborted()
|
void DataMigrationTask::dryRunAborted()
|
||||||
{
|
{
|
||||||
emitFailed(tr("Aborted"));
|
emitAborted();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataMigrationTask::copyFinished()
|
void DataMigrationTask::copyFinished()
|
||||||
|
|
@ -81,5 +81,5 @@ void DataMigrationTask::copyFinished()
|
||||||
|
|
||||||
void DataMigrationTask::copyAborted()
|
void DataMigrationTask::copyAborted()
|
||||||
{
|
{
|
||||||
emitFailed(tr("Aborted"));
|
emitAborted();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
class DefaultVariable {
|
|
||||||
public:
|
|
||||||
DefaultVariable(const T& value) { defaultValue = value; }
|
|
||||||
DefaultVariable<T>& operator=(const T& value)
|
|
||||||
{
|
|
||||||
currentValue = value;
|
|
||||||
is_default = currentValue == defaultValue;
|
|
||||||
is_explicit = true;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
operator const T&() const { return is_default ? defaultValue : currentValue; }
|
|
||||||
bool isDefault() const { return is_default; }
|
|
||||||
bool isExplicit() const { return is_explicit; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
T currentValue;
|
|
||||||
T defaultValue;
|
|
||||||
bool is_default = true;
|
|
||||||
bool is_explicit = false;
|
|
||||||
};
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
/*
|
/*
|
||||||
* Prism Launcher - Minecraft Launcher
|
* Prism Launcher - Minecraft Launcher
|
||||||
* Copyright (C) 2022 dada513 <dada513@protonmail.com>
|
* Copyright (C) 2022 dada513 <dada513@protonmail.com>
|
||||||
* Copyright (C) 2025 Seth Flynn <getchoo@tuta.io>
|
|
||||||
*
|
*
|
||||||
* 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
|
||||||
|
|
@ -76,15 +75,6 @@ bool isFlatpak()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSelfContained()
|
|
||||||
{
|
|
||||||
#ifdef Q_OS_LINUX
|
|
||||||
return QFileInfo(QCoreApplication::applicationFilePath()).fileName().startsWith("ld-linux");
|
|
||||||
#else
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isSnap()
|
bool isSnap()
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_LINUX
|
#ifdef Q_OS_LINUX
|
||||||
|
|
|
||||||
|
|
@ -37,11 +37,6 @@ bool openUrl(const QUrl& url);
|
||||||
*/
|
*/
|
||||||
bool isFlatpak();
|
bool isFlatpak();
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the launcher is running in a self-contained Linux bundle
|
|
||||||
*/
|
|
||||||
bool isSelfContained();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine whether the launcher is running in a Snap environment
|
* Determine whether the launcher is running in a Snap environment
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -44,4 +44,4 @@ QIcon FastFileIconProvider::icon(const QFileInfo& info) const
|
||||||
}
|
}
|
||||||
|
|
||||||
return QApplication::style()->standardIcon(icon);
|
return QApplication::style()->standardIcon(icon);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,4 +23,4 @@
|
||||||
class FastFileIconProvider : public QFileIconProvider {
|
class FastFileIconProvider : public QFileIconProvider {
|
||||||
public:
|
public:
|
||||||
QIcon icon(const QFileInfo& info) const override;
|
QIcon icon(const QFileInfo& info) const override;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -266,7 +266,21 @@ bool FileIgnoreProxy::filterAcceptsRow(int sourceRow, const QModelIndex& sourceP
|
||||||
|
|
||||||
bool FileIgnoreProxy::ignoreFile(QFileInfo fileInfo) const
|
bool FileIgnoreProxy::ignoreFile(QFileInfo fileInfo) const
|
||||||
{
|
{
|
||||||
return m_ignoreFiles.contains(fileInfo.fileName()) || m_ignoreFilePaths.covers(relPath(fileInfo.absoluteFilePath()));
|
if (m_ignoreFiles.contains(fileInfo.fileName())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& suffix : m_ignoreFilesSuffixes) {
|
||||||
|
if (fileInfo.fileName().endsWith(suffix)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_ignoreFilePaths.covers(relPath(fileInfo.absoluteFilePath()))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileIgnoreProxy::filterFile(const QFileInfo& file) const
|
bool FileIgnoreProxy::filterFile(const QFileInfo& file) const
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@ class FileIgnoreProxy : public QSortFilterProxyModel {
|
||||||
|
|
||||||
// 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; }
|
||||||
|
inline QStringList& ignoreFilesWithSuffix() { return m_ignoreFilesSuffixes; }
|
||||||
// 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; }
|
||||||
|
|
||||||
|
|
@ -85,5 +86,6 @@ class FileIgnoreProxy : public QSortFilterProxyModel {
|
||||||
const QString m_root;
|
const QString m_root;
|
||||||
SeparatorPrefixTree<'/'> m_blocked;
|
SeparatorPrefixTree<'/'> m_blocked;
|
||||||
QStringList m_ignoreFiles;
|
QStringList m_ignoreFiles;
|
||||||
|
QStringList m_ignoreFilesSuffixes;
|
||||||
SeparatorPrefixTree<'/'> m_ignoreFilePaths;
|
SeparatorPrefixTree<'/'> m_ignoreFilePaths;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
|
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
|
||||||
* Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com>
|
* Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com>
|
||||||
* Copyright (C) 2025 Seth Flynn <getchoo@tuta.io>
|
|
||||||
*
|
*
|
||||||
* 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
|
||||||
|
|
@ -37,6 +36,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
|
#include <qcontainerfwd.h>
|
||||||
#include <QPair>
|
#include <QPair>
|
||||||
|
|
||||||
#include "BuildConfig.h"
|
#include "BuildConfig.h"
|
||||||
|
|
@ -283,6 +283,9 @@ bool copyFileAttributes(QString src, QString dst)
|
||||||
if (attrs == INVALID_FILE_ATTRIBUTES)
|
if (attrs == INVALID_FILE_ATTRIBUTES)
|
||||||
return false;
|
return false;
|
||||||
return SetFileAttributesW(dst.toStdWString().c_str(), attrs);
|
return SetFileAttributesW(dst.toStdWString().c_str(), attrs);
|
||||||
|
#else
|
||||||
|
Q_UNUSED(src);
|
||||||
|
Q_UNUSED(dst);
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -433,7 +436,7 @@ void create_link::make_link_list(const QString& offset)
|
||||||
link_file(src, "");
|
link_file(src, "");
|
||||||
} else {
|
} else {
|
||||||
if (m_debug)
|
if (m_debug)
|
||||||
qDebug() << "linking recursively:" << src << "to" << dst << ", max_depth:" << m_max_depth;
|
qDebug().nospace() << "linking recursively: " << src << " to " << dst << ", max_depth: " << m_max_depth;
|
||||||
QDir src_dir(src);
|
QDir src_dir(src);
|
||||||
QDirIterator source_it(src, QDir::Filter::Files | QDir::Filter::Hidden, QDirIterator::Subdirectories);
|
QDirIterator source_it(src, QDir::Filter::Files | QDir::Filter::Hidden, QDirIterator::Subdirectories);
|
||||||
|
|
||||||
|
|
@ -593,7 +596,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, [this, &gotResults]() { emit finishedPrivileged(gotResults); });
|
||||||
connect(linkFileProcess, &ExternalLinkFileProcess::finished, linkFileProcess, &QObject::deleteLater);
|
connect(linkFileProcess, &ExternalLinkFileProcess::finished, linkFileProcess, &QObject::deleteLater);
|
||||||
|
|
||||||
linkFileProcess->start();
|
linkFileProcess->start();
|
||||||
|
|
@ -681,6 +684,32 @@ bool deletePath(QString path)
|
||||||
return err.value() == 0;
|
return err.value() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool deleteContents(const QString& path)
|
||||||
|
{
|
||||||
|
const QFileInfo info(path);
|
||||||
|
if (!info.exists()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!info.isDir()) {
|
||||||
|
qWarning() << "Attempted to delete contents of non-directory path:" << path;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ret = true;
|
||||||
|
|
||||||
|
for (const auto& entry : fs::directory_iterator(StringUtils::toStdString(path))) {
|
||||||
|
std::error_code err;
|
||||||
|
|
||||||
|
fs::remove_all(entry.path(), err);
|
||||||
|
if (err.value() != 0) {
|
||||||
|
qWarning().nospace() << "Could not delete directory entry " << entry.path() << ": " << QString::fromStdString(err.message());
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
bool trash(QString path, QString* pathInTrash)
|
bool trash(QString path, QString* pathInTrash)
|
||||||
{
|
{
|
||||||
// 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
|
||||||
|
|
@ -773,34 +802,6 @@ QString ResolveExecutable(QString path)
|
||||||
return pathInfo.absoluteFilePath();
|
return pathInfo.absoluteFilePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<QProcess> createProcess(const QString& program, const QStringList& arguments)
|
|
||||||
{
|
|
||||||
qDebug() << "Creating process for" << program;
|
|
||||||
auto proc = std::unique_ptr<QProcess>(new QProcess());
|
|
||||||
|
|
||||||
#if defined(Q_OS_LINUX)
|
|
||||||
if (DesktopServices::isSelfContained()) {
|
|
||||||
const auto linkerPath = QCoreApplication::applicationFilePath();
|
|
||||||
qDebug() << "Wrapping" << program << "with self-contained linker at" << linkerPath;
|
|
||||||
|
|
||||||
QStringList wrappedArguments;
|
|
||||||
wrappedArguments << "--inhibit-cache" << program;
|
|
||||||
wrappedArguments += arguments;
|
|
||||||
|
|
||||||
proc->setProgram(linkerPath);
|
|
||||||
proc->setArguments(wrappedArguments);
|
|
||||||
} else {
|
|
||||||
proc->setProgram(program);
|
|
||||||
proc->setArguments(arguments);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
proc->setProgram(program);
|
|
||||||
proc->setArguments(arguments);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return proc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalize path
|
* Normalize path
|
||||||
*
|
*
|
||||||
|
|
@ -822,68 +823,33 @@ QString NormalizePath(QString path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const QString BAD_WIN_CHARS = "<>:\"|?*\r\n";
|
namespace {
|
||||||
static const QString BAD_NTFS_CHARS = "<>:\"|?*";
|
const QString g_badChars = "<>:\"|?*\r\n!";
|
||||||
static const QString BAD_HFS_CHARS = ":";
|
QString removeChars(QString source, QChar replace, const QString& extraChars = "")
|
||||||
|
|
||||||
static const QString BAD_FILENAME_CHARS = BAD_WIN_CHARS + "\\/";
|
|
||||||
|
|
||||||
QString RemoveInvalidFilenameChars(QString string, QChar replaceWith)
|
|
||||||
{
|
{
|
||||||
for (int i = 0; i < string.length(); i++)
|
auto badChars = g_badChars;
|
||||||
if (string.at(i) < ' ' || BAD_FILENAME_CHARS.contains(string.at(i)))
|
if (!extraChars.isEmpty()) {
|
||||||
string[i] = replaceWith;
|
badChars += extraChars;
|
||||||
return string;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString RemoveInvalidPathChars(QString path, QChar replaceWith)
|
|
||||||
{
|
|
||||||
QString invalidChars;
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
invalidChars = BAD_WIN_CHARS;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// the null character is ignored in this check as it was not a problem until now
|
|
||||||
switch (statFS(path).fsType) {
|
|
||||||
case FilesystemType::FAT: // similar to NTFS
|
|
||||||
/* fallthrough */
|
|
||||||
case FilesystemType::NTFS:
|
|
||||||
/* fallthrough */
|
|
||||||
case FilesystemType::REFS: // similar to NTFS(should be available only on windows)
|
|
||||||
invalidChars += BAD_NTFS_CHARS;
|
|
||||||
break;
|
|
||||||
// case FilesystemType::EXT:
|
|
||||||
// case FilesystemType::EXT_2_OLD:
|
|
||||||
// case FilesystemType::EXT_2_3_4:
|
|
||||||
// case FilesystemType::XFS:
|
|
||||||
// case FilesystemType::BTRFS:
|
|
||||||
// case FilesystemType::NFS:
|
|
||||||
// case FilesystemType::ZFS:
|
|
||||||
case FilesystemType::APFS:
|
|
||||||
/* fallthrough */
|
|
||||||
case FilesystemType::HFS:
|
|
||||||
/* fallthrough */
|
|
||||||
case FilesystemType::HFSPLUS:
|
|
||||||
/* fallthrough */
|
|
||||||
case FilesystemType::HFSX:
|
|
||||||
invalidChars += BAD_HFS_CHARS;
|
|
||||||
break;
|
|
||||||
// case FilesystemType::FUSEBLK:
|
|
||||||
// case FilesystemType::F2FS:
|
|
||||||
// case FilesystemType::UNKNOWN:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (invalidChars.size() != 0) {
|
for (auto& c : source) {
|
||||||
for (int i = 0; i < path.length(); i++) {
|
if (c.unicode() < 0x20 || !c.isPrint() || badChars.contains(c)) {
|
||||||
if (path.at(i) < ' ' || invalidChars.contains(path.at(i))) {
|
c = replace;
|
||||||
path[i] = replaceWith;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return path;
|
return source;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
QString RemoveInvalidFilenameChars(QString string, QChar replaceWith)
|
||||||
|
{
|
||||||
|
return removeChars(std::move(string), replaceWith, "\\/");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString RemoveInvalidPathChars(QString string, QChar replaceWith)
|
||||||
|
{
|
||||||
|
return removeChars(std::move(string), replaceWith);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString DirNameFromString(QString string, QString inDir)
|
QString DirNameFromString(QString string, QString inDir)
|
||||||
|
|
@ -979,7 +945,10 @@ QString createShortcut(QString destination, QString target, QStringList args, QS
|
||||||
qWarning() << "Couldn't create directories within application";
|
qWarning() << "Couldn't create directories within application";
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
info.open(QIODevice::WriteOnly | QIODevice::Text);
|
if (!info.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||||
|
qWarning() << "Failed to open file" << info.fileName() << "for writing:" << info.errorString();
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
QFile(icon).rename(resources.path() + "/Icon.icns");
|
QFile(icon).rename(resources.path() + "/Icon.icns");
|
||||||
|
|
||||||
|
|
@ -987,7 +956,10 @@ QString createShortcut(QString destination, QString target, QStringList args, QS
|
||||||
QString exec = binaryDir.path() + "/Run.command";
|
QString exec = binaryDir.path() + "/Run.command";
|
||||||
|
|
||||||
QFile f(exec);
|
QFile f(exec);
|
||||||
f.open(QIODevice::WriteOnly | QIODevice::Text);
|
if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||||
|
qWarning() << "Failed to open file" << f.fileName() << "for writing:" << f.errorString();
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
QTextStream stream(&f);
|
QTextStream stream(&f);
|
||||||
|
|
||||||
auto argstring = quoteArgs(args, "\"", "\\\"");
|
auto argstring = quoteArgs(args, "\"", "\\\"");
|
||||||
|
|
@ -1030,7 +1002,7 @@ QString createShortcut(QString destination, QString target, QStringList args, QS
|
||||||
destination += ".desktop";
|
destination += ".desktop";
|
||||||
QFile f(destination);
|
QFile f(destination);
|
||||||
if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||||
qWarning() << "Failed to open file '" << f.fileName() << "' for writing!";
|
qWarning() << "Failed to open file" << f.fileName() << "for writing:" << f.errorString();
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
QTextStream stream(&f);
|
QTextStream stream(&f);
|
||||||
|
|
@ -1129,17 +1101,17 @@ QString createShortcut(QString destination, QString target, QStringList args, QS
|
||||||
hres = ppf->Save(wsz, TRUE);
|
hres = ppf->Save(wsz, TRUE);
|
||||||
if (FAILED(hres)) {
|
if (FAILED(hres)) {
|
||||||
qWarning() << "IPresistFile->Save() failed";
|
qWarning() << "IPresistFile->Save() failed";
|
||||||
qWarning() << "hres = " << hres;
|
qWarning() << "hres =" << hres;
|
||||||
}
|
}
|
||||||
ppf->Release();
|
ppf->Release();
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "Failed to query IPersistFile interface from IShellLink instance";
|
qWarning() << "Failed to query IPersistFile interface from IShellLink instance";
|
||||||
qWarning() << "hres = " << hres;
|
qWarning() << "hres =" << hres;
|
||||||
}
|
}
|
||||||
psl->Release();
|
psl->Release();
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "Failed to create IShellLink instance";
|
qWarning() << "Failed to create IShellLink instance";
|
||||||
qWarning() << "hres = " << hres;
|
qWarning() << "hres =" << hres;
|
||||||
}
|
}
|
||||||
|
|
||||||
// go away COM, nobody likes you
|
// go away COM, nobody likes you
|
||||||
|
|
@ -1428,14 +1400,14 @@ bool win_ioctl_clone(const std::wstring& src_path, const std::wstring& dst_path,
|
||||||
ULONG fs_flags;
|
ULONG fs_flags;
|
||||||
if (!GetVolumeInformationByHandleW(hSourceFile, nullptr, 0, nullptr, nullptr, &fs_flags, nullptr, 0)) {
|
if (!GetVolumeInformationByHandleW(hSourceFile, nullptr, 0, nullptr, nullptr, &fs_flags, nullptr, 0)) {
|
||||||
ec = std::error_code(GetLastError(), std::system_category());
|
ec = std::error_code(GetLastError(), std::system_category());
|
||||||
qDebug() << "Failed to get Filesystem information for " << src_path.c_str();
|
qDebug() << "Failed to get Filesystem information for" << src_path.c_str();
|
||||||
CloseHandle(hSourceFile);
|
CloseHandle(hSourceFile);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!(fs_flags & FILE_SUPPORTS_BLOCK_REFCOUNTING)) {
|
if (!(fs_flags & FILE_SUPPORTS_BLOCK_REFCOUNTING)) {
|
||||||
SetLastError(ERROR_NOT_CAPABLE);
|
SetLastError(ERROR_NOT_CAPABLE);
|
||||||
ec = std::error_code(GetLastError(), std::system_category());
|
ec = std::error_code(GetLastError(), std::system_category());
|
||||||
qWarning() << "Filesystem at " << src_path.c_str() << " does not support reflink";
|
qWarning() << "Filesystem at" << src_path.c_str() << "does not support reflink";
|
||||||
CloseHandle(hSourceFile);
|
CloseHandle(hSourceFile);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
|
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
|
||||||
* Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com>
|
* Copyright (C) 2022 Rachel Powers <508861+Ryex@users.noreply.github.com>
|
||||||
* Copyright (C) 2025 Seth Flynn <getchoo@tuta.io>
|
|
||||||
*
|
*
|
||||||
* 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
|
||||||
|
|
@ -43,13 +42,11 @@
|
||||||
|
|
||||||
#include <system_error>
|
#include <system_error>
|
||||||
|
|
||||||
#include <QCoreApplication>
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFlags>
|
#include <QFlags>
|
||||||
#include <QLocalServer>
|
#include <QLocalServer>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QPair>
|
#include <QPair>
|
||||||
#include <QProcess>
|
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
|
||||||
namespace FS {
|
namespace FS {
|
||||||
|
|
@ -294,6 +291,13 @@ bool move(const QString& source, const QString& dest);
|
||||||
*/
|
*/
|
||||||
bool deletePath(QString path);
|
bool deletePath(QString path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a folder's contents recursively but not the folder itself.
|
||||||
|
* @param path The path to the folder.
|
||||||
|
* @return Whether the deletion was completely successful.
|
||||||
|
*/
|
||||||
|
bool deleteContents(const QString& path);
|
||||||
|
|
||||||
bool removeFiles(QStringList listFile);
|
bool removeFiles(QStringList listFile);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -336,14 +340,6 @@ QString pathTruncate(const QString& path, int depth);
|
||||||
*/
|
*/
|
||||||
QString ResolveExecutable(QString path);
|
QString ResolveExecutable(QString path);
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a QProcess instance
|
|
||||||
*
|
|
||||||
* This wrapper is currently only required for wrapping binaries called in
|
|
||||||
* self-contained AppImages (like those created by `go-appimage`)
|
|
||||||
*/
|
|
||||||
std::unique_ptr<QProcess> createProcess(const QString& program, const QStringList& arguments);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalize path
|
* Normalize path
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -172,7 +172,8 @@ int inf(QFile* source, std::function<bool(const QByteArray&)> handleBlock)
|
||||||
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
|
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case Z_NEED_DICT:
|
case Z_NEED_DICT:
|
||||||
ret = Z_DATA_ERROR; /* and fall through */
|
ret = Z_DATA_ERROR;
|
||||||
|
[[fallthrough]];
|
||||||
case Z_DATA_ERROR:
|
case Z_DATA_ERROR:
|
||||||
case Z_MEM_ERROR:
|
case Z_MEM_ERROR:
|
||||||
(void)inflateEnd(&strm);
|
(void)inflateEnd(&strm);
|
||||||
|
|
@ -215,4 +216,4 @@ QString GZip::readGzFileByBlocks(QFile* source, std::function<bool(const QByteAr
|
||||||
{
|
{
|
||||||
auto ret = inf(source, handleBlock);
|
auto ret = inf(source, handleBlock);
|
||||||
return zerr(ret);
|
return zerr(ret);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
355
launcher/HardwareInfo.cpp
Normal file
355
launcher/HardwareInfo.cpp
Normal file
|
|
@ -0,0 +1,355 @@
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (C) 2026 Octol1ttle <l1ttleofficial@outlook.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "HardwareInfo.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
#if defined(Q_OS_MACOS) || defined(Q_OS_LINUX)
|
||||||
|
namespace {
|
||||||
|
QString afterColon(QString str)
|
||||||
|
{
|
||||||
|
return str.remove(0, str.indexOf(':') + 2).trimmed();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
bool readFromOutput(const char* command, F function)
|
||||||
|
{
|
||||||
|
FILE* file = popen(command, "r"); // NOLINT(*-command-processor)
|
||||||
|
if (!file) {
|
||||||
|
qWarning().nospace() << "Could not execute command '" << command << "': " << strerror(errno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr size_t bufferSize = 512;
|
||||||
|
std::array<char, bufferSize> buffer{};
|
||||||
|
while (fgets(buffer.data(), bufferSize, file) != nullptr) {
|
||||||
|
function(buffer.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
const int exitCode = pclose(file);
|
||||||
|
if (exitCode != 0) {
|
||||||
|
if (exitCode == -1) {
|
||||||
|
qWarning().nospace() << "Could not close stream for command '" << command << "': " << strerror(errno);
|
||||||
|
} else {
|
||||||
|
qWarning().nospace() << "Command '" << command << "' exited with code " << exitCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef Q_OS_WINDOWS
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
#include <QSettings>
|
||||||
|
|
||||||
|
#include <dxgi1_6.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <wrl/client.h>
|
||||||
|
using Microsoft::WRL::ComPtr;
|
||||||
|
|
||||||
|
QString HardwareInfo::cpuInfo()
|
||||||
|
{
|
||||||
|
const QSettings registry(R"(HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessor\0)", QSettings::NativeFormat);
|
||||||
|
return registry.value("ProcessorNameString").toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t HardwareInfo::totalRamMiB()
|
||||||
|
{
|
||||||
|
MEMORYSTATUSEX status;
|
||||||
|
status.dwLength = sizeof status;
|
||||||
|
|
||||||
|
if (GlobalMemoryStatusEx(&status) == TRUE) {
|
||||||
|
// transforming bytes -> mib
|
||||||
|
return status.ullTotalPhys / 1024 / 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
qWarning() << "Could not get total RAM: GlobalMemoryStatusEx";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t HardwareInfo::availableRamMiB()
|
||||||
|
{
|
||||||
|
MEMORYSTATUSEX status;
|
||||||
|
status.dwLength = sizeof status;
|
||||||
|
|
||||||
|
if (GlobalMemoryStatusEx(&status) == TRUE) {
|
||||||
|
// transforming bytes -> mib
|
||||||
|
return status.ullAvailPhys / 1024 / 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
qWarning() << "Could not get available RAM: GlobalMemoryStatusEx";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList HardwareInfo::gpuInfo()
|
||||||
|
{
|
||||||
|
ComPtr<IDXGIFactory6> factory;
|
||||||
|
HRESULT hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory));
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
qWarning() << "Could not create DXGI factory:" << Qt::hex << hr;
|
||||||
|
return { "GPU discovery failed: could not create DXGI factory" };
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT i = 0;
|
||||||
|
ComPtr<IDXGIAdapter> adapter;
|
||||||
|
QStringList out;
|
||||||
|
while (factory->EnumAdapterByGpuPreference(i, DXGI_GPU_PREFERENCE_HIGH_PERFORMANCE, IID_PPV_ARGS(&adapter)) != DXGI_ERROR_NOT_FOUND) {
|
||||||
|
DXGI_ADAPTER_DESC desc;
|
||||||
|
hr = adapter->GetDesc(&desc);
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
out << "GPU: " + QString::fromWCharArray(desc.Description); // NOLINT(*-pro-bounds-array-to-pointer-decay, *-no-array-decay)
|
||||||
|
} else {
|
||||||
|
qWarning() << "Could not get DXGI adapter description:" << Qt::hex << hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(Q_OS_MACOS)
|
||||||
|
#include "sys/sysctl.h"
|
||||||
|
|
||||||
|
QString HardwareInfo::cpuInfo()
|
||||||
|
{
|
||||||
|
std::array<char, 512> buffer{};
|
||||||
|
size_t bufferSize = buffer.size();
|
||||||
|
if (sysctlbyname("machdep.cpu.brand_string", &buffer, &bufferSize, nullptr, 0) == 0) {
|
||||||
|
return { buffer.data() };
|
||||||
|
}
|
||||||
|
|
||||||
|
qWarning() << "Could not get CPU model: sysctlbyname";
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t HardwareInfo::totalRamMiB()
|
||||||
|
{
|
||||||
|
uint64_t memsize = 0;
|
||||||
|
size_t memsizeSize = sizeof memsize;
|
||||||
|
if (sysctlbyname("hw.memsize", &memsize, &memsizeSize, nullptr, 0) == 0) {
|
||||||
|
// transforming bytes -> mib
|
||||||
|
return memsize / 1024 / 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
qWarning() << "Could not get total RAM: sysctlbyname";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t HardwareInfo::availableRamMiB()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
MacOSHardwareInfo::MemoryPressureLevel MacOSHardwareInfo::memoryPressureLevel()
|
||||||
|
{
|
||||||
|
uint32_t level = 0;
|
||||||
|
size_t levelSize = sizeof level;
|
||||||
|
if (sysctlbyname("kern.memorystatus_vm_pressure_level", &level, &levelSize, nullptr, 0) == 0) {
|
||||||
|
return static_cast<MemoryPressureLevel>(level);
|
||||||
|
}
|
||||||
|
|
||||||
|
qWarning() << "Could not get memory pressure level: sysctlbyname";
|
||||||
|
return MemoryPressureLevel::Normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString MacOSHardwareInfo::memoryPressureLevelName()
|
||||||
|
{
|
||||||
|
// The names are internal, users refer to levels by their graph colors in Activity Monitor
|
||||||
|
switch (memoryPressureLevel()) {
|
||||||
|
case MemoryPressureLevel::Normal:
|
||||||
|
return "Green";
|
||||||
|
case MemoryPressureLevel::Warning:
|
||||||
|
return "Yellow";
|
||||||
|
case MemoryPressureLevel::Critical:
|
||||||
|
return "Red";
|
||||||
|
default:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList HardwareInfo::gpuInfo()
|
||||||
|
{
|
||||||
|
QStringList out;
|
||||||
|
const bool success = readFromOutput("system_profiler SPDisplaysDataType", [&](const QString& str) {
|
||||||
|
// Chipset Model: Intel HD Graphics 620
|
||||||
|
if (str.contains("Chipset Model")) {
|
||||||
|
out << "GPU: " + afterColon(str);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!success) {
|
||||||
|
return { "GPU discovery failed: could not read from system_profiler" };
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(Q_OS_LINUX)
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
QString HardwareInfo::cpuInfo()
|
||||||
|
{
|
||||||
|
std::ifstream cpuin("/proc/cpuinfo");
|
||||||
|
for (std::string line; std::getline(cpuin, line);) {
|
||||||
|
// model name : AMD Ryzen 7 5800X 8-Core Processor
|
||||||
|
if (const QString str = QString::fromStdString(line); str.startsWith("model name")) {
|
||||||
|
return afterColon(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qWarning() << "Could not get CPU model: /proc/cpuinfo";
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
uint64_t readMemInfo(const QString& searchTarget)
|
||||||
|
{
|
||||||
|
std::ifstream memin("/proc/meminfo");
|
||||||
|
for (std::string line; std::getline(memin, line);) {
|
||||||
|
// MemTotal: 16287480 kB
|
||||||
|
if (const QString str = QString::fromStdString(line); str.startsWith(searchTarget)) {
|
||||||
|
bool ok = false;
|
||||||
|
const uint total = str.simplified().section(' ', 1, 1).toUInt(&ok);
|
||||||
|
if (!ok) {
|
||||||
|
qWarning() << "Could not read /proc/meminfo: failed to parse string:" << str;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// transforming kib -> mib
|
||||||
|
return total / 1024;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qWarning() << "Could not read /proc/meminfo: search target not found:" << searchTarget;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
uint64_t HardwareInfo::totalRamMiB()
|
||||||
|
{
|
||||||
|
return readMemInfo("MemTotal");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t HardwareInfo::availableRamMiB()
|
||||||
|
{
|
||||||
|
return readMemInfo("MemAvailable");
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList HardwareInfo::gpuInfo()
|
||||||
|
{
|
||||||
|
bool readingGpuInfo = false;
|
||||||
|
QString gpu;
|
||||||
|
QString driverInUse = "NONE";
|
||||||
|
QString driversAvailable = "NONE";
|
||||||
|
QStringList out;
|
||||||
|
|
||||||
|
const bool success = readFromOutput("lspci -k", [&](const QString& str) {
|
||||||
|
// clang-format off
|
||||||
|
// 04:00.0 VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Ellesmere [Radeon RX 470/480/570/570X/580/580X/590] (rev e7)
|
||||||
|
// Subsystem: Sapphire Technology Limited Radeon RX 580 Pulse 4GB
|
||||||
|
// Kernel driver in use: amdgpu
|
||||||
|
// Kernel modules: amdgpu
|
||||||
|
// clang-format on
|
||||||
|
if (str.contains("VGA compatible controller") || str.contains("3D controller")) {
|
||||||
|
readingGpuInfo = true;
|
||||||
|
} else if (!str.startsWith('\t')) {
|
||||||
|
if (readingGpuInfo) {
|
||||||
|
out << QString("GPU: %1 (driver in use: %2; drivers available: %3)").arg(gpu, driverInUse, driversAvailable);
|
||||||
|
driverInUse = "NONE";
|
||||||
|
driversAvailable = "NONE";
|
||||||
|
}
|
||||||
|
readingGpuInfo = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!readingGpuInfo) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString value = afterColon(str);
|
||||||
|
if (str.contains("Subsystem")) {
|
||||||
|
gpu = value;
|
||||||
|
}
|
||||||
|
if (str.contains("Kernel driver in use")) {
|
||||||
|
driverInUse = value;
|
||||||
|
}
|
||||||
|
if (str.contains("Kernel modules")) {
|
||||||
|
driversAvailable = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!success) {
|
||||||
|
return { "GPU discovery failed: could not read from lspci" };
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
QString HardwareInfo::cpuInfo()
|
||||||
|
{
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
uint64_t HardwareInfo::totalRamMiB()
|
||||||
|
{
|
||||||
|
uint64_t out = 0;
|
||||||
|
|
||||||
|
const bool success = readFromOutput("sysctl hw.physmem", [&](const QString& str) {
|
||||||
|
const uint64_t mem = str.mid(12).toULong();
|
||||||
|
|
||||||
|
// transforming kib -> mib
|
||||||
|
out = mem / 1024;
|
||||||
|
});
|
||||||
|
if (!success) {
|
||||||
|
qWarning() << "Could not get total RAM: could not read from sysctl";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
uint64_t HardwareInfo::totalRamMiB()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint64_t HardwareInfo::availableRamMiB()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList HardwareInfo::gpuInfo()
|
||||||
|
{
|
||||||
|
return { "GPU discovery failed: not implemented for this OS" };
|
||||||
|
}
|
||||||
|
#endif
|
||||||
42
launcher/HardwareInfo.h
Normal file
42
launcher/HardwareInfo.h
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (C) 2026 Octol1ttle <l1ttleofficial@outlook.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace HardwareInfo {
|
||||||
|
QString cpuInfo();
|
||||||
|
uint64_t totalRamMiB();
|
||||||
|
uint64_t availableRamMiB();
|
||||||
|
QStringList gpuInfo();
|
||||||
|
} // namespace HardwareInfo
|
||||||
|
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
namespace MacOSHardwareInfo {
|
||||||
|
enum class MemoryPressureLevel : uint8_t {
|
||||||
|
Normal = 1,
|
||||||
|
Warning = 2,
|
||||||
|
Critical = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
MemoryPressureLevel memoryPressureLevel();
|
||||||
|
QString memoryPressureLevelName();
|
||||||
|
} // namespace MacOSHardwareInfo
|
||||||
|
#endif
|
||||||
|
|
@ -189,4 +189,4 @@ void InstanceCopyPrefs::enableDontLinkSaves(bool b)
|
||||||
void InstanceCopyPrefs::enableUseClone(bool b)
|
void InstanceCopyPrefs::enableUseClone(bool b)
|
||||||
{
|
{
|
||||||
useClone = b;
|
useClone = b;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
#include "settings/INISettingsObject.h"
|
#include "settings/INISettingsObject.h"
|
||||||
#include "tasks/Task.h"
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
InstanceCopyTask::InstanceCopyTask(InstancePtr origInstance, const InstanceCopyPrefs& prefs)
|
InstanceCopyTask::InstanceCopyTask(BaseInstance* origInstance, const InstanceCopyPrefs& prefs)
|
||||||
{
|
{
|
||||||
m_origInstance = origInstance;
|
m_origInstance = origInstance;
|
||||||
m_keepPlaytime = prefs.isKeepPlaytimeEnabled();
|
m_keepPlaytime = prefs.isKeepPlaytimeEnabled();
|
||||||
|
|
@ -64,7 +64,6 @@ void InstanceCopyTask::executeTask()
|
||||||
|
|
||||||
savesCopy = std::make_unique<FS::copy>(FS::PathCombine(m_origInstance->gameRoot(), "saves"),
|
savesCopy = std::make_unique<FS::copy>(FS::PathCombine(m_origInstance->gameRoot(), "saves"),
|
||||||
FS::PathCombine(staging_mc_dir, "saves"));
|
FS::PathCombine(staging_mc_dir, "saves"));
|
||||||
savesCopy->followSymlinks(true);
|
|
||||||
(*savesCopy)(true);
|
(*savesCopy)(true);
|
||||||
setProgress(0, savesCopy->totalCopied());
|
setProgress(0, savesCopy->totalCopied());
|
||||||
connect(savesCopy.get(), &FS::copy::fileCopied, [this](QString src) { setProgress(m_progress + 1, m_progressTotal); });
|
connect(savesCopy.get(), &FS::copy::fileCopied, [this](QString src) { setProgress(m_progress + 1, m_progressTotal); });
|
||||||
|
|
@ -126,11 +125,11 @@ void InstanceCopyTask::executeTask()
|
||||||
return !there_were_errors;
|
return !there_were_errors;
|
||||||
}
|
}
|
||||||
FS::copy folderCopy(m_origInstance->instanceRoot(), m_stagingPath);
|
FS::copy folderCopy(m_origInstance->instanceRoot(), m_stagingPath);
|
||||||
folderCopy.followSymlinks(false).matcher(m_matcher);
|
folderCopy.matcher(m_matcher);
|
||||||
|
|
||||||
folderCopy(true);
|
folderCopy(true);
|
||||||
setProgress(0, folderCopy.totalCopied());
|
setProgress(0, folderCopy.totalCopied());
|
||||||
connect(&folderCopy, &FS::copy::fileCopied, [this](QString src) { setProgress(m_progress + 1, m_progressTotal); });
|
connect(&folderCopy, &FS::copy::fileCopied, [this]() { setProgress(m_progress + 1, m_progressTotal); });
|
||||||
return folderCopy();
|
return folderCopy();
|
||||||
});
|
});
|
||||||
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &InstanceCopyTask::copyFinished);
|
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &InstanceCopyTask::copyFinished);
|
||||||
|
|
@ -147,9 +146,9 @@ void InstanceCopyTask::copyFinished()
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: shouldn't this be able to report errors?
|
// FIXME: shouldn't this be able to report errors?
|
||||||
auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(m_stagingPath, "instance.cfg"));
|
auto instanceSettings = std::make_unique<INISettingsObject>(FS::PathCombine(m_stagingPath, "instance.cfg"));
|
||||||
|
|
||||||
InstancePtr inst(new NullInstance(m_globalSettings, instanceSettings, m_stagingPath));
|
BaseInstance* inst(new NullInstance(m_globalSettings, std::move(instanceSettings), m_stagingPath));
|
||||||
inst->setName(name());
|
inst->setName(name());
|
||||||
inst->setIconKey(m_instIcon);
|
inst->setIconKey(m_instIcon);
|
||||||
if (!m_keepPlaytime) {
|
if (!m_keepPlaytime) {
|
||||||
|
|
@ -197,4 +196,4 @@ bool InstanceCopyTask::abort()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
class InstanceCopyTask : public InstanceTask {
|
class InstanceCopyTask : public InstanceTask {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit InstanceCopyTask(InstancePtr origInstance, const InstanceCopyPrefs& prefs);
|
explicit InstanceCopyTask(BaseInstance* origInstance, const InstanceCopyPrefs& prefs);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//! Entry point for tasks.
|
//! Entry point for tasks.
|
||||||
|
|
@ -26,7 +26,7 @@ class InstanceCopyTask : public InstanceTask {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* data */
|
/* data */
|
||||||
InstancePtr m_origInstance;
|
BaseInstance* m_origInstance;
|
||||||
QFuture<bool> m_copyFuture;
|
QFuture<bool> m_copyFuture;
|
||||||
QFutureWatcher<bool> m_copyFutureWatcher;
|
QFutureWatcher<bool> m_copyFutureWatcher;
|
||||||
Filter m_matcher;
|
Filter m_matcher;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,25 @@
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include "FileSystem.h"
|
|
||||||
|
#include "Application.h"
|
||||||
|
#include "InstanceTask.h"
|
||||||
|
#include "minecraft/MinecraftLoadAndCheck.h"
|
||||||
|
#include "tasks/SequentialTask.h"
|
||||||
|
|
||||||
|
bool InstanceCreationTask::abort()
|
||||||
|
{
|
||||||
|
if (!canAbort()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_abort = true;
|
||||||
|
if (m_gameFilesTask) {
|
||||||
|
return m_gameFilesTask->abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
return InstanceTask::abort();
|
||||||
|
}
|
||||||
|
|
||||||
void InstanceCreationTask::executeTask()
|
void InstanceCreationTask::executeTask()
|
||||||
{
|
{
|
||||||
|
|
@ -19,13 +37,15 @@ void InstanceCreationTask::executeTask()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!createInstance()) {
|
m_instance = createInstance();
|
||||||
if (m_abort)
|
if (!m_instance) {
|
||||||
|
if (m_abort) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
qWarning() << "Instance creation failed!";
|
qWarning() << "Instance creation failed!";
|
||||||
if (!m_error_message.isEmpty()) {
|
if (!m_error_message.isEmpty()) {
|
||||||
qWarning() << "Reason: " << m_error_message;
|
qWarning() << "Reason:" << m_error_message;
|
||||||
emitFailed(tr("Error while creating new instance:\n%1").arg(m_error_message));
|
emitFailed(tr("Error while creating new instance:\n%1").arg(m_error_message));
|
||||||
} else {
|
} else {
|
||||||
emitFailed(tr("Error while creating new instance."));
|
emitFailed(tr("Error while creating new instance."));
|
||||||
|
|
@ -44,9 +64,10 @@ void InstanceCreationTask::executeTask()
|
||||||
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 (const QString& path : m_filesToRemove) {
|
||||||
if (!QFile::exists(path))
|
if (!QFile::exists(path)) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
qDebug() << "Removing" << path;
|
qDebug() << "Removing" << path;
|
||||||
|
|
||||||
|
|
@ -61,6 +82,61 @@ void InstanceCreationTask::executeTask()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!m_abort)
|
|
||||||
emitSucceeded();
|
if (!m_abort) {
|
||||||
|
if (!APPLICATION->settings()->get("DownloadGameFilesDuringInstanceCreation").toBool()) {
|
||||||
|
emitSucceeded();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setAbortable(true);
|
||||||
|
setAbortButtonText(tr("Skip"));
|
||||||
|
qDebug() << "Downloading game files";
|
||||||
|
|
||||||
|
auto updateTasks = m_instance->createUpdateTask();
|
||||||
|
if (updateTasks.isEmpty()) {
|
||||||
|
emitSucceeded();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto task = makeShared<SequentialTask>();
|
||||||
|
task->addTask(makeShared<MinecraftLoadAndCheck>(m_instance.get(), Net::Mode::Online));
|
||||||
|
for (const auto& t : updateTasks) {
|
||||||
|
task->addTask(t);
|
||||||
|
}
|
||||||
|
connect(task.get(), &Task::finished, this, [this, task] {
|
||||||
|
if (task->wasSuccessful() || m_abort) {
|
||||||
|
emitSucceeded();
|
||||||
|
} else {
|
||||||
|
emitFailed(tr("Could not download game files: %1").arg(task->failReason()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
propagateFromOther(task.get());
|
||||||
|
setDetails(tr("Downloading game files"));
|
||||||
|
|
||||||
|
m_gameFilesTask = task;
|
||||||
|
m_gameFilesTask->start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InstanceCreationTask::scheduleToDelete(QWidget* parent, const QDir& dir, const QString& path, bool checkDisabled)
|
||||||
|
{
|
||||||
|
if (path.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (path.startsWith("saves/")) {
|
||||||
|
if (m_shouldDeleteSaves == ShouldDeleteSaves::NotAsked) {
|
||||||
|
m_shouldDeleteSaves = askIfShouldDeleteSaves(parent);
|
||||||
|
}
|
||||||
|
if (m_shouldDeleteSaves == ShouldDeleteSaves::No) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
qDebug() << "Scheduling" << path << "for removal";
|
||||||
|
m_filesToRemove.append(dir.absoluteFilePath(path));
|
||||||
|
if (checkDisabled) {
|
||||||
|
if (path.endsWith(".disabled")) { // remove it if it was enabled/disabled by user
|
||||||
|
m_filesToRemove.append(dir.absoluteFilePath(path.chopped(9)));
|
||||||
|
} else {
|
||||||
|
m_filesToRemove.append(dir.absoluteFilePath(path + ".disabled"));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "BaseVersion.h"
|
#include "BaseVersion.h"
|
||||||
#include "InstanceTask.h"
|
#include "InstanceTask.h"
|
||||||
|
#include "minecraft/MinecraftInstance.h"
|
||||||
|
|
||||||
class InstanceCreationTask : public InstanceTask {
|
class InstanceCreationTask : public InstanceTask {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
@ -9,6 +10,8 @@ class InstanceCreationTask : public InstanceTask {
|
||||||
InstanceCreationTask() = default;
|
InstanceCreationTask() = default;
|
||||||
virtual ~InstanceCreationTask() = default;
|
virtual ~InstanceCreationTask() = default;
|
||||||
|
|
||||||
|
bool abort() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void executeTask() final override;
|
void executeTask() final override;
|
||||||
|
|
||||||
|
|
@ -27,20 +30,24 @@ class InstanceCreationTask : public InstanceTask {
|
||||||
/**
|
/**
|
||||||
* Creates a new instance.
|
* Creates a new instance.
|
||||||
*
|
*
|
||||||
* Returns whether the instance creation was successful (true) or not (false).
|
* Returns the instance if it was created or nullptr otherwise.
|
||||||
*/
|
*/
|
||||||
virtual bool createInstance() { return false; };
|
virtual std::unique_ptr<MinecraftInstance> createInstance() { return nullptr; }
|
||||||
|
|
||||||
QString getError() const { return m_error_message; }
|
QString getError() const { return m_error_message; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void setError(const QString& message) { m_error_message = message; };
|
void setError(const QString& message) { m_error_message = message; };
|
||||||
|
void scheduleToDelete(QWidget* parent, const QDir& dir, const QString& path, bool checkDisabled = false);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool m_abort = false;
|
bool m_abort = false;
|
||||||
|
|
||||||
QStringList m_files_to_remove;
|
QStringList m_filesToRemove;
|
||||||
|
ShouldDeleteSaves m_shouldDeleteSaves;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_error_message;
|
QString m_error_message;
|
||||||
|
std::unique_ptr<MinecraftInstance> m_instance;
|
||||||
|
Task::Ptr m_gameFilesTask;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@
|
||||||
#include "InstanceList.h"
|
#include "InstanceList.h"
|
||||||
#include "ui/dialogs/CustomMessageBox.h"
|
#include "ui/dialogs/CustomMessageBox.h"
|
||||||
|
|
||||||
QString askToUpdateInstanceDirName(InstancePtr instance, const QString& oldName, const QString& newName, QWidget* parent)
|
QString askToUpdateInstanceDirName(BaseInstance* instance, const QString& oldName, const QString& newName, QWidget* parent)
|
||||||
{
|
{
|
||||||
if (oldName == newName)
|
if (oldName == newName)
|
||||||
return QString();
|
return QString();
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
#include "BaseInstance.h"
|
#include "BaseInstance.h"
|
||||||
|
|
||||||
/// Update instanceRoot to make it sync with name/id; return newRoot if a directory rename happened
|
/// 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);
|
QString askToUpdateInstanceDirName(BaseInstance* instance, const QString& oldName, const QString& newName, QWidget* parent);
|
||||||
|
|
||||||
/// Check if there are linked instances, and display a warning; return true if the operation should proceed
|
/// 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);
|
bool checkLinkedInstances(const QString& id, QWidget* parent, const QString& verb);
|
||||||
|
|
|
||||||
|
|
@ -150,22 +150,15 @@ void InstanceImportTask::processZipPack()
|
||||||
extractDir.cd("minecraft");
|
extractDir.cd("minecraft");
|
||||||
m_modpackType = ModpackType::Technic;
|
m_modpackType = ModpackType::Technic;
|
||||||
stop = true;
|
stop = true;
|
||||||
} else {
|
} else if (fileName == "manifest.json") {
|
||||||
QFileInfo fileInfo(fileName);
|
qDebug() << "Flame:" << true;
|
||||||
if (fileInfo.fileName() == "instance.cfg") {
|
m_modpackType = ModpackType::Flame;
|
||||||
qDebug() << "MultiMC:" << true;
|
stop = true;
|
||||||
m_modpackType = ModpackType::MultiMC;
|
} else if (QFileInfo fileInfo(fileName); fileInfo.fileName() == "instance.cfg") {
|
||||||
root = cleanPath(fileInfo.path());
|
qDebug() << "MultiMC:" << true;
|
||||||
stop = true;
|
m_modpackType = ModpackType::MultiMC;
|
||||||
return true;
|
root = cleanPath(fileInfo.path());
|
||||||
}
|
stop = true;
|
||||||
if (fileInfo.fileName() == "manifest.json") {
|
|
||||||
qDebug() << "Flame:" << true;
|
|
||||||
m_modpackType = ModpackType::Flame;
|
|
||||||
root = cleanPath(fileInfo.path());
|
|
||||||
stop = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
QCoreApplication::processEvents();
|
QCoreApplication::processEvents();
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -271,7 +264,7 @@ bool installIcon(QString root, QString instIconKey)
|
||||||
if (iconList->iconFileExists(instIconKey)) {
|
if (iconList->iconFileExists(instIconKey)) {
|
||||||
iconList->deleteIcon(instIconKey);
|
iconList->deleteIcon(instIconKey);
|
||||||
}
|
}
|
||||||
iconList->installIcon(importIconPath, instIconKey + ".png");
|
iconList->installIcon(importIconPath, instIconKey + "." + QFileInfo(importIconPath).suffix());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -329,6 +322,7 @@ void InstanceImportTask::processFlame()
|
||||||
|
|
||||||
connect(inst_creation_task.get(), &Task::aborted, this, &InstanceImportTask::emitAborted);
|
connect(inst_creation_task.get(), &Task::aborted, this, &InstanceImportTask::emitAborted);
|
||||||
connect(inst_creation_task.get(), &Task::abortStatusChanged, this, &Task::setAbortable);
|
connect(inst_creation_task.get(), &Task::abortStatusChanged, this, &Task::setAbortable);
|
||||||
|
connect(inst_creation_task.get(), &Task::abortButtonTextChanged, this, &Task::setAbortButtonText);
|
||||||
|
|
||||||
connect(inst_creation_task.get(), &Task::warningLogged, this, [this](const QString& line) { m_Warnings.append(line); });
|
connect(inst_creation_task.get(), &Task::warningLogged, this, [this](const QString& line) { m_Warnings.append(line); });
|
||||||
|
|
||||||
|
|
@ -348,9 +342,9 @@ void InstanceImportTask::processTechnic()
|
||||||
void InstanceImportTask::processMultiMC()
|
void InstanceImportTask::processMultiMC()
|
||||||
{
|
{
|
||||||
QString configPath = FS::PathCombine(m_stagingPath, "instance.cfg");
|
QString configPath = FS::PathCombine(m_stagingPath, "instance.cfg");
|
||||||
auto instanceSettings = std::make_shared<INISettingsObject>(configPath);
|
auto instanceSettings = std::make_unique<INISettingsObject>(configPath);
|
||||||
|
|
||||||
NullInstance instance(m_globalSettings, instanceSettings, m_stagingPath);
|
NullInstance instance(m_globalSettings, std::move(instanceSettings), m_stagingPath);
|
||||||
|
|
||||||
// reset time played on import... because packs.
|
// reset time played on import... because packs.
|
||||||
instance.resetTimePlayed();
|
instance.resetTimePlayed();
|
||||||
|
|
@ -428,6 +422,7 @@ void InstanceImportTask::processModrinth()
|
||||||
|
|
||||||
connect(inst_creation_task.get(), &Task::aborted, this, &InstanceImportTask::emitAborted);
|
connect(inst_creation_task.get(), &Task::aborted, this, &InstanceImportTask::emitAborted);
|
||||||
connect(inst_creation_task.get(), &Task::abortStatusChanged, this, &Task::setAbortable);
|
connect(inst_creation_task.get(), &Task::abortStatusChanged, this, &Task::setAbortable);
|
||||||
|
connect(inst_creation_task.get(), &Task::abortButtonTextChanged, this, &Task::setAbortButtonText);
|
||||||
|
|
||||||
connect(inst_creation_task.get(), &Task::warningLogged, this, [this](const QString& line) { m_Warnings.append(line); });
|
connect(inst_creation_task.get(), &Task::warningLogged, this, [this](const QString& line) { m_Warnings.append(line); });
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,42 +34,37 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "InstanceList.h"
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDir>
|
|
||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QFileSystemWatcher>
|
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QMimeData>
|
#include <QMimeData>
|
||||||
#include <QPair>
|
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QStack>
|
#include <QStack>
|
||||||
#include <QTextStream>
|
|
||||||
#include <QThread>
|
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
#include <QXmlStreamReader>
|
|
||||||
|
|
||||||
#include "BaseInstance.h"
|
#include "BaseInstance.h"
|
||||||
#include "ExponentialSeries.h"
|
#include "ExponentialSeries.h"
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include "InstanceList.h"
|
|
||||||
#include "InstanceTask.h"
|
#include "InstanceTask.h"
|
||||||
#include "NullInstance.h"
|
#include "NullInstance.h"
|
||||||
#include "WatchLock.h"
|
#include "WatchLock.h"
|
||||||
#include "minecraft/MinecraftInstance.h"
|
#include "minecraft/MinecraftInstance.h"
|
||||||
#include "minecraft/ShortcutUtils.h"
|
|
||||||
#include "settings/INISettingsObject.h"
|
#include "settings/INISettingsObject.h"
|
||||||
|
|
||||||
#ifdef Q_OS_WIN32
|
#ifdef Q_OS_WIN32
|
||||||
#include <Windows.h>
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const static int GROUP_FILE_FORMAT_VERSION = 1;
|
const static int GROUP_FILE_FORMAT_VERSION = 1;
|
||||||
|
|
||||||
InstanceList::InstanceList(SettingsObjectPtr settings, const QString& instDir, QObject* parent)
|
InstanceList::InstanceList(SettingsObject* settings, const QString& instDir, QObject* parent)
|
||||||
: QAbstractListModel(parent), m_globalSettings(settings)
|
: QAbstractListModel(parent), m_globalSettings(settings)
|
||||||
{
|
{
|
||||||
resumeWatch();
|
resumeWatch();
|
||||||
|
|
@ -143,7 +138,7 @@ QMimeData* InstanceList::mimeData(const QModelIndexList& indexes) const
|
||||||
QStringList InstanceList::getLinkedInstancesById(const QString& id) const
|
QStringList InstanceList::getLinkedInstancesById(const QString& id) const
|
||||||
{
|
{
|
||||||
QStringList linkedInstances;
|
QStringList linkedInstances;
|
||||||
for (auto inst : m_instances) {
|
for (auto& inst : m_instances) {
|
||||||
if (inst->isLinkedToInstanceId(id))
|
if (inst->isLinkedToInstanceId(id))
|
||||||
linkedInstances.append(inst->id());
|
linkedInstances.append(inst->id());
|
||||||
}
|
}
|
||||||
|
|
@ -153,15 +148,15 @@ QStringList InstanceList::getLinkedInstancesById(const QString& id) const
|
||||||
int InstanceList::rowCount(const QModelIndex& parent) const
|
int InstanceList::rowCount(const QModelIndex& parent) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(parent);
|
Q_UNUSED(parent);
|
||||||
return m_instances.count();
|
return count();
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex InstanceList::index(int row, int column, const QModelIndex& parent) const
|
QModelIndex InstanceList::index(int row, int column, const QModelIndex& parent) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(parent);
|
Q_UNUSED(parent);
|
||||||
if (row < 0 || row >= m_instances.size())
|
if (row < 0 || row >= count())
|
||||||
return QModelIndex();
|
return QModelIndex();
|
||||||
return createIndex(row, column, (void*)m_instances.at(row).get());
|
return createIndex(row, column, m_instances.at(row).get());
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant InstanceList::data(const QModelIndex& index, int role) const
|
QVariant InstanceList::data(const QModelIndex& index, int role) const
|
||||||
|
|
@ -266,7 +261,7 @@ void InstanceList::setInstanceGroup(const InstanceId& id, GroupId name)
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
increaseGroupCount(name);
|
increaseGroupCount(name);
|
||||||
auto idx = getInstIndex(inst.get());
|
auto idx = getInstIndex(inst);
|
||||||
emit dataChanged(index(idx), index(idx), { GroupRole });
|
emit dataChanged(index(idx), index(idx), { GroupRole });
|
||||||
saveGroupList();
|
saveGroupList();
|
||||||
}
|
}
|
||||||
|
|
@ -457,7 +452,7 @@ void InstanceList::deleteInstance(const InstanceId& id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static QMap<InstanceId, InstanceLocator> getIdMapping(const QList<InstancePtr>& list)
|
static QMap<InstanceId, InstanceLocator> getIdMapping(const std::vector<std::unique_ptr<BaseInstance>>& list)
|
||||||
{
|
{
|
||||||
QMap<InstanceId, InstanceLocator> out;
|
QMap<InstanceId, InstanceLocator> out;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
@ -466,7 +461,7 @@ static QMap<InstanceId, InstanceLocator> getIdMapping(const QList<InstancePtr>&
|
||||||
if (out.contains(id)) {
|
if (out.contains(id)) {
|
||||||
qWarning() << "Duplicate ID" << id << "in instance list";
|
qWarning() << "Duplicate ID" << id << "in instance list";
|
||||||
}
|
}
|
||||||
out[id] = std::make_pair(item, i);
|
out[id] = std::make_pair(item.get(), i);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
|
|
@ -504,17 +499,16 @@ InstanceList::InstListError InstanceList::loadList()
|
||||||
{
|
{
|
||||||
auto existingIds = getIdMapping(m_instances);
|
auto existingIds = getIdMapping(m_instances);
|
||||||
|
|
||||||
QList<InstancePtr> newList;
|
std::vector<std::unique_ptr<BaseInstance>> newList;
|
||||||
|
|
||||||
for (auto& id : discoverInstances()) {
|
for (auto& id : discoverInstances()) {
|
||||||
if (existingIds.contains(id)) {
|
if (existingIds.contains(id)) {
|
||||||
auto instPair = existingIds[id];
|
|
||||||
existingIds.remove(id);
|
existingIds.remove(id);
|
||||||
qInfo() << "Should keep and soft-reload" << id;
|
qInfo() << "Should keep and soft-reload" << id;
|
||||||
} else {
|
} else {
|
||||||
InstancePtr instPtr = loadInstance(id);
|
std::unique_ptr<BaseInstance> instPtr = loadInstance(id);
|
||||||
if (instPtr) {
|
if (instPtr) {
|
||||||
newList.append(instPtr);
|
newList.push_back(std::move(instPtr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -566,8 +560,8 @@ InstanceList::InstListError InstanceList::loadList()
|
||||||
void InstanceList::updateTotalPlayTime()
|
void InstanceList::updateTotalPlayTime()
|
||||||
{
|
{
|
||||||
totalPlayTime = 0;
|
totalPlayTime = 0;
|
||||||
for (auto const& itr : m_instances) {
|
for (const auto& itr : m_instances) {
|
||||||
totalPlayTime += itr.get()->totalTimePlayed();
|
totalPlayTime += itr->totalTimePlayed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -578,12 +572,12 @@ void InstanceList::saveNow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceList::add(const QList<InstancePtr>& t)
|
void InstanceList::add(std::vector<std::unique_ptr<BaseInstance>>& t)
|
||||||
{
|
{
|
||||||
beginInsertRows(QModelIndex(), m_instances.count(), m_instances.count() + t.size() - 1);
|
beginInsertRows(QModelIndex(), count(), static_cast<int>(count() + t.size() - 1));
|
||||||
m_instances.append(t);
|
|
||||||
for (auto& ptr : t) {
|
for (auto& ptr : t) {
|
||||||
connect(ptr.get(), &BaseInstance::propertiesChanged, this, &InstanceList::propertiesChanged);
|
m_instances.push_back(std::move(ptr));
|
||||||
|
connect(m_instances.back().get(), &BaseInstance::propertiesChanged, this, &InstanceList::propertiesChanged);
|
||||||
}
|
}
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
}
|
}
|
||||||
|
|
@ -613,26 +607,26 @@ void InstanceList::providerUpdated()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InstancePtr InstanceList::getInstanceById(QString instId) const
|
BaseInstance* InstanceList::getInstanceById(QString instId) const
|
||||||
{
|
{
|
||||||
if (instId.isEmpty())
|
if (instId.isEmpty())
|
||||||
return InstancePtr();
|
return nullptr;
|
||||||
for (auto& inst : m_instances) {
|
for (auto& inst : m_instances) {
|
||||||
if (inst->id() == instId) {
|
if (inst->id() == instId) {
|
||||||
return inst;
|
return inst.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return InstancePtr();
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
InstancePtr InstanceList::getInstanceByManagedName(const QString& managed_name) const
|
BaseInstance* InstanceList::getInstanceByManagedName(const QString& managed_name) const
|
||||||
{
|
{
|
||||||
if (managed_name.isEmpty())
|
if (managed_name.isEmpty())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
for (auto instance : m_instances) {
|
for (auto& instance : m_instances) {
|
||||||
if (instance->getManagedPackName() == managed_name)
|
if (instance->getManagedPackName() == managed_name)
|
||||||
return instance;
|
return instance.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
|
@ -640,14 +634,14 @@ InstancePtr InstanceList::getInstanceByManagedName(const QString& managed_name)
|
||||||
|
|
||||||
QModelIndex InstanceList::getInstanceIndexById(const QString& id) const
|
QModelIndex InstanceList::getInstanceIndexById(const QString& id) const
|
||||||
{
|
{
|
||||||
return index(getInstIndex(getInstanceById(id).get()));
|
return index(getInstIndex(getInstanceById(id)));
|
||||||
}
|
}
|
||||||
|
|
||||||
int InstanceList::getInstIndex(BaseInstance* inst) const
|
int InstanceList::getInstIndex(BaseInstance* inst) const
|
||||||
{
|
{
|
||||||
int count = m_instances.count();
|
int count = this->count();
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
if (inst == m_instances[i].get()) {
|
if (inst == m_instances.at(i).get()) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -663,15 +657,15 @@ void InstanceList::propertiesChanged(BaseInstance* inst)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InstancePtr InstanceList::loadInstance(const InstanceId& id)
|
std::unique_ptr<BaseInstance> InstanceList::loadInstance(const InstanceId& id)
|
||||||
{
|
{
|
||||||
if (!m_groupsLoaded) {
|
if (!m_groupsLoaded) {
|
||||||
loadGroupList();
|
loadGroupList();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto instanceRoot = FS::PathCombine(m_instDir, id);
|
auto instanceRoot = FS::PathCombine(m_instDir, id);
|
||||||
auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(instanceRoot, "instance.cfg"));
|
auto instanceSettings = std::make_unique<INISettingsObject>(FS::PathCombine(instanceRoot, "instance.cfg"));
|
||||||
InstancePtr inst;
|
std::unique_ptr<BaseInstance> inst;
|
||||||
|
|
||||||
instanceSettings->registerSetting("InstanceType", "");
|
instanceSettings->registerSetting("InstanceType", "");
|
||||||
|
|
||||||
|
|
@ -680,9 +674,9 @@ InstancePtr InstanceList::loadInstance(const InstanceId& id)
|
||||||
// NOTE: Some launcher versions didn't save the InstanceType properly. We will just bank on the probability that this is probably a
|
// NOTE: Some launcher versions didn't save the InstanceType properly. We will just bank on the probability that this is probably a
|
||||||
// OneSix instance
|
// OneSix 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, std::move(instanceSettings), instanceRoot));
|
||||||
} else {
|
} else {
|
||||||
inst.reset(new NullInstance(m_globalSettings, instanceSettings, instanceRoot));
|
inst.reset(new NullInstance(m_globalSettings, std::move(instanceSettings), instanceRoot));
|
||||||
}
|
}
|
||||||
qDebug() << "Loaded instance" << inst->name() << "from" << inst->instanceRoot();
|
qDebug() << "Loaded instance" << inst->name() << "from" << inst->instanceRoot();
|
||||||
|
|
||||||
|
|
@ -911,20 +905,20 @@ class InstanceStaging : public Task {
|
||||||
const unsigned maxBackoff = 16;
|
const unsigned maxBackoff = 16;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
InstanceStaging(InstanceList* parent, InstanceTask* child, SettingsObjectPtr settings)
|
InstanceStaging(InstanceList* parent, InstanceTask* child, SettingsObject* settings) : m_parent(parent), backoff(minBackoff, maxBackoff)
|
||||||
: m_parent(parent), backoff(minBackoff, maxBackoff)
|
|
||||||
{
|
{
|
||||||
m_stagingPath = parent->getStagedInstancePath();
|
m_stagingPath = parent->getStagedInstancePath();
|
||||||
|
|
||||||
m_child.reset(child);
|
m_child.reset(child);
|
||||||
|
|
||||||
m_child->setStagingPath(m_stagingPath);
|
m_child->setStagingPath(m_stagingPath);
|
||||||
m_child->setParentSettings(std::move(settings));
|
m_child->setParentSettings(settings);
|
||||||
|
|
||||||
connect(child, &Task::succeeded, this, &InstanceStaging::childSucceeded);
|
connect(child, &Task::succeeded, this, &InstanceStaging::childSucceeded);
|
||||||
connect(child, &Task::failed, this, &InstanceStaging::childFailed);
|
connect(child, &Task::failed, this, &InstanceStaging::childFailed);
|
||||||
connect(child, &Task::aborted, this, &InstanceStaging::childAborted);
|
connect(child, &Task::aborted, this, &InstanceStaging::childAborted);
|
||||||
connect(child, &Task::abortStatusChanged, this, &InstanceStaging::setAbortable);
|
connect(child, &Task::abortStatusChanged, this, &InstanceStaging::setAbortable);
|
||||||
|
connect(child, &Task::abortButtonTextChanged, this, &InstanceStaging::setAbortButtonText);
|
||||||
connect(child, &Task::status, this, &InstanceStaging::setStatus);
|
connect(child, &Task::status, this, &InstanceStaging::setStatus);
|
||||||
connect(child, &Task::details, this, &InstanceStaging::setDetails);
|
connect(child, &Task::details, this, &InstanceStaging::setDetails);
|
||||||
connect(child, &Task::progress, this, &InstanceStaging::setProgress);
|
connect(child, &Task::progress, this, &InstanceStaging::setProgress);
|
||||||
|
|
@ -932,22 +926,21 @@ class InstanceStaging : public Task {
|
||||||
connect(&m_backoffTimer, &QTimer::timeout, this, &InstanceStaging::childSucceeded);
|
connect(&m_backoffTimer, &QTimer::timeout, this, &InstanceStaging::childSucceeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~InstanceStaging() {}
|
~InstanceStaging() override = default;
|
||||||
|
|
||||||
// FIXME/TODO: add ability to abort during instance commit retries
|
// FIXME/TODO: add ability to abort during instance commit retries
|
||||||
bool abort() override
|
bool abort() override
|
||||||
{
|
{
|
||||||
if (!canAbort())
|
if (!canAbort()) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
m_child->abort();
|
return m_child->abort();
|
||||||
|
|
||||||
return Task::abort();
|
|
||||||
}
|
}
|
||||||
bool canAbort() const override { return (m_child && m_child->canAbort()); }
|
bool canAbort() const override { return (m_child && m_child->canAbort()); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void executeTask() override
|
void executeTask() override
|
||||||
{
|
{
|
||||||
if (m_stagingPath.isNull()) {
|
if (m_stagingPath.isNull()) {
|
||||||
emitFailed(tr("Could not create staging folder"));
|
emitFailed(tr("Could not create staging folder"));
|
||||||
|
|
@ -962,12 +955,14 @@ class InstanceStaging : public Task {
|
||||||
void childSucceeded()
|
void childSucceeded()
|
||||||
{
|
{
|
||||||
unsigned sleepTime = backoff();
|
unsigned sleepTime = backoff();
|
||||||
if (m_parent->commitStagedInstance(m_stagingPath, *m_child.get(), m_child->group(), *m_child.get())) {
|
if (m_parent->commitStagedInstance(m_stagingPath, *m_child, m_child->group(), *m_child)) {
|
||||||
|
m_backoffTimer.stop();
|
||||||
emitSucceeded();
|
emitSucceeded();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// we actually failed, retry?
|
// we actually failed, retry?
|
||||||
if (sleepTime == maxBackoff) {
|
if (sleepTime == maxBackoff) {
|
||||||
|
m_backoffTimer.stop();
|
||||||
emitFailed(tr("Failed to commit instance, even after multiple retries. It is being blocked by something."));
|
emitFailed(tr("Failed to commit instance, even after multiple retries. It is being blocked by something."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -976,12 +971,14 @@ class InstanceStaging : public Task {
|
||||||
}
|
}
|
||||||
void childFailed(const QString& reason)
|
void childFailed(const QString& reason)
|
||||||
{
|
{
|
||||||
|
m_backoffTimer.stop();
|
||||||
m_parent->destroyStagingPath(m_stagingPath);
|
m_parent->destroyStagingPath(m_stagingPath);
|
||||||
emitFailed(reason);
|
emitFailed(reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
void childAborted()
|
void childAborted()
|
||||||
{
|
{
|
||||||
|
m_backoffTimer.stop();
|
||||||
m_parent->destroyStagingPath(m_stagingPath);
|
m_parent->destroyStagingPath(m_stagingPath);
|
||||||
emitAborted();
|
emitAborted();
|
||||||
}
|
}
|
||||||
|
|
@ -995,7 +992,7 @@ class InstanceStaging : public Task {
|
||||||
*/
|
*/
|
||||||
ExponentialSeries backoff;
|
ExponentialSeries backoff;
|
||||||
QString m_stagingPath;
|
QString m_stagingPath;
|
||||||
unique_qobject_ptr<InstanceTask> m_child;
|
std::unique_ptr<InstanceTask> m_child;
|
||||||
QTimer m_backoffTimer;
|
QTimer m_backoffTimer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1028,15 +1025,14 @@ QString InstanceList::getStagedInstancePath()
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InstanceList::commitStagedInstance(const QString& path,
|
bool InstanceList::commitStagedInstance(const QString& path,
|
||||||
InstanceName const& instanceName,
|
const InstanceName& instanceName,
|
||||||
QString groupName,
|
QString groupName,
|
||||||
InstanceTask const& commiting)
|
const InstanceTask& commiting)
|
||||||
{
|
{
|
||||||
if (groupName.isEmpty() && !groupName.isNull())
|
if (groupName.isEmpty() && !groupName.isNull())
|
||||||
groupName = QString();
|
groupName = QString();
|
||||||
|
|
||||||
QString instID;
|
QString instID;
|
||||||
InstancePtr inst;
|
|
||||||
|
|
||||||
auto should_override = commiting.shouldOverride();
|
auto should_override = commiting.shouldOverride();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ struct InstanceName;
|
||||||
|
|
||||||
using InstanceId = QString;
|
using InstanceId = QString;
|
||||||
using GroupId = QString;
|
using GroupId = QString;
|
||||||
using InstanceLocator = std::pair<InstancePtr, int>;
|
using InstanceLocator = std::pair<BaseInstance*, int>;
|
||||||
|
|
||||||
enum class InstCreateError { NoCreateError = 0, NoSuchVersion, UnknownCreateError, InstExists, CantCreateDir };
|
enum class InstCreateError { NoCreateError = 0, NoSuchVersion, UnknownCreateError, InstExists, CantCreateDir };
|
||||||
|
|
||||||
|
|
@ -73,7 +73,7 @@ class InstanceList : public QAbstractListModel {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit InstanceList(SettingsObjectPtr settings, const QString& instDir, QObject* parent = 0);
|
explicit InstanceList(SettingsObject* settings, const QString& instDir, QObject* parent = 0);
|
||||||
virtual ~InstanceList();
|
virtual ~InstanceList();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -96,17 +96,17 @@ class InstanceList : public QAbstractListModel {
|
||||||
*/
|
*/
|
||||||
enum InstListError { NoError = 0, UnknownError };
|
enum InstListError { NoError = 0, UnknownError };
|
||||||
|
|
||||||
InstancePtr at(int i) const { return m_instances.at(i); }
|
BaseInstance* at(int i) const { return m_instances.at(i).get(); }
|
||||||
|
|
||||||
int count() const { return m_instances.count(); }
|
int count() const { return static_cast<int>(m_instances.size()); }
|
||||||
|
|
||||||
InstListError loadList();
|
InstListError loadList();
|
||||||
void saveNow();
|
void saveNow();
|
||||||
|
|
||||||
/* O(n) */
|
/* O(n) */
|
||||||
InstancePtr getInstanceById(QString id) const;
|
BaseInstance* getInstanceById(QString id) const;
|
||||||
/* O(n) */
|
/* O(n) */
|
||||||
InstancePtr getInstanceByManagedName(const QString& managed_name) const;
|
BaseInstance* getInstanceByManagedName(const QString& managed_name) const;
|
||||||
QModelIndex getInstanceIndexById(const QString& id) const;
|
QModelIndex getInstanceIndexById(const QString& id) const;
|
||||||
QStringList getGroups();
|
QStringList getGroups();
|
||||||
bool isGroupCollapsed(const QString& groupName);
|
bool isGroupCollapsed(const QString& groupName);
|
||||||
|
|
@ -179,11 +179,11 @@ class InstanceList : public QAbstractListModel {
|
||||||
void updateTotalPlayTime();
|
void updateTotalPlayTime();
|
||||||
void suspendWatch();
|
void suspendWatch();
|
||||||
void resumeWatch();
|
void resumeWatch();
|
||||||
void add(const QList<InstancePtr>& list);
|
void add(std::vector<std::unique_ptr<BaseInstance>>& list);
|
||||||
void loadGroupList();
|
void loadGroupList();
|
||||||
void saveGroupList();
|
void saveGroupList();
|
||||||
QList<InstanceId> discoverInstances();
|
QList<InstanceId> discoverInstances();
|
||||||
InstancePtr loadInstance(const InstanceId& id);
|
std::unique_ptr<BaseInstance> loadInstance(const InstanceId& id);
|
||||||
|
|
||||||
void increaseGroupCount(const QString& group);
|
void increaseGroupCount(const QString& group);
|
||||||
void decreaseGroupCount(const QString& group);
|
void decreaseGroupCount(const QString& group);
|
||||||
|
|
@ -192,11 +192,11 @@ class InstanceList : public QAbstractListModel {
|
||||||
int m_watchLevel = 0;
|
int m_watchLevel = 0;
|
||||||
int totalPlayTime = 0;
|
int totalPlayTime = 0;
|
||||||
bool m_dirty = false;
|
bool m_dirty = false;
|
||||||
QList<InstancePtr> m_instances;
|
std::vector<std::unique_ptr<BaseInstance>> m_instances;
|
||||||
// id -> refs
|
// id -> refs
|
||||||
QMap<QString, int> m_groupNameCache;
|
QMap<QString, int> m_groupNameCache;
|
||||||
|
|
||||||
SettingsObjectPtr m_globalSettings;
|
SettingsObject* m_globalSettings;
|
||||||
QString m_instDir;
|
QString m_instDir;
|
||||||
QFileSystemWatcher* m_watcher;
|
QFileSystemWatcher* m_watcher;
|
||||||
// FIXME: this is so inefficient that looking at it is almost painful.
|
// FIXME: this is so inefficient that looking at it is almost painful.
|
||||||
|
|
|
||||||
|
|
@ -21,26 +21,26 @@
|
||||||
class InstancePageProvider : protected QObject, public BasePageProvider {
|
class InstancePageProvider : protected QObject, public BasePageProvider {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit InstancePageProvider(InstancePtr parent) { inst = parent; }
|
explicit InstancePageProvider(BaseInstance* parent) { inst = parent; }
|
||||||
|
|
||||||
virtual ~InstancePageProvider() = default;
|
virtual ~InstancePageProvider() = default;
|
||||||
virtual QList<BasePage*> getPages() override
|
virtual QList<BasePage*> getPages() override
|
||||||
{
|
{
|
||||||
QList<BasePage*> values;
|
QList<BasePage*> values;
|
||||||
values.append(new LogPage(inst));
|
values.append(new LogPage(inst));
|
||||||
std::shared_ptr<MinecraftInstance> onesix = std::dynamic_pointer_cast<MinecraftInstance>(inst);
|
MinecraftInstance* onesix = dynamic_cast<MinecraftInstance*>(inst);
|
||||||
values.append(new VersionPage(onesix.get()));
|
values.append(new VersionPage(onesix));
|
||||||
values.append(ManagedPackPage::createPage(onesix.get()));
|
values.append(ManagedPackPage::createPage(onesix));
|
||||||
auto modsPage = new ModFolderPage(onesix.get(), onesix->loaderModList());
|
auto modsPage = new ModFolderPage(onesix, onesix->loaderModList());
|
||||||
modsPage->setFilter("%1 (*.zip *.jar *.litemod *.nilmod)");
|
modsPage->setFilter("%1 (*.zip *.jar *.litemod *.nilmod)");
|
||||||
values.append(modsPage);
|
values.append(modsPage);
|
||||||
values.append(new CoreModFolderPage(onesix.get(), onesix->coreModList()));
|
values.append(new CoreModFolderPage(onesix, onesix->coreModList()));
|
||||||
values.append(new NilModFolderPage(onesix.get(), onesix->nilModList()));
|
values.append(new NilModFolderPage(onesix, onesix->nilModList()));
|
||||||
values.append(new ResourcePackPage(onesix.get(), onesix->resourcePackList()));
|
values.append(new ResourcePackPage(onesix, onesix->resourcePackList()));
|
||||||
values.append(new GlobalDataPackPage(onesix.get()));
|
values.append(new GlobalDataPackPage(onesix));
|
||||||
values.append(new TexturePackPage(onesix.get(), onesix->texturePackList()));
|
values.append(new TexturePackPage(onesix, onesix->texturePackList()));
|
||||||
values.append(new ShaderPackPage(onesix.get(), onesix->shaderPackList()));
|
values.append(new ShaderPackPage(onesix, onesix->shaderPackList()));
|
||||||
values.append(new NotesPage(onesix.get()));
|
values.append(new NotesPage(onesix));
|
||||||
values.append(new WorldListPage(onesix, onesix->worldList()));
|
values.append(new WorldListPage(onesix, onesix->worldList()));
|
||||||
values.append(new ServersPage(onesix));
|
values.append(new ServersPage(onesix));
|
||||||
values.append(new ScreenshotsPage(FS::PathCombine(onesix->gameRoot(), "screenshots")));
|
values.append(new ScreenshotsPage(FS::PathCombine(onesix->gameRoot(), "screenshots")));
|
||||||
|
|
@ -52,5 +52,5 @@ class InstancePageProvider : protected QObject, public BasePageProvider {
|
||||||
virtual QString dialogTitle() override { return tr("Edit Instance (%1)").arg(inst->name()); }
|
virtual QString dialogTitle() override { return tr("Edit Instance (%1)").arg(inst->name()); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
InstancePtr inst;
|
BaseInstance* inst;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include "InstanceTask.h"
|
#include "InstanceTask.h"
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "settings/SettingsObject.h"
|
#include "settings/SettingsObject.h"
|
||||||
|
|
@ -82,3 +83,13 @@ void InstanceName::setName(InstanceName& other)
|
||||||
}
|
}
|
||||||
|
|
||||||
InstanceTask::InstanceTask() : Task(), InstanceName() {}
|
InstanceTask::InstanceTask() : Task(), InstanceName() {}
|
||||||
|
|
||||||
|
ShouldDeleteSaves askIfShouldDeleteSaves(QWidget* parent)
|
||||||
|
{
|
||||||
|
auto dialog = CustomMessageBox::selectable(parent, QObject::tr("Delete Existing Save Files"),
|
||||||
|
QObject::tr("An earlier version of this mod pack installed save files.\n"
|
||||||
|
"Would you like to remove those existing saves as part of this update?"),
|
||||||
|
QMessageBox::Question, QMessageBox::No | QMessageBox::Yes);
|
||||||
|
auto result = dialog->exec();
|
||||||
|
return result == QMessageBox::Yes ? ShouldDeleteSaves::Yes : ShouldDeleteSaves::No;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ enum class InstanceNameChange { ShouldChange, ShouldKeep };
|
||||||
[[nodiscard]] InstanceNameChange askForChangingInstanceName(QWidget* parent, const QString& old_name, const QString& new_name);
|
[[nodiscard]] InstanceNameChange askForChangingInstanceName(QWidget* parent, const QString& old_name, const QString& new_name);
|
||||||
enum class ShouldUpdate { Update, SkipUpdating, Cancel };
|
enum class ShouldUpdate { Update, SkipUpdating, Cancel };
|
||||||
[[nodiscard]] ShouldUpdate askIfShouldUpdate(QWidget* parent, QString original_version_name);
|
[[nodiscard]] ShouldUpdate askIfShouldUpdate(QWidget* parent, QString original_version_name);
|
||||||
|
enum class ShouldDeleteSaves { NotAsked, Yes, No };
|
||||||
|
[[nodiscard]] ShouldDeleteSaves askIfShouldDeleteSaves(QWidget* parent);
|
||||||
|
|
||||||
struct InstanceName {
|
struct InstanceName {
|
||||||
public:
|
public:
|
||||||
|
|
@ -35,7 +37,7 @@ class InstanceTask : public Task, public InstanceName {
|
||||||
InstanceTask();
|
InstanceTask();
|
||||||
~InstanceTask() override = default;
|
~InstanceTask() override = default;
|
||||||
|
|
||||||
void setParentSettings(SettingsObjectPtr settings) { m_globalSettings = settings; }
|
void setParentSettings(SettingsObject* settings) { m_globalSettings = settings; }
|
||||||
|
|
||||||
void setStagingPath(const QString& stagingPath) { m_stagingPath = stagingPath; }
|
void setStagingPath(const QString& stagingPath) { m_stagingPath = stagingPath; }
|
||||||
|
|
||||||
|
|
@ -60,7 +62,7 @@ class InstanceTask : public Task, public InstanceName {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected: /* data */
|
protected: /* data */
|
||||||
SettingsObjectPtr m_globalSettings;
|
SettingsObject* m_globalSettings;
|
||||||
QString m_instIcon;
|
QString m_instIcon;
|
||||||
QString m_instGroup;
|
QString m_instGroup;
|
||||||
QString m_stagingPath;
|
QString m_stagingPath;
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,21 @@ QJsonArray requireArray(const QJsonDocument& doc, const QString& what)
|
||||||
return doc.array();
|
return doc.array();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QJsonDocument parseUntilGarbage(const QByteArray& json, QJsonParseError* error, QString* garbage)
|
||||||
|
{
|
||||||
|
auto doc = QJsonDocument::fromJson(json, error);
|
||||||
|
if (error->error == QJsonParseError::GarbageAtEnd) {
|
||||||
|
qsizetype offset = error->offset;
|
||||||
|
QByteArray validJson = json.left(offset);
|
||||||
|
doc = QJsonDocument::fromJson(validJson, error);
|
||||||
|
|
||||||
|
if (garbage)
|
||||||
|
*garbage = json.right(json.size() - offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
void writeString(QJsonObject& to, const QString& key, const QString& value)
|
void writeString(QJsonObject& to, const QString& key, const QString& value)
|
||||||
{
|
{
|
||||||
if (!value.isEmpty()) {
|
if (!value.isEmpty()) {
|
||||||
|
|
@ -288,7 +303,7 @@ QStringList toStringList(const QString& jsonString)
|
||||||
return {};
|
return {};
|
||||||
try {
|
try {
|
||||||
return requireIsArrayOf<QString>(doc);
|
return requireIsArrayOf<QString>(doc);
|
||||||
} catch (Json::JsonException& e) {
|
} catch (Json::JsonException&) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,9 @@ QJsonArray toJsonArray(const QList<T>& container)
|
||||||
|
|
||||||
////////////////// READING ////////////////////
|
////////////////// READING ////////////////////
|
||||||
|
|
||||||
|
// Attempt to parse JSON up until garbage is encountered
|
||||||
|
QJsonDocument parseUntilGarbage(const QByteArray& json, QJsonParseError* error = nullptr, QString* garbage = nullptr);
|
||||||
|
|
||||||
/// @throw JsonException
|
/// @throw JsonException
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T requireIsType(const QJsonValue& value, const QString& what = "Value");
|
T requireIsType(const QJsonValue& value, const QString& what = "Value");
|
||||||
|
|
|
||||||
|
|
@ -40,22 +40,18 @@
|
||||||
#include "minecraft/auth/AccountData.h"
|
#include "minecraft/auth/AccountData.h"
|
||||||
#include "minecraft/auth/AccountList.h"
|
#include "minecraft/auth/AccountList.h"
|
||||||
|
|
||||||
|
#include "net/NetUtils.h"
|
||||||
#include "ui/InstanceWindow.h"
|
#include "ui/InstanceWindow.h"
|
||||||
#include "ui/MainWindow.h"
|
|
||||||
#include "ui/dialogs/CustomMessageBox.h"
|
#include "ui/dialogs/CustomMessageBox.h"
|
||||||
#include "ui/dialogs/MSALoginDialog.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"
|
||||||
|
|
||||||
#include <QHostAddress>
|
|
||||||
#include <QHostInfo>
|
|
||||||
#include <QInputDialog>
|
#include <QInputDialog>
|
||||||
#include <QLineEdit>
|
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QRegularExpression>
|
#include <utility>
|
||||||
#include <QStringList>
|
|
||||||
|
|
||||||
#include "BuildConfig.h"
|
#include "BuildConfig.h"
|
||||||
#include "JavaCommon.h"
|
#include "JavaCommon.h"
|
||||||
|
|
@ -63,7 +59,7 @@
|
||||||
#include "tasks/Task.h"
|
#include "tasks/Task.h"
|
||||||
#include "ui/dialogs/ChooseOfflineNameDialog.h"
|
#include "ui/dialogs/ChooseOfflineNameDialog.h"
|
||||||
|
|
||||||
LaunchController::LaunchController() : Task() {}
|
LaunchController::LaunchController() = default;
|
||||||
|
|
||||||
void LaunchController::executeTask()
|
void LaunchController::executeTask()
|
||||||
{
|
{
|
||||||
|
|
@ -86,9 +82,17 @@ void LaunchController::decideAccount()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find an account to use.
|
// Select the account to use. If the instance has a specific account set, that will be used. Otherwise, the default account will be used
|
||||||
auto accounts = APPLICATION->accounts();
|
auto* accounts = APPLICATION->accounts();
|
||||||
if (accounts->count() <= 0 || !accounts->anyAccountIsValid()) {
|
const auto instanceAccountId = m_instance->settings()->get("InstanceAccountId").toString();
|
||||||
|
const auto instanceAccountIndex = accounts->findAccountByProfileId(instanceAccountId);
|
||||||
|
if (instanceAccountIndex == -1 || instanceAccountId.isEmpty()) {
|
||||||
|
m_accountToUse = accounts->defaultAccount();
|
||||||
|
} else {
|
||||||
|
m_accountToUse = accounts->at(instanceAccountIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!accounts->anyAccountIsValid()) {
|
||||||
// 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 "
|
||||||
|
|
@ -106,16 +110,7 @@ void LaunchController::decideAccount()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select the account to use. If the instance has a specific account set, that will be used. Otherwise, the default account will be used
|
if (!m_accountToUse && accounts->anyAccountIsValid()) {
|
||||||
auto instanceAccountId = m_instance->settings()->get("InstanceAccountId").toString();
|
|
||||||
auto instanceAccountIndex = accounts->findAccountByProfileId(instanceAccountId);
|
|
||||||
if (instanceAccountIndex == -1 || instanceAccountId.isEmpty()) {
|
|
||||||
m_accountToUse = accounts->defaultAccount();
|
|
||||||
} else {
|
|
||||||
m_accountToUse = accounts->at(instanceAccountIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_accountToUse) {
|
|
||||||
// If no default account is set, ask the user which one to use.
|
// If no default account is set, ask the user which one to use.
|
||||||
ProfileSelectDialog selectDialog(tr("Which account would you like to use?"), ProfileSelectDialog::GlobalDefaultCheckbox,
|
ProfileSelectDialog selectDialog(tr("Which account would you like to use?"), ProfileSelectDialog::GlobalDefaultCheckbox,
|
||||||
m_parentWidget);
|
m_parentWidget);
|
||||||
|
|
@ -132,46 +127,146 @@ void LaunchController::decideAccount()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LaunchController::askPlayDemo()
|
LaunchDecision LaunchController::decideLaunchMode()
|
||||||
|
{
|
||||||
|
if (!m_accountToUse || m_wantedLaunchMode == LaunchMode::Demo) {
|
||||||
|
m_actualLaunchMode = LaunchMode::Demo;
|
||||||
|
return LaunchDecision::Continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto* accounts = APPLICATION->accounts();
|
||||||
|
MinecraftAccountPtr accountToCheck = nullptr;
|
||||||
|
|
||||||
|
if (m_accountToUse->accountType() != AccountType::Offline) {
|
||||||
|
accountToCheck = m_accountToUse->ownsMinecraft() ? m_accountToUse : nullptr;
|
||||||
|
} else if (const auto defaultAccount = accounts->defaultAccount(); defaultAccount && defaultAccount->ownsMinecraft()) {
|
||||||
|
accountToCheck = defaultAccount;
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < accounts->count(); i++) {
|
||||||
|
if (const auto account = accounts->at(i); account->ownsMinecraft()) {
|
||||||
|
accountToCheck = account;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!accountToCheck) {
|
||||||
|
m_actualLaunchMode = LaunchMode::Demo;
|
||||||
|
return LaunchDecision::Continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto state = accountToCheck->accountState();
|
||||||
|
const bool needsRefresh =
|
||||||
|
m_wantedLaunchMode == LaunchMode::Normal && (state == AccountState::Offline || accountToCheck->shouldRefresh());
|
||||||
|
if (state == AccountState::Unchecked || state == AccountState::Errored || needsRefresh) {
|
||||||
|
accountToCheck->refresh();
|
||||||
|
state = AccountState::Working;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state == AccountState::Working) {
|
||||||
|
// refresh is in progress, we need to wait for it to finish to proceed.
|
||||||
|
ProgressDialog progDialog(m_parentWidget);
|
||||||
|
progDialog.setSkipButton(true, tr("Abort"));
|
||||||
|
|
||||||
|
// TODO: this relies on tasks' synchronous signal dispatching nature
|
||||||
|
// TODO: meaning currentTask can't complete and become null while this code is running
|
||||||
|
// TODO: this code will produce a race condition when tasks become fully async
|
||||||
|
auto task = accountToCheck->currentTask();
|
||||||
|
progDialog.execWithTask(task.get());
|
||||||
|
|
||||||
|
if (task->getState() == State::AbortedByUser) {
|
||||||
|
return LaunchDecision::Abort;
|
||||||
|
}
|
||||||
|
|
||||||
|
state = accountToCheck->accountState();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString reauthReason;
|
||||||
|
switch (state) {
|
||||||
|
case AccountState::Errored:
|
||||||
|
reauthReason = tr("An error occurred while refreshing '%1'").arg(accountToCheck->profileName());
|
||||||
|
break;
|
||||||
|
case AccountState::Expired:
|
||||||
|
reauthReason = tr("'%1' has expired and needs to be reauthenticated").arg(accountToCheck->profileName());
|
||||||
|
break;
|
||||||
|
case AccountState::Disabled:
|
||||||
|
reauthReason = tr("The launcher's client identification has changed");
|
||||||
|
break;
|
||||||
|
case AccountState::Gone:
|
||||||
|
reauthReason = tr("'%1' no longer exists on the servers").arg(accountToCheck->profileName());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
m_actualLaunchMode =
|
||||||
|
state == AccountState::Online && m_wantedLaunchMode == LaunchMode::Normal ? LaunchMode::Normal : LaunchMode::Offline;
|
||||||
|
return LaunchDecision::Continue; // All good to go
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reauthenticateAccount(accountToCheck, reauthReason)) {
|
||||||
|
return LaunchDecision::Undecided;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LaunchDecision::Abort;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LaunchController::askPlayDemo() const
|
||||||
{
|
{
|
||||||
QMessageBox box(m_parentWidget);
|
QMessageBox box(m_parentWidget);
|
||||||
box.setWindowTitle(tr("Play demo?"));
|
box.setWindowTitle(tr("Play demo?"));
|
||||||
box.setText(
|
QString text = m_accountToUse
|
||||||
tr("This account does not own Minecraft.\nYou need to purchase the game first to play it.\n\nDo you want to play "
|
? tr("This account does not own Minecraft.\nYou need to purchase the game first to play the full version.")
|
||||||
"the demo?"));
|
: tr("No account was selected for launch.");
|
||||||
|
text += tr("\n\nDo you want to play the demo?");
|
||||||
|
box.setText(text);
|
||||||
box.setIcon(QMessageBox::Warning);
|
box.setIcon(QMessageBox::Warning);
|
||||||
auto demoButton = box.addButton(tr("Play Demo"), QMessageBox::ButtonRole::YesRole);
|
const auto* demoButton = box.addButton(tr("Play Demo"), QMessageBox::ButtonRole::YesRole);
|
||||||
auto cancelButton = box.addButton(tr("Cancel"), QMessageBox::ButtonRole::NoRole);
|
auto* cancelButton = box.addButton(tr("Cancel"), QMessageBox::ButtonRole::NoRole);
|
||||||
box.setDefaultButton(cancelButton);
|
box.setDefaultButton(cancelButton);
|
||||||
|
|
||||||
box.exec();
|
box.exec();
|
||||||
return box.clickedButton() == demoButton;
|
return box.clickedButton() == demoButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString LaunchController::askOfflineName(QString playerName, bool demo, bool* ok)
|
QString LaunchController::askOfflineName(const QString& playerName, bool* ok)
|
||||||
{
|
{
|
||||||
if (ok != nullptr) {
|
if (ok != nullptr) {
|
||||||
*ok = false;
|
*ok = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we ask the user for a player name
|
QString title, message;
|
||||||
QString message = tr("Choose your offline mode player name.");
|
title = tr("Player name");
|
||||||
if (demo) {
|
switch (m_actualLaunchMode) {
|
||||||
message = tr("Choose your demo mode player name.");
|
case LaunchMode::Normal:
|
||||||
|
Q_ASSERT(false);
|
||||||
|
return "";
|
||||||
|
case LaunchMode::Demo:
|
||||||
|
message = tr("Choose your demo mode player name");
|
||||||
|
break;
|
||||||
|
case LaunchMode::Offline:
|
||||||
|
if (m_wantedLaunchMode == LaunchMode::Normal) {
|
||||||
|
auto netErr = m_accountToUse->accountData()->networkError;
|
||||||
|
if (Net::isServerError(netErr)) {
|
||||||
|
title = tr("Auth servers offline");
|
||||||
|
message = tr("The Minecraft authentication servers are currently unavailable, launching in offline mode.\n\n");
|
||||||
|
} else {
|
||||||
|
title = tr("No internet connection");
|
||||||
|
message = tr("You are not connected to the Internet, launching in offline mode.\n\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
message += tr("Choose your offline mode player name");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString lastOfflinePlayerName = APPLICATION->settings()->get("LastOfflinePlayerName").toString();
|
const QString lastOfflinePlayerName = APPLICATION->settings()->get("LastOfflinePlayerName").toString();
|
||||||
QString usedname = lastOfflinePlayerName.isEmpty() ? playerName : lastOfflinePlayerName;
|
QString usedname = lastOfflinePlayerName.isEmpty() ? playerName : lastOfflinePlayerName;
|
||||||
|
|
||||||
ChooseOfflineNameDialog dialog(message, m_parentWidget);
|
ChooseOfflineNameDialog dialog(message, m_parentWidget);
|
||||||
dialog.setWindowTitle(tr("Player name"));
|
dialog.setWindowTitle(title);
|
||||||
dialog.setUsername(usedname);
|
dialog.setUsername(usedname);
|
||||||
if (dialog.exec() != QDialog::Accepted) {
|
if (dialog.exec() != QDialog::Accepted) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString name = dialog.getUsername();
|
usedname = dialog.getUsername();
|
||||||
usedname = name;
|
|
||||||
APPLICATION->settings()->set("LastOfflinePlayerName", usedname);
|
APPLICATION->settings()->set("LastOfflinePlayerName", usedname);
|
||||||
|
|
||||||
if (ok != nullptr) {
|
if (ok != nullptr) {
|
||||||
|
|
@ -184,189 +279,79 @@ void LaunchController::login()
|
||||||
{
|
{
|
||||||
decideAccount();
|
decideAccount();
|
||||||
|
|
||||||
if (!m_accountToUse) {
|
LaunchDecision decision = decideLaunchMode();
|
||||||
// if no account is selected, ask about demo
|
while (decision == LaunchDecision::Undecided) {
|
||||||
if (!m_demo) {
|
decision = decideLaunchMode();
|
||||||
m_demo = askPlayDemo();
|
}
|
||||||
}
|
if (decision == LaunchDecision::Abort) {
|
||||||
if (m_demo) {
|
emitAborted();
|
||||||
// we ask the user for a player name
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_actualLaunchMode == LaunchMode::Demo) {
|
||||||
|
if (m_wantedLaunchMode == LaunchMode::Demo || askPlayDemo()) {
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
auto name = askOfflineName("Player", m_demo, &ok);
|
auto name = askOfflineName("Player", &ok);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
m_session = std::make_shared<AuthSession>();
|
m_session = std::make_shared<AuthSession>();
|
||||||
static const QRegularExpression s_removeChars("[{}-]");
|
m_session->MakeDemo(name, MinecraftAccount::uuidFromUsername(name).toString(QUuid::Id128));
|
||||||
m_session->MakeDemo(name, MinecraftAccount::uuidFromUsername(name).toString().remove(s_removeChars));
|
|
||||||
launchInstance();
|
launchInstance();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if no account is selected, we bail
|
|
||||||
emitFailed(tr("No account selected for launch."));
|
emitFailed(tr("No account selected for launch"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// we loop until the user succeeds in logging in or gives up
|
m_session = std::make_shared<AuthSession>();
|
||||||
bool tryagain = true;
|
m_session->launchMode = m_actualLaunchMode;
|
||||||
unsigned int tries = 0;
|
m_accountToUse->fillSession(m_session);
|
||||||
|
|
||||||
if ((m_accountToUse->accountType() != AccountType::Offline && m_accountToUse->accountState() == AccountState::Offline) ||
|
if (m_accountToUse->accountType() != AccountType::Offline) {
|
||||||
m_accountToUse->shouldRefresh()) {
|
if (m_actualLaunchMode == LaunchMode::Normal && !m_accountToUse->hasProfile()) {
|
||||||
// Force account refresh on the account used to launch the instance updating the AccountState
|
// Now handle setting up a profile name here...
|
||||||
// only on first try and if it is not meant to be offline
|
if (ProfileSetupDialog dialog(m_accountToUse, m_parentWidget); dialog.exec() != QDialog::Accepted) {
|
||||||
m_accountToUse->refresh();
|
|
||||||
}
|
|
||||||
while (tryagain) {
|
|
||||||
if (tries > 0 && tries % 3 == 0) {
|
|
||||||
auto result =
|
|
||||||
QMessageBox::question(m_parentWidget, tr("Continue launch?"),
|
|
||||||
tr("It looks like we couldn't launch after %1 tries. Do you want to continue trying?").arg(tries));
|
|
||||||
|
|
||||||
if (result == QMessageBox::No) {
|
|
||||||
emitAborted();
|
emitAborted();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tries++;
|
|
||||||
m_session = std::make_shared<AuthSession>();
|
|
||||||
m_session->wants_online = m_online;
|
|
||||||
m_session->demo = m_demo;
|
|
||||||
m_accountToUse->fillSession(m_session);
|
|
||||||
|
|
||||||
MinecraftAccountPtr accountToCheck;
|
if (m_actualLaunchMode == LaunchMode::Offline && m_accountToUse->accountType() != AccountType::Offline) {
|
||||||
|
bool ok = false;
|
||||||
if (m_accountToUse->ownsMinecraft())
|
QString name = m_offlineName;
|
||||||
accountToCheck = m_accountToUse;
|
if (name.isEmpty()) {
|
||||||
else if (const MinecraftAccountPtr defaultAccount = APPLICATION->accounts()->defaultAccount();
|
name = askOfflineName(m_session->player_name, &ok);
|
||||||
defaultAccount != nullptr && defaultAccount->ownsMinecraft()) {
|
if (!ok) {
|
||||||
accountToCheck = defaultAccount;
|
emitAborted();
|
||||||
} else {
|
return;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (accountToCheck->accountState()) {
|
|
||||||
case AccountState::Offline: {
|
|
||||||
m_session->wants_online = false;
|
|
||||||
}
|
|
||||||
/* fallthrough */
|
|
||||||
case AccountState::Online: {
|
|
||||||
if (!m_session->wants_online) {
|
|
||||||
// we ask the user for a player name
|
|
||||||
bool ok = false;
|
|
||||||
QString name;
|
|
||||||
if (m_offlineName.isEmpty()) {
|
|
||||||
name = askOfflineName(m_session->player_name, m_session->demo, &ok);
|
|
||||||
if (!ok) {
|
|
||||||
tryagain = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
name = m_offlineName;
|
|
||||||
}
|
|
||||||
m_session->MakeOffline(name);
|
|
||||||
// offline flavored game from here :3
|
|
||||||
} else if (m_accountToUse == accountToCheck && !m_accountToUse->hasProfile()) {
|
|
||||||
// Now handle setting up a profile name here...
|
|
||||||
ProfileSetupDialog dialog(m_accountToUse, m_parentWidget);
|
|
||||||
if (dialog.exec() == QDialog::Accepted) {
|
|
||||||
tryagain = true;
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
emitFailed(tr("Received undetermined session status during login."));
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
case AccountState::Errored:
|
|
||||||
// This means some sort of soft error that we can fix with a refresh ... so let's refresh.
|
|
||||||
case AccountState::Unchecked: {
|
|
||||||
accountToCheck->refresh();
|
|
||||||
}
|
|
||||||
/* fallthrough */
|
|
||||||
case AccountState::Working: {
|
|
||||||
// refresh is in progress, we need to wait for it to finish to proceed.
|
|
||||||
ProgressDialog progDialog(m_parentWidget);
|
|
||||||
progDialog.setSkipButton(true, tr("Abort"));
|
|
||||||
|
|
||||||
auto task = accountToCheck->currentTask();
|
|
||||||
progDialog.execWithTask(task.get());
|
|
||||||
|
|
||||||
// don't retry if aborted
|
|
||||||
if (task->getState() == Task::State::AbortedByUser)
|
|
||||||
tryagain = false;
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
case AccountState::Expired: {
|
|
||||||
if (reauthenticateAccount(accountToCheck))
|
|
||||||
continue;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case AccountState::Disabled: {
|
|
||||||
auto errorString = tr("The launcher's client identification has changed. Please remove '%1' and try again.")
|
|
||||||
.arg(accountToCheck->profileName());
|
|
||||||
|
|
||||||
QMessageBox::warning(m_parentWidget, tr("Client identification changed"), errorString, QMessageBox::StandardButton::Ok,
|
|
||||||
QMessageBox::StandardButton::Ok);
|
|
||||||
emitFailed(errorString);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case AccountState::Gone: {
|
|
||||||
auto errorString =
|
|
||||||
tr("'%1' no longer exists on the servers. It may have been migrated, in which case please add the new account "
|
|
||||||
"you migrated this one to.")
|
|
||||||
.arg(accountToCheck->profileName());
|
|
||||||
QMessageBox::warning(m_parentWidget, tr("Account gone"), errorString, QMessageBox::StandardButton::Ok,
|
|
||||||
QMessageBox::StandardButton::Ok);
|
|
||||||
emitFailed(errorString);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
m_session->MakeOffline(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
emitFailed(tr("Failed to launch."));
|
|
||||||
|
launchInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LaunchController::reauthenticateAccount(MinecraftAccountPtr account)
|
bool LaunchController::reauthenticateAccount(const MinecraftAccountPtr& account, const QString& reason)
|
||||||
{
|
{
|
||||||
auto button = QMessageBox::warning(
|
auto button = QMessageBox::warning(
|
||||||
m_parentWidget, tr("Account refresh failed"),
|
m_parentWidget, tr("Account refresh failed"), tr("%1. Do you want to reauthenticate this account?").arg(reason),
|
||||||
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);
|
QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No, QMessageBox::StandardButton::Yes);
|
||||||
if (button == QMessageBox::StandardButton::Yes) {
|
if (button == QMessageBox::StandardButton::Yes) {
|
||||||
auto accounts = APPLICATION->accounts();
|
auto* accounts = APPLICATION->accounts();
|
||||||
bool isDefault = accounts->defaultAccount() == account;
|
const bool isDefault = accounts->defaultAccount() == account;
|
||||||
accounts->removeAccount(accounts->index(accounts->findAccountByProfileId(account->profileId())));
|
|
||||||
if (account->accountType() == AccountType::MSA) {
|
if (account->accountType() == AccountType::MSA) {
|
||||||
auto newAccount = MSALoginDialog::newAccount(m_parentWidget);
|
auto newAccount = MSALoginDialog::newAccount(m_parentWidget);
|
||||||
|
|
||||||
if (newAccount != nullptr) {
|
if (newAccount != nullptr) {
|
||||||
|
accounts->removeAccount(accounts->index(accounts->findAccountByProfileId(account->profileId())));
|
||||||
accounts->addAccount(newAccount);
|
accounts->addAccount(newAccount);
|
||||||
|
|
||||||
if (isDefault)
|
if (isDefault) {
|
||||||
accounts->setDefaultAccount(newAccount);
|
accounts->setDefaultAccount(newAccount);
|
||||||
|
}
|
||||||
|
|
||||||
if (m_accountToUse == account) {
|
if (m_accountToUse == account) {
|
||||||
m_accountToUse = nullptr;
|
m_accountToUse = nullptr;
|
||||||
|
|
@ -377,14 +362,13 @@ bool LaunchController::reauthenticateAccount(MinecraftAccountPtr account)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emitFailed(tr("The account has expired and needs to be reauthenticated"));
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaunchController::launchInstance()
|
void LaunchController::launchInstance()
|
||||||
{
|
{
|
||||||
Q_ASSERT_X(m_instance != NULL, "launchInstance", "instance is NULL");
|
Q_ASSERT(m_instance != nullptr);
|
||||||
Q_ASSERT_X(m_session.get() != nullptr, "launchInstance", "session is NULL");
|
Q_ASSERT(m_session.get() != nullptr);
|
||||||
|
|
||||||
if (!m_instance->reloadSettings()) {
|
if (!m_instance->reloadSettings()) {
|
||||||
QMessageBox::critical(m_parentWidget, tr("Error!"), tr("Couldn't load the instance profile."));
|
QMessageBox::critical(m_parentWidget, tr("Error!"), tr("Couldn't load the instance profile."));
|
||||||
|
|
@ -398,37 +382,36 @@ void LaunchController::launchInstance()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto console = qobject_cast<InstanceWindow*>(m_parentWidget);
|
const auto* console = qobject_cast<InstanceWindow*>(m_parentWidget);
|
||||||
auto showConsole = m_instance->settings()->get("ShowConsole").toBool();
|
const auto showConsole = m_instance->settings()->get("ShowConsole").toBool();
|
||||||
if (!console && showConsole) {
|
if (!console && showConsole) {
|
||||||
APPLICATION->showInstanceWindow(m_instance);
|
APPLICATION->showInstanceWindow(m_instance);
|
||||||
}
|
}
|
||||||
connect(m_launcher.get(), &LaunchTask::readyForLaunch, this, &LaunchController::readyForLaunch);
|
connect(m_launcher, &LaunchTask::readyForLaunch, this, &LaunchController::readyForLaunch);
|
||||||
connect(m_launcher.get(), &LaunchTask::succeeded, this, &LaunchController::onSucceeded);
|
connect(m_launcher, &LaunchTask::succeeded, this, &LaunchController::onSucceeded);
|
||||||
connect(m_launcher.get(), &LaunchTask::failed, this, &LaunchController::onFailed);
|
connect(m_launcher, &LaunchTask::failed, this, &LaunchController::onFailed);
|
||||||
connect(m_launcher.get(), &LaunchTask::requestProgress, this, &LaunchController::onProgressRequested);
|
connect(m_launcher, &LaunchTask::requestProgress, this, &LaunchController::onProgressRequested);
|
||||||
|
|
||||||
// Prepend Online and Auth Status
|
// Prepend Online and Auth Status
|
||||||
QString online_mode;
|
QString online_mode;
|
||||||
if (m_session->wants_online) {
|
if (m_actualLaunchMode == LaunchMode::Normal) {
|
||||||
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" };
|
const QStringList servers = { "login.microsoftonline.com", "session.minecraft.net", "textures.minecraft.net", "api.mojang.com" };
|
||||||
|
|
||||||
m_launcher->prependStep(makeShared<PrintServers>(m_launcher.get(), servers));
|
m_launcher->prependStep(makeShared<PrintServers>(m_launcher, servers));
|
||||||
} else {
|
} else {
|
||||||
online_mode = m_demo ? "demo" : "offline";
|
online_mode = m_actualLaunchMode == LaunchMode::Demo ? "demo" : "offline";
|
||||||
}
|
}
|
||||||
|
|
||||||
m_launcher->prependStep(
|
m_launcher->prependStep(makeShared<TextPrint>(m_launcher, "Launched instance in " + online_mode + " mode\n", MessageLevel::Launcher));
|
||||||
makeShared<TextPrint>(m_launcher.get(), "Launched instance in " + online_mode + " mode\n", MessageLevel::Launcher));
|
|
||||||
|
|
||||||
// Prepend Version
|
// Prepend Version
|
||||||
{
|
{
|
||||||
auto versionString = QString("%1 version: %2 (%3)")
|
auto versionString = QString("%1 version: %2 (%3)")
|
||||||
.arg(BuildConfig.LAUNCHER_DISPLAYNAME, BuildConfig.printableVersionString(), BuildConfig.BUILD_PLATFORM);
|
.arg(BuildConfig.LAUNCHER_DISPLAYNAME, BuildConfig.printableVersionString(), BuildConfig.BUILD_PLATFORM);
|
||||||
m_launcher->prependStep(makeShared<TextPrint>(m_launcher.get(), versionString + "\n\n", MessageLevel::Launcher));
|
m_launcher->prependStep(makeShared<TextPrint>(m_launcher, versionString + "\n", MessageLevel::Launcher));
|
||||||
}
|
}
|
||||||
m_launcher->start();
|
m_launcher->start();
|
||||||
}
|
}
|
||||||
|
|
@ -485,10 +468,10 @@ void LaunchController::onFailed(QString reason)
|
||||||
if (m_instance->settings()->get("ShowConsoleOnError").toBool()) {
|
if (m_instance->settings()->get("ShowConsoleOnError").toBool()) {
|
||||||
APPLICATION->showInstanceWindow(m_instance, "console");
|
APPLICATION->showInstanceWindow(m_instance, "console");
|
||||||
}
|
}
|
||||||
emitFailed(reason);
|
emitFailed(std::move(reason));
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaunchController::onProgressRequested(Task* task)
|
void LaunchController::onProgressRequested(Task* task) const
|
||||||
{
|
{
|
||||||
ProgressDialog progDialog(m_parentWidget);
|
ProgressDialog progDialog(m_parentWidget);
|
||||||
progDialog.setSkipButton(true, tr("Abort"));
|
progDialog.setSkipButton(true, tr("Abort"));
|
||||||
|
|
|
||||||
|
|
@ -36,30 +36,30 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <BaseInstance.h>
|
#include <BaseInstance.h>
|
||||||
#include <tools/BaseProfiler.h>
|
#include <tools/BaseProfiler.h>
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
#include "minecraft/auth/MinecraftAccount.h"
|
#include "minecraft/auth/MinecraftAccount.h"
|
||||||
#include "minecraft/launch/MinecraftTarget.h"
|
#include "minecraft/launch/MinecraftTarget.h"
|
||||||
|
|
||||||
class InstanceWindow;
|
class InstanceWindow;
|
||||||
|
|
||||||
|
enum class LaunchDecision { Undecided, Continue, Abort };
|
||||||
|
|
||||||
class LaunchController : public Task {
|
class LaunchController : public Task {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
void executeTask() override;
|
void executeTask() override;
|
||||||
|
|
||||||
LaunchController();
|
LaunchController();
|
||||||
virtual ~LaunchController() = default;
|
~LaunchController() override = default;
|
||||||
|
|
||||||
void setInstance(InstancePtr instance) { m_instance = instance; }
|
void setInstance(BaseInstance* instance) { m_instance = instance; }
|
||||||
|
|
||||||
InstancePtr instance() { return m_instance; }
|
BaseInstance* instance() const { return m_instance; }
|
||||||
|
|
||||||
void setOnline(bool online) { m_online = online; }
|
void setLaunchMode(const LaunchMode mode) { m_wantedLaunchMode = mode; }
|
||||||
|
|
||||||
void setOfflineName(const QString& offlineName) { m_offlineName = offlineName; }
|
void setOfflineName(const QString& offlineName) { m_offlineName = offlineName; }
|
||||||
|
|
||||||
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; }
|
||||||
|
|
@ -68,7 +68,7 @@ class LaunchController : public Task {
|
||||||
|
|
||||||
void setAccountToUse(MinecraftAccountPtr accountToUse) { m_accountToUse = std::move(accountToUse); }
|
void setAccountToUse(MinecraftAccountPtr accountToUse) { m_accountToUse = std::move(accountToUse); }
|
||||||
|
|
||||||
QString id() { return m_instance->id(); }
|
QString id() const { return m_instance->id(); }
|
||||||
|
|
||||||
bool abort() override;
|
bool abort() override;
|
||||||
|
|
||||||
|
|
@ -76,27 +76,28 @@ class LaunchController : public Task {
|
||||||
void login();
|
void login();
|
||||||
void launchInstance();
|
void launchInstance();
|
||||||
void decideAccount();
|
void decideAccount();
|
||||||
bool askPlayDemo();
|
LaunchDecision decideLaunchMode();
|
||||||
QString askOfflineName(QString playerName, bool demo, bool* ok = nullptr);
|
bool askPlayDemo() const;
|
||||||
bool reauthenticateAccount(MinecraftAccountPtr account);
|
QString askOfflineName(const QString& playerName, bool* ok = nullptr);
|
||||||
|
bool reauthenticateAccount(const MinecraftAccountPtr& account, const QString& reason);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void readyForLaunch();
|
void readyForLaunch();
|
||||||
|
|
||||||
void onSucceeded();
|
void onSucceeded();
|
||||||
void onFailed(QString reason);
|
void onFailed(QString reason);
|
||||||
void onProgressRequested(Task* task);
|
void onProgressRequested(Task* task) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
LaunchMode m_wantedLaunchMode = LaunchMode::Normal;
|
||||||
|
LaunchMode m_actualLaunchMode = LaunchMode::Normal;
|
||||||
BaseProfilerFactory* m_profiler = nullptr;
|
BaseProfilerFactory* m_profiler = nullptr;
|
||||||
bool m_online = true;
|
|
||||||
QString m_offlineName;
|
QString m_offlineName;
|
||||||
bool m_demo = false;
|
BaseInstance* m_instance = nullptr;
|
||||||
InstancePtr m_instance;
|
|
||||||
QWidget* m_parentWidget = nullptr;
|
QWidget* m_parentWidget = nullptr;
|
||||||
InstanceWindow* m_console = nullptr;
|
InstanceWindow* m_console = nullptr;
|
||||||
MinecraftAccountPtr m_accountToUse = nullptr;
|
MinecraftAccountPtr m_accountToUse = nullptr;
|
||||||
AuthSessionPtr m_session;
|
AuthSessionPtr m_session = nullptr;
|
||||||
shared_qobject_ptr<LaunchTask> m_launcher;
|
LaunchTask* m_launcher = nullptr;
|
||||||
MinecraftTarget::Ptr m_targetToJoin;
|
MinecraftTarget::Ptr m_targetToJoin = nullptr;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
25
launcher/LaunchMode.h
Normal file
25
launcher/LaunchMode.h
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (C) 2026 Octol1ttle <l1ttleofficial@outlook.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
enum class LaunchMode {
|
||||||
|
Normal,
|
||||||
|
Offline,
|
||||||
|
Demo,
|
||||||
|
};
|
||||||
|
|
@ -15,92 +15,28 @@ fi
|
||||||
|
|
||||||
|
|
||||||
LAUNCHER_NAME=@Launcher_APP_BINARY_NAME@
|
LAUNCHER_NAME=@Launcher_APP_BINARY_NAME@
|
||||||
|
LAUNCHER_ENVNAME=@Launcher_ENVName@
|
||||||
LAUNCHER_DIR="$(dirname "$(readlink -f "$0")")"
|
LAUNCHER_DIR="$(dirname "$(readlink -f "$0")")"
|
||||||
echo "Launcher Dir: ${LAUNCHER_DIR}"
|
echo "Launcher Dir: ${LAUNCHER_DIR}"
|
||||||
|
|
||||||
# Set up env.
|
# Makes the launcher use portals for file picking
|
||||||
# Pass our custom variables separately so that the launcher can remove them for child processes
|
export QT_QPA_PLATFORMTHEME=xdgdesktopportal
|
||||||
export LAUNCHER_LD_LIBRARY_PATH="${LAUNCHER_DIR}/lib@LIB_SUFFIX@"
|
|
||||||
export LAUNCHER_LD_PRELOAD=""
|
|
||||||
export LAUNCHER_QT_PLUGIN_PATH="${LAUNCHER_DIR}/plugins"
|
|
||||||
export LAUNCHER_QT_FONTPATH="${LAUNCHER_DIR}/fonts"
|
|
||||||
|
|
||||||
export LD_LIBRARY_PATH="$LAUNCHER_LD_LIBRARY_PATH:$LD_LIBRARY_PATH"
|
# disable OpenGL and Vulkan launcher features on sharun until https://github.com/VHSgunzo/sharun/issues/35
|
||||||
export LD_PRELOAD="$LAUNCHER_LD_PRELOAD:$LD_PRELOAD"
|
if [[ -f "${LAUNCHER_DIR}/sharun" ]]; then
|
||||||
export QT_PLUGIN_PATH="$LAUNCHER_QT_PLUGIN_PATH:$QT_PLUGIN_PATH"
|
export ${LAUNCHER_ENVNAME}_DISABLE_GLVULKAN=1
|
||||||
export QT_FONTPATH="$LAUNCHER_QT_FONTPATH:$QT_FONTPATH"
|
|
||||||
|
|
||||||
# Detect missing dependencies...
|
|
||||||
DEPS_LIST=`ldd "${LAUNCHER_DIR}"/plugins/*/*.so 2>/dev/null | grep "not found" | sort -u | awk -vORS=", " '{ print $1 }'`
|
|
||||||
if [ "x$DEPS_LIST" = "x" ]; then
|
|
||||||
# We have all our dependencies. Run the launcher.
|
|
||||||
echo "No missing dependencies found."
|
|
||||||
|
|
||||||
# Just to be sure...
|
|
||||||
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
|
|
||||||
exec -a "${ARGS[@]}"
|
|
||||||
|
|
||||||
# Run the launcher in valgrind
|
|
||||||
# valgrind --log-file="valgrind.log" --leak-check=full --track-origins=yes "${LAUNCHER_DIR}/bin/${LAUNCHER_NAME}" -d "${LAUNCHER_DIR}" "$@"
|
|
||||||
|
|
||||||
# Run the launcher with callgrind, delay instrumentation
|
|
||||||
# valgrind --log-file="valgrind.log" --tool=callgrind --instr-atstart=no "${LAUNCHER_DIR}/bin/${LAUNCHER_NAME}" -d "${LAUNCHER_DIR}" "$@"
|
|
||||||
# use callgrind_control -i on/off to profile actions
|
|
||||||
|
|
||||||
# Exit with launcher's exit code.
|
|
||||||
# exit $?
|
|
||||||
else
|
|
||||||
# apt
|
|
||||||
if which apt-file &>/dev/null; then
|
|
||||||
LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
|
|
||||||
COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do apt-file -l search $LIBRARY; done`
|
|
||||||
COMMAND_LIBS=`echo "$COMMAND_LIBS" | sort -u | awk -vORS=" " '{ print $1 }'`
|
|
||||||
INSTALL_CMD="sudo apt-get install $COMMAND_LIBS"
|
|
||||||
# pacman
|
|
||||||
elif which pkgfile &>/dev/null; then
|
|
||||||
LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
|
|
||||||
COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do pkgfile $LIBRARY; done`
|
|
||||||
COMMAND_LIBS=`echo "$COMMAND_LIBS" | sort -u | awk -vORS=" " '{ print $1 }'`
|
|
||||||
INSTALL_CMD="sudo pacman -S $COMMAND_LIBS"
|
|
||||||
# dnf
|
|
||||||
elif which dnf &>/dev/null; then
|
|
||||||
LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
|
|
||||||
COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do dnf whatprovides -q $LIBRARY; done`
|
|
||||||
COMMAND_LIBS=`echo "$COMMAND_LIBS" | grep -v 'Repo' | sort -u | awk -vORS=" " '{ print $1 }'`
|
|
||||||
INSTALL_CMD="sudo dnf install $COMMAND_LIBS"
|
|
||||||
# yum
|
|
||||||
elif which yum &>/dev/null; then
|
|
||||||
LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
|
|
||||||
COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do yum whatprovides $LIBRARY; done`
|
|
||||||
COMMAND_LIBS=`echo "$COMMAND_LIBS" | sort -u | awk -vORS=" " '{ print $1 }'`
|
|
||||||
INSTALL_CMD="sudo yum install $COMMAND_LIBS"
|
|
||||||
# zypper
|
|
||||||
elif which zypper &>/dev/null; then
|
|
||||||
LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
|
|
||||||
COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do zypper wp $LIBRARY; done`
|
|
||||||
COMMAND_LIBS=`echo "$COMMAND_LIBS" | sort -u | awk -vORS=" " '{ print $1 }'`
|
|
||||||
INSTALL_CMD="sudo zypper install $COMMAND_LIBS"
|
|
||||||
# emerge
|
|
||||||
elif which pfl &>/dev/null; then
|
|
||||||
LIBRARIES=`echo "$DEPS_LIST" | grep -oP "[^, ]*" | sort -u`
|
|
||||||
COMMAND_LIBS=`for LIBRARY in $LIBRARIES; do pfl $LIBRARY; done`
|
|
||||||
COMMAND_LIBS=`echo "$COMMAND_LIBS" | sort -u | awk -vORS=" " '{ print $1 }'`
|
|
||||||
INSTALL_CMD="sudo emerge $COMMAND_LIBS"
|
|
||||||
fi
|
|
||||||
|
|
||||||
MESSAGE="Error: The launcher is missing the following libraries that it needs to work correctly:\n\t${DEPS_LIST}\nPlease install them from your distribution's package manager."
|
|
||||||
MESSAGE="$MESSAGE\n\nHint (please apply common sense): $INSTALL_CMD\n"
|
|
||||||
|
|
||||||
printerror "$MESSAGE"
|
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Just to be sure...
|
||||||
|
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
|
||||||
|
exec -a "${ARGS[@]}"
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
|
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include "Json.h"
|
#include "Json.h"
|
||||||
#include "MangoHud.h"
|
#include "LibraryUtils.h"
|
||||||
|
|
||||||
#ifdef __GLIBC__
|
#ifdef __GLIBC__
|
||||||
#ifndef _GNU_SOURCE
|
#ifndef _GNU_SOURCE
|
||||||
|
|
@ -36,9 +36,9 @@
|
||||||
#include <linux/limits.h>
|
#include <linux/limits.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace MangoHud {
|
namespace LibraryUtils {
|
||||||
|
|
||||||
QString getLibraryString()
|
QString findMangoHud()
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Guess MangoHud install location by searching for vulkan layers in this order:
|
* Guess MangoHud install location by searching for vulkan layers in this order:
|
||||||
|
|
@ -123,7 +123,7 @@ QString getLibraryString()
|
||||||
|
|
||||||
#ifdef __GLIBC__
|
#ifdef __GLIBC__
|
||||||
// Check whether mangohud is usable on a glibc based system
|
// Check whether mangohud is usable on a glibc based system
|
||||||
QString libraryPath = findLibrary(libraryName);
|
QString libraryPath = find(libraryName);
|
||||||
if (!libraryPath.isEmpty()) {
|
if (!libraryPath.isEmpty()) {
|
||||||
return libraryPath;
|
return libraryPath;
|
||||||
}
|
}
|
||||||
|
|
@ -138,7 +138,7 @@ QString getLibraryString()
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
QString findLibrary(QString libName)
|
QString find(QString libName)
|
||||||
{
|
{
|
||||||
#ifdef __GLIBC__
|
#ifdef __GLIBC__
|
||||||
const char* library = libName.toLocal8Bit().constData();
|
const char* library = libName.toLocal8Bit().constData();
|
||||||
|
|
@ -161,11 +161,11 @@ QString findLibrary(QString libName)
|
||||||
dlclose(handle);
|
dlclose(handle);
|
||||||
return fullPath;
|
return fullPath;
|
||||||
#else
|
#else
|
||||||
qWarning() << "MangoHud::findLibrary is not implemented on this platform";
|
qWarning() << "LibraryUtils::find is not implemented on this platform";
|
||||||
return {};
|
return {};
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
} // namespace MangoHud
|
} // namespace LibraryUtils
|
||||||
|
|
||||||
#ifdef UNDEF_GNU_SOURCE
|
#ifdef UNDEF_GNU_SOURCE
|
||||||
#undef _GNU_SOURCE
|
#undef _GNU_SOURCE
|
||||||
|
|
@ -21,9 +21,9 @@
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
namespace MangoHud {
|
namespace LibraryUtils {
|
||||||
|
|
||||||
QString getLibraryString();
|
QString findMangoHud();
|
||||||
|
|
||||||
QString findLibrary(QString libName);
|
QString find(QString libName);
|
||||||
} // namespace MangoHud
|
} // namespace LibraryUtils
|
||||||
|
|
@ -114,7 +114,7 @@ void LoggedProcess::on_error(QProcess::ProcessError error)
|
||||||
{
|
{
|
||||||
switch (error) {
|
switch (error) {
|
||||||
case QProcess::FailedToStart: {
|
case QProcess::FailedToStart: {
|
||||||
emit log({ tr("The process failed to start.") }, MessageLevel::Fatal);
|
emit log({ tr("The process failed to start: %1").arg(errorString()) }, MessageLevel::Fatal);
|
||||||
changeState(LoggedProcess::FailedToStart);
|
changeState(LoggedProcess::FailedToStart);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <MMCTime.h>
|
#include <MMCTime.h>
|
||||||
#include <qobject.h>
|
|
||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
@ -99,4 +98,4 @@ QString Time::humanReadableDuration(double duration, int precision)
|
||||||
os.flush();
|
os.flush();
|
||||||
|
|
||||||
return outStr;
|
return outStr;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,18 +56,18 @@ bool mergeZipFiles(ArchiveWriter& into, QFileInfo from, QSet<QString>& contained
|
||||||
return r.parse([&into, &contained, &filter, from](ArchiveReader::File* f) {
|
return r.parse([&into, &contained, &filter, from](ArchiveReader::File* f) {
|
||||||
auto filename = f->filename();
|
auto filename = f->filename();
|
||||||
if (filter && !filter(filename)) {
|
if (filter && !filter(filename)) {
|
||||||
qDebug() << "Skipping file " << filename << " from " << from.fileName() << " - filtered";
|
qDebug() << "Skipping file" << filename << "from" << from.fileName() << "- filtered";
|
||||||
f->skip();
|
f->skip();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (contained.contains(filename)) {
|
if (contained.contains(filename)) {
|
||||||
qDebug() << "Skipping already contained file " << filename << " from " << from.fileName();
|
qDebug() << "Skipping already contained file" << filename << "from" << from.fileName();
|
||||||
f->skip();
|
f->skip();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
contained.insert(filename);
|
contained.insert(filename);
|
||||||
if (!into.addFile(f)) {
|
if (!into.addFile(f)) {
|
||||||
qCritical() << "Failed to copy data of " << filename << " into the jar";
|
qCritical() << "Failed to copy data of" << filename << "into the jar";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -149,7 +149,7 @@ bool createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<M
|
||||||
qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar.";
|
qCritical() << "Failed to add" << mod->fileinfo().fileName() << "to the jar.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
qDebug() << "Adding folder " << filename.fileName() << " from " << filename.absoluteFilePath();
|
qDebug() << "Adding folder" << filename.fileName() << "from" << filename.absoluteFilePath();
|
||||||
} 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();
|
||||||
|
|
@ -233,7 +233,7 @@ std::optional<QStringList> extractSubDir(ArchiveReader* zip, const QString& subd
|
||||||
<< target;
|
<< target;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!f->writeFile(ext, target_file_path)) {
|
if (!f->writeFile(ext, target_file_path, target)) {
|
||||||
qWarning() << "Failed to extract file" << original_name << "to" << target_file_path;
|
qWarning() << "Failed to extract file" << original_name << "to" << target_file_path;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -321,7 +321,7 @@ bool collectFileListRecursively(const QString& rootDir, const QString& subDir, Q
|
||||||
for (const auto& e : entries) {
|
for (const auto& e : entries) {
|
||||||
if (excludeFilter && excludeFilter(e)) {
|
if (excludeFilter && excludeFilter(e)) {
|
||||||
QString relativeFilePath = rootDirectory.relativeFilePath(e.absoluteFilePath());
|
QString relativeFilePath = rootDirectory.relativeFilePath(e.absoluteFilePath());
|
||||||
qDebug() << "Skipping file " << relativeFilePath;
|
qDebug() << "Skipping file" << relativeFilePath;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,26 +14,26 @@
|
||||||
else \
|
else \
|
||||||
type = Qt::DirectConnection;
|
type = Qt::DirectConnection;
|
||||||
|
|
||||||
#define DEFINE_FUNC_NO_PARAM(NAME, RET_TYPE) \
|
#define DEFINE_FUNC_NO_PARAM(NAME, RET_TYPE, RET_DEF) \
|
||||||
static RET_TYPE NAME() \
|
static RET_TYPE NAME() \
|
||||||
{ \
|
{ \
|
||||||
RET_TYPE ret; \
|
RET_TYPE ret = RET_DEF; \
|
||||||
GET_TYPE() \
|
GET_TYPE() \
|
||||||
QMetaObject::invokeMethod(s_instance, "_" #NAME, type, Q_RETURN_ARG(RET_TYPE, ret)); \
|
QMetaObject::invokeMethod(s_instance, "_" #NAME, type, Q_RETURN_ARG(RET_TYPE, ret)); \
|
||||||
return ret; \
|
return ret; \
|
||||||
}
|
}
|
||||||
#define DEFINE_FUNC_ONE_PARAM(NAME, RET_TYPE, PARAM_1_TYPE) \
|
#define DEFINE_FUNC_ONE_PARAM(NAME, RET_TYPE, RET_DEF, PARAM_1_TYPE) \
|
||||||
static RET_TYPE NAME(PARAM_1_TYPE p1) \
|
static RET_TYPE NAME(PARAM_1_TYPE p1) \
|
||||||
{ \
|
{ \
|
||||||
RET_TYPE ret; \
|
RET_TYPE ret = RET_DEF; \
|
||||||
GET_TYPE() \
|
GET_TYPE() \
|
||||||
QMetaObject::invokeMethod(s_instance, "_" #NAME, type, Q_RETURN_ARG(RET_TYPE, ret), Q_ARG(PARAM_1_TYPE, p1)); \
|
QMetaObject::invokeMethod(s_instance, "_" #NAME, type, Q_RETURN_ARG(RET_TYPE, ret), Q_ARG(PARAM_1_TYPE, p1)); \
|
||||||
return ret; \
|
return ret; \
|
||||||
}
|
}
|
||||||
#define DEFINE_FUNC_TWO_PARAM(NAME, RET_TYPE, PARAM_1_TYPE, PARAM_2_TYPE) \
|
#define DEFINE_FUNC_TWO_PARAM(NAME, RET_TYPE, RET_DEF, PARAM_1_TYPE, PARAM_2_TYPE) \
|
||||||
static RET_TYPE NAME(PARAM_1_TYPE p1, PARAM_2_TYPE p2) \
|
static RET_TYPE NAME(PARAM_1_TYPE p1, PARAM_2_TYPE p2) \
|
||||||
{ \
|
{ \
|
||||||
RET_TYPE ret; \
|
RET_TYPE ret = RET_DEF; \
|
||||||
GET_TYPE() \
|
GET_TYPE() \
|
||||||
QMetaObject::invokeMethod(s_instance, "_" #NAME, type, Q_RETURN_ARG(RET_TYPE, ret), Q_ARG(PARAM_1_TYPE, p1), \
|
QMetaObject::invokeMethod(s_instance, "_" #NAME, type, Q_RETURN_ARG(RET_TYPE, ret), Q_ARG(PARAM_1_TYPE, p1), \
|
||||||
Q_ARG(PARAM_2_TYPE, p2)); \
|
Q_ARG(PARAM_2_TYPE, p2)); \
|
||||||
|
|
@ -53,18 +53,18 @@ class PixmapCache final : public QObject {
|
||||||
static void setInstance(PixmapCache* i) { s_instance = i; }
|
static void setInstance(PixmapCache* i) { s_instance = i; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DEFINE_FUNC_NO_PARAM(cacheLimit, int)
|
DEFINE_FUNC_NO_PARAM(cacheLimit, int, -1)
|
||||||
DEFINE_FUNC_NO_PARAM(clear, bool)
|
DEFINE_FUNC_NO_PARAM(clear, bool, false)
|
||||||
DEFINE_FUNC_TWO_PARAM(find, bool, const QString&, QPixmap*)
|
DEFINE_FUNC_TWO_PARAM(find, bool, false, const QString&, QPixmap*)
|
||||||
DEFINE_FUNC_TWO_PARAM(find, bool, const QPixmapCache::Key&, QPixmap*)
|
DEFINE_FUNC_TWO_PARAM(find, bool, false, const QPixmapCache::Key&, QPixmap*)
|
||||||
DEFINE_FUNC_TWO_PARAM(insert, bool, const QString&, const QPixmap&)
|
DEFINE_FUNC_TWO_PARAM(insert, bool, false, const QString&, const QPixmap&)
|
||||||
DEFINE_FUNC_ONE_PARAM(insert, QPixmapCache::Key, const QPixmap&)
|
DEFINE_FUNC_ONE_PARAM(insert, QPixmapCache::Key, {}, const QPixmap&)
|
||||||
DEFINE_FUNC_ONE_PARAM(remove, bool, const QString&)
|
DEFINE_FUNC_ONE_PARAM(remove, bool, false, const QString&)
|
||||||
DEFINE_FUNC_ONE_PARAM(remove, bool, const QPixmapCache::Key&)
|
DEFINE_FUNC_ONE_PARAM(remove, bool, false, const QPixmapCache::Key&)
|
||||||
DEFINE_FUNC_TWO_PARAM(replace, bool, const QPixmapCache::Key&, const QPixmap&)
|
DEFINE_FUNC_TWO_PARAM(replace, bool, false, const QPixmapCache::Key&, const QPixmap&)
|
||||||
DEFINE_FUNC_ONE_PARAM(setCacheLimit, bool, int)
|
DEFINE_FUNC_ONE_PARAM(setCacheLimit, bool, false, int)
|
||||||
DEFINE_FUNC_NO_PARAM(markCacheMissByEviciton, bool)
|
DEFINE_FUNC_NO_PARAM(markCacheMissByEviciton, bool, false)
|
||||||
DEFINE_FUNC_ONE_PARAM(setFastEvictionThreshold, bool, int)
|
DEFINE_FUNC_ONE_PARAM(setFastEvictionThreshold, bool, false, int)
|
||||||
|
|
||||||
// NOTE: Every function returns something non-void to simplify the macros.
|
// NOTE: Every function returns something non-void to simplify the macros.
|
||||||
private slots:
|
private slots:
|
||||||
|
|
|
||||||
|
|
@ -28,4 +28,4 @@ QString markdownToHTML(const QString& markdown)
|
||||||
free(buffer);
|
free(buffer);
|
||||||
|
|
||||||
return htmlStr;
|
return htmlStr;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,4 +21,4 @@
|
||||||
#include <cmark.h>
|
#include <cmark.h>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
QString markdownToHTML(const QString& markdown);
|
QString markdownToHTML(const QString& markdown);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <qlogging.h>
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <compare>
|
#include <compare>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,8 @@
|
||||||
class NullInstance : public BaseInstance {
|
class NullInstance : public BaseInstance {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
NullInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString& rootDir)
|
NullInstance(SettingsObject* globalSettings, std::unique_ptr<SettingsObject> settings, const QString& rootDir)
|
||||||
: BaseInstance(globalSettings, settings, rootDir)
|
: BaseInstance(globalSettings, std::move(settings), rootDir)
|
||||||
{
|
{
|
||||||
setVersionBroken(true);
|
setVersionBroken(true);
|
||||||
}
|
}
|
||||||
|
|
@ -52,7 +52,7 @@ class NullInstance : public BaseInstance {
|
||||||
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; }
|
LaunchTask* createLaunchTask(AuthSessionPtr, MinecraftTarget::Ptr) override { return nullptr; }
|
||||||
QList<Task::Ptr> createUpdateTask() override { return {}; }
|
QList<Task::Ptr> createUpdateTask() override { return {}; }
|
||||||
QProcessEnvironment createEnvironment() override { return QProcessEnvironment(); }
|
QProcessEnvironment createEnvironment() override { return QProcessEnvironment(); }
|
||||||
QProcessEnvironment createLaunchEnvironment() override { return QProcessEnvironment(); }
|
QProcessEnvironment createLaunchEnvironment() override { return QProcessEnvironment(); }
|
||||||
|
|
|
||||||
|
|
@ -67,5 +67,5 @@ class PSaveFile : public QSaveFile {
|
||||||
QString m_absoluteFilePath;
|
QString m_absoluteFilePath;
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
#define PSaveFile QSaveFile
|
using PSaveFile = QSaveFile;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -66,4 +66,4 @@ inline QVariant fromList(QList<T> val)
|
||||||
return variantList;
|
return variantList;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace QVariantUtils
|
} // namespace QVariantUtils
|
||||||
|
|
|
||||||
|
|
@ -19,23 +19,52 @@
|
||||||
|
|
||||||
#include "ResourceDownloadTask.h"
|
#include "ResourceDownloadTask.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
|
#include "minecraft/MinecraftInstance.h"
|
||||||
|
#include "minecraft/PackProfile.h"
|
||||||
#include "minecraft/mod/ResourceFolderModel.h"
|
#include "minecraft/mod/ResourceFolderModel.h"
|
||||||
|
|
||||||
#include "minecraft/mod/ShaderPackFolderModel.h"
|
#include "minecraft/mod/ShaderPackFolderModel.h"
|
||||||
|
#include "modplatform/ModIndex.h"
|
||||||
#include "modplatform/helpers/HashUtils.h"
|
#include "modplatform/helpers/HashUtils.h"
|
||||||
#include "net/ApiDownload.h"
|
#include "net/ApiDownload.h"
|
||||||
#include "net/ChecksumValidator.h"
|
#include "net/ChecksumValidator.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
Net::ModrinthDownloadMeta createModrinthMeta(BaseInstance* instance, QString reason)
|
||||||
|
{
|
||||||
|
auto* mcInstance = dynamic_cast<MinecraftInstance*>(instance);
|
||||||
|
if (!mcInstance) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* profile = mcInstance->getPackProfile();
|
||||||
|
if (!profile) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto loaders = profile->getModLoadersList();
|
||||||
|
|
||||||
|
return {
|
||||||
|
.reason = std::move(reason),
|
||||||
|
.gameVersion = profile->getComponentVersion("net.minecraft"),
|
||||||
|
.loader = !loaders.isEmpty() ? ModPlatform::getModLoaderAsString(loaders.first()) : "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
ResourceDownloadTask::ResourceDownloadTask(ModPlatform::IndexedPack::Ptr pack,
|
ResourceDownloadTask::ResourceDownloadTask(ModPlatform::IndexedPack::Ptr pack,
|
||||||
ModPlatform::IndexedVersion version,
|
ModPlatform::IndexedVersion version,
|
||||||
const std::shared_ptr<ResourceFolderModel> packs,
|
ResourceFolderModel* packs,
|
||||||
bool is_indexed)
|
bool isIndexed,
|
||||||
|
QString downloadReason)
|
||||||
: m_pack(std::move(pack)), m_pack_version(std::move(version)), m_pack_model(packs)
|
: m_pack(std::move(pack)), m_pack_version(std::move(version)), m_pack_model(packs)
|
||||||
{
|
{
|
||||||
if (is_indexed) {
|
if (isIndexed) {
|
||||||
m_update_task.reset(new LocalResourceUpdateTask(m_pack_model->indexDir(), *m_pack, m_pack_version));
|
m_update_task.reset(new LocalResourceUpdateTask(m_pack_model->indexDir(), *m_pack, m_pack_version));
|
||||||
connect(m_update_task.get(), &LocalResourceUpdateTask::hasOldResource, this, &ResourceDownloadTask::hasOldResource);
|
connect(m_update_task.get(), &LocalResourceUpdateTask::hasOldResource, this, &ResourceDownloadTask::hasOldResource);
|
||||||
|
|
||||||
|
|
@ -45,7 +74,9 @@ ResourceDownloadTask::ResourceDownloadTask(ModPlatform::IndexedPack::Ptr pack,
|
||||||
m_filesNetJob.reset(new NetJob(tr("Resource download"), APPLICATION->network()));
|
m_filesNetJob.reset(new NetJob(tr("Resource download"), APPLICATION->network()));
|
||||||
m_filesNetJob->setStatus(tr("Downloading resource:\n%1").arg(m_pack_version.downloadUrl));
|
m_filesNetJob->setStatus(tr("Downloading resource:\n%1").arg(m_pack_version.downloadUrl));
|
||||||
|
|
||||||
auto action = Net::ApiDownload::makeFile(m_pack_version.downloadUrl, m_pack_model->dir().absoluteFilePath(getFilename()));
|
auto action = Net::ApiDownload::makeFile(m_pack_version.downloadUrl, m_pack_model->dir().absoluteFilePath(getFilename()),
|
||||||
|
Net::Download::Option::NoOptions,
|
||||||
|
createModrinthMeta(m_pack_model->instance(), std::move(downloadReason)));
|
||||||
if (!m_pack_version.hash_type.isEmpty() && !m_pack_version.hash.isEmpty()) {
|
if (!m_pack_version.hash_type.isEmpty() && !m_pack_version.hash.isEmpty()) {
|
||||||
switch (Hashing::algorithmFromString(m_pack_version.hash_type)) {
|
switch (Hashing::algorithmFromString(m_pack_version.hash_type)) {
|
||||||
case Hashing::Algorithm::Md4:
|
case Hashing::Algorithm::Md4:
|
||||||
|
|
@ -82,29 +113,31 @@ void ResourceDownloadTask::downloadSucceeded()
|
||||||
auto oldName = std::get<0>(to_delete);
|
auto oldName = std::get<0>(to_delete);
|
||||||
auto oldFilename = std::get<1>(to_delete);
|
auto oldFilename = std::get<1>(to_delete);
|
||||||
|
|
||||||
if (oldName.isEmpty() || oldFilename == m_pack_version.fileName)
|
if (oldName.isEmpty() || oldFilename == m_pack_version.fileName) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
m_pack_model->uninstallResource(oldFilename, true);
|
m_pack_model->uninstallResource(oldFilename, true);
|
||||||
|
|
||||||
// also rename the shader config file
|
// also rename the shader config file
|
||||||
if (dynamic_cast<ShaderPackFolderModel*>(m_pack_model.get()) != nullptr) {
|
if (dynamic_cast<ShaderPackFolderModel*>(m_pack_model) != nullptr) {
|
||||||
QFileInfo oldConfig(m_pack_model->dir(), oldFilename + ".txt");
|
QFileInfo oldConfig(m_pack_model->dir(), oldFilename + ".txt");
|
||||||
QFileInfo newConfig(m_pack_model->dir(), getFilename() + ".txt");
|
QFileInfo newConfig(m_pack_model->dir(), getFilename() + ".txt");
|
||||||
|
|
||||||
if (oldConfig.exists() && !newConfig.exists()) {
|
if (oldConfig.exists() && !newConfig.exists()) {
|
||||||
bool success = FS::move(oldConfig.filePath(), newConfig.filePath());
|
bool success = FS::move(oldConfig.filePath(), newConfig.filePath());
|
||||||
|
|
||||||
if (!success)
|
if (!success) {
|
||||||
emit logWarning(tr("Failed to rename shader config from '%1' to '%2'").arg(oldConfig.fileName(), newConfig.fileName()));
|
emit logWarning(tr("Failed to rename shader config from '%1' to '%2'").arg(oldConfig.fileName(), newConfig.fileName()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResourceDownloadTask::downloadFailed(QString reason)
|
void ResourceDownloadTask::downloadFailed(QString reason)
|
||||||
{
|
{
|
||||||
emitFailed(reason);
|
|
||||||
m_filesNetJob.reset();
|
m_filesNetJob.reset();
|
||||||
|
emitFailed(std::move(reason));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResourceDownloadTask::downloadProgressChanged(qint64 current, qint64 total)
|
void ResourceDownloadTask::downloadProgressChanged(qint64 current, qint64 total)
|
||||||
|
|
@ -114,7 +147,7 @@ void ResourceDownloadTask::downloadProgressChanged(qint64 current, qint64 total)
|
||||||
|
|
||||||
// This indirection is done so that we don't delete a mod before being sure it was
|
// This indirection is done so that we don't delete a mod before being sure it was
|
||||||
// downloaded successfully!
|
// downloaded successfully!
|
||||||
void ResourceDownloadTask::hasOldResource(QString name, QString filename)
|
void ResourceDownloadTask::hasOldResource(const QString& name, const QString& filename)
|
||||||
{
|
{
|
||||||
to_delete = { name, filename };
|
to_delete = { name, filename };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue