Compare commits
930 Commits
Author | SHA1 | Date | |
---|---|---|---|
dca4ea5cea | |||
be1e2c07ec | |||
ac4497a1f2 | |||
d72c75db23 | |||
6821a45b7f | |||
f24cdd6564 | |||
cb69869836 | |||
0b85051a23 | |||
f2e2053134 | |||
b181f4bc30 | |||
f00dbdc215 | |||
309dcc82ca | |||
0922a7f410 | |||
7d91db607f | |||
efcba698ac | |||
b191291737 | |||
90007e2d9d | |||
29ef1e2c4b | |||
fbe84f9e47 | |||
b036d95bab | |||
bfffcb3910 | |||
bc450e4cee | |||
de02deac98 | |||
e2ad3b0183 | |||
caf6d02728 | |||
35f71f5793 | |||
b2a89ee4b9 | |||
b84d52be3d | |||
305973c0e7 | |||
7c251efc47 | |||
9a0d6124f3 | |||
2646ae29f0 | |||
b4707f46ad | |||
482e049ac7 | |||
c04adf7452 | |||
92e8aaf36f | |||
3cab0e69f1 | |||
1ec7878c07 | |||
cdd83c279c | |||
12cadf3af0 | |||
2bc6da038d | |||
3b4b34b369 | |||
6542f5f15a | |||
30b56dbcbd | |||
cbc8c1aed6 | |||
6afe59e76b | |||
88a93945d4 | |||
2847cefff7 | |||
96f16069a9 | |||
188c5aaa35 | |||
f5f59203a2 | |||
c329730de8 | |||
97a83c9b7a | |||
1e6df7eec0 | |||
3806f23b02 | |||
36045a8b0a | |||
943090db98 | |||
77caaca50d | |||
f66e0fa0e8 | |||
441075f610 | |||
b2878dca1d | |||
b883ce5c51 | |||
127dfadc6c | |||
ff9f3cb31f | |||
a21bd41580 | |||
8e9f1bcf18 | |||
4b06fc5323 | |||
cc27bb3231 | |||
c1700054f4 | |||
cc13310083 | |||
1012912272 | |||
edbd90a4e6 | |||
ddc3b5eb0b | |||
17bbfe8d89 | |||
96deb5b09d | |||
9b387d73e5 | |||
c02a6780b0 | |||
85ec9d95a4 | |||
6dfec4db40 | |||
2e9d7f5c3d | |||
696a711e39 | |||
887246a66b | |||
2993318d19 | |||
2b52cf01f5 | |||
cd9e0e0cc0 | |||
f66598db8a | |||
cf5c752dda | |||
a6d2c5e181 | |||
82760f4b91 | |||
62e099ace5 | |||
e92b7bd25e | |||
e7bb3b2776 | |||
ec3c882a44 | |||
66ce5a4a2d | |||
a110d445ac | |||
a67f3131e7 | |||
7f305aad1b | |||
80908efdcb | |||
e5d0097116 | |||
6d78ea5a45 | |||
550d6a6a9b | |||
9be8160bf2 | |||
3070565fa3 | |||
7194bb1b81 | |||
78cf0c73c8 | |||
4adc61bda9 | |||
93e0041d0e | |||
682a7fb6ba | |||
5f2398fe59 | |||
3abf466632 | |||
4bb429a0fb | |||
4a0e4fdb85 | |||
a43f882d48 | |||
9731e06728 | |||
8e764fc8fb | |||
4745ed2818 | |||
49de5d9b07 | |||
365cc198ba | |||
9899a0e098 | |||
5ea8cec16f | |||
9dd70ca9ae | |||
4fda35b466 | |||
31988f0529 | |||
db03846358 | |||
c6b3eccbdf | |||
3f259eb97a | |||
fac0b027b3 | |||
84b962f256 | |||
123ed5bd2e | |||
c3336251e0 | |||
c054d0f329 | |||
8dd68580a6 | |||
067484a6a8 | |||
c83e16aba4 | |||
d85fc456a9 | |||
dd2b324d8f | |||
0bce08d30f | |||
57d65177c8 | |||
040ee919e5 | |||
efa3fbff39 | |||
8c8eabf7ac | |||
3aea639fe4 | |||
046f1e6e58 | |||
37e8f495b4 | |||
512d7b07d0 | |||
527fa7ba9c | |||
288e7bc9c5 | |||
649b8ac7c6 | |||
96b2758169 | |||
40e0252d7d | |||
5171d99fe5 | |||
ea9d61c21c | |||
da25f3b84e | |||
1e34de98ab | |||
7b46f50cf1 | |||
cab40026f2 | |||
ac66bddeda | |||
f4237be9bd | |||
dd11ccb3fd | |||
c4549a5375 | |||
e9b3140d12 | |||
bdd2d57808 | |||
22f5128e39 | |||
ae1aa6f63e | |||
29a53d7e95 | |||
2fbb7be23b | |||
f7f39854f8 | |||
113528e1f2 | |||
6bffa06063 | |||
dcc41ef885 | |||
e909cc363d | |||
9a87ae575e | |||
860a7af679 | |||
4fdb21b414 | |||
eeb5297284 | |||
8de63b60b1 | |||
0b38d878a1 | |||
d29720fbce | |||
0556ae4749 | |||
1a86f72690 | |||
25d380f051 | |||
546d394868 | |||
8110040f86 | |||
239e4adf29 | |||
5662d41062 | |||
1e03ef484d | |||
1d95f10090 | |||
6768768373 | |||
dac801c8ac | |||
ece5ca52b2 | |||
3205d9e9da | |||
b931dc0f93 | |||
efe4e7df06 | |||
b94f70ea96 | |||
bd946c78f3 | |||
a507907443 | |||
0507b56bed | |||
ac405aa564 | |||
aad7c63282 | |||
1ff459d995 | |||
52454ca77b | |||
884f772362 | |||
bc06571dba | |||
1e8ad3d979 | |||
b0a469baab | |||
c968c1be78 | |||
a0bafa4952 | |||
e56f0db11b | |||
8bcbe07c87 | |||
ba9059c7c8 | |||
45783c1661 | |||
71777e7a6f | |||
c86ec0bd36 | |||
08b1b2669a | |||
94a655b055 | |||
717067e9eb | |||
5a5797d914 | |||
75826aca13 | |||
f52b7c030f | |||
c1386bcb04 | |||
234a9e48e9 | |||
908e6364c9 | |||
3ec511010f | |||
b3e1691c01 | |||
5adcc26190 | |||
db6dae7541 | |||
4e97f2a6fe | |||
4643046989 | |||
3c3ce71214 | |||
0682fe544a | |||
27e803e4a4 | |||
405c44c9e1 | |||
4c5f701b05 | |||
c7563a5f7c | |||
3ff3c335bc | |||
b9d5e1bbf1 | |||
e313b366a0 | |||
027c666265 | |||
4a3d94aaf9 | |||
c637e3657c | |||
9462dd3ddc | |||
c3524a9d57 | |||
53ff66c317 | |||
ec2ac2e80c | |||
27c72935f8 | |||
31c757d912 | |||
fcdc7a1a35 | |||
f13c776099 | |||
ebded1ec49 | |||
7b9d462fbc | |||
c174a1eb01 | |||
ac77997a7a | |||
fa352ff4d3 | |||
fd7745cbeb | |||
c348de96e4 | |||
1bb35b9204 | |||
cbbcc2d68b | |||
fcbf37f60f | |||
56ce7f5dcd | |||
0ccbc801cf | |||
4c52cc414f | |||
6b45386252 | |||
3acc761419 | |||
dd4c67b654 | |||
0c581cfb62 | |||
703bf9bb7a | |||
a40dee2230 | |||
cab9afa45f | |||
ba5946dc60 | |||
9bad83a551 | |||
a549828655 | |||
c1398a6a1a | |||
e11d1b5202 | |||
abdb846c3f | |||
b0b6dd8f87 | |||
4a971226e4 | |||
b10d4d3b8f | |||
6ed130fc16 | |||
90d4acd1a1 | |||
a42d2afcee | |||
ba020fbd21 | |||
af167e8e67 | |||
be82f4db9e | |||
6a97ac603a | |||
e59d3a339f | |||
db7cb12551 | |||
1049507b3f | |||
1303771b58 | |||
f6605bc3f8 | |||
80ec178d5f | |||
ef76bd355a | |||
b0a8bd7dfe | |||
5d8d7740ba | |||
3e64935844 | |||
7577115c3c | |||
2cb242e9b3 | |||
7aeccbb6b0 | |||
8406c7f431 | |||
8c98cc9458 | |||
715d7d4424 | |||
8e9eca6a97 | |||
5f15f51610 | |||
277de41200 | |||
63bce04648 | |||
76dfb7825a | |||
5cb0e75093 | |||
c730fd6e5f | |||
c2b97c3e3f | |||
e0ab8207ed | |||
ecad388846 | |||
9a120f43c8 | |||
4ff1306e0c | |||
1dd663af6e | |||
06d9821b2c | |||
abb20c65e3 | |||
9fb5674233 | |||
18ac109e5a | |||
14a0e85862 | |||
fa2b3bcc63 | |||
620555d210 | |||
ea3ceb382a | |||
37a30fbc3f | |||
99193a2d7b | |||
abfb99ba3f | |||
fcb311eecd | |||
54e4f88ada | |||
89125fde22 | |||
9f3eed6ca2 | |||
ab82358dcb | |||
75fddd0052 | |||
8a2c5f5b0d | |||
66caac0bbc | |||
ab8d897bd7 | |||
3024dbcf2c | |||
eeae3eca67 | |||
d0cda6d605 | |||
167e32a69f | |||
be2512bb4b | |||
c3f1c13a31 | |||
35cfb41a9c | |||
74cdf5350d | |||
9349232bd4 | |||
1811302deb | |||
e6564aa69f | |||
566a83b245 | |||
9eb9ddc668 | |||
cc5261051f | |||
fa870bc026 | |||
99d569ed0e | |||
a1a7b9c151 | |||
dc6340bf38 | |||
8732bea99b | |||
bbc6b71138 | |||
5fb096d7b9 | |||
cf8680f1ab | |||
115d8b5945 | |||
bd8b61651a | |||
d2ffaee9f8 | |||
8f61633551 | |||
d33d5b847d | |||
c8879df621 | |||
c367769781 | |||
02b44256b2 | |||
b6e722a048 | |||
7f2615b2a5 | |||
a232c2d509 | |||
c8205fda9f | |||
8df88e7fbb | |||
c8092269ba | |||
9d88f07955 | |||
f267375ac2 | |||
d44fa416ca | |||
41d7b27d43 | |||
5f461374b8 | |||
d5576779b7 | |||
c098be40ab | |||
333f7cc320 | |||
9180c751d8 | |||
131a04653f | |||
6e6d495bc7 | |||
2c07f758a0 | |||
251f0efec2 | |||
e8697068fb | |||
269c1bbf58 | |||
9b8493c304 | |||
c389a711ed | |||
382548e0a7 | |||
a90fc3d7fe | |||
48a6380e31 | |||
64ca96f470 | |||
59b3e30821 | |||
92e5e0e95b | |||
9202996c62 | |||
e22d54abd3 | |||
b53ba12fa2 | |||
335115041c | |||
bac67800be | |||
306df9e17f | |||
5f2e768376 | |||
575c92ec47 | |||
4d8bf0b621 | |||
954074942e | |||
341eb16a4c | |||
3a7eeff135 | |||
659f93b1de | |||
ea60e48d9d | |||
6054abaffb | |||
3a1feed723 | |||
85f3fc9944 | |||
87cf38a377 | |||
5e77b548b1 | |||
104de9e795 | |||
424f4a72ff | |||
ec6409914d | |||
6a25cacc3e | |||
b1af689546 | |||
0a5dfeb3d7 | |||
6a180f495f | |||
3672dbc5af | |||
81b50c0387 | |||
bd60c54911 | |||
87acaa0926 | |||
54d2c91320 | |||
94e7961df0 | |||
0d46ea5c71 | |||
6bd345b1ad | |||
cb384261b8 | |||
75301bec4b | |||
d00c320c00 | |||
e13ca94061 | |||
e02369ba6b | |||
82c35f2746 | |||
a9d935f9ef | |||
92f3154e8f | |||
eb06d0116f | |||
f66910d054 | |||
1b47132ebb | |||
a89cbf116d | |||
471ea680a5 | |||
51de84407f | |||
d252917792 | |||
dfa5f614aa | |||
f3a244e90a | |||
c7c83a35fa | |||
6025cd0ca5 | |||
ce05ce92bb | |||
a5fc640f2c | |||
0a4a3fece5 | |||
fcf728f3b5 | |||
cd4851c98b | |||
3db5f30403 | |||
58957122b9 | |||
8b46658b05 | |||
571e322d66 | |||
ddda02f092 | |||
bf6fa6bce4 | |||
025a3cf730 | |||
6d9eaee7f9 | |||
7471ce4530 | |||
149ffb844f | |||
4cf3ac42c8 | |||
d16c6b0e69 | |||
76e1aba58b | |||
c560d06b8d | |||
0681568d3e | |||
c7fdfb8116 | |||
c6b1a776dc | |||
8accb6f04e | |||
d1d055564c | |||
2741c58a01 | |||
64399dd8d6 | |||
f2ca11688e | |||
3c0c57359b | |||
062fc79286 | |||
2da565f5d4 | |||
e8373bbf65 | |||
26acc836d9 | |||
9c22af9685 | |||
75d0078a38 | |||
536b1a23fc | |||
cafff5e504 | |||
dd5c4b6864 | |||
a2c85a8531 | |||
de4d757650 | |||
f22cd0e8c7 | |||
702a1da0ac | |||
768007d980 | |||
2e40ab6244 | |||
95182ed74b | |||
8bc6cdf55c | |||
6c0b101fed | |||
9841c0a63d | |||
17d200dc88 | |||
c8fec556c0 | |||
b7f2959353 | |||
4899d3c458 | |||
c311dba465 | |||
75ec4256e2 | |||
bb5a91c179 | |||
8225f1ac92 | |||
06d16c6b13 | |||
90780818ca | |||
a160bd0062 | |||
7e0312493b | |||
ccfd06ad21 | |||
48c2146a42 | |||
abb9fa8cbd | |||
f99245b917 | |||
e35db82c27 | |||
6202525372 | |||
ec66c8fd3d | |||
19804c5718 | |||
fa5fa53592 | |||
da43ed8ce1 | |||
2d1f99b765 | |||
f01b8f29c6 | |||
440e9731e2 | |||
acdb54b88e | |||
00c3336ec8 | |||
a268ac7141 | |||
aedb513c9e | |||
ac3a7acc45 | |||
8409aa2571 | |||
199740cc61 | |||
a0f76cba62 | |||
5b8003cbe5 | |||
c0719102a0 | |||
9d8bbf34e6 | |||
ec9d0e70fb | |||
f1e44291cc | |||
b3b613d8b4 | |||
177b685557 | |||
71a4333f55 | |||
f1c21a912a | |||
84a142096f | |||
bb2b344d33 | |||
b96572774f | |||
641a96e4a9 | |||
9f8983b570 | |||
e42c5b00a4 | |||
a3d7ad731d | |||
dc98609ef8 | |||
c799faaca6 | |||
07e4c4d189 | |||
c4a8fd353c | |||
91524d6d6e | |||
c1201997a3 | |||
d814e21f0d | |||
49d122a2c4 | |||
0813eba367 | |||
4fe13c64a1 | |||
b3c2a56ece | |||
9c57b54a81 | |||
b131d3b2ec | |||
16bfafa29e | |||
f714adf6d2 | |||
dc9e250868 | |||
b6cf0359fa | |||
39bd04f06f | |||
d755174bee | |||
1229e90817 | |||
5a638fa977 | |||
5e9d49a910 | |||
ae39d16c11 | |||
b93daf1fb7 | |||
6545d250e8 | |||
b162351ff4 | |||
53468ea474 | |||
3697d70b48 | |||
e0c025b162 | |||
9e443faba3 | |||
f95cebaf06 | |||
9a8599e4ba | |||
2d68308d49 | |||
0dd1c26cf3 | |||
881b2f2b38 | |||
ca211558b5 | |||
3a03f90831 | |||
9020f632b2 | |||
8bdd2befe9 | |||
ebececf8c6 | |||
e1f28be151 | |||
10231aa404 | |||
139ff82432 | |||
4e8f075ff3 | |||
148775b3e9 | |||
075d900d45 | |||
5d1ca33b84 | |||
ccc493cb2b | |||
2745325ae0 | |||
84e9ce71b0 | |||
88fc1e32ee | |||
4f975bfb04 | |||
692b9cf0e0 | |||
ae354688c9 | |||
c9bf7f9896 | |||
e8929599a5 | |||
27f37315f8 | |||
c4f4e9e620 | |||
f2b850ad20 | |||
ccc27d1b7c | |||
4835ec3f6d | |||
40a9828fba | |||
04840d0638 | |||
38f12c50f7 | |||
ca8b62291f | |||
69d01204e0 | |||
1e3b896fda | |||
9e35560554 | |||
f9d4751ec0 | |||
a66e6a413f | |||
2c911a5475 | |||
e2c2a38005 | |||
aa4a6bb3be | |||
4af020161d | |||
f8b0d6453a | |||
0102e91940 | |||
1004211a66 | |||
f5cf4eb45f | |||
512395e3f1 | |||
9c6727e27f | |||
624ab25cd4 | |||
a70d1f1a91 | |||
3059f13011 | |||
6d1f9d4d02 | |||
d3e7d30ee0 | |||
5bbb4f31dc | |||
da70122d9c | |||
8556ff5eac | |||
adacab3349 | |||
613b351f13 | |||
80a29af497 | |||
7e1fad55d9 | |||
9b7cd029a7 | |||
c5d9944993 | |||
14717396eb | |||
9c71f364d2 | |||
be910374dc | |||
10de75623e | |||
7fc55b58fe | |||
12c8a04458 | |||
796e58b6f2 | |||
a7d37fa69a | |||
7b4b997a34 | |||
6b4469c6cc | |||
107a0ea852 | |||
6d7676202f | |||
0305b7a1fd | |||
02384f81c7 | |||
4536b19512 | |||
45f89c6255 | |||
b1cf77e847 | |||
037b0d7190 | |||
ff17202b43 | |||
a3d8313dcb | |||
36841eaf63 | |||
e24a183dad | |||
8596753a63 | |||
51183bef33 | |||
2cd837896d | |||
c75ae71190 | |||
48c20f5aaa | |||
929a035f96 | |||
5779f20fa1 | |||
384e0df9e1 | |||
a5b06514c6 | |||
a309f4e721 | |||
159d868b77 | |||
0854e83ce4 | |||
bb02226870 | |||
9ddbaaf7e8 | |||
3b7cc4391a | |||
70a055bc27 | |||
61db1c46be | |||
a60b2feb5f | |||
6ba031f048 | |||
812f00eb81 | |||
2f6973e08b | |||
fb14796ed7 | |||
7d912726d0 | |||
e3c8eb062c | |||
3cf81faabc | |||
0df605e559 | |||
e97a6ef957 | |||
c4dd8d9c72 | |||
bcfa3246cb | |||
f67871e79e | |||
11f892380e | |||
fd72cb034c | |||
b9be8d08d2 | |||
33d369d78c | |||
0e6e6a7521 | |||
eb692c2ee9 | |||
3eee38fedd | |||
0ba61bb590 | |||
9497485103 | |||
551d9c86ba | |||
e61e827eb9 | |||
92a5b12bd9 | |||
35d1330fe2 | |||
b4e0b7584a | |||
2341212337 | |||
53ea261350 | |||
a17e5d0a4d | |||
5d4a66ed8a | |||
8d2e7db178 | |||
383c93ff01 | |||
13d41bde7f | |||
d42d6fe25a | |||
beaac54dc9 | |||
70f8cb81b8 | |||
f8ca6b4867 | |||
49f5f67467 | |||
35d2ae3ef7 | |||
22ca572ae0 | |||
619fcbfabf | |||
292869141f | |||
ca9929214d | |||
121ad4e4bf | |||
2f87a4477e | |||
d72c511131 | |||
8b68c06547 | |||
b911151786 | |||
7531a2894b | |||
5b507a8944 | |||
d2f86cbf32 | |||
08dff6613b | |||
901ec15dc8 | |||
5284d604ef | |||
b2b4ab3f0c | |||
b646fc5a13 | |||
d35cbfd9c4 | |||
f25152e068 | |||
dd8946b15a | |||
305350fdc8 | |||
f31d5372e7 | |||
ca1a2bbe2c | |||
dba9199e58 | |||
e806903d7e | |||
41d8e3cbd7 | |||
5e32783c4e | |||
fdc3a4104b | |||
8199941a81 | |||
651d237200 | |||
6f5b380199 | |||
c746d77a06 | |||
9ab3841570 | |||
3a28741cc3 | |||
22f7a85cf2 | |||
86935068f5 | |||
00e12b776b | |||
3b96a9a8fa | |||
5ac5c767e0 | |||
f1d3d4a366 | |||
1160066f0d | |||
8d603d6162 | |||
076efc4cb2 | |||
2c62a34c2f | |||
2177aa2a6b | |||
e8a4902a3d | |||
e2952061af | |||
fcc4420cfe | |||
f5358aa1ca | |||
3d3f9a8609 | |||
1f176fcb7b | |||
3ca661127f | |||
407f9d9ef0 | |||
bff683e6d4 | |||
770da6317e | |||
cf3c2482c9 | |||
2001c5dec7 | |||
80cf716c98 | |||
37e1962845 | |||
f8c5d80c66 | |||
11841c47e6 | |||
71b1ac9f34 | |||
eda06df878 | |||
c4cb7ddc4f | |||
a8089b76c0 | |||
71516e6c72 | |||
88686ef065 | |||
0442b80a2c | |||
81c72c2038 | |||
3aa809b8c0 | |||
efa414c442 | |||
c39da093bf | |||
aa2c27bf69 | |||
1f92125a7f | |||
5c48b7dfab | |||
d664361b15 | |||
813de1c703 | |||
02f24117f0 | |||
7a7a937f1e | |||
0211ee3ef1 | |||
c569bfbe6d | |||
b925338688 | |||
2cf04d034a | |||
049aafd0a1 | |||
e0a04c5031 | |||
9d23ac562f | |||
0065a29901 | |||
8ea1ebaf1b | |||
5c2d3e430d | |||
b710b719a8 | |||
7df5091fdc | |||
5abb97362f | |||
b34239ebc6 | |||
7ef6c586c5 | |||
9d36cf4b5a | |||
04be2404ce | |||
7f4fd04cfe | |||
b2bcdb9d9b | |||
d81e2bb0b0 | |||
177c10bb0f | |||
304775952f | |||
ca00103ee2 | |||
3aa9f5c376 | |||
efc44c56a6 | |||
8b790a6dd9 | |||
f36930d812 | |||
232295bda7 | |||
451768ccf9 | |||
c1aaf89baa | |||
5ac528f141 | |||
204e3dca22 | |||
33aac2985a | |||
361ce7818e | |||
ad6e3a0868 | |||
fd2269ac15 | |||
14a8ead6b4 | |||
bbf0508846 | |||
79314ee67b | |||
86b0637ef7 | |||
1c982b0182 | |||
cd5faee7d7 | |||
ec1e27031a | |||
02889b7a11 | |||
0eff21a4f1 | |||
0680945839 | |||
631e670775 | |||
4edd2cff9f | |||
0235eb5c28 | |||
8804b035b2 | |||
54e3438e37 | |||
ddfed7bb87 | |||
70c04745ee | |||
63d4486855 | |||
1d0e6bf453 | |||
a2d88f6df4 | |||
019c77f9f7 | |||
5b5c5afc3a | |||
af20b5ee0e | |||
a1b779da15 | |||
8b31c638f3 | |||
3da69d8e53 | |||
dd76fb0ec7 | |||
caeab926bc | |||
35caa3c21a | |||
7022d3d401 | |||
6d22794cf9 | |||
b50e584369 | |||
affc2521aa | |||
63098b6f19 | |||
83e1dd285a | |||
b9beb3c7d2 | |||
2dd2555a63 | |||
126e6d13aa | |||
236c0166f6 | |||
9a33fb1f49 | |||
2c2c22ccf8 | |||
55597b458c | |||
f55297eca9 | |||
0bc8baf117 | |||
5f9270ed4b | |||
81fe41a038 | |||
0316cf88aa | |||
917f8a31e3 | |||
aa770b63fb | |||
c1bf31cb27 | |||
86d99f80c3 | |||
975f77756d | |||
8172dcd2d5 | |||
b95c27ceef | |||
f78bb90ed9 | |||
dc129fd886 | |||
621e0ba4a8 | |||
f6de472da2 | |||
4b37c46889 | |||
c371558883 | |||
0bbd0ac0b9 | |||
ac93c64cd4 | |||
6cd4375aff | |||
a606b47a22 | |||
a62155c1c9 | |||
b4f750e7db | |||
b19e315615 | |||
41dba376a8 | |||
2896f70cd8 | |||
1a8c972aef | |||
cdaa397dcf | |||
9e6fa8f29a | |||
4d599eb118 | |||
4e9039be2d | |||
395e265564 | |||
b07853c9ef | |||
b635a7e693 | |||
f84fc783b6 | |||
2301a934b0 | |||
60e9d2754a | |||
d06c2cacb1 | |||
49c2bd477c | |||
46a3b4de6e | |||
6ecc8c5496 | |||
a1ff3b1ee3 | |||
d4b522b6cb | |||
3b524e99cc | |||
3329d94c9b | |||
a12118f1a0 | |||
5fe33a98a2 | |||
1d8196e11a | |||
c7f6f94930 | |||
131615811b | |||
3fa6e22430 | |||
c86ac772c8 | |||
52420963cf | |||
addf5f4e52 | |||
03d7300732 | |||
a97d0a36f4 | |||
e9c52ec696 | |||
75f2dab3c8 |
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1 @@
|
||||
open_collective: polymc
|
11
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
11
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -1,6 +1,6 @@
|
||||
name: Bug Report
|
||||
description: File a bug report
|
||||
labels: [bug, needs-triage]
|
||||
labels: [bug]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
@ -8,7 +8,7 @@ body:
|
||||
If you need help with running Minecraft, please visit us on our Discord before making a bug report.
|
||||
|
||||
Before submitting a bug report, please make sure you have read this *entire* form, and that:
|
||||
* You have read the [FAQ](https://github.com/PolyMC/PolyMC/wiki/FAQ) and it has not answered your question
|
||||
* You have read the [PolyMC wiki](https://polymc.org/wiki/) and it has not answered your question.
|
||||
* Your bug is not caused by Minecraft or any mods you have installed.
|
||||
* Your issue has not been reported before, [make sure to use the search function!](https://github.com/PolyMC/PolyMC/issues)
|
||||
|
||||
@ -23,6 +23,13 @@ body:
|
||||
- macOS
|
||||
- Linux
|
||||
- Other
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Version of PolyMC
|
||||
description: The version of PolyMC used in the bug report.
|
||||
placeholder: PolyMC 1.2.2
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Description of bug
|
||||
|
68
.github/ISSUE_TEMPLATE/rfc.yml
vendored
Normal file
68
.github/ISSUE_TEMPLATE/rfc.yml
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
# Template based on https://gitlab.archlinux.org/archlinux/rfcs/-/blob/0ba3b61e987e197f8d1901709409b8564958f78a/rfcs/0000-template.rst
|
||||
name: Request for Comment (RFC)
|
||||
description: Propose a larger change and start a discussion.
|
||||
labels: [rfc]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
### Use this form to suggest a larger change for PolyMC.
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Goal
|
||||
description: Short description, 1-2 sentences.
|
||||
placeholder: Remove the cat from the launcher.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Motivation
|
||||
description: |
|
||||
Introduce the topic. If this is a not-well-known section of PolyMC, a detailed explanation of the background is recommended.
|
||||
Some example points of discussion:
|
||||
- What specific problems are you facing right now that you're trying to address?
|
||||
- Are there any previous discussions? Link to them and summarize them (don't force your readers to read them though!).
|
||||
- Is there any precedent set by other software? If so, link to resources.
|
||||
placeholder: I don't like cats. I think many users also don't like cats.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Specification
|
||||
description: A concrete, thorough explanation of what is being planned.
|
||||
placeholder: Remove the cat button and all references to the cat from the codebase. Including resource files.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Drawbacks
|
||||
description: Carefully consider every possible objection and issue with your proposal. This section should be updated as feedback comes in from discussion.
|
||||
placeholder: Some users might like cats.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Unresolved Questions
|
||||
description: |
|
||||
Are there any portions of your proposal which need to be discussed with the community before the RFC can proceed?
|
||||
Be careful here -- an RFC with a lot of remaining questions is likely to be stalled.
|
||||
If your RFC is mostly unresolved questions and not too much substance, it may not be ready.
|
||||
placeholder: Do a lot of users care about the cat?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Alternatives Considered
|
||||
description: A list of alternatives, that have been considered and offer equal or similar features to the proposed change.
|
||||
placeholder: Maybe the cat could be replaced with an axolotl?
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: This suggestion is unique
|
||||
options:
|
||||
- label: I have searched the issue tracker and did not find an issue describing my suggestion, especially not one that has been rejected.
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: You may use the editor below to elaborate further.
|
2
.github/ISSUE_TEMPLATE/suggestion.yml
vendored
2
.github/ISSUE_TEMPLATE/suggestion.yml
vendored
@ -1,6 +1,6 @@
|
||||
name: Suggestion
|
||||
description: Make a suggestion
|
||||
labels: [idea, needs-triage]
|
||||
labels: [enhancement]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
|
41
.github/scripts/prepare_JREs.sh
vendored
Executable file
41
.github/scripts/prepare_JREs.sh
vendored
Executable file
@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
URL_JDK8="https://api.adoptium.net/v3/binary/version/jdk8u312-b07/linux/x64/jre/hotspot/normal/eclipse"
|
||||
URL_JDK17="https://api.adoptium.net/v3/binary/latest/17/ga/linux/x64/jre/hotspot/normal/eclipse"
|
||||
|
||||
mkdir -p JREs
|
||||
pushd JREs
|
||||
|
||||
wget --content-disposition "$URL_JDK8"
|
||||
wget --content-disposition "$URL_JDK17"
|
||||
|
||||
for file in *;
|
||||
do
|
||||
mkdir temp
|
||||
|
||||
re='(OpenJDK([[:digit:]]+)U-jre_x64_linux_hotspot_([[:digit:]]+)(.*).tar.gz)'
|
||||
if [[ $file =~ $re ]];
|
||||
then
|
||||
version_major=${BASH_REMATCH[2]}
|
||||
version_trailing=${BASH_REMATCH[4]}
|
||||
|
||||
if [ $version_major = 17 ];
|
||||
then
|
||||
hyphen='-'
|
||||
else
|
||||
hyphen=''
|
||||
fi
|
||||
|
||||
version_edit=$(echo $version_trailing | sed -e 's/_/+/g' | sed -e 's/b/-b/g')
|
||||
dir_name=jdk$hyphen$version_major$version_edit-jre
|
||||
mkdir jre$version_major
|
||||
tar -xzf $file -C temp
|
||||
pushd temp/$dir_name
|
||||
cp -r . ../../jre$version_major
|
||||
popd
|
||||
fi
|
||||
|
||||
rm -rf temp
|
||||
done
|
||||
|
||||
popd
|
19
.github/workflows/backport.yml
vendored
Normal file
19
.github/workflows/backport.yml
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
name: Backport PR to stable
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ develop ]
|
||||
types: [ closed ]
|
||||
jobs:
|
||||
release_pull_request:
|
||||
if: github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'backport')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Backport PR by cherry-pick-ing
|
||||
uses: Nathanmalnoury/gh-backport-action@master
|
||||
with:
|
||||
pr_branch: 'stable'
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
303
.github/workflows/build.yml
vendored
Normal file
303
.github/workflows/build.yml
vendored
Normal file
@ -0,0 +1,303 @@
|
||||
name: Build
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
build_type:
|
||||
description: Type of build (Debug, Release, RelWithDebInfo, MinSizeRel)
|
||||
type: string
|
||||
default: Debug
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
|
||||
- os: ubuntu-20.04
|
||||
|
||||
- os: ubuntu-20.04
|
||||
appimage: true
|
||||
|
||||
- os: windows-2022
|
||||
name: "Windows-i686"
|
||||
msystem: mingw32
|
||||
|
||||
- os: windows-2022
|
||||
name: "Windows-x86_64"
|
||||
msystem: mingw64
|
||||
|
||||
- os: macos-11
|
||||
macosx_deployment_target: 10.13
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
env:
|
||||
MACOSX_DEPLOYMENT_TARGET: ${{ matrix.macosx_deployment_target }}
|
||||
INSTALL_DIR: "install"
|
||||
INSTALL_PORTABLE_DIR: "install-portable"
|
||||
INSTALL_APPIMAGE_DIR: "install-appdir"
|
||||
BUILD_DIR: "build"
|
||||
CCACHE_VAR: ""
|
||||
|
||||
steps:
|
||||
##
|
||||
# PREPARE
|
||||
##
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'true'
|
||||
|
||||
- name: 'Setup MSYS2'
|
||||
if: runner.os == 'Windows'
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: ${{ matrix.msystem }}
|
||||
update: true
|
||||
install: >-
|
||||
git
|
||||
pacboy: >-
|
||||
toolchain:p
|
||||
cmake:p
|
||||
ninja:p
|
||||
qt5:p
|
||||
ccache:p
|
||||
nsis:p
|
||||
|
||||
- name: Setup ccache
|
||||
if: runner.os != 'Windows' && inputs.build_type == 'Debug'
|
||||
uses: hendrikmuhs/ccache-action@v1.2.1
|
||||
with:
|
||||
key: ${{ matrix.os }}-${{ matrix.appimage }}
|
||||
|
||||
- name: Setup ccache (Windows)
|
||||
if: runner.os == 'Windows' && inputs.build_type == 'Debug'
|
||||
shell: msys2 {0}
|
||||
run: |
|
||||
ccache --set-config=cache_dir='${{ github.workspace }}\.ccache'
|
||||
ccache --set-config=max_size='500M'
|
||||
ccache --set-config=compression=true
|
||||
ccache -p # Show config
|
||||
ccache -z # Zero stats
|
||||
|
||||
- name: Use ccache on Debug builds only
|
||||
if: inputs.build_type == 'Debug'
|
||||
shell: bash
|
||||
run: |
|
||||
echo "CCACHE_VAR=ccache" >> $GITHUB_ENV
|
||||
|
||||
- name: Retrieve ccache cache (Windows)
|
||||
if: runner.os == 'Windows' && inputs.build_type == 'Debug'
|
||||
uses: actions/cache@v3.0.2
|
||||
with:
|
||||
path: '${{ github.workspace }}\.ccache'
|
||||
key: ${{ matrix.os }}-${{ matrix.msystem }}
|
||||
restore-keys: |
|
||||
${{ matrix.os }}-${{ matrix.msystem }}
|
||||
|
||||
- name: Set short version
|
||||
shell: bash
|
||||
run: |
|
||||
ver_short=`git rev-parse --short HEAD`
|
||||
echo "VERSION=$ver_short" >> $GITHUB_ENV
|
||||
|
||||
- name: Install Qt (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
brew update
|
||||
brew install qt@5 ninja
|
||||
|
||||
- name: Update Qt (AppImage)
|
||||
if: runner.os == 'Linux' && matrix.appimage == true
|
||||
run: |
|
||||
sudo add-apt-repository ppa:savoury1/qt-5-15
|
||||
|
||||
- name: Install Qt (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
sudo apt-get -y update
|
||||
sudo apt-get -y install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5 ninja-build
|
||||
|
||||
- name: Prepare AppImage (Linux)
|
||||
if: runner.os == 'Linux' && matrix.appimage == true
|
||||
run: |
|
||||
wget "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage"
|
||||
wget "https://github.com/linuxdeploy/linuxdeploy-plugin-appimage/releases/download/continuous/linuxdeploy-plugin-appimage-x86_64.AppImage"
|
||||
wget "https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage"
|
||||
|
||||
${{ github.workspace }}/.github/scripts/prepare_JREs.sh
|
||||
|
||||
##
|
||||
# CONFIGURE
|
||||
##
|
||||
|
||||
- name: Configure CMake (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DQt5_DIR=/usr/local/opt/qt@5 -DCMAKE_PREFIX_PATH=/usr/local/opt/qt@5 -DLauncher_BUILD_PLATFORM=macOS -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -G Ninja
|
||||
|
||||
- name: Configure CMake (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
shell: msys2 {0}
|
||||
run: |
|
||||
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=${{ matrix.name }} -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -G Ninja
|
||||
|
||||
- name: Configure CMake (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_BUILD_PLATFORM=Linux -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -G Ninja
|
||||
|
||||
##
|
||||
# BUILD
|
||||
##
|
||||
|
||||
- name: Build
|
||||
if: runner.os != 'Windows'
|
||||
run: |
|
||||
cmake --build ${{ env.BUILD_DIR }}
|
||||
|
||||
- name: Build (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
shell: msys2 {0}
|
||||
run: |
|
||||
cmake --build ${{ env.BUILD_DIR }}
|
||||
|
||||
##
|
||||
# PACKAGE BUILDS
|
||||
##
|
||||
|
||||
- name: Package (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
cmake --install ${{ env.BUILD_DIR }}
|
||||
|
||||
cd ${{ env.INSTALL_DIR }}
|
||||
chmod +x "PolyMC.app/Contents/MacOS/polymc"
|
||||
sudo codesign --sign - --deep --force --entitlements "../program_info/App.entitlements" --options runtime "PolyMC.app/Contents/MacOS/polymc"
|
||||
tar -czf ../PolyMC.tar.gz *
|
||||
|
||||
- name: Package (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
shell: msys2 {0}
|
||||
run: |
|
||||
cmake --install ${{ env.BUILD_DIR }}
|
||||
|
||||
cd ${{ env.INSTALL_DIR }}
|
||||
if [ "${{ matrix.msystem }}" == "mingw32" ]; then
|
||||
cp /mingw32/bin/libcrypto-1_1.dll /mingw32/bin/libssl-1_1.dll ./
|
||||
elif [ "${{ matrix.msystem }}" == "mingw64" ]; then
|
||||
cp /mingw64/bin/libcrypto-1_1-x64.dll /mingw64/bin/libssl-1_1-x64.dll ./
|
||||
fi
|
||||
|
||||
- name: Package (Windows, portable)
|
||||
if: runner.os == 'Windows'
|
||||
shell: msys2 {0}
|
||||
run: |
|
||||
cp -r ${{ env.INSTALL_DIR }} ${{ env.INSTALL_PORTABLE_DIR }} # cmake install on Windows is slow, let's just copy instead
|
||||
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable
|
||||
|
||||
- name: Package (Windows, installer)
|
||||
if: runner.os == 'Windows'
|
||||
shell: msys2 {0}
|
||||
run: |
|
||||
cd ${{ env.INSTALL_DIR }}
|
||||
makensis -NOCD "-DVERSION=${{ env.VERSION }}" "-DMUI_ICON=${{ github.workspace }}/program_info/polymc.ico" "-XOutFile ${{ github.workspace }}/PolyMC-Setup.exe" "${{ github.workspace }}/program_info/win_install.nsi"
|
||||
|
||||
- name: Package (Linux)
|
||||
if: runner.os == 'Linux' && matrix.appimage != true
|
||||
run: |
|
||||
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_DIR }}
|
||||
|
||||
cd ${{ env.INSTALL_DIR }}
|
||||
tar --owner root --group root -czf ../PolyMC.tar.gz *
|
||||
|
||||
- name: Package (Linux, portable)
|
||||
if: runner.os == 'Linux' && matrix.appimage != true
|
||||
run: |
|
||||
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }}
|
||||
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_PORTABLE_DIR }} --component portable
|
||||
|
||||
cd ${{ env.INSTALL_PORTABLE_DIR }}
|
||||
tar -czf ../PolyMC-portable.tar.gz *
|
||||
|
||||
- name: Package AppImage (Linux)
|
||||
if: runner.os == 'Linux' && matrix.appimage == true
|
||||
shell: bash
|
||||
run: |
|
||||
cmake --install ${{ env.BUILD_DIR }} --prefix ${{ env.INSTALL_APPIMAGE_DIR }}/usr
|
||||
|
||||
export OUTPUT="PolyMC-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage"
|
||||
|
||||
chmod +x linuxdeploy-*.AppImage
|
||||
|
||||
mkdir -p ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-{8,17}-openjdk
|
||||
|
||||
cp -r ${{ github.workspace }}/JREs/jre8/* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-8-openjdk
|
||||
|
||||
cp -r ${{ github.workspace }}/JREs/jre17/* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-17-openjdk
|
||||
|
||||
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib"
|
||||
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-8-openjdk/lib/amd64/server"
|
||||
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-8-openjdk/lib/amd64"
|
||||
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-17-openjdk/lib/server"
|
||||
LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/jvm/java-17-openjdk/lib"
|
||||
export LD_LIBRARY_PATH
|
||||
|
||||
./linuxdeploy-x86_64.AppImage --appdir ${{ env.INSTALL_APPIMAGE_DIR }} --output appimage --plugin qt -i ${{ env.INSTALL_APPIMAGE_DIR }}/usr/share/icons/hicolor/scalable/apps/org.polymc.PolyMC.svg
|
||||
|
||||
##
|
||||
# UPLOAD BUILDS
|
||||
##
|
||||
|
||||
- name: Upload binary tarball (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: PolyMC-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||
path: PolyMC.tar.gz
|
||||
|
||||
- name: Upload binary zip (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: PolyMC-${{ matrix.name }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||
path: ${{ env.INSTALL_DIR }}/**
|
||||
|
||||
- name: Upload binary zip (Windows, portable)
|
||||
if: runner.os == 'Windows'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: PolyMC-${{ matrix.name }}-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||
path: ${{ env.INSTALL_PORTABLE_DIR }}/**
|
||||
|
||||
- name: Upload installer (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: PolyMC-${{ matrix.name }}-Setup-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||
path: PolyMC-Setup.exe
|
||||
|
||||
- name: Upload binary tarball (Linux)
|
||||
if: runner.os == 'Linux' && matrix.appimage != true
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: PolyMC-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||
path: PolyMC.tar.gz
|
||||
|
||||
- name: Upload binary tarball (Linux, portable)
|
||||
if: runner.os == 'Linux' && matrix.appimage != true
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: PolyMC-${{ runner.os }}-Portable-${{ env.VERSION }}-${{ inputs.build_type }}
|
||||
path: PolyMC-portable.tar.gz
|
||||
|
||||
- name: Upload AppImage (Linux)
|
||||
if: runner.os == 'Linux' && matrix.appimage == true
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: PolyMC-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
|
||||
path: PolyMC-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage
|
||||
|
||||
|
61
.github/workflows/pr-comment.yml
vendored
Normal file
61
.github/workflows/pr-comment.yml
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
name: Comment on pull request
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ['Build Application']
|
||||
types: [completed]
|
||||
jobs:
|
||||
pr_comment:
|
||||
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/github-script@v5
|
||||
with:
|
||||
# This snippet is public-domain, taken from
|
||||
# https://github.com/oprypin/nightly.link/blob/master/.github/workflows/pr-comment.yml
|
||||
script: |
|
||||
async function upsertComment(owner, repo, issue_number, purpose, body) {
|
||||
const {data: comments} = await github.rest.issues.listComments(
|
||||
{owner, repo, issue_number});
|
||||
|
||||
const marker = `<!-- bot: ${purpose} -->`;
|
||||
body = marker + "\n" + body;
|
||||
|
||||
const existing = comments.filter((c) => c.body.includes(marker));
|
||||
if (existing.length > 0) {
|
||||
const last = existing[existing.length - 1];
|
||||
core.info(`Updating comment ${last.id}`);
|
||||
await github.rest.issues.updateComment({
|
||||
owner, repo,
|
||||
body,
|
||||
comment_id: last.id,
|
||||
});
|
||||
} else {
|
||||
core.info(`Creating a comment in issue / PR #${issue_number}`);
|
||||
await github.rest.issues.createComment({issue_number, body, owner, repo});
|
||||
}
|
||||
}
|
||||
|
||||
const {owner, repo} = context.repo;
|
||||
const run_id = ${{github.event.workflow_run.id}};
|
||||
|
||||
const pull_requests = ${{ toJSON(github.event.workflow_run.pull_requests) }};
|
||||
if (!pull_requests.length) {
|
||||
return core.error("This workflow doesn't match any pull requests!");
|
||||
}
|
||||
|
||||
const artifacts = await github.paginate(
|
||||
github.rest.actions.listWorkflowRunArtifacts, {owner, repo, run_id});
|
||||
if (!artifacts.length) {
|
||||
return core.error(`No artifacts found`);
|
||||
}
|
||||
let body = `Download the artifacts for this pull request:\n`;
|
||||
for (const art of artifacts) {
|
||||
body += `\n* [${art.name}.zip](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
|
||||
}
|
||||
|
||||
core.info("Review thread message body:", body);
|
||||
|
||||
for (const pr of pull_requests) {
|
||||
await upsertComment(owner, repo, pr.number,
|
||||
"nightly-link", body);
|
||||
}
|
30
.github/workflows/trigger_builds.yml
vendored
Normal file
30
.github/workflows/trigger_builds.yml
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
name: Build Application
|
||||
|
||||
on:
|
||||
push:
|
||||
branches-ignore:
|
||||
- 'stable'
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- '**/LICENSE'
|
||||
- 'flake.lock'
|
||||
- '**.nix'
|
||||
- 'packages/**'
|
||||
- '.github/ISSUE_TEMPLATE/**'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- '**/LICENSE'
|
||||
- 'flake.lock'
|
||||
- '**.nix'
|
||||
- 'packages/**'
|
||||
- '.github/ISSUE_TEMPLATE/**'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
|
||||
build_debug:
|
||||
name: Build Debug
|
||||
uses: ./.github/workflows/build.yml
|
||||
with:
|
||||
build_type: Debug
|
76
.github/workflows/trigger_release.yml
vendored
Normal file
76
.github/workflows/trigger_release.yml
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
name: Build Application and Make Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
|
||||
build_release:
|
||||
name: Build Release
|
||||
uses: ./.github/workflows/build.yml
|
||||
with:
|
||||
build_type: Release
|
||||
|
||||
create_release:
|
||||
needs: build_release
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: 'true'
|
||||
path: 'PolyMC-source'
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
- name: Grab and store version
|
||||
run: |
|
||||
tag_name=$(echo ${{ github.ref }} | grep -oE "[^/]+$")
|
||||
echo "VERSION=$tag_name" >> $GITHUB_ENV
|
||||
- name: Package artifacts properly
|
||||
run: |
|
||||
mv ${{ github.workspace }}/PolyMC-source PolyMC-${{ env.VERSION }}
|
||||
mv PolyMC-Linux-Portable*/PolyMC-portable.tar.gz PolyMC-Linux-Portable-${{ env.VERSION }}.tar.gz
|
||||
mv PolyMC-Linux*/PolyMC.tar.gz PolyMC-Linux-${{ env.VERSION }}.tar.gz
|
||||
mv PolyMC-*.AppImage/PolyMC-*.AppImage PolyMC-Linux-${{ env.VERSION }}-x86_64.AppImage
|
||||
mv PolyMC-macOS*/PolyMC.tar.gz PolyMC-macOS-${{ env.VERSION }}.tar.gz
|
||||
|
||||
tar -czf PolyMC-${{ env.VERSION }}.tar.gz PolyMC-${{ env.VERSION }}
|
||||
|
||||
for d in PolyMC-Windows-*; do
|
||||
cd "${d}" || continue
|
||||
ARCH="$(echo -n ${d} | cut -d '-' -f 3)"
|
||||
INST="$(echo -n ${d} | grep -o Setup || true)"
|
||||
PORT="$(echo -n ${d} | grep -o Portable || true)"
|
||||
NAME="PolyMC-Windows-${ARCH}"
|
||||
test -z "${PORT}" || NAME="${NAME}-Portable"
|
||||
test -z "${INST}" || mv PolyMC-*.exe ../${NAME}-Setup-${{ env.VERSION }}.exe
|
||||
test -n "${INST}" || zip -r -9 "../${NAME}-${{ env.VERSION }}.zip" *
|
||||
cd ..
|
||||
done
|
||||
|
||||
- name: Create release
|
||||
id: create_release
|
||||
uses: softprops/action-gh-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
name: PolyMC ${{ env.VERSION }}
|
||||
draft: true
|
||||
prerelease: false
|
||||
files: |
|
||||
PolyMC-Linux-${{ env.VERSION }}.tar.gz
|
||||
PolyMC-Linux-Portable-${{ env.VERSION }}.tar.gz
|
||||
PolyMC-Linux-${{ env.VERSION }}-x86_64.AppImage
|
||||
PolyMC-Windows-i686-${{ env.VERSION }}.zip
|
||||
PolyMC-Windows-i686-Portable-${{ env.VERSION }}.zip
|
||||
PolyMC-Windows-i686-Setup-${{ env.VERSION }}.exe
|
||||
PolyMC-Windows-x86_64-${{ env.VERSION }}.zip
|
||||
PolyMC-Windows-x86_64-Portable-${{ env.VERSION }}.zip
|
||||
PolyMC-Windows-x86_64-Setup-${{ env.VERSION }}.exe
|
||||
PolyMC-macOS-${{ env.VERSION }}.tar.gz
|
||||
PolyMC-${{ env.VERSION }}.tar.gz
|
14
.gitignore
vendored
14
.gitignore
vendored
@ -14,6 +14,8 @@ CMakeLists.txt.user.*
|
||||
/.project
|
||||
/.settings
|
||||
/.idea
|
||||
/.vscode
|
||||
.clang-format
|
||||
cmake-build-*/
|
||||
Debug
|
||||
|
||||
@ -40,13 +42,9 @@ run/
|
||||
|
||||
.cache/
|
||||
|
||||
# Flatpak builds
|
||||
.flatpak-builder
|
||||
flatbuild
|
||||
builddir
|
||||
# Deb
|
||||
packages/debian/polymc/usr/
|
||||
packages/debian/polymc.deb
|
||||
packages/debian/polymc/DEBIAN/control
|
||||
# Nix/NixOS
|
||||
result/
|
||||
|
||||
# Flatpak
|
||||
.flatpak-builder
|
||||
flatbuild
|
||||
|
10
.gitmodules
vendored
10
.gitmodules
vendored
@ -1,8 +1,8 @@
|
||||
[submodule "depends/libnbtplusplus"]
|
||||
path = libraries/libnbtplusplus
|
||||
url = https://github.com/MultiMC/libnbtplusplus.git
|
||||
pushurl = git@github.com:MultiMC/libnbtplusplus.git
|
||||
url = https://github.com/PolyMC/libnbtplusplus.git
|
||||
pushurl = git@github.com:PolyMC/libnbtplusplus.git
|
||||
|
||||
[submodule "libraries/quazip"]
|
||||
path = libraries/quazip
|
||||
url = https://github.com/PolyMC/quazip.git
|
||||
pushurl = git@github.com:PolyMC/quazip.git
|
||||
path = libraries/quazip
|
||||
url = https://github.com/stachenov/quazip.git
|
||||
|
245
BUILD.md
245
BUILD.md
@ -1,244 +1,5 @@
|
||||
Build Instructions
|
||||
==================
|
||||
# Build Instructions
|
||||
|
||||
# Contents
|
||||
Build instructions are available on [the website](https://polymc.org/wiki/development/build-instructions/).
|
||||
|
||||
* [Note](#note)
|
||||
* [Getting the source](#source)
|
||||
* [Linux](#linux)
|
||||
* [Windows](#windows)
|
||||
* [macOS](#macos)
|
||||
|
||||
|
||||
# Getting the source
|
||||
|
||||
Clone the source code using git and grab all the submodules:
|
||||
|
||||
```
|
||||
git clone https://github.com/PolyMC/PolyMC.git
|
||||
git submodule init
|
||||
git submodule update
|
||||
```
|
||||
|
||||
# Linux
|
||||
|
||||
Getting the project to build and run on Linux is easy if you use any modern and up-to-date linux distribution.
|
||||
|
||||
## Build dependencies
|
||||
* A C++ compiler capable of building C++11 code.
|
||||
* Qt Development tools 5.6 or newer (`qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5` on Debian-based system)
|
||||
* cmake 3.1 or newer (`cmake` on Debian-based system)
|
||||
* zlib (`zlib1g-dev` on Debian-based system)
|
||||
* Java JDK (`openjdk-17-jdk`on Debian-based system)
|
||||
* GL headers (`libgl1-mesa-dev` on Debian-based system)
|
||||
|
||||
### Building a .deb
|
||||
|
||||
You need to install the build dependencies first
|
||||
|
||||
```
|
||||
git clone https://github.com/PolyMC/PolyMC.git
|
||||
git submodule init && git submodule update
|
||||
cd packages/debian
|
||||
./makedeb.sh
|
||||
```
|
||||
|
||||
If everything works correctly, the .deb will be next to the build script, in `PolyMC/packages/debian`
|
||||
|
||||
### Building a .rpm
|
||||
|
||||
You don't need to install the build dependencies, as the script will use `dnf` to install them for you.
|
||||
|
||||
```
|
||||
git clone https://github.com/PolyMC/PolyMC.git
|
||||
cd packages/rpm
|
||||
./makerpm.sh
|
||||
```
|
||||
|
||||
If everything works correctly, the .rpm will be next to the build script, in `PolyMC/packages/rpm`
|
||||
|
||||
### Building from command line
|
||||
You need a source folder, a build folder and an install folder.
|
||||
|
||||
```
|
||||
# make all the folders
|
||||
mkdir ~/PolyMC && cd ~/PolyMC
|
||||
mkdir build
|
||||
mkdir install
|
||||
# clone the complete source
|
||||
git clone --recursive https://github.com/PolyMC/PolyMC.git src
|
||||
# configure the project
|
||||
cd build
|
||||
cmake -DCMAKE_INSTALL_PREFIX=../install ../src
|
||||
make -j$(nproc) install
|
||||
```
|
||||
|
||||
You can use IDEs like KDevelop or QtCreator to open the CMake project if you want to work on the code.
|
||||
|
||||
### Building & Installing to the System
|
||||
This is the preferred method for installation, and is suitable for packages.
|
||||
|
||||
```
|
||||
git clone --recursive https://github.com/PolyMC/PolyMC.git && cd PolyMC
|
||||
|
||||
# configure everything
|
||||
cmake -S . -B build \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_INSTALL_PREFIX="/usr" \ # Use "/usr" for packages, otherwise, leave it at the default "/usr/local".
|
||||
-DLauncher_LAYOUT=lin-system
|
||||
|
||||
make -j$(nproc) install # Optionally specify DESTDIR for packages (i.e. DESTDIR=${pkgdir})
|
||||
```
|
||||
|
||||
### Installing Qt using the installer (optional)
|
||||
1. Run the Qt installer.
|
||||
2. Choose a place to install Qt.
|
||||
3. Choose the components you want to install.
|
||||
- You need Qt 5.6.x 64-bit ticked.
|
||||
- You need Tools/Qt Creator ticked.
|
||||
- Other components are selected by default, you can untick them if you don't need them.
|
||||
4. Accept the license agreements.
|
||||
5. Double check the install details and then click "Install".
|
||||
- Installation can take a very long time, go grab a cup of tea or something and let it work.
|
||||
|
||||
### Loading the project in Qt Creator (optional)
|
||||
1. Open Qt Creator.
|
||||
2. Choose `File->Open File or Project`.
|
||||
3. Navigate to the Launcher source folder you cloned and choose CMakeLists.txt.
|
||||
4. Read the instructions that just popped up about a build location and choose one.
|
||||
5. You should see "Run CMake" in the window.
|
||||
- Make sure that Generator is set to "Unix Generator (Desktop Qt 5.6.x GCC 64bit)".
|
||||
- Hit the "Run CMake" button.
|
||||
- You'll see warnings and it might not be clear that it succeeded until you scroll to the bottom of the window.
|
||||
- Hit "Finish" if CMake ran successfully.
|
||||
6. Cross your fingers and press the Run button (bottom left of Qt Creator).
|
||||
- If the project builds successfully it will run and the Launcher window will pop up.
|
||||
|
||||
**If this doesn't work for you, let us know on our Discord.**
|
||||
|
||||
# Windows
|
||||
|
||||
Getting the project to build and run on Windows is easy if you use Qt's IDE, Qt Creator. The project will simply not compile using Microsoft build tools, because that's not something we do. If it does compile, it is by chance only.
|
||||
|
||||
## Dependencies
|
||||
* [Qt 5.6+ Development tools](http://qt-project.org/downloads) -- Qt Online Installer for Windows
|
||||
- http://download.qt.io/new_archive/qt/5.6/5.6.0/qt-opensource-windows-x86-mingw492-5.6.0.exe
|
||||
- Download the MinGW version (MSVC version does not work).
|
||||
* [OpenSSL](https://github.com/IndySockets/OpenSSL-Binaries/tree/master/Archive/) -- Win32 OpenSSL, version 1.0.2g (from 2016)
|
||||
- https://github.com/IndySockets/OpenSSL-Binaries/raw/master/Archive/openssl-1.0.2g-i386-win32.zip
|
||||
- the usual OpenSSL for Windows (http://slproweb.com/products/Win32OpenSSL.html) only provides the newest version of OpenSSL, and we need the 1.0.2g version
|
||||
- **Download the 32-bit version, not 64-bit.**
|
||||
- Microsoft Visual C++ 2008 Redist is required for this, there's a link on the OpenSSL download page above next to the main download.
|
||||
- We use a custom build of OpenSSL that doesn't have this dependency. For normal development, the custom build is not necessary though.
|
||||
* [zlib 1.2+](http://gnuwin32.sourceforge.net/packages/zlib.htm) - the Setup is fine
|
||||
* [Java JDK 8](https://adoptium.net/releases.html?variant=openjdk8) - Use the MSI installer.
|
||||
* [CMake](http://www.cmake.org/cmake/resources/software.html) -- Windows (Win32 Installer)
|
||||
|
||||
Ensure that OpenSSL, zlib, Java and CMake are on `PATH`.
|
||||
|
||||
## Getting set up
|
||||
|
||||
### Installing Qt
|
||||
1. Run the Qt installer
|
||||
2. Choose a place to install Qt (C:\Qt is the default),
|
||||
3. Choose the components you want to install
|
||||
- You need Qt 5.6 (32 bit) ticked,
|
||||
- You need Tools/Qt Creator ticked,
|
||||
- Other components are selected by default, you can untick them if you don't need them.
|
||||
4. Accept the license agreements,
|
||||
5. Double check the install details and then click "Install"
|
||||
- Installation can take a very long time, go grab a cup of tea or something and let it work.
|
||||
|
||||
### Installing OpenSSL
|
||||
1. Download .zip file from the link above.
|
||||
2. Unzip and add the directory to PATH, so CMake can find it.
|
||||
|
||||
### Installing CMake
|
||||
1. Run the CMake installer,
|
||||
2. It's easiest if you choose to add CMake to the PATH for all users,
|
||||
- If you don't choose to do this, remember where you installed CMake.
|
||||
|
||||
### Loading the project
|
||||
1. Open Qt Creator,
|
||||
2. Choose File->Open File or Project,
|
||||
3. Navigate to the Launcher source folder you cloned and choose CMakeLists.txt,
|
||||
4. Read the instructions that just popped up about a build location and choose one,
|
||||
5. If you chose not to add CMake to the system PATH, tell Qt Creator where you installed it,
|
||||
- Otherwise you can skip this step.
|
||||
6. You should see "Run CMake" in the window,
|
||||
- Make sure that Generator is set to "MinGW Generator (Desktop Qt 5.6.x MinGW 32bit)",
|
||||
- Hit the "Run CMake" button,
|
||||
- You'll see warnings and it might not be clear that it succeeded until you scroll to the bottom of the window.
|
||||
- Hit "Finish" if CMake ran successfully.
|
||||
7. Cross your fingers and press the Run button (bottom left of Qt Creator)!
|
||||
- If the project builds successfully it will run and the Launcher window will pop up,
|
||||
- Test OpenSSL by making an instance and trying to log in. If Qt Creator couldn't find OpenSSL during the CMake stage, login will fail and you'll get an error.
|
||||
|
||||
The following .dlls are needed for the app to run (copy them to build directory if you want to be able to move the build to another pc):
|
||||
```
|
||||
platforms/qwindows.dll
|
||||
libeay32.dll
|
||||
libgcc_s_dw2-1.dll
|
||||
libssp-0.dll
|
||||
libstdc++-6.dll
|
||||
libwinpthread-1.dll
|
||||
Qt5Core.dll
|
||||
Qt5Gui.dll
|
||||
Qt5Network.dll
|
||||
Qt5Svg.dll
|
||||
Qt5Widgets.dll
|
||||
Qt5Xml.dll
|
||||
ssleay32.dll
|
||||
zlib1.dll
|
||||
```
|
||||
|
||||
**These build instructions worked for me (Drayshak) on a fresh Windows 8 x64 Professional install. If they don't work for you, let us know on our Discord.**
|
||||
### Compile from command line on Windows
|
||||
1. If you installed Qt with the web installer, there should be a shortcut called `Qt 5.4 for Desktop (MinGW 4.9 32-bit)` in the Start menu on Windows 7 and 10. Best way to find it is to search for it. Do note you cannot just use cmd.exe, you have to use the shortcut, otherwise the proper MinGW software will not be on the PATH.
|
||||
2. Once that is open, change into your user directory, and clone PolyMC by doing `git clone --recursive https://github.com/PolyMC/PolyMC.git`, and change directory to the folder you cloned to.
|
||||
3. Make a build directory, and change directory to the directory and do `cmake -G "MinGW Makefiles" -DCMAKE_INSTALL_PREFIX=C:\Path\that\makes\sense\for\you`. By default, it will install to C:\Program Files (x86), which you might not want, if you want a local installation. If you want to install it to that directory, make sure to run the command window as administrator.
|
||||
3. Do `mingw32-make -jX`, where X is the number of cores your CPU has plus one.
|
||||
4. Now to wait for it to compile. This could take some time. Hopefully it compiles properly.
|
||||
5. Run the command `mingw32-make install`, and it should install PolyMC, to whatever the `-DCMAKE_INSTALL_PREFIX` was.
|
||||
6. In most cases, whenever compiling, the OpenSSL dll's aren't put into the directory to where PolyMC installs, meaning you cannot log in. The best way to fix this is just to do `copy C:\OpenSSL-Win32\*.dll C:\Where\you\installed\PolyMC\to`. This should copy the required OpenSSL dll's to log in.
|
||||
|
||||
# macOS
|
||||
|
||||
### Install prerequisites:
|
||||
- Install XCode Command Line tools
|
||||
- Install the official build of CMake (https://cmake.org/download/)
|
||||
- Install JDK 8 (https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html)
|
||||
- Get Qt 5.6 and install it (https://download.qt.io/new_archive/qt/5.6/5.6.3/)
|
||||
|
||||
### XCode Command Line tools
|
||||
|
||||
If you don't have XCode CommandLine tools installed, you can install them by using this command in the Terminal App
|
||||
|
||||
```bash
|
||||
xcode-select --install
|
||||
```
|
||||
|
||||
### Build
|
||||
|
||||
Pick an installation path - this is where the final `.app` will be constructed when you run `make install`. Supply it as the `CMAKE_INSTALL_PREFIX` argument during CMake configuration.
|
||||
|
||||
```
|
||||
git clone --recursive https://github.com/PolyMC/PolyMC.git
|
||||
cd Launcher
|
||||
mkdir build
|
||||
cd build
|
||||
cmake \
|
||||
-DCMAKE_C_COMPILER=/usr/bin/clang \
|
||||
-DCMAKE_CXX_COMPILER=/usr/bin/clang++ \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_INSTALL_PREFIX:PATH="$(dirname $PWD)/dist/" \
|
||||
-DCMAKE_PREFIX_PATH="/path/to/Qt5.6/" \
|
||||
-DQt5_DIR="/path/to/Qt5.6/" \
|
||||
-DLauncher_LAYOUT=mac-bundle \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.7 \
|
||||
..
|
||||
make install
|
||||
```
|
||||
|
||||
**Note:** The final app bundle may not run due to code signing issues, which
|
||||
need to be fixed with `codesign -fs -`.
|
||||
If you would like to contribute or fix an issue with the Build instructions you can do so [here](https://github.com/PolyMC/polymc.github.io/blob/master/src/wiki/development/build-instructions.md).
|
||||
|
192
CMakeLists.txt
192
CMakeLists.txt
@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
cmake_minimum_required(VERSION 3.15) # minimum version required by QuaZip
|
||||
|
||||
if(WIN32)
|
||||
# In Qt 5.1+ we have our own main() function, don't autolink to qtmain on Windows
|
||||
@ -6,7 +6,7 @@ if(WIN32)
|
||||
endif()
|
||||
|
||||
project(Launcher)
|
||||
enable_testing()
|
||||
include(CTest)
|
||||
|
||||
string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BUILD_DIR}" IS_IN_SOURCE_BUILD)
|
||||
if(IS_IN_SOURCE_BUILD)
|
||||
@ -34,57 +34,91 @@ set(CMAKE_C_STANDARD_REQUIRED true)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
include(GenerateExportHeader)
|
||||
set(CMAKE_CXX_FLAGS " -Wall -pedantic -Werror -Wno-deprecated-declarations -D_GLIBCXX_USE_CXX11_ABI=0 -fstack-protector-strong --param=ssp-buffer-size=4 -O3 -D_FORTIFY_SOURCE=2 ${CMAKE_CXX_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "-Wall -pedantic -Werror -Wno-deprecated-declarations -D_GLIBCXX_USE_CXX11_ABI=0 -fstack-protector-strong --param=ssp-buffer-size=4 ${CMAKE_CXX_FLAGS}")
|
||||
if(UNIX AND APPLE)
|
||||
set(CMAKE_CXX_FLAGS " -stdlib=libc++ ${CMAKE_CXX_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "-stdlib=libc++ ${CMAKE_CXX_FLAGS}")
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Werror=return-type")
|
||||
|
||||
# Fix build with Qt 5.13
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_NO_DEPRECATED_WARNINGS=Y")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_DISABLE_DEPRECATED_BEFORE=0x050C00")
|
||||
|
||||
# set CXXFLAGS for build targets
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-O2 -D_FORTIFY_SOURCE=2 ${CMAKE_CXX_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -D_FORTIFY_SOURCE=2 ${CMAKE_CXX_FLAGS}")
|
||||
|
||||
option(ENABLE_LTO "Enable Link Time Optimization" off)
|
||||
|
||||
if(ENABLE_LTO)
|
||||
include(CheckIPOSupported)
|
||||
check_ipo_supported(RESULT ipo_supported OUTPUT ipo_error)
|
||||
|
||||
if(ipo_supported AND (CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "MinSizeRel"))
|
||||
message(STATUS "IPO / LTO enabled")
|
||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
|
||||
elseif(ipo_supported)
|
||||
message(STATUS "Not enabling IPO / LTO on debug builds")
|
||||
else()
|
||||
message(STATUS "IPO / LTO not supported: <${ipo_error}>")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
##################################### Set Application options #####################################
|
||||
|
||||
######## Set URLs ########
|
||||
set(Launcher_NEWS_RSS_URL "https://multimc.org/rss.xml" CACHE STRING "URL to fetch Launcher's news RSS feed from.")
|
||||
set(Launcher_NEWS_RSS_URL "https://polymc.org/feed/feed.xml" CACHE STRING "URL to fetch PolyMC's news RSS feed from.")
|
||||
set(Launcher_NEWS_OPEN_URL "https://polymc.org/news" CACHE STRING "URL that gets opened when the user clicks 'More News'")
|
||||
set(Launcher_HELP_URL "https://polymc.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 version numbers ########
|
||||
set(Launcher_VERSION_MAJOR 1)
|
||||
set(Launcher_VERSION_MINOR 0)
|
||||
set(Launcher_VERSION_HOTFIX 5)
|
||||
set(Launcher_VERSION_MINOR 3)
|
||||
set(Launcher_VERSION_HOTFIX 0)
|
||||
|
||||
# Build number
|
||||
set(Launcher_VERSION_BUILD -1 CACHE STRING "Build number. -1 for no build number.")
|
||||
|
||||
# Build platform.
|
||||
set(Launcher_BUILD_PLATFORM "" CACHE STRING "A short string identifying the platform that this build was built for. Only used by the notification system and to display in the about dialog.")
|
||||
set(Launcher_BUILD_PLATFORM "" CACHE STRING "A short string identifying the platform that this build was built for. Only used to display in the about dialog.")
|
||||
|
||||
# Channel list URL
|
||||
set(Launcher_UPDATER_BASE "" CACHE STRING "Base URL for the updater.")
|
||||
|
||||
# Notification URL
|
||||
set(Launcher_NOTIFICATION_URL "" CACHE STRING "URL for checking for notifications.")
|
||||
|
||||
# The metadata server
|
||||
set(Launcher_META_URL "https://meta.multimc.org/v1/" CACHE STRING "URL to fetch Launcher's meta files from.")
|
||||
|
||||
# paste.ee API key
|
||||
set(Launcher_PASTE_EE_API_KEY "utLvciUouSURFzfjPxLBf5W4ISsUX4pwBDF7N1AfZ" CACHE STRING "API key you can get from paste.ee when you register an account")
|
||||
set(Launcher_META_URL "https://meta.polymc.org/v1/" CACHE STRING "URL to fetch Launcher's meta files from.")
|
||||
|
||||
# Imgur API Client ID
|
||||
set(Launcher_IMGUR_CLIENT_ID "5b97b0713fba4a3" CACHE STRING "Client ID you can get from Imgur when you register an application")
|
||||
|
||||
# MSA Client ID
|
||||
set(Launcher_MSA_CLIENT_ID "17b47edd-c884-4997-926d-9e7f9a6b4647" CACHE STRING "Client ID you can get from Microsoft Identity Platform when you register an application")
|
||||
set(Launcher_MSA_CLIENT_ID "549033b2-1532-4d4e-ae77-1bbaa46f9d74" CACHE STRING "Client ID you can get from Microsoft Identity Platform when you register an application")
|
||||
|
||||
# CurseForge API Key
|
||||
# CHANGE THIS IF YOU FORK THIS PROJECT!
|
||||
set(Launcher_CURSEFORGE_API_KEY "$2a$10$1Oqr2MX3O4n/ilhFGc597u8tfI3L2Hyr9/rtWDAMRjghSQV2QUuxq" CACHE STRING "CurseForge API Key")
|
||||
|
||||
# Bug tracker URL
|
||||
set(Launcher_BUG_TRACKER_URL "https://github.com/PolyMC/PolyMC/issues" CACHE STRING "URL for the bug tracker.")
|
||||
|
||||
# Translations Platform URL
|
||||
set(Launcher_TRANSLATIONS_URL "https://hosted.weblate.org/projects/polymc/polymc/" CACHE STRING "URL for the translations platform.")
|
||||
|
||||
# Matrix Space
|
||||
set(Launcher_MATRIX_URL "https://matrix.to/#/#polymc:matrix.org" CACHE STRING "URL to the Matrix Space")
|
||||
|
||||
# Discord URL
|
||||
set(Launcher_DISCORD_URL "https://discord.gg/Z52pwxWCHP" CACHE STRING "URL for the Discord guild.")
|
||||
|
||||
|
||||
|
||||
# Subreddit URL
|
||||
set(Launcher_SUBREDDIT_URL "" CACHE STRING "URL for the subreddit.")
|
||||
set(Launcher_SUBREDDIT_URL "https://www.reddit.com/r/PolyMCLauncher/" CACHE STRING "URL for the subreddit.")
|
||||
|
||||
# Builds
|
||||
set(Launcher_FORCE_BUNDLED_LIBS OFF CACHE BOOL "Prevent using system libraries, if they are available as submodules")
|
||||
set(Launcher_QT_VERSION_MAJOR "5" CACHE STRING "Major Qt version to build against")
|
||||
|
||||
|
||||
#### Check the current Git commit and branch
|
||||
include(GetGitRevisionDescription)
|
||||
@ -94,6 +128,8 @@ message(STATUS "Git commit: ${Launcher_GIT_COMMIT}")
|
||||
message(STATUS "Git refspec: ${Launcher_GIT_REFSPEC}")
|
||||
|
||||
set(Launcher_RELEASE_VERSION_NAME "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_HOTFIX}")
|
||||
string(TIMESTAMP TODAY "%Y-%m-%d")
|
||||
set(Launcher_RELEASE_TIMESTAMP "${TODAY}")
|
||||
|
||||
#### Custom target to just print the version.
|
||||
add_custom_target(version echo "Version: ${Launcher_RELEASE_VERSION_NAME}")
|
||||
@ -102,12 +138,20 @@ add_custom_target(tcversion echo "\\#\\#teamcity[setParameter name=\\'env.LAUNCH
|
||||
################################ 3rd Party Libs ################################
|
||||
|
||||
# Find the required Qt parts
|
||||
find_package(Qt5Core REQUIRED)
|
||||
find_package(Qt5Widgets REQUIRED)
|
||||
find_package(Qt5Concurrent REQUIRED)
|
||||
find_package(Qt5Network REQUIRED)
|
||||
find_package(Qt5Test REQUIRED)
|
||||
find_package(Qt5Xml REQUIRED)
|
||||
if(Launcher_QT_VERSION_MAJOR EQUAL 5)
|
||||
set(QT_VERSION_MAJOR 5)
|
||||
find_package(Qt5 REQUIRED COMPONENTS Core Widgets Concurrent Network Test Xml)
|
||||
|
||||
if(NOT Launcher_FORCE_BUNDLED_LIBS)
|
||||
find_package(QuaZip-Qt5 1.3)
|
||||
endif()
|
||||
if (NOT QuaZip-Qt5_FOUND)
|
||||
set(QUAZIP_QT_MAJOR_VERSION ${QT_VERSION_MAJOR} CACHE STRING "Qt version to use (4, 5 or 6), defaults to ${QT_VERSION_MAJOR}" FORCE)
|
||||
set(FORCE_BUNDLED_QUAZIP 1)
|
||||
endif()
|
||||
else()
|
||||
message(FATAL_ERROR "Qt version ${Launcher_QT_VERSION_MAJOR} is not supported")
|
||||
endif()
|
||||
|
||||
# The Qt5 cmake files don't provide its install paths, so ask qmake.
|
||||
include(QMakeQuery)
|
||||
@ -129,45 +173,30 @@ add_subdirectory(program_info)
|
||||
|
||||
####################################### Install layout #######################################
|
||||
|
||||
# How to install the build results
|
||||
set(Launcher_LAYOUT "auto" CACHE STRING "The layout for the launcher installation (auto, win-bundle, lin-nodeps, lin-system, mac-bundle)")
|
||||
set_property(CACHE Launcher_LAYOUT PROPERTY STRINGS auto win-bundle lin-nodeps lin-system mac-bundle)
|
||||
|
||||
if(Launcher_LAYOUT STREQUAL "auto")
|
||||
if(UNIX AND APPLE)
|
||||
set(Launcher_LAYOUT_REAL "mac-bundle")
|
||||
elseif(UNIX)
|
||||
set(Launcher_LAYOUT_REAL "lin-nodeps")
|
||||
elseif(WIN32)
|
||||
set(Launcher_LAYOUT_REAL "win-bundle")
|
||||
else()
|
||||
message(FATAL_ERROR "Cannot choose a sensible install layout for your platform.")
|
||||
endif()
|
||||
else()
|
||||
set(Launcher_LAYOUT_REAL ${Launcher_LAYOUT})
|
||||
if(NOT (UNIX AND APPLE))
|
||||
# Install "portable.txt" if selected component is "portable"
|
||||
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_Portable_File}" DESTINATION "." COMPONENT portable EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
if(Launcher_LAYOUT_REAL STREQUAL "mac-bundle")
|
||||
if(UNIX AND APPLE)
|
||||
set(BINARY_DEST_DIR "${Launcher_Name}.app/Contents/MacOS")
|
||||
set(LIBRARY_DEST_DIR "${Launcher_Name}.app/Contents/MacOS")
|
||||
set(PLUGIN_DEST_DIR "${Launcher_Name}.app/Contents/MacOS")
|
||||
set(RESOURCES_DEST_DIR "${Launcher_Name}.app/Contents/Resources")
|
||||
set(JARS_DEST_DIR "${Launcher_Name}.app/Contents/MacOS/jars")
|
||||
|
||||
set(BUNDLE_DEST_DIR ".")
|
||||
|
||||
# Apps to bundle
|
||||
set(APPS "\${CMAKE_INSTALL_PREFIX}/${Launcher_Name}.app")
|
||||
|
||||
# Mac bundle settings
|
||||
set(MACOSX_BUNDLE_BUNDLE_NAME "${Launcher_Name}")
|
||||
set(MACOSX_BUNDLE_INFO_STRING "${Launcher_Name}: Minecraft launcher and management utility.")
|
||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER "org.multimc.${Launcher_Name}")
|
||||
set(MACOSX_BUNDLE_BUNDLE_VERSION "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_HOTFIX}.${Launcher_VERSION_BUILD}")
|
||||
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_HOTFIX}.${Launcher_VERSION_BUILD}")
|
||||
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_HOTFIX}.${Launcher_VERSION_BUILD}")
|
||||
set(MACOSX_BUNDLE_INFO_STRING "${Launcher_Name}: A custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once.")
|
||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER "org.polymc.${Launcher_Name}")
|
||||
set(MACOSX_BUNDLE_BUNDLE_VERSION "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_HOTFIX}")
|
||||
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_HOTFIX}")
|
||||
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${Launcher_VERSION_MAJOR}.${Launcher_VERSION_MINOR}.${Launcher_VERSION_HOTFIX}")
|
||||
set(MACOSX_BUNDLE_ICON_FILE ${Launcher_Name}.icns)
|
||||
set(MACOSX_BUNDLE_COPYRIGHT "Copyright 2015-2021 ${Launcher_Copyright}")
|
||||
set(MACOSX_BUNDLE_COPYRIGHT "Copyright 2021-2022 ${Launcher_Copyright}")
|
||||
|
||||
# directories to look for dependencies
|
||||
set(DIRS ${QT_LIBS_DIR} ${QT_LIBEXECS_DIR} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
|
||||
@ -178,13 +207,14 @@ if(Launcher_LAYOUT_REAL STREQUAL "mac-bundle")
|
||||
# Add the icon
|
||||
install(FILES ${Launcher_Branding_ICNS} DESTINATION ${RESOURCES_DEST_DIR} RENAME ${Launcher_Name}.icns)
|
||||
|
||||
elseif(Launcher_LAYOUT_REAL STREQUAL "lin-nodeps")
|
||||
elseif(UNIX)
|
||||
set(BINARY_DEST_DIR "bin")
|
||||
set(LIBRARY_DEST_DIR "bin")
|
||||
set(PLUGIN_DEST_DIR "plugins")
|
||||
set(BUNDLE_DEST_DIR ".")
|
||||
set(RESOURCES_DEST_DIR ".")
|
||||
set(JARS_DEST_DIR "bin/jars")
|
||||
set(LIBRARY_DEST_DIR "lib${LIB_SUFFIX}")
|
||||
set(JARS_DEST_DIR "share/jars")
|
||||
set(LAUNCHER_DESKTOP_DEST_DIR "share/applications" CACHE STRING "Path to the desktop file directory")
|
||||
set(LAUNCHER_METAINFO_DEST_DIR "share/metainfo" CACHE STRING "Path to the metainfo directory")
|
||||
set(LAUNCHER_ICON_DEST_DIR "share/icons/hicolor/scalable/apps" CACHE STRING "Path to the scalable icon directory")
|
||||
set(LAUNCHER_MAN_DEST_DIR "share/man/man6" CACHE STRING "Path to the man page directory")
|
||||
|
||||
# install as bundle with no dependencies included
|
||||
set(INSTALL_BUNDLE "nodeps")
|
||||
@ -192,37 +222,22 @@ elseif(Launcher_LAYOUT_REAL STREQUAL "lin-nodeps")
|
||||
# Set RPATH
|
||||
SET(Launcher_BINARY_RPATH "$ORIGIN/")
|
||||
|
||||
# Install basic runner script
|
||||
# jars path is determined on runtime, relative to "Application root path", generally /usr or the root of the portable bundle
|
||||
set(Launcher_APP_BINARY_DEFS "-DLAUNCHER_JARS_LOCATION=${JARS_DEST_DIR}")
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_Desktop} DESTINATION ${LAUNCHER_DESKTOP_DEST_DIR})
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_MetaInfo} DESTINATION ${LAUNCHER_METAINFO_DEST_DIR})
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_SVG} DESTINATION ${LAUNCHER_ICON_DEST_DIR})
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_ManPage} DESTINATION ${LAUNCHER_MAN_DEST_DIR} RENAME "${Launcher_APP_BINARY_NAME}.6")
|
||||
|
||||
# Install basic runner script if component "portable" is selected
|
||||
configure_file(launcher/Launcher.in "${CMAKE_CURRENT_BINARY_DIR}/LauncherScript" @ONLY)
|
||||
install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/LauncherScript" DESTINATION ${BUNDLE_DEST_DIR} RENAME ${Launcher_Name})
|
||||
install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/LauncherScript" DESTINATION "." RENAME ${Launcher_Name} COMPONENT portable EXCLUDE_FROM_ALL)
|
||||
|
||||
elseif(Launcher_LAYOUT_REAL STREQUAL "lin-system")
|
||||
set(Launcher_BINARY_DEST_DIR "bin" CACHE STRING "Path to the binary directory")
|
||||
set(Launcher_LIBRARY_DEST_DIR "lib${LIB_SUFFIX}" CACHE STRING "Path to the library directory")
|
||||
set(Launcher_SHARE_DEST_DIR "share/polymc" CACHE STRING "Path to the shared data directory")
|
||||
set(JARS_DEST_DIR "${Launcher_SHARE_DEST_DIR}/jars")
|
||||
set(Launcher_DESKTOP_DEST_DIR "share/applications" CACHE STRING "Path to the desktop file directory")
|
||||
set(Launcher_METAINFO_DEST_DIR "share/metainfo" CACHE STRING "Path to the metainfo directory")
|
||||
set(Launcher_ICON_DEST_DIR "share/icons/hicolor/scalable/apps" CACHE STRING "Path to the scalable icon directory")
|
||||
|
||||
set(BINARY_DEST_DIR ${Launcher_BINARY_DEST_DIR})
|
||||
set(LIBRARY_DEST_DIR ${Launcher_LIBRARY_DEST_DIR})
|
||||
|
||||
MESSAGE(STATUS "Compiling for linux system with ${Launcher_SHARE_DEST_DIR} and LAUNCHER_LINUX_DATADIR")
|
||||
SET(Launcher_APP_BINARY_DEFS "-DMULTIMC_JARS_LOCATION=${CMAKE_INSTALL_PREFIX}/${JARS_DEST_DIR}" "-DLAUNCHER_LINUX_DATADIR")
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_Desktop} DESTINATION ${Launcher_DESKTOP_DEST_DIR})
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${Launcher_MetaInfo} DESTINATION ${Launcher_METAINFO_DEST_DIR})
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${Launcher_SVG} DESTINATION ${Launcher_ICON_DEST_DIR})
|
||||
|
||||
# install as bundle with no dependencies included
|
||||
set(INSTALL_BUNDLE "nodeps")
|
||||
|
||||
elseif(Launcher_LAYOUT_REAL STREQUAL "win-bundle")
|
||||
elseif(WIN32)
|
||||
set(BINARY_DEST_DIR ".")
|
||||
set(LIBRARY_DEST_DIR ".")
|
||||
set(PLUGIN_DEST_DIR ".")
|
||||
set(BUNDLE_DEST_DIR ".")
|
||||
set(RESOURCES_DEST_DIR ".")
|
||||
set(JARS_DEST_DIR "jars")
|
||||
|
||||
@ -235,7 +250,7 @@ elseif(Launcher_LAYOUT_REAL STREQUAL "win-bundle")
|
||||
# install as bundle
|
||||
set(INSTALL_BUNDLE "full")
|
||||
else()
|
||||
message(FATAL_ERROR "No sensible install layout set.")
|
||||
message(FATAL_ERROR "Platform not supported")
|
||||
endif()
|
||||
|
||||
################################ Included Libs ################################
|
||||
@ -243,11 +258,9 @@ endif()
|
||||
include(ExternalProject)
|
||||
set_directory_properties(PROPERTIES EP_BASE External)
|
||||
|
||||
option(NBT_BUILD_SHARED "Build NBT shared library" ON)
|
||||
option(NBT_BUILD_SHARED "Build NBT shared library" OFF)
|
||||
option(NBT_USE_ZLIB "Build NBT library with zlib support" OFF)
|
||||
option(NBT_BUILD_TESTS "Build NBT library tests" OFF) #FIXME: fix unit tests.
|
||||
set(NBT_NAME Launcher_nbt++)
|
||||
set(NBT_DEST_DIR ${LIBRARY_DEST_DIR})
|
||||
add_subdirectory(libraries/libnbtplusplus)
|
||||
|
||||
add_subdirectory(libraries/systeminfo) # system information library
|
||||
@ -255,7 +268,14 @@ add_subdirectory(libraries/hoedown) # markdown parser
|
||||
add_subdirectory(libraries/launcher) # java based launcher part for Minecraft
|
||||
add_subdirectory(libraries/javacheck) # java compatibility checker
|
||||
add_subdirectory(libraries/xz-embedded) # xz compression
|
||||
add_subdirectory(libraries/quazip) # zip manipulation library
|
||||
if (FORCE_BUNDLED_QUAZIP)
|
||||
message(STATUS "Using bundled QuaZip")
|
||||
set(BUILD_SHARED_LIBS 0) # link statically to avoid conflicts.
|
||||
set(QUAZIP_INSTALL 0)
|
||||
add_subdirectory(libraries/quazip) # zip manipulation library
|
||||
else()
|
||||
message(STATUS "Using system QuaZip")
|
||||
endif()
|
||||
add_subdirectory(libraries/rainbow) # Qt extension for colors
|
||||
add_subdirectory(libraries/iconfix) # fork of Qt's QIcon loader
|
||||
add_subdirectory(libraries/LocalPeer) # fork of a library from Qt solutions
|
||||
|
136
CODE_OF_CONDUCT.md
Normal file
136
CODE_OF_CONDUCT.md
Normal file
@ -0,0 +1,136 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
This is a modified version of the Contributor Covenant.
|
||||
See commit history to see our changes.
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, caste, color, religion, or sexual
|
||||
identity and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the overall
|
||||
community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or advances of
|
||||
any kind
|
||||
* Trolling (antagonistic, inflammatory, insincere behaviour), insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email address,
|
||||
without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement via email at
|
||||
[polymc-enforcement@scrumplex.net](mailto:polymc-enforcement@scrumplex.net) (Email
|
||||
address subject to change).
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series of
|
||||
actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or permanent
|
||||
ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within the
|
||||
community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.1, available at
|
||||
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
||||
|
||||
Community Impact Guidelines were inspired by
|
||||
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
|
||||
[https://www.contributor-covenant.org/translations][translations].
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
||||
[Mozilla CoC]: https://github.com/mozilla/diversity
|
||||
[FAQ]: https://www.contributor-covenant.org/faq
|
||||
[translations]: https://www.contributor-covenant.org/translations
|
||||
|
19
COPYING.md
19
COPYING.md
@ -1,12 +1,11 @@
|
||||
# PolyMC
|
||||
|
||||
Copyright (C) 2012-2021 MultiMC Contributors
|
||||
Copyright (C) 2021 PolyMC Contributors
|
||||
Copyright (C) 2021-2022 PolyMC Contributors
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
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
|
||||
@ -16,6 +15,20 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# Launcher (https://github.com/MultiMC/Launcher)
|
||||
Copyright 2012-2021 MultiMC Contributors
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
# MinGW runtime (Windows)
|
||||
|
||||
Copyright (c) 2012 MinGW.org project
|
||||
|
109
README.md
109
README.md
@ -1,66 +1,89 @@
|
||||
<p align="center">
|
||||
<img src="/program_info/polymc-light.png#gh-light-mode-only" alt="PolyMC logo"/>
|
||||
<img src="/program_info/polymc-dark.png#gh-dark-mode-only" alt="PolyMC logo"/>
|
||||
<img src="./program_info/polymc-header-black.svg#gh-light-mode-only" alt="PolyMC logo"/>
|
||||
<img src="./program_info/polymc-header.svg#gh-dark-mode-only" alt="PolyMC logo"/>
|
||||
</p>
|
||||
<br>
|
||||
|
||||
PolyMC is a custom launcher for Minecraft that focuses on predictability, long term stability and simplicity.
|
||||
|
||||
This is a **fork** of the MultiMC Launcher and not endorsed by MultiMC. The PolyMC community felt that the maintainer was not acting in the spirit of Free Software so this fork was made. Read "[Why was this fork made?](https://github.com/PolyMC/PolyMC/wiki/FAQ)" on the wiki for more details.
|
||||
|
||||
## Packages
|
||||
Several source build packages are available, along with experimental pre-built generic packages.
|
||||
|
||||
<a href='https://flathub.org/apps/details/org.polymc.PolyMC'><img width='240' alt='Download on Flathub' src='https://flathub.org/assets/badges/flathub-badge-en.png'/></a>
|
||||
This is a **fork** of the MultiMC Launcher and not endorsed by MultiMC.
|
||||
If you want to read about why this fork was created, check out [our FAQ page](https://polymc.org/wiki/overview/faq/).
|
||||
<br>
|
||||
[](https://aur.archlinux.org/packages/polymc-git/)
|
||||
- A [Nix](packages/nix/NIX.md) derivation is available in repo.
|
||||
- A Gentoo ebuild is available in the [swirl](https://git.swurl.xyz/swirl/ebuilds) overlay, named `games-action/polymc`. Check the README for instructions on how to add the overlay.
|
||||
- The Flatpak can be built using [this source](https://github.com/flathub/org.polymc.PolyMC).
|
||||
- An RPM package is available on [COPR](https://copr.fedorainfracloud.org/coprs/sentry/polymc/), or can be built by going to the `packages/rpm` directory and running `rpmbuild -bb polymc.spec`.
|
||||
- Generic, prebuilt packages (archived by version) can be found [here](https://packages.polymc.org/) ([latest](https://packages.polymc.org/latest)).
|
||||
- Last build status: https://jenkins.polymc.org/job/PolyMC/lastBuild/
|
||||
- [Linux (AMD64) System](https://packages.polymc.org/latest/lin64-system/lin64-system.tar.zst) ([SHA256](https://packages.polymc.org/latest/lin64-system/lin64-system.tar.zst.sha256)) - this is a generic system package intended to be used as a base for making distro-specific packages.
|
||||
- [Windows (32-bit)](https://packages.polymc.org/latest/win32/win32.zip) ([SHA256](https://packages.polymc.org/latest/win32/win32.zip.sha256)) - this is a portable package, you can extract it anywhere and run it. This package needs testing.
|
||||
- [Debian (AMD64)](https://packages.polymc.org/latest/deb/polymc-amd64.deb) ([SHA256](https://packages.polymc.org/latest/deb/polymc-amd64.deb.sha256)) - this is intended to be installed with `dpkg -i`. Alternatively, you may build the `.deb` yourself, by going to `packages/debian` and running `./makedeb.sh`.
|
||||
- [AppImage (AMD64)](https://packages.polymc.org/latest/appimage/PolyMC-latest-x86_64.AppImage) ([SHA256](https://packages.polymc.org/latest/appimage/PolyMC-latest-x86_64.AppImage.sha256)) - `chmod +x` must be run on this file before usage. This should work on any distribution.
|
||||
- MacOS currently does not have any packages. We are still working on setting up MacOS packaging.
|
||||
|
||||
## Development
|
||||
If you want to contribute to PolyMC you might find it useful to join [#development:polymc.org on Matrix](https://matrix.to/#/#development:polymc.org) or join [our Discord server](https://discord.gg/xq7fxrgtMP), which is bridged with the PolyMC Matrix rooms. Thank you!
|
||||
# Installation
|
||||
|
||||
### Building
|
||||
If you want to build PolyMC yourself, check [BUILD.md](BUILD.md) for build instructions.
|
||||
- All downloads and instructions for PolyMC can be found [here](https://polymc.org/download/)
|
||||
- Last build status: https://github.com/PolyMC/PolyMC/actions
|
||||
|
||||
You can build the flatpak using [this source](https://github.com/flathub/org.polymc.PolyMC).
|
||||
|
||||
### Code formatting
|
||||
Just follow the existing formatting.
|
||||
## Development Builds
|
||||
|
||||
In general, in order of importance:
|
||||
* Make sure your IDE is not messing up line endings or whitespace and avoid using linters.
|
||||
* Prefer readability over dogma.
|
||||
* Keep to the existing formatting.
|
||||
* Indent with 4 space unless it's in a submodule.
|
||||
* Keep lists (of arguments, parameters, initializers...) as lists, not paragraphs. It should either read from top to bottom, or left to right. Not both.
|
||||
There are per-commit development builds available [here](https://github.com/PolyMC/PolyMC/actions). These have debug information in the binaries, so their file sizes are relatively larger.
|
||||
Portable builds are provided for AppImage on Linux, Windows, and macOS.
|
||||
|
||||
## Translations
|
||||
TODO
|
||||
For Debian and Arch, you can use these packages for the latest development versions:
|
||||
[](https://aur.archlinux.org/packages/polymc-git/)
|
||||
[](https://mpr.makedeb.org/packages/polymc-git)
|
||||
For flatpak, you can use [flathub-beta](https://discourse.flathub.org/t/how-to-use-flathub-beta/2111)
|
||||
|
||||
## Forking/Redistributing/Custom builds policy
|
||||
Do whatever you want, we don't care. Just follow the license. If you have any questions about this feel free to ask in an issue.
|
||||
# Help & Support
|
||||
|
||||
## Help & Support
|
||||
Feel free to create an issue if you need help. However, you might find it easier to ask in the Discord server.
|
||||
|
||||
[](https://discord.gg/xq7fxrgtMP)
|
||||
|
||||
For people who don't want to use Discord, we have a Matrix Space which is bridged to the Discord server:
|
||||
|
||||
[](https://matrix.to/#/#polymc:polymc.org)
|
||||
[](https://matrix.to/#/#polymc:matrix.org)
|
||||
|
||||
If there are any issues with the space or you are using a client that does not support the feature here are the individual rooms:
|
||||
|
||||
[](https://matrix.to/#/#support:polymc.org)
|
||||
[](https://matrix.to/#/#discussion:polymc.org)
|
||||
[](https://matrix.to/#/#development:polymc.org)
|
||||
[](https://matrix.to/#/#news:polymc.org)
|
||||
[](https://matrix.to/#/#polymc-development:matrix.org)
|
||||
[](https://matrix.to/#/#polymc-discussion:matrix.org)
|
||||
[](https://matrix.to/#/#polymc-github:matrix.org)
|
||||
[](https://matrix.to/#/#polymc-maintainers:matrix.org)
|
||||
[](https://matrix.to/#/#polymc-news:matrix.org)
|
||||
[](https://matrix.to/#/#polymc-offtopic:matrix.org)
|
||||
[](https://matrix.to/#/#polymc-support:matrix.org)
|
||||
[](https://matrix.to/#/#polymc-voice:matrix.org)
|
||||
|
||||
we also have a subreddit you can post your issues and suggestions on:
|
||||
|
||||
[r/PolyMCLauncher](https://www.reddit.com/r/PolyMCLauncher/)
|
||||
|
||||
# Development
|
||||
|
||||
If you want to contribute to PolyMC you might find it useful to join our Discord Server or Matrix Space.
|
||||
|
||||
## Building
|
||||
|
||||
If you want to build PolyMC yourself, check [Build Instructions](https://polymc.org/wiki/development/build-instructions/) for build instructions.
|
||||
|
||||
## Code formatting
|
||||
|
||||
Just follow the existing formatting.
|
||||
|
||||
In general, in order of importance:
|
||||
|
||||
- Make sure your IDE is not messing up line endings or whitespace and avoid using linters.
|
||||
- Prefer readability over dogma.
|
||||
- Keep to the existing formatting.
|
||||
- Indent with 4 space unless it's in a submodule.
|
||||
- Keep lists (of arguments, parameters, initializers...) as lists, not paragraphs. It should either read from top to bottom, or left to right. Not both.
|
||||
|
||||
## Translations
|
||||
|
||||
The translation effort for PolyMC is hosted on [Weblate](https://hosted.weblate.org/projects/polymc/polymc/) and information about translating PolyMC is available at https://github.com/PolyMC/Translations
|
||||
|
||||
## Download information
|
||||
To modify download information or change packaging information send a pull request or issue to the website [Here](https://github.com/PolyMC/polymc.github.io/blob/master/src/download.md)
|
||||
|
||||
## Forking/Redistributing/Custom builds policy
|
||||
|
||||
Do whatever you want, we don't care. Just follow the license. If you have any questions about this feel free to ask in an issue.
|
||||
|
||||
All launcher code is available under the GPL-3.0-only license.
|
||||
|
||||
[Source for the website](https://github.com/PolyMC/polymc.github.io) is hosted under the AGPL-3.0-or-later License.
|
||||
|
||||
The logo and related assets are under the CC BY-SA 4.0 license.
|
||||
|
@ -1,3 +1,38 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "BuildConfig.h"
|
||||
#include <QObject>
|
||||
|
||||
@ -12,6 +47,7 @@ Config::Config()
|
||||
LAUNCHER_DOMAIN = "@Launcher_Domain@";
|
||||
LAUNCHER_CONFIGFILE = "@Launcher_ConfigFile@";
|
||||
LAUNCHER_GIT = "@Launcher_Git@";
|
||||
LAUNCHER_DESKTOPFILENAME = "@Launcher_DesktopFileName@";
|
||||
|
||||
USER_AGENT = "@Launcher_UserAgent@";
|
||||
USER_AGENT_UNCACHED = USER_AGENT + " (Uncached)";
|
||||
@ -24,30 +60,42 @@ Config::Config()
|
||||
|
||||
BUILD_PLATFORM = "@Launcher_BUILD_PLATFORM@";
|
||||
UPDATER_BASE = "@Launcher_UPDATER_BASE@";
|
||||
NOTIFICATION_URL = "@Launcher_NOTIFICATION_URL@";
|
||||
FULL_VERSION_STR = "@Launcher_VERSION_MAJOR@.@Launcher_VERSION_MINOR@.@Launcher_VERSION_BUILD@";
|
||||
|
||||
GIT_COMMIT = "@Launcher_GIT_COMMIT@";
|
||||
GIT_REFSPEC = "@Launcher_GIT_REFSPEC@";
|
||||
if(GIT_REFSPEC.startsWith("refs/heads/") && !UPDATER_BASE.isEmpty() && !BUILD_PLATFORM.isEmpty() && VERSION_BUILD >= 0)
|
||||
if (GIT_REFSPEC == QStringLiteral("GITDIR-NOTFOUND"))
|
||||
{
|
||||
VERSION_CHANNEL = QStringLiteral("stable");
|
||||
}
|
||||
else if(GIT_REFSPEC.startsWith("refs/heads/"))
|
||||
{
|
||||
VERSION_CHANNEL = GIT_REFSPEC;
|
||||
VERSION_CHANNEL.remove("refs/heads/");
|
||||
UPDATER_ENABLED = true;
|
||||
if(!UPDATER_BASE.isEmpty() && !BUILD_PLATFORM.isEmpty() && VERSION_BUILD >= 0) {
|
||||
UPDATER_ENABLED = true;
|
||||
}
|
||||
}
|
||||
else if (!GIT_COMMIT.isEmpty())
|
||||
{
|
||||
VERSION_CHANNEL = GIT_COMMIT.mid(0, 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
VERSION_CHANNEL = QObject::tr("custom");
|
||||
VERSION_CHANNEL = QObject::tr("unknown");
|
||||
}
|
||||
|
||||
VERSION_STR = "@Launcher_VERSION_STRING@";
|
||||
NEWS_RSS_URL = "@Launcher_NEWS_RSS_URL@";
|
||||
PASTE_EE_KEY = "@Launcher_PASTE_EE_API_KEY@";
|
||||
NEWS_OPEN_URL = "@Launcher_NEWS_OPEN_URL@";
|
||||
HELP_URL = "@Launcher_HELP_URL@";
|
||||
IMGUR_CLIENT_ID = "@Launcher_IMGUR_CLIENT_ID@";
|
||||
MSA_CLIENT_ID = "@Launcher_MSA_CLIENT_ID@";
|
||||
CURSEFORGE_API_KEY = "@Launcher_CURSEFORGE_API_KEY@";
|
||||
META_URL = "@Launcher_META_URL@";
|
||||
|
||||
BUG_TRACKER_URL = "@Launcher_BUG_TRACKER_URL@";
|
||||
TRANSLATIONS_URL = "@Launcher_TRANSLATIONS_URL@";
|
||||
MATRIX_URL = "@Launcher_MATRIX_URL@";
|
||||
DISCORD_URL = "@Launcher_DISCORD_URL@";
|
||||
SUBREDDIT_URL = "@Launcher_SUBREDDIT_URL@";
|
||||
}
|
||||
|
@ -1,12 +1,47 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <QString>
|
||||
|
||||
/**
|
||||
* \brief The Config class holds all the build-time information passed from the build system.
|
||||
*/
|
||||
class Config
|
||||
{
|
||||
public:
|
||||
class Config {
|
||||
public:
|
||||
Config();
|
||||
QString LAUNCHER_NAME;
|
||||
QString LAUNCHER_DISPLAYNAME;
|
||||
@ -14,6 +49,7 @@ public:
|
||||
QString LAUNCHER_DOMAIN;
|
||||
QString LAUNCHER_CONFIGFILE;
|
||||
QString LAUNCHER_GIT;
|
||||
QString LAUNCHER_DESKTOPFILENAME;
|
||||
|
||||
/// The major version number.
|
||||
int VERSION_MAJOR;
|
||||
@ -38,20 +74,12 @@ public:
|
||||
/// URL for the updater's channel
|
||||
QString UPDATER_BASE;
|
||||
|
||||
|
||||
/// User-Agent to use.
|
||||
QString USER_AGENT;
|
||||
|
||||
/// User-Agent to use for uncached requests.
|
||||
QString USER_AGENT_UNCACHED;
|
||||
|
||||
|
||||
/// URL for notifications
|
||||
QString NOTIFICATION_URL;
|
||||
|
||||
/// Used for matching notifications
|
||||
QString FULL_VERSION_STR;
|
||||
|
||||
/// The git commit hash of this build
|
||||
QString GIT_COMMIT;
|
||||
|
||||
@ -68,9 +96,14 @@ public:
|
||||
QString NEWS_RSS_URL;
|
||||
|
||||
/**
|
||||
* API key you can get from paste.ee when you register an account
|
||||
* URL that gets opened when the user clicks "More News"
|
||||
*/
|
||||
QString PASTE_EE_KEY;
|
||||
QString NEWS_OPEN_URL;
|
||||
|
||||
/**
|
||||
* URL (with arg %1 to be substituted with page-id) that gets opened when the user requests help
|
||||
*/
|
||||
QString HELP_URL;
|
||||
|
||||
/**
|
||||
* Client ID you can get from Imgur when you register an application
|
||||
@ -82,12 +115,19 @@ public:
|
||||
*/
|
||||
QString MSA_CLIENT_ID;
|
||||
|
||||
/**
|
||||
* Client API key for CurseForge
|
||||
*/
|
||||
QString CURSEFORGE_API_KEY;
|
||||
|
||||
/**
|
||||
* Metadata repository URL prefix
|
||||
*/
|
||||
QString META_URL;
|
||||
|
||||
QString BUG_TRACKER_URL;
|
||||
QString TRANSLATIONS_URL;
|
||||
QString MATRIX_URL;
|
||||
QString DISCORD_URL;
|
||||
QString SUBREDDIT_URL;
|
||||
|
||||
@ -95,14 +135,24 @@ public:
|
||||
QString LIBRARY_BASE = "https://libraries.minecraft.net/";
|
||||
QString AUTH_BASE = "https://authserver.mojang.com/";
|
||||
QString IMGUR_BASE_URL = "https://api.imgur.com/3/";
|
||||
QString FMLLIBS_BASE_URL = "https://files.multimc.org/fmllibs/";
|
||||
QString TRANSLATIONS_BASE_URL = "https://files.multimc.org/translations/";
|
||||
QString FMLLIBS_BASE_URL = "https://files.polymc.org/fmllibs/";
|
||||
QString TRANSLATIONS_BASE_URL = "https://i18n.polymc.org/";
|
||||
|
||||
QString MODPACKSCH_API_BASE_URL = "https://api.modpacks.ch/";
|
||||
|
||||
QString LEGACY_FTB_CDN_BASE_URL = "https://dist.creeper.host/FTB2/";
|
||||
|
||||
QString ATL_DOWNLOAD_SERVER_URL = "https://download.nodecdn.net/containers/atl/";
|
||||
QString ATL_API_BASE_URL = "https://api.atlauncher.com/v1/";
|
||||
|
||||
QString TECHNIC_API_BASE_URL = "https://api.technicpack.net/";
|
||||
/**
|
||||
* The build that is reported to the Technic API.
|
||||
*/
|
||||
QString TECHNIC_API_BUILD = "multimc";
|
||||
|
||||
QString MODRINTH_STAGING_URL = "https://staging-api.modrinth.com/v2";
|
||||
QString MODRINTH_PROD_URL = "https://api.modrinth.com/v2";
|
||||
|
||||
/**
|
||||
* \brief Converts the Version to a string.
|
||||
@ -112,4 +162,3 @@ public:
|
||||
};
|
||||
|
||||
extern const Config BuildConfig;
|
||||
|
||||
|
1532
changelog.md
1532
changelog.md
File diff suppressed because it is too large
Load Diff
@ -1,786 +0,0 @@
|
||||
# - Functions to help assemble a standalone bundle application.
|
||||
# A collection of CMake utility functions useful for dealing with .app
|
||||
# bundles on the Mac and bundle-like directories on any OS.
|
||||
#
|
||||
# The following functions are provided by this module:
|
||||
# fixup_bundle
|
||||
# copy_and_fixup_bundle
|
||||
# verify_app
|
||||
# get_bundle_main_executable
|
||||
# get_dotapp_dir
|
||||
# get_bundle_and_executable
|
||||
# get_bundle_all_executables
|
||||
# get_item_key
|
||||
# clear_bundle_keys
|
||||
# set_bundle_key_values
|
||||
# get_bundle_keys
|
||||
# copy_resolved_item_into_bundle
|
||||
# copy_resolved_framework_into_bundle
|
||||
# fixup_bundle_item
|
||||
# verify_bundle_prerequisites
|
||||
# verify_bundle_symlinks
|
||||
# Requires CMake 2.6 or greater because it uses function, break and
|
||||
# PARENT_SCOPE. Also depends on GetPrerequisites.cmake.
|
||||
#
|
||||
# FIXUP_BUNDLE(<app> <libs> <dirs>)
|
||||
# Fix up a bundle in-place and make it standalone, such that it can be
|
||||
# drag-n-drop copied to another machine and run on that machine as long as all
|
||||
# of the system libraries are compatible.
|
||||
#
|
||||
# If you pass plugins to fixup_bundle as the libs parameter, you should install
|
||||
# them or copy them into the bundle before calling fixup_bundle. The "libs"
|
||||
# parameter is a list of libraries that must be fixed up, but that cannot be
|
||||
# determined by otool output analysis. (i.e., plugins)
|
||||
#
|
||||
# Gather all the keys for all the executables and libraries in a bundle, and
|
||||
# then, for each key, copy each prerequisite into the bundle. Then fix each one
|
||||
# up according to its own list of prerequisites.
|
||||
#
|
||||
# Then clear all the keys and call verify_app on the final bundle to ensure
|
||||
# that it is truly standalone.
|
||||
#
|
||||
# COPY_AND_FIXUP_BUNDLE(<src> <dst> <libs> <dirs>)
|
||||
# Makes a copy of the bundle <src> at location <dst> and then fixes up the
|
||||
# new copied bundle in-place at <dst>...
|
||||
#
|
||||
# VERIFY_APP(<app>)
|
||||
# Verifies that an application <app> appears valid based on running analysis
|
||||
# tools on it. Calls "message(FATAL_ERROR" if the application is not verified.
|
||||
#
|
||||
# GET_BUNDLE_MAIN_EXECUTABLE(<bundle> <result_var>)
|
||||
# The result will be the full path name of the bundle's main executable file
|
||||
# or an "error:" prefixed string if it could not be determined.
|
||||
#
|
||||
# GET_DOTAPP_DIR(<exe> <dotapp_dir_var>)
|
||||
# Returns the nearest parent dir whose name ends with ".app" given the full
|
||||
# path to an executable. If there is no such parent dir, then simply return
|
||||
# the dir containing the executable.
|
||||
#
|
||||
# The returned directory may or may not exist.
|
||||
#
|
||||
# GET_BUNDLE_AND_EXECUTABLE(<app> <bundle_var> <executable_var> <valid_var>)
|
||||
# Takes either a ".app" directory name or the name of an executable
|
||||
# nested inside a ".app" directory and returns the path to the ".app"
|
||||
# directory in <bundle_var> and the path to its main executable in
|
||||
# <executable_var>
|
||||
#
|
||||
# GET_BUNDLE_ALL_EXECUTABLES(<bundle> <exes_var>)
|
||||
# Scans the given bundle recursively for all executable files and accumulates
|
||||
# them into a variable.
|
||||
#
|
||||
# GET_ITEM_KEY(<item> <key_var>)
|
||||
# Given a file (item) name, generate a key that should be unique considering
|
||||
# the set of libraries that need copying or fixing up to make a bundle
|
||||
# standalone. This is essentially the file name including extension with "."
|
||||
# replaced by "_"
|
||||
#
|
||||
# This key is used as a prefix for CMake variables so that we can associate a
|
||||
# set of variables with a given item based on its key.
|
||||
#
|
||||
# CLEAR_BUNDLE_KEYS(<keys_var>)
|
||||
# Loop over the list of keys, clearing all the variables associated with each
|
||||
# key. After the loop, clear the list of keys itself.
|
||||
#
|
||||
# Caller of get_bundle_keys should call clear_bundle_keys when done with list
|
||||
# of keys.
|
||||
#
|
||||
# SET_BUNDLE_KEY_VALUES(<keys_var> <context> <item> <exepath> <dirs>
|
||||
# <copyflag>)
|
||||
# Add a key to the list (if necessary) for the given item. If added,
|
||||
# also set all the variables associated with that key.
|
||||
#
|
||||
# GET_BUNDLE_KEYS(<app> <libs> <dirs> <keys_var>)
|
||||
# Loop over all the executable and library files within the bundle (and given
|
||||
# as extra <libs>) and accumulate a list of keys representing them. Set
|
||||
# values associated with each key such that we can loop over all of them and
|
||||
# copy prerequisite libs into the bundle and then do appropriate
|
||||
# install_name_tool fixups.
|
||||
#
|
||||
# COPY_RESOLVED_ITEM_INTO_BUNDLE(<resolved_item> <resolved_embedded_item>)
|
||||
# Copy a resolved item into the bundle if necessary. Copy is not necessary if
|
||||
# the resolved_item is "the same as" the resolved_embedded_item.
|
||||
#
|
||||
# COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE(<resolved_item> <resolved_embedded_item>)
|
||||
# Copy a resolved framework into the bundle if necessary. Copy is not necessary
|
||||
# if the resolved_item is "the same as" the resolved_embedded_item.
|
||||
#
|
||||
# By default, BU_COPY_FULL_FRAMEWORK_CONTENTS is not set. If you want full
|
||||
# frameworks embedded in your bundles, set BU_COPY_FULL_FRAMEWORK_CONTENTS to
|
||||
# ON before calling fixup_bundle. By default,
|
||||
# COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE copies the framework dylib itself plus
|
||||
# the framework Resources directory.
|
||||
#
|
||||
# FIXUP_BUNDLE_ITEM(<resolved_embedded_item> <exepath> <dirs>)
|
||||
# Get the direct/non-system prerequisites of the resolved embedded item. For
|
||||
# each prerequisite, change the way it is referenced to the value of the
|
||||
# _EMBEDDED_ITEM keyed variable for that prerequisite. (Most likely changing to
|
||||
# an "@executable_path" style reference.)
|
||||
#
|
||||
# This function requires that the resolved_embedded_item be "inside" the bundle
|
||||
# already. In other words, if you pass plugins to fixup_bundle as the libs
|
||||
# parameter, you should install them or copy them into the bundle before
|
||||
# calling fixup_bundle. The "libs" parameter is a list of libraries that must
|
||||
# be fixed up, but that cannot be determined by otool output analysis. (i.e.,
|
||||
# plugins)
|
||||
#
|
||||
# Also, change the id of the item being fixed up to its own _EMBEDDED_ITEM
|
||||
# value.
|
||||
#
|
||||
# Accumulate changes in a local variable and make *one* call to
|
||||
# install_name_tool at the end of the function with all the changes at once.
|
||||
#
|
||||
# If the BU_CHMOD_BUNDLE_ITEMS variable is set then bundle items will be
|
||||
# marked writable before install_name_tool tries to change them.
|
||||
#
|
||||
# VERIFY_BUNDLE_PREREQUISITES(<bundle> <result_var> <info_var>)
|
||||
# Verifies that the sum of all prerequisites of all files inside the bundle
|
||||
# are contained within the bundle or are "system" libraries, presumed to exist
|
||||
# everywhere.
|
||||
#
|
||||
# VERIFY_BUNDLE_SYMLINKS(<bundle> <result_var> <info_var>)
|
||||
# Verifies that any symlinks found in the bundle point to other files that are
|
||||
# already also in the bundle... Anything that points to an external file causes
|
||||
# this function to fail the verification.
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2008-2009 Kitware, Inc.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
# The functions defined in this file depend on the get_prerequisites function
|
||||
# (and possibly others) found in:
|
||||
#
|
||||
get_filename_component(BundleUtilities_cmake_dir "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
||||
include("${BundleUtilities_cmake_dir}/GetPrerequisites.cmake")
|
||||
|
||||
|
||||
function(get_bundle_main_executable bundle result_var)
|
||||
set(result "error: '${bundle}/Contents/Info.plist' file does not exist")
|
||||
|
||||
if(EXISTS "${bundle}/Contents/Info.plist")
|
||||
set(result "error: no CFBundleExecutable in '${bundle}/Contents/Info.plist' file")
|
||||
set(line_is_main_executable 0)
|
||||
set(bundle_executable "")
|
||||
|
||||
# Read Info.plist as a list of lines:
|
||||
#
|
||||
set(eol_char "E")
|
||||
file(READ "${bundle}/Contents/Info.plist" info_plist)
|
||||
string(REGEX REPLACE ";" "\\\\;" info_plist "${info_plist}")
|
||||
string(REGEX REPLACE "\n" "${eol_char};" info_plist "${info_plist}")
|
||||
|
||||
# Scan the lines for "<key>CFBundleExecutable</key>" - the line after that
|
||||
# is the name of the main executable.
|
||||
#
|
||||
foreach(line ${info_plist})
|
||||
if(line_is_main_executable)
|
||||
string(REGEX REPLACE "^.*<string>(.*)</string>.*$" "\\1" bundle_executable "${line}")
|
||||
break()
|
||||
endif()
|
||||
|
||||
if(line MATCHES "^.*<key>CFBundleExecutable</key>.*$")
|
||||
set(line_is_main_executable 1)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(NOT "${bundle_executable}" STREQUAL "")
|
||||
if(EXISTS "${bundle}/Contents/MacOS/${bundle_executable}")
|
||||
set(result "${bundle}/Contents/MacOS/${bundle_executable}")
|
||||
else()
|
||||
|
||||
# Ultimate goal:
|
||||
# If not in "Contents/MacOS" then scan the bundle for matching files. If
|
||||
# there is only one executable file that matches, then use it, otherwise
|
||||
# it's an error...
|
||||
#
|
||||
#file(GLOB_RECURSE file_list "${bundle}/${bundle_executable}")
|
||||
|
||||
# But for now, pragmatically, it's an error. Expect the main executable
|
||||
# for the bundle to be in Contents/MacOS, it's an error if it's not:
|
||||
#
|
||||
set(result "error: '${bundle}/Contents/MacOS/${bundle_executable}' does not exist")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
#
|
||||
# More inclusive technique... (This one would work on Windows and Linux
|
||||
# too, if a developer followed the typical Mac bundle naming convention...)
|
||||
#
|
||||
# If there is no Info.plist file, try to find an executable with the same
|
||||
# base name as the .app directory:
|
||||
#
|
||||
endif()
|
||||
|
||||
set(${result_var} "${result}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(get_dotapp_dir exe dotapp_dir_var)
|
||||
set(s "${exe}")
|
||||
|
||||
if(s MATCHES "^.*/.*\\.app/.*$")
|
||||
# If there is a ".app" parent directory,
|
||||
# ascend until we hit it:
|
||||
# (typical of a Mac bundle executable)
|
||||
#
|
||||
set(done 0)
|
||||
while(NOT ${done})
|
||||
get_filename_component(snamewe "${s}" NAME_WE)
|
||||
get_filename_component(sname "${s}" NAME)
|
||||
get_filename_component(sdir "${s}" PATH)
|
||||
set(s "${sdir}")
|
||||
if(sname MATCHES "\\.app$")
|
||||
set(done 1)
|
||||
set(dotapp_dir "${sdir}/${sname}")
|
||||
endif()
|
||||
endwhile()
|
||||
else()
|
||||
# Otherwise use a directory containing the exe
|
||||
# (typical of a non-bundle executable on Mac, Windows or Linux)
|
||||
#
|
||||
is_file_executable("${s}" is_executable)
|
||||
if(is_executable)
|
||||
get_filename_component(sdir "${s}" PATH)
|
||||
set(dotapp_dir "${sdir}")
|
||||
else()
|
||||
set(dotapp_dir "${s}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
set(${dotapp_dir_var} "${dotapp_dir}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(get_bundle_and_executable app bundle_var executable_var valid_var)
|
||||
set(valid 0)
|
||||
|
||||
if(EXISTS "${app}")
|
||||
# Is it a directory ending in .app?
|
||||
if(IS_DIRECTORY "${app}")
|
||||
if(app MATCHES "\\.app$")
|
||||
get_bundle_main_executable("${app}" executable)
|
||||
if(EXISTS "${app}" AND EXISTS "${executable}")
|
||||
set(${bundle_var} "${app}" PARENT_SCOPE)
|
||||
set(${executable_var} "${executable}" PARENT_SCOPE)
|
||||
set(valid 1)
|
||||
#message(STATUS "info: handled .app directory case...")
|
||||
else()
|
||||
message(STATUS "warning: *NOT* handled - .app directory case...")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "warning: *NOT* handled - directory but not .app case...")
|
||||
endif()
|
||||
else()
|
||||
# Is it an executable file?
|
||||
is_file_executable("${app}" is_executable)
|
||||
if(is_executable)
|
||||
get_dotapp_dir("${app}" dotapp_dir)
|
||||
if(EXISTS "${dotapp_dir}")
|
||||
set(${bundle_var} "${dotapp_dir}" PARENT_SCOPE)
|
||||
set(${executable_var} "${app}" PARENT_SCOPE)
|
||||
set(valid 1)
|
||||
#message(STATUS "info: handled executable file in .app dir case...")
|
||||
else()
|
||||
get_filename_component(app_dir "${app}" PATH)
|
||||
set(${bundle_var} "${app_dir}" PARENT_SCOPE)
|
||||
set(${executable_var} "${app}" PARENT_SCOPE)
|
||||
set(valid 1)
|
||||
#message(STATUS "info: handled executable file in any dir case...")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "warning: *NOT* handled - not .app dir, not executable file...")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "warning: *NOT* handled - directory/file ${app} does not exist...")
|
||||
endif()
|
||||
|
||||
if(NOT valid)
|
||||
set(${bundle_var} "error: not a bundle" PARENT_SCOPE)
|
||||
set(${executable_var} "error: not a bundle" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
set(${valid_var} ${valid} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(get_bundle_all_executables bundle exes_var)
|
||||
set(exes "")
|
||||
|
||||
file(GLOB_RECURSE file_list "${bundle}/*")
|
||||
foreach(f ${file_list})
|
||||
is_file_executable("${f}" is_executable)
|
||||
if(is_executable)
|
||||
set(exes ${exes} "${f}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(${exes_var} "${exes}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(get_item_key item key_var)
|
||||
get_filename_component(item_name "${item}" NAME)
|
||||
if(WIN32)
|
||||
string(TOLOWER "${item_name}" item_name)
|
||||
endif()
|
||||
string(REGEX REPLACE "\\." "_" ${key_var} "${item_name}")
|
||||
set(${key_var} ${${key_var}} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(clear_bundle_keys keys_var)
|
||||
foreach(key ${${keys_var}})
|
||||
set(${key}_ITEM PARENT_SCOPE)
|
||||
set(${key}_RESOLVED_ITEM PARENT_SCOPE)
|
||||
set(${key}_DEFAULT_EMBEDDED_PATH PARENT_SCOPE)
|
||||
set(${key}_EMBEDDED_ITEM PARENT_SCOPE)
|
||||
set(${key}_RESOLVED_EMBEDDED_ITEM PARENT_SCOPE)
|
||||
set(${key}_COPYFLAG PARENT_SCOPE)
|
||||
endforeach()
|
||||
set(${keys_var} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(set_bundle_key_values keys_var context item exepath dirs copyflag)
|
||||
get_filename_component(item_name "${item}" NAME)
|
||||
|
||||
get_item_key("${item}" key)
|
||||
|
||||
list(LENGTH ${keys_var} length_before)
|
||||
gp_append_unique(${keys_var} "${key}")
|
||||
list(LENGTH ${keys_var} length_after)
|
||||
|
||||
if(NOT length_before EQUAL length_after)
|
||||
gp_resolve_item("${context}" "${item}" "${exepath}" "${dirs}" resolved_item)
|
||||
|
||||
gp_item_default_embedded_path("${item}" default_embedded_path)
|
||||
|
||||
if(item MATCHES "[^/]+\\.framework/")
|
||||
# For frameworks, construct the name under the embedded path from the
|
||||
# opening "${item_name}.framework/" to the closing "/${item_name}":
|
||||
#
|
||||
string(REGEX REPLACE "^.*(${item_name}.framework/.*/?${item_name}).*$" "${default_embedded_path}/\\1" embedded_item "${item}")
|
||||
else()
|
||||
# For other items, just use the same name as the original, but in the
|
||||
# embedded path:
|
||||
#
|
||||
set(embedded_item "${default_embedded_path}/${item_name}")
|
||||
endif()
|
||||
|
||||
# Replace @executable_path and resolve ".." references:
|
||||
#
|
||||
string(REPLACE "@executable_path" "${exepath}" resolved_embedded_item "${embedded_item}")
|
||||
get_filename_component(resolved_embedded_item "${resolved_embedded_item}" ABSOLUTE)
|
||||
|
||||
# *But* -- if we are not copying, then force resolved_embedded_item to be
|
||||
# the same as resolved_item. In the case of multiple executables in the
|
||||
# original bundle, using the default_embedded_path results in looking for
|
||||
# the resolved executable next to the main bundle executable. This is here
|
||||
# so that exes in the other sibling directories (like "bin") get fixed up
|
||||
# properly...
|
||||
#
|
||||
if(NOT copyflag)
|
||||
set(resolved_embedded_item "${resolved_item}")
|
||||
endif()
|
||||
|
||||
set(${keys_var} ${${keys_var}} PARENT_SCOPE)
|
||||
set(${key}_ITEM "${item}" PARENT_SCOPE)
|
||||
set(${key}_RESOLVED_ITEM "${resolved_item}" PARENT_SCOPE)
|
||||
set(${key}_DEFAULT_EMBEDDED_PATH "${default_embedded_path}" PARENT_SCOPE)
|
||||
set(${key}_EMBEDDED_ITEM "${embedded_item}" PARENT_SCOPE)
|
||||
set(${key}_RESOLVED_EMBEDDED_ITEM "${resolved_embedded_item}" PARENT_SCOPE)
|
||||
set(${key}_COPYFLAG "${copyflag}" PARENT_SCOPE)
|
||||
else()
|
||||
#message("warning: item key '${key}' already in the list, subsequent references assumed identical to first")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(get_bundle_keys app libs dirs keys_var)
|
||||
set(${keys_var} PARENT_SCOPE)
|
||||
|
||||
get_bundle_and_executable("${app}" bundle executable valid)
|
||||
if(valid)
|
||||
# Always use the exepath of the main bundle executable for @executable_path
|
||||
# replacements:
|
||||
#
|
||||
get_filename_component(exepath "${executable}" PATH)
|
||||
|
||||
# But do fixups on all executables in the bundle:
|
||||
#
|
||||
get_bundle_all_executables("${bundle}" exes)
|
||||
|
||||
# For each extra lib, accumulate a key as well and then also accumulate
|
||||
# any of its prerequisites. (Extra libs are typically dynamically loaded
|
||||
# plugins: libraries that are prerequisites for full runtime functionality
|
||||
# but that do not show up in otool -L output...)
|
||||
#
|
||||
foreach(lib ${libs})
|
||||
set_bundle_key_values(${keys_var} "${lib}" "${lib}" "${exepath}" "${dirs}" 0)
|
||||
|
||||
set(prereqs "")
|
||||
get_prerequisites("${lib}" prereqs 1 1 "${exepath}" "${dirs}")
|
||||
foreach(pr ${prereqs})
|
||||
set_bundle_key_values(${keys_var} "${lib}" "${pr}" "${exepath}" "${dirs}" 1)
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
# For each executable found in the bundle, accumulate keys as we go.
|
||||
# The list of keys should be complete when all prerequisites of all
|
||||
# binaries in the bundle have been analyzed.
|
||||
#
|
||||
foreach(exe ${exes})
|
||||
# Add the exe itself to the keys:
|
||||
#
|
||||
set_bundle_key_values(${keys_var} "${exe}" "${exe}" "${exepath}" "${dirs}" 0)
|
||||
|
||||
# Add each prerequisite to the keys:
|
||||
#
|
||||
set(prereqs "")
|
||||
get_prerequisites("${exe}" prereqs 1 1 "${exepath}" "${dirs}")
|
||||
foreach(pr ${prereqs})
|
||||
set_bundle_key_values(${keys_var} "${exe}" "${pr}" "${exepath}" "${dirs}" 1)
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
# Propagate values to caller's scope:
|
||||
#
|
||||
set(${keys_var} ${${keys_var}} PARENT_SCOPE)
|
||||
foreach(key ${${keys_var}})
|
||||
set(${key}_ITEM "${${key}_ITEM}" PARENT_SCOPE)
|
||||
set(${key}_RESOLVED_ITEM "${${key}_RESOLVED_ITEM}" PARENT_SCOPE)
|
||||
set(${key}_DEFAULT_EMBEDDED_PATH "${${key}_DEFAULT_EMBEDDED_PATH}" PARENT_SCOPE)
|
||||
set(${key}_EMBEDDED_ITEM "${${key}_EMBEDDED_ITEM}" PARENT_SCOPE)
|
||||
set(${key}_RESOLVED_EMBEDDED_ITEM "${${key}_RESOLVED_EMBEDDED_ITEM}" PARENT_SCOPE)
|
||||
set(${key}_COPYFLAG "${${key}_COPYFLAG}" PARENT_SCOPE)
|
||||
endforeach()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(copy_resolved_item_into_bundle resolved_item resolved_embedded_item)
|
||||
if(WIN32)
|
||||
# ignore case on Windows
|
||||
string(TOLOWER "${resolved_item}" resolved_item_compare)
|
||||
string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare)
|
||||
else()
|
||||
set(resolved_item_compare "${resolved_item}")
|
||||
set(resolved_embedded_item_compare "${resolved_embedded_item}")
|
||||
endif()
|
||||
|
||||
if("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}")
|
||||
message(STATUS "warning: resolved_item == resolved_embedded_item - not copying...")
|
||||
else()
|
||||
#message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}")
|
||||
if(UNIX AND NOT APPLE)
|
||||
file(RPATH_REMOVE FILE "${resolved_embedded_item}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endfunction()
|
||||
|
||||
|
||||
function(copy_resolved_framework_into_bundle resolved_item resolved_embedded_item)
|
||||
if(WIN32)
|
||||
# ignore case on Windows
|
||||
string(TOLOWER "${resolved_item}" resolved_item_compare)
|
||||
string(TOLOWER "${resolved_embedded_item}" resolved_embedded_item_compare)
|
||||
else()
|
||||
set(resolved_item_compare "${resolved_item}")
|
||||
set(resolved_embedded_item_compare "${resolved_embedded_item}")
|
||||
endif()
|
||||
|
||||
if("${resolved_item_compare}" STREQUAL "${resolved_embedded_item_compare}")
|
||||
message(STATUS "warning: resolved_item == resolved_embedded_item - not copying...")
|
||||
else()
|
||||
if(BU_COPY_FULL_FRAMEWORK_CONTENTS)
|
||||
# Full Framework (everything):
|
||||
get_filename_component(resolved_dir "${resolved_item}" PATH)
|
||||
get_filename_component(resolved_dir "${resolved_dir}/../.." ABSOLUTE)
|
||||
get_filename_component(resolved_embedded_dir "${resolved_embedded_item}" PATH)
|
||||
get_filename_component(resolved_embedded_dir "${resolved_embedded_dir}/../.." ABSOLUTE)
|
||||
#message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_dir}' '${resolved_embedded_dir}'")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${resolved_dir}" "${resolved_embedded_dir}")
|
||||
else()
|
||||
# Framework lib itself:
|
||||
#message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy ${resolved_item} ${resolved_embedded_item}")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${resolved_item}" "${resolved_embedded_item}")
|
||||
|
||||
# Plus Resources, if they exist:
|
||||
string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$" "\\1/Resources" resolved_resources "${resolved_item}")
|
||||
string(REGEX REPLACE "^(.*)/[^/]+/[^/]+/[^/]+$" "\\1/Resources" resolved_embedded_resources "${resolved_embedded_item}")
|
||||
if(EXISTS "${resolved_resources}")
|
||||
#message(STATUS "copying COMMAND ${CMAKE_COMMAND} -E copy_directory '${resolved_resources}' '${resolved_embedded_resources}'")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${resolved_resources}" "${resolved_embedded_resources}")
|
||||
endif()
|
||||
endif()
|
||||
if(UNIX AND NOT APPLE)
|
||||
file(RPATH_REMOVE FILE "${resolved_embedded_item}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endfunction()
|
||||
|
||||
|
||||
function(fixup_bundle_item resolved_embedded_item exepath dirs)
|
||||
# This item's key is "ikey":
|
||||
#
|
||||
get_item_key("${resolved_embedded_item}" ikey)
|
||||
|
||||
# Ensure the item is "inside the .app bundle" -- it should not be fixed up if
|
||||
# it is not in the .app bundle... Otherwise, we'll modify files in the build
|
||||
# tree, or in other varied locations around the file system, with our call to
|
||||
# install_name_tool. Make sure that doesn't happen here:
|
||||
#
|
||||
get_dotapp_dir("${exepath}" exe_dotapp_dir)
|
||||
string(LENGTH "${exe_dotapp_dir}/" exe_dotapp_dir_length)
|
||||
string(LENGTH "${resolved_embedded_item}" resolved_embedded_item_length)
|
||||
set(path_too_short 0)
|
||||
set(is_embedded 0)
|
||||
if(${resolved_embedded_item_length} LESS ${exe_dotapp_dir_length})
|
||||
set(path_too_short 1)
|
||||
endif()
|
||||
if(NOT path_too_short)
|
||||
string(SUBSTRING "${resolved_embedded_item}" 0 ${exe_dotapp_dir_length} item_substring)
|
||||
if("${exe_dotapp_dir}/" STREQUAL "${item_substring}")
|
||||
set(is_embedded 1)
|
||||
endif()
|
||||
endif()
|
||||
if(NOT is_embedded)
|
||||
message(" exe_dotapp_dir/='${exe_dotapp_dir}/'")
|
||||
message(" item_substring='${item_substring}'")
|
||||
message(" resolved_embedded_item='${resolved_embedded_item}'")
|
||||
message("")
|
||||
message("Install or copy the item into the bundle before calling fixup_bundle.")
|
||||
message("Or maybe there's a typo or incorrect path in one of the args to fixup_bundle?")
|
||||
message("")
|
||||
message(FATAL_ERROR "cannot fixup an item that is not in the bundle...")
|
||||
endif()
|
||||
|
||||
set(prereqs "")
|
||||
get_prerequisites("${resolved_embedded_item}" prereqs 1 0 "${exepath}" "${dirs}")
|
||||
|
||||
set(changes "")
|
||||
|
||||
foreach(pr ${prereqs})
|
||||
# Each referenced item's key is "rkey" in the loop:
|
||||
#
|
||||
get_item_key("${pr}" rkey)
|
||||
|
||||
if(NOT "${${rkey}_EMBEDDED_ITEM}" STREQUAL "")
|
||||
set(changes ${changes} "-change" "${pr}" "${${rkey}_EMBEDDED_ITEM}")
|
||||
else()
|
||||
message("warning: unexpected reference to '${pr}'")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(BU_CHMOD_BUNDLE_ITEMS)
|
||||
execute_process(COMMAND chmod u+w "${resolved_embedded_item}")
|
||||
endif()
|
||||
|
||||
# Change this item's id and all of its references in one call
|
||||
# to install_name_tool:
|
||||
#
|
||||
execute_process(COMMAND install_name_tool
|
||||
${changes} -id "${${ikey}_EMBEDDED_ITEM}" "${resolved_embedded_item}"
|
||||
)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(fixup_bundle app libs dirs)
|
||||
message(STATUS "fixup_bundle")
|
||||
message(STATUS " app='${app}'")
|
||||
message(STATUS " libs='${libs}'")
|
||||
message(STATUS " dirs='${dirs}'")
|
||||
|
||||
get_bundle_and_executable("${app}" bundle executable valid)
|
||||
if(valid)
|
||||
get_filename_component(exepath "${executable}" PATH)
|
||||
|
||||
message(STATUS "fixup_bundle: preparing...")
|
||||
get_bundle_keys("${app}" "${libs}" "${dirs}" keys)
|
||||
|
||||
message(STATUS "fixup_bundle: copying...")
|
||||
list(LENGTH keys n)
|
||||
math(EXPR n ${n}*2)
|
||||
|
||||
set(i 0)
|
||||
foreach(key ${keys})
|
||||
math(EXPR i ${i}+1)
|
||||
if(${${key}_COPYFLAG})
|
||||
message(STATUS "${i}/${n}: copying '${${key}_RESOLVED_ITEM}'")
|
||||
else()
|
||||
message(STATUS "${i}/${n}: *NOT* copying '${${key}_RESOLVED_ITEM}'")
|
||||
endif()
|
||||
|
||||
set(show_status 0)
|
||||
if(show_status)
|
||||
message(STATUS "key='${key}'")
|
||||
message(STATUS "item='${${key}_ITEM}'")
|
||||
message(STATUS "resolved_item='${${key}_RESOLVED_ITEM}'")
|
||||
message(STATUS "default_embedded_path='${${key}_DEFAULT_EMBEDDED_PATH}'")
|
||||
message(STATUS "embedded_item='${${key}_EMBEDDED_ITEM}'")
|
||||
message(STATUS "resolved_embedded_item='${${key}_RESOLVED_EMBEDDED_ITEM}'")
|
||||
message(STATUS "copyflag='${${key}_COPYFLAG}'")
|
||||
message(STATUS "")
|
||||
endif()
|
||||
|
||||
if(${${key}_COPYFLAG})
|
||||
set(item "${${key}_ITEM}")
|
||||
if(item MATCHES "[^/]+\\.framework/")
|
||||
copy_resolved_framework_into_bundle("${${key}_RESOLVED_ITEM}"
|
||||
"${${key}_RESOLVED_EMBEDDED_ITEM}")
|
||||
else()
|
||||
copy_resolved_item_into_bundle("${${key}_RESOLVED_ITEM}"
|
||||
"${${key}_RESOLVED_EMBEDDED_ITEM}")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
message(STATUS "fixup_bundle: fixing...")
|
||||
foreach(key ${keys})
|
||||
math(EXPR i ${i}+1)
|
||||
if(APPLE)
|
||||
message(STATUS "${i}/${n}: fixing up '${${key}_RESOLVED_EMBEDDED_ITEM}'")
|
||||
fixup_bundle_item("${${key}_RESOLVED_EMBEDDED_ITEM}" "${exepath}" "${dirs}")
|
||||
else()
|
||||
message(STATUS "${i}/${n}: fix-up not required on this platform '${${key}_RESOLVED_EMBEDDED_ITEM}'")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
message(STATUS "fixup_bundle: cleaning up...")
|
||||
clear_bundle_keys(keys)
|
||||
|
||||
message(STATUS "fixup_bundle: verifying...")
|
||||
verify_app("${app}")
|
||||
else()
|
||||
message(SEND_ERROR "error: fixup_bundle: not a valid bundle")
|
||||
endif()
|
||||
|
||||
message(STATUS "fixup_bundle: done")
|
||||
endfunction()
|
||||
|
||||
|
||||
function(copy_and_fixup_bundle src dst libs dirs)
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory "${src}" "${dst}")
|
||||
fixup_bundle("${dst}" "${libs}" "${dirs}")
|
||||
endfunction()
|
||||
|
||||
|
||||
function(verify_bundle_prerequisites bundle result_var info_var)
|
||||
set(result 1)
|
||||
set(info "")
|
||||
set(count 0)
|
||||
|
||||
get_bundle_main_executable("${bundle}" main_bundle_exe)
|
||||
|
||||
file(GLOB_RECURSE file_list "${bundle}/*")
|
||||
foreach(f ${file_list})
|
||||
is_file_executable("${f}" is_executable)
|
||||
if(is_executable)
|
||||
get_filename_component(exepath "${f}" PATH)
|
||||
math(EXPR count "${count} + 1")
|
||||
|
||||
message(STATUS "executable file ${count}: ${f}")
|
||||
|
||||
set(prereqs "")
|
||||
get_prerequisites("${f}" prereqs 1 1 "${exepath}" "")
|
||||
|
||||
# On the Mac,
|
||||
# "embedded" and "system" prerequisites are fine... anything else means
|
||||
# the bundle's prerequisites are not verified (i.e., the bundle is not
|
||||
# really "standalone")
|
||||
#
|
||||
# On Windows (and others? Linux/Unix/...?)
|
||||
# "local" and "system" prereqs are fine...
|
||||
#
|
||||
set(external_prereqs "")
|
||||
|
||||
foreach(p ${prereqs})
|
||||
set(p_type "")
|
||||
gp_file_type("${f}" "${p}" p_type)
|
||||
|
||||
if(APPLE)
|
||||
if(NOT "${p_type}" STREQUAL "embedded" AND NOT "${p_type}" STREQUAL "system")
|
||||
set(external_prereqs ${external_prereqs} "${p}")
|
||||
endif()
|
||||
else()
|
||||
if(NOT "${p_type}" STREQUAL "local" AND NOT "${p_type}" STREQUAL "system")
|
||||
set(external_prereqs ${external_prereqs} "${p}")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(external_prereqs)
|
||||
# Found non-system/somehow-unacceptable prerequisites:
|
||||
set(result 0)
|
||||
set(info ${info} "external prerequisites found:\nf='${f}'\nexternal_prereqs='${external_prereqs}'\n")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(result)
|
||||
set(info "Verified ${count} executable files in '${bundle}'")
|
||||
endif()
|
||||
|
||||
set(${result_var} "${result}" PARENT_SCOPE)
|
||||
set(${info_var} "${info}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(verify_bundle_symlinks bundle result_var info_var)
|
||||
set(result 1)
|
||||
set(info "")
|
||||
set(count 0)
|
||||
|
||||
# TODO: implement this function for real...
|
||||
# Right now, it is just a stub that verifies unconditionally...
|
||||
|
||||
set(${result_var} "${result}" PARENT_SCOPE)
|
||||
set(${info_var} "${info}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(verify_app app)
|
||||
set(verified 0)
|
||||
set(info "")
|
||||
|
||||
get_bundle_and_executable("${app}" bundle executable valid)
|
||||
|
||||
message(STATUS "===========================================================================")
|
||||
message(STATUS "Analyzing app='${app}'")
|
||||
message(STATUS "bundle='${bundle}'")
|
||||
message(STATUS "executable='${executable}'")
|
||||
message(STATUS "valid='${valid}'")
|
||||
|
||||
# Verify that the bundle does not have any "external" prerequisites:
|
||||
#
|
||||
verify_bundle_prerequisites("${bundle}" verified info)
|
||||
message(STATUS "verified='${verified}'")
|
||||
message(STATUS "info='${info}'")
|
||||
message(STATUS "")
|
||||
|
||||
if(verified)
|
||||
# Verify that the bundle does not have any symlinks to external files:
|
||||
#
|
||||
verify_bundle_symlinks("${bundle}" verified info)
|
||||
message(STATUS "verified='${verified}'")
|
||||
message(STATUS "info='${info}'")
|
||||
message(STATUS "")
|
||||
endif()
|
||||
|
||||
if(NOT verified)
|
||||
message(FATAL_ERROR "error: verify_app failed")
|
||||
endif()
|
||||
endfunction()
|
@ -1,902 +0,0 @@
|
||||
# - Functions to analyze and list executable file prerequisites.
|
||||
# This module provides functions to list the .dll, .dylib or .so
|
||||
# files that an executable or shared library file depends on. (Its
|
||||
# prerequisites.)
|
||||
#
|
||||
# It uses various tools to obtain the list of required shared library files:
|
||||
# dumpbin (Windows)
|
||||
# objdump (MinGW on Windows)
|
||||
# ldd (Linux/Unix)
|
||||
# otool (Mac OSX)
|
||||
# The following functions are provided by this module:
|
||||
# get_prerequisites
|
||||
# list_prerequisites
|
||||
# list_prerequisites_by_glob
|
||||
# gp_append_unique
|
||||
# is_file_executable
|
||||
# gp_item_default_embedded_path
|
||||
# (projects can override with gp_item_default_embedded_path_override)
|
||||
# gp_resolve_item
|
||||
# (projects can override with gp_resolve_item_override)
|
||||
# gp_resolved_file_type
|
||||
# (projects can override with gp_resolved_file_type_override)
|
||||
# gp_file_type
|
||||
# Requires CMake 2.6 or greater because it uses function, break, return and
|
||||
# PARENT_SCOPE.
|
||||
#
|
||||
# GET_PREREQUISITES(<target> <prerequisites_var> <exclude_system> <recurse>
|
||||
# <exepath> <dirs>)
|
||||
# Get the list of shared library files required by <target>. The list in
|
||||
# the variable named <prerequisites_var> should be empty on first entry to
|
||||
# this function. On exit, <prerequisites_var> will contain the list of
|
||||
# required shared library files.
|
||||
#
|
||||
# <target> is the full path to an executable file. <prerequisites_var> is the
|
||||
# name of a CMake variable to contain the results. <exclude_system> must be 0
|
||||
# or 1 indicating whether to include or exclude "system" prerequisites. If
|
||||
# <recurse> is set to 1 all prerequisites will be found recursively, if set to
|
||||
# 0 only direct prerequisites are listed. <exepath> is the path to the top
|
||||
# level executable used for @executable_path replacment on the Mac. <dirs> is
|
||||
# a list of paths where libraries might be found: these paths are searched
|
||||
# first when a target without any path info is given. Then standard system
|
||||
# locations are also searched: PATH, Framework locations, /usr/lib...
|
||||
#
|
||||
# LIST_PREREQUISITES(<target> [<recurse> [<exclude_system> [<verbose>]]])
|
||||
# Print a message listing the prerequisites of <target>.
|
||||
#
|
||||
# <target> is the name of a shared library or executable target or the full
|
||||
# path to a shared library or executable file. If <recurse> is set to 1 all
|
||||
# prerequisites will be found recursively, if set to 0 only direct
|
||||
# prerequisites are listed. <exclude_system> must be 0 or 1 indicating whether
|
||||
# to include or exclude "system" prerequisites. With <verbose> set to 0 only
|
||||
# the full path names of the prerequisites are printed, set to 1 extra
|
||||
# informatin will be displayed.
|
||||
#
|
||||
# LIST_PREREQUISITES_BY_GLOB(<glob_arg> <glob_exp>)
|
||||
# Print the prerequisites of shared library and executable files matching a
|
||||
# globbing pattern. <glob_arg> is GLOB or GLOB_RECURSE and <glob_exp> is a
|
||||
# globbing expression used with "file(GLOB" or "file(GLOB_RECURSE" to retrieve
|
||||
# a list of matching files. If a matching file is executable, its prerequisites
|
||||
# are listed.
|
||||
#
|
||||
# Any additional (optional) arguments provided are passed along as the
|
||||
# optional arguments to the list_prerequisites calls.
|
||||
#
|
||||
# GP_APPEND_UNIQUE(<list_var> <value>)
|
||||
# Append <value> to the list variable <list_var> only if the value is not
|
||||
# already in the list.
|
||||
#
|
||||
# IS_FILE_EXECUTABLE(<file> <result_var>)
|
||||
# Return 1 in <result_var> if <file> is a binary executable, 0 otherwise.
|
||||
#
|
||||
# GP_ITEM_DEFAULT_EMBEDDED_PATH(<item> <default_embedded_path_var>)
|
||||
# Return the path that others should refer to the item by when the item
|
||||
# is embedded inside a bundle.
|
||||
#
|
||||
# Override on a per-project basis by providing a project-specific
|
||||
# gp_item_default_embedded_path_override function.
|
||||
#
|
||||
# GP_RESOLVE_ITEM(<context> <item> <exepath> <dirs> <resolved_item_var>)
|
||||
# Resolve an item into an existing full path file.
|
||||
#
|
||||
# Override on a per-project basis by providing a project-specific
|
||||
# gp_resolve_item_override function.
|
||||
#
|
||||
# GP_RESOLVED_FILE_TYPE(<original_file> <file> <exepath> <dirs> <type_var>)
|
||||
# Return the type of <file> with respect to <original_file>. String
|
||||
# describing type of prerequisite is returned in variable named <type_var>.
|
||||
#
|
||||
# Use <exepath> and <dirs> if necessary to resolve non-absolute <file>
|
||||
# values -- but only for non-embedded items.
|
||||
#
|
||||
# Possible types are:
|
||||
# system
|
||||
# local
|
||||
# embedded
|
||||
# other
|
||||
# Override on a per-project basis by providing a project-specific
|
||||
# gp_resolved_file_type_override function.
|
||||
#
|
||||
# GP_FILE_TYPE(<original_file> <file> <type_var>)
|
||||
# Return the type of <file> with respect to <original_file>. String
|
||||
# describing type of prerequisite is returned in variable named <type_var>.
|
||||
#
|
||||
# Possible types are:
|
||||
# system
|
||||
# local
|
||||
# embedded
|
||||
# other
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2008-2009 Kitware, Inc.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
function(gp_append_unique list_var value)
|
||||
set(contains 0)
|
||||
|
||||
foreach(item ${${list_var}})
|
||||
if("${item}" STREQUAL "${value}")
|
||||
set(contains 1)
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(NOT contains)
|
||||
set(${list_var} ${${list_var}} "${value}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(is_file_executable file result_var)
|
||||
#
|
||||
# A file is not executable until proven otherwise:
|
||||
#
|
||||
set(${result_var} 0 PARENT_SCOPE)
|
||||
|
||||
get_filename_component(file_full "${file}" ABSOLUTE)
|
||||
string(TOLOWER "${file_full}" file_full_lower)
|
||||
|
||||
# If file name ends in .exe on Windows, *assume* executable:
|
||||
#
|
||||
if(WIN32 AND NOT UNIX)
|
||||
if("${file_full_lower}" MATCHES "\\.exe$")
|
||||
set(${result_var} 1 PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# A clause could be added here that uses output or return value of dumpbin
|
||||
# to determine ${result_var}. In 99%+? practical cases, the exe name
|
||||
# match will be sufficient...
|
||||
#
|
||||
endif()
|
||||
|
||||
# Use the information returned from the Unix shell command "file" to
|
||||
# determine if ${file_full} should be considered an executable file...
|
||||
#
|
||||
# If the file command's output contains "executable" and does *not* contain
|
||||
# "text" then it is likely an executable suitable for prerequisite analysis
|
||||
# via the get_prerequisites macro.
|
||||
#
|
||||
if(UNIX)
|
||||
if(NOT file_cmd)
|
||||
find_program(file_cmd "file")
|
||||
mark_as_advanced(file_cmd)
|
||||
endif()
|
||||
|
||||
if(file_cmd)
|
||||
execute_process(COMMAND "${file_cmd}" "${file_full}"
|
||||
OUTPUT_VARIABLE file_ov
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
# Replace the name of the file in the output with a placeholder token
|
||||
# (the string " _file_full_ ") so that just in case the path name of
|
||||
# the file contains the word "text" or "executable" we are not fooled
|
||||
# into thinking "the wrong thing" because the file name matches the
|
||||
# other 'file' command output we are looking for...
|
||||
#
|
||||
string(REPLACE "${file_full}" " _file_full_ " file_ov "${file_ov}")
|
||||
string(TOLOWER "${file_ov}" file_ov)
|
||||
|
||||
#message(STATUS "file_ov='${file_ov}'")
|
||||
if("${file_ov}" MATCHES "executable")
|
||||
#message(STATUS "executable!")
|
||||
if("${file_ov}" MATCHES "text")
|
||||
#message(STATUS "but text, so *not* a binary executable!")
|
||||
else()
|
||||
set(${result_var} 1 PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Also detect position independent executables on Linux,
|
||||
# where "file" gives "shared object ... (uses shared libraries)"
|
||||
if("${file_ov}" MATCHES "shared object.*\(uses shared libs\)")
|
||||
set(${result_var} 1 PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# "file" version 5.22 does not print "(used shared libraries)"
|
||||
# but uses "interpreter"
|
||||
if("${file_ov}" MATCHES "shared object.*interpreter")
|
||||
set(${result_var} 1 PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
else()
|
||||
message(STATUS "warning: No 'file' command, skipping execute_process...")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(gp_item_default_embedded_path item default_embedded_path_var)
|
||||
|
||||
# On Windows and Linux, "embed" prerequisites in the same directory
|
||||
# as the executable by default:
|
||||
#
|
||||
set(path "@executable_path")
|
||||
set(overridden 0)
|
||||
|
||||
# On the Mac, relative to the executable depending on the type
|
||||
# of the thing we are embedding:
|
||||
#
|
||||
if(APPLE)
|
||||
#
|
||||
# The assumption here is that all executables in the bundle will be
|
||||
# in same-level-directories inside the bundle. The parent directory
|
||||
# of an executable inside the bundle should be MacOS or a sibling of
|
||||
# MacOS and all embedded paths returned from here will begin with
|
||||
# "@executable_path/../" and will work from all executables in all
|
||||
# such same-level-directories inside the bundle.
|
||||
#
|
||||
|
||||
# By default, embed things right next to the main bundle executable:
|
||||
#
|
||||
set(path "@executable_path/../../Contents/MacOS")
|
||||
|
||||
# Embed .dylibs right next to the main bundle executable:
|
||||
#
|
||||
if(item MATCHES "\\.dylib$")
|
||||
set(path "@executable_path/../MacOS")
|
||||
set(overridden 1)
|
||||
endif()
|
||||
|
||||
# Embed frameworks in the embedded "Frameworks" directory (sibling of MacOS):
|
||||
#
|
||||
if(NOT overridden)
|
||||
if(item MATCHES "[^/]+\\.framework/")
|
||||
set(path "@executable_path/../Frameworks")
|
||||
set(overridden 1)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Provide a hook so that projects can override the default embedded location
|
||||
# of any given library by whatever logic they choose:
|
||||
#
|
||||
if(COMMAND gp_item_default_embedded_path_override)
|
||||
gp_item_default_embedded_path_override("${item}" path)
|
||||
endif()
|
||||
|
||||
set(${default_embedded_path_var} "${path}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(gp_resolve_item context item exepath dirs resolved_item_var)
|
||||
set(resolved 0)
|
||||
set(resolved_item "${item}")
|
||||
|
||||
# Is it already resolved?
|
||||
#
|
||||
if(IS_ABSOLUTE "${resolved_item}" AND EXISTS "${resolved_item}")
|
||||
set(resolved 1)
|
||||
endif()
|
||||
|
||||
if(NOT resolved)
|
||||
if(item MATCHES "@executable_path")
|
||||
#
|
||||
# @executable_path references are assumed relative to exepath
|
||||
#
|
||||
string(REPLACE "@executable_path" "${exepath}" ri "${item}")
|
||||
get_filename_component(ri "${ri}" ABSOLUTE)
|
||||
|
||||
if(EXISTS "${ri}")
|
||||
#message(STATUS "info: embedded item exists (${ri})")
|
||||
set(resolved 1)
|
||||
set(resolved_item "${ri}")
|
||||
else()
|
||||
message(STATUS "warning: embedded item does not exist '${ri}'")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT resolved)
|
||||
if(item MATCHES "@loader_path")
|
||||
#
|
||||
# @loader_path references are assumed relative to the
|
||||
# PATH of the given "context" (presumably another library)
|
||||
#
|
||||
get_filename_component(contextpath "${context}" PATH)
|
||||
string(REPLACE "@loader_path" "${contextpath}" ri "${item}")
|
||||
get_filename_component(ri "${ri}" ABSOLUTE)
|
||||
|
||||
if(EXISTS "${ri}")
|
||||
#message(STATUS "info: embedded item exists (${ri})")
|
||||
set(resolved 1)
|
||||
set(resolved_item "${ri}")
|
||||
else()
|
||||
message(STATUS "warning: embedded item does not exist '${ri}'")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT resolved)
|
||||
if(item MATCHES "@rpath")
|
||||
#
|
||||
# @rpath references are relative to the paths built into the binaries with -rpath
|
||||
# We handle this case like we do for other Unixes
|
||||
#
|
||||
string(REPLACE "@rpath/" "" norpath_item "${item}")
|
||||
|
||||
set(ri "ri-NOTFOUND")
|
||||
find_file(ri "${norpath_item}" ${exepath} ${dirs} NO_DEFAULT_PATH)
|
||||
if(ri)
|
||||
#message(STATUS "info: 'find_file' in exepath/dirs (${ri})")
|
||||
set(resolved 1)
|
||||
set(resolved_item "${ri}")
|
||||
set(ri "ri-NOTFOUND")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT resolved)
|
||||
set(ri "ri-NOTFOUND")
|
||||
find_file(ri "${item}" ${exepath} ${dirs} NO_DEFAULT_PATH)
|
||||
find_file(ri "${item}" ${exepath} ${dirs} /usr/lib)
|
||||
if(ri)
|
||||
#message(STATUS "info: 'find_file' in exepath/dirs (${ri})")
|
||||
set(resolved 1)
|
||||
set(resolved_item "${ri}")
|
||||
set(ri "ri-NOTFOUND")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT resolved)
|
||||
if(item MATCHES "[^/]+\\.framework/")
|
||||
set(fw "fw-NOTFOUND")
|
||||
find_file(fw "${item}"
|
||||
"~/Library/Frameworks"
|
||||
"/Library/Frameworks"
|
||||
"/System/Library/Frameworks"
|
||||
)
|
||||
if(fw)
|
||||
#message(STATUS "info: 'find_file' found framework (${fw})")
|
||||
set(resolved 1)
|
||||
set(resolved_item "${fw}")
|
||||
set(fw "fw-NOTFOUND")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Using find_program on Windows will find dll files that are in the PATH.
|
||||
# (Converting simple file names into full path names if found.)
|
||||
#
|
||||
if(WIN32 AND NOT UNIX)
|
||||
if(NOT resolved)
|
||||
set(ri "ri-NOTFOUND")
|
||||
find_program(ri "${item}" PATHS "${exepath};${dirs}" NO_DEFAULT_PATH)
|
||||
find_program(ri "${item}" PATHS "${exepath};${dirs}")
|
||||
if(ri)
|
||||
#message(STATUS "info: 'find_program' in exepath/dirs (${ri})")
|
||||
set(resolved 1)
|
||||
set(resolved_item "${ri}")
|
||||
set(ri "ri-NOTFOUND")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Provide a hook so that projects can override item resolution
|
||||
# by whatever logic they choose:
|
||||
#
|
||||
if(COMMAND gp_resolve_item_override)
|
||||
gp_resolve_item_override("${context}" "${item}" "${exepath}" "${dirs}" resolved_item resolved)
|
||||
endif()
|
||||
|
||||
if(NOT resolved)
|
||||
message(STATUS "
|
||||
warning: cannot resolve item '${item}'
|
||||
|
||||
possible problems:
|
||||
need more directories?
|
||||
need to use InstallRequiredSystemLibraries?
|
||||
run in install tree instead of build tree?
|
||||
")
|
||||
# message(STATUS "
|
||||
#******************************************************************************
|
||||
#warning: cannot resolve item '${item}'
|
||||
#
|
||||
# possible problems:
|
||||
# need more directories?
|
||||
# need to use InstallRequiredSystemLibraries?
|
||||
# run in install tree instead of build tree?
|
||||
#
|
||||
# context='${context}'
|
||||
# item='${item}'
|
||||
# exepath='${exepath}'
|
||||
# dirs='${dirs}'
|
||||
# resolved_item_var='${resolved_item_var}'
|
||||
#******************************************************************************
|
||||
#")
|
||||
endif()
|
||||
|
||||
set(${resolved_item_var} "${resolved_item}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(gp_resolved_file_type original_file file exepath dirs type_var)
|
||||
#message(STATUS "**")
|
||||
|
||||
if(NOT IS_ABSOLUTE "${original_file}")
|
||||
message(STATUS "warning: gp_resolved_file_type expects absolute full path for first arg original_file")
|
||||
endif()
|
||||
|
||||
set(is_embedded 0)
|
||||
set(is_local 0)
|
||||
set(is_system 0)
|
||||
|
||||
set(resolved_file "${file}")
|
||||
|
||||
if("${file}" MATCHES "^@(executable|loader)_path")
|
||||
set(is_embedded 1)
|
||||
endif()
|
||||
|
||||
if(NOT is_embedded)
|
||||
if(NOT IS_ABSOLUTE "${file}")
|
||||
gp_resolve_item("${original_file}" "${file}" "${exepath}" "${dirs}" resolved_file)
|
||||
endif()
|
||||
|
||||
string(TOLOWER "${original_file}" original_lower)
|
||||
string(TOLOWER "${resolved_file}" lower)
|
||||
|
||||
if(UNIX)
|
||||
if(resolved_file MATCHES "^(/lib/|/lib32/|/lib64/|/usr/lib/|/usr/lib32/|/usr/lib64/|/usr/X11R6/|/usr/bin/)")
|
||||
set(is_system 1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
if(resolved_file MATCHES "^(/System/Library/|/usr/lib/)")
|
||||
set(is_system 1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
string(TOLOWER "$ENV{SystemRoot}" sysroot)
|
||||
string(REGEX REPLACE "\\\\" "/" sysroot "${sysroot}")
|
||||
|
||||
string(TOLOWER "$ENV{windir}" windir)
|
||||
string(REGEX REPLACE "\\\\" "/" windir "${windir}")
|
||||
|
||||
if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*msvc[^/]+dll)")
|
||||
set(is_system 1)
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
# if cygwin, we can get the properly formed windows paths from cygpath
|
||||
find_program(CYGPATH_EXECUTABLE cygpath)
|
||||
|
||||
if(CYGPATH_EXECUTABLE)
|
||||
execute_process(COMMAND ${CYGPATH_EXECUTABLE} -W
|
||||
OUTPUT_VARIABLE env_windir
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
execute_process(COMMAND ${CYGPATH_EXECUTABLE} -S
|
||||
OUTPUT_VARIABLE env_sysdir
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
string(TOLOWER "${env_windir}" windir)
|
||||
string(TOLOWER "${env_sysdir}" sysroot)
|
||||
|
||||
if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*msvc[^/]+dll)")
|
||||
set(is_system 1)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT is_system)
|
||||
get_filename_component(original_path "${original_lower}" PATH)
|
||||
get_filename_component(path "${lower}" PATH)
|
||||
if("${original_path}" STREQUAL "${path}")
|
||||
set(is_local 1)
|
||||
else()
|
||||
string(LENGTH "${original_path}/" original_length)
|
||||
string(LENGTH "${lower}" path_length)
|
||||
if(${path_length} GREATER ${original_length})
|
||||
string(SUBSTRING "${lower}" 0 ${original_length} path)
|
||||
if("${original_path}/" STREQUAL "${path}")
|
||||
set(is_embedded 1)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Return type string based on computed booleans:
|
||||
#
|
||||
set(type "other")
|
||||
|
||||
if(is_system)
|
||||
set(type "system")
|
||||
elseif(is_embedded)
|
||||
set(type "embedded")
|
||||
elseif(is_local)
|
||||
set(type "local")
|
||||
endif()
|
||||
|
||||
#message(STATUS "gp_resolved_file_type: '${file}' '${resolved_file}'")
|
||||
#message(STATUS " type: '${type}'")
|
||||
|
||||
if(NOT is_embedded)
|
||||
if(NOT IS_ABSOLUTE "${resolved_file}")
|
||||
if(lower MATCHES "^msvc[^/]+dll" AND is_system)
|
||||
message(STATUS "info: non-absolute msvc file '${file}' returning type '${type}'")
|
||||
else()
|
||||
message(STATUS "warning: gp_resolved_file_type non-absolute file '${file}' returning type '${type}' -- possibly incorrect")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Provide a hook so that projects can override the decision on whether a
|
||||
# library belongs to the system or not by whatever logic they choose:
|
||||
#
|
||||
if(COMMAND gp_resolved_file_type_override)
|
||||
gp_resolved_file_type_override("${resolved_file}" type)
|
||||
endif()
|
||||
|
||||
set(${type_var} "${type}" PARENT_SCOPE)
|
||||
|
||||
#message(STATUS "**")
|
||||
endfunction()
|
||||
|
||||
|
||||
function(gp_file_type original_file file type_var)
|
||||
if(NOT IS_ABSOLUTE "${original_file}")
|
||||
message(STATUS "warning: gp_file_type expects absolute full path for first arg original_file")
|
||||
endif()
|
||||
|
||||
get_filename_component(exepath "${original_file}" PATH)
|
||||
|
||||
set(type "")
|
||||
gp_resolved_file_type("${original_file}" "${file}" "${exepath}" "" type)
|
||||
|
||||
set(${type_var} "${type}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(get_prerequisites target prerequisites_var exclude_system recurse exepath dirs)
|
||||
set(verbose 0)
|
||||
set(eol_char "E")
|
||||
|
||||
if(NOT IS_ABSOLUTE "${target}")
|
||||
message("warning: target '${target}' is not absolute...")
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${target}")
|
||||
message("warning: target '${target}' does not exist...")
|
||||
endif()
|
||||
|
||||
set(gp_cmd_paths ${gp_cmd_paths}
|
||||
"C:/Program Files/Microsoft Visual Studio 9.0/VC/bin"
|
||||
"C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin"
|
||||
"C:/Program Files/Microsoft Visual Studio 8/VC/BIN"
|
||||
"C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN"
|
||||
"C:/Program Files/Microsoft Visual Studio .NET 2003/VC7/BIN"
|
||||
"C:/Program Files (x86)/Microsoft Visual Studio .NET 2003/VC7/BIN"
|
||||
"/usr/local/bin"
|
||||
"/usr/bin"
|
||||
)
|
||||
|
||||
# <setup-gp_tool-vars>
|
||||
#
|
||||
# Try to choose the right tool by default. Caller can set gp_tool prior to
|
||||
# calling this function to force using a different tool.
|
||||
#
|
||||
if("${gp_tool}" STREQUAL "")
|
||||
set(gp_tool "ldd")
|
||||
|
||||
if(APPLE)
|
||||
set(gp_tool "otool")
|
||||
endif()
|
||||
|
||||
if(WIN32 AND NOT UNIX) # This is how to check for cygwin, har!
|
||||
find_program(gp_dumpbin "dumpbin" PATHS ${gp_cmd_paths})
|
||||
if(gp_dumpbin)
|
||||
set(gp_tool "dumpbin")
|
||||
else() # Try harder. Maybe we're on MinGW
|
||||
set(gp_tool "objdump")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_program(gp_cmd ${gp_tool} PATHS ${gp_cmd_paths})
|
||||
|
||||
if(NOT gp_cmd)
|
||||
message(FATAL_ERROR "FATAL ERROR: could not find '${gp_tool}' - cannot analyze prerequisites!")
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(gp_tool_known 0)
|
||||
|
||||
if("${gp_tool}" STREQUAL "ldd")
|
||||
set(gp_cmd_args "")
|
||||
set(gp_regex "^[\t ]*[^\t ]+ => ([^\t\(]+) .*${eol_char}$")
|
||||
set(gp_regex_error "not found${eol_char}$")
|
||||
set(gp_regex_fallback "^[\t ]*([^\t ]+) => ([^\t ]+).*${eol_char}$")
|
||||
set(gp_regex_cmp_count 1)
|
||||
set(gp_tool_known 1)
|
||||
endif()
|
||||
|
||||
if("${gp_tool}" STREQUAL "otool")
|
||||
set(gp_cmd_args "-L")
|
||||
set(gp_regex "^\t([^\t]+) \\(compatibility version ([0-9]+.[0-9]+.[0-9]+), current version ([0-9]+.[0-9]+.[0-9]+)\\)${eol_char}$")
|
||||
set(gp_regex_error "")
|
||||
set(gp_regex_fallback "")
|
||||
set(gp_regex_cmp_count 3)
|
||||
set(gp_tool_known 1)
|
||||
endif()
|
||||
|
||||
if("${gp_tool}" STREQUAL "dumpbin")
|
||||
set(gp_cmd_args "/dependents")
|
||||
set(gp_regex "^ ([^ ].*[Dd][Ll][Ll])${eol_char}$")
|
||||
set(gp_regex_error "")
|
||||
set(gp_regex_fallback "")
|
||||
set(gp_regex_cmp_count 1)
|
||||
set(gp_tool_known 1)
|
||||
endif()
|
||||
|
||||
if("${gp_tool}" STREQUAL "objdump")
|
||||
set(gp_cmd_args "-p")
|
||||
set(gp_regex "^\t*DLL Name: (.*\\.[Dd][Ll][Ll])${eol_char}$")
|
||||
set(gp_regex_error "")
|
||||
set(gp_regex_fallback "")
|
||||
set(gp_regex_cmp_count 1)
|
||||
set(gp_tool_known 1)
|
||||
endif()
|
||||
|
||||
if(NOT gp_tool_known)
|
||||
message(STATUS "warning: gp_tool='${gp_tool}' is an unknown tool...")
|
||||
message(STATUS "CMake function get_prerequisites needs more code to handle '${gp_tool}'")
|
||||
message(STATUS "Valid gp_tool values are dumpbin, ldd, objdump and otool.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
|
||||
if("${gp_tool}" STREQUAL "dumpbin")
|
||||
# When running dumpbin, it also needs the "Common7/IDE" directory in the
|
||||
# PATH. It will already be in the PATH if being run from a Visual Studio
|
||||
# command prompt. Add it to the PATH here in case we are running from a
|
||||
# different command prompt.
|
||||
#
|
||||
get_filename_component(gp_cmd_dir "${gp_cmd}" PATH)
|
||||
get_filename_component(gp_cmd_dlls_dir "${gp_cmd_dir}/../../Common7/IDE" ABSOLUTE)
|
||||
# Use cmake paths as a user may have a PATH element ending with a backslash.
|
||||
# This will escape the list delimiter and create havoc!
|
||||
if(EXISTS "${gp_cmd_dlls_dir}")
|
||||
# only add to the path if it is not already in the path
|
||||
set(gp_found_cmd_dlls_dir 0)
|
||||
file(TO_CMAKE_PATH "$ENV{PATH}" env_path)
|
||||
foreach(gp_env_path_element ${env_path})
|
||||
if("${gp_env_path_element}" STREQUAL "${gp_cmd_dlls_dir}")
|
||||
set(gp_found_cmd_dlls_dir 1)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(NOT gp_found_cmd_dlls_dir)
|
||||
file(TO_NATIVE_PATH "${gp_cmd_dlls_dir}" gp_cmd_dlls_dir)
|
||||
set(ENV{PATH} "$ENV{PATH};${gp_cmd_dlls_dir}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
#
|
||||
# </setup-gp_tool-vars>
|
||||
|
||||
if("${gp_tool}" STREQUAL "ldd")
|
||||
set(old_ld_env "$ENV{LD_LIBRARY_PATH}")
|
||||
foreach(dir ${exepath} ${dirs})
|
||||
set(ENV{LD_LIBRARY_PATH} "${dir}:$ENV{LD_LIBRARY_PATH}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
|
||||
# Track new prerequisites at each new level of recursion. Start with an
|
||||
# empty list at each level:
|
||||
#
|
||||
set(unseen_prereqs)
|
||||
|
||||
# Run gp_cmd on the target:
|
||||
#
|
||||
execute_process(
|
||||
COMMAND ${gp_cmd} ${gp_cmd_args} ${target}
|
||||
OUTPUT_VARIABLE gp_cmd_ov
|
||||
)
|
||||
|
||||
if("${gp_tool}" STREQUAL "ldd")
|
||||
set(ENV{LD_LIBRARY_PATH} "${old_ld_env}")
|
||||
endif()
|
||||
|
||||
if(verbose)
|
||||
message(STATUS "<RawOutput cmd='${gp_cmd} ${gp_cmd_args} ${target}'>")
|
||||
message(STATUS "gp_cmd_ov='${gp_cmd_ov}'")
|
||||
message(STATUS "</RawOutput>")
|
||||
endif()
|
||||
|
||||
get_filename_component(target_dir "${target}" PATH)
|
||||
|
||||
# Convert to a list of lines:
|
||||
#
|
||||
string(REGEX REPLACE ";" "\\\\;" candidates "${gp_cmd_ov}")
|
||||
string(REGEX REPLACE "\n" "${eol_char};" candidates "${candidates}")
|
||||
|
||||
# check for install id and remove it from list, since otool -L can include a
|
||||
# reference to itself
|
||||
set(gp_install_id)
|
||||
if("${gp_tool}" STREQUAL "otool")
|
||||
execute_process(
|
||||
COMMAND otool -D ${target}
|
||||
OUTPUT_VARIABLE gp_install_id_ov
|
||||
)
|
||||
# second line is install name
|
||||
string(REGEX REPLACE ".*:\n" "" gp_install_id "${gp_install_id_ov}")
|
||||
if(gp_install_id)
|
||||
# trim
|
||||
string(REGEX MATCH "[^\n ].*[^\n ]" gp_install_id "${gp_install_id}")
|
||||
#message("INSTALL ID is \"${gp_install_id}\"")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Analyze each line for file names that match the regular expression:
|
||||
#
|
||||
foreach(candidate ${candidates})
|
||||
if("${candidate}" MATCHES "${gp_regex}")
|
||||
|
||||
# Extract information from each candidate:
|
||||
if(gp_regex_error AND "${candidate}" MATCHES "${gp_regex_error}")
|
||||
string(REGEX REPLACE "${gp_regex_fallback}" "\\1" raw_item "${candidate}")
|
||||
else()
|
||||
string(REGEX REPLACE "${gp_regex}" "\\1" raw_item "${candidate}")
|
||||
endif()
|
||||
|
||||
if(gp_regex_cmp_count GREATER 1)
|
||||
string(REGEX REPLACE "${gp_regex}" "\\2" raw_compat_version "${candidate}")
|
||||
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" compat_major_version "${raw_compat_version}")
|
||||
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" compat_minor_version "${raw_compat_version}")
|
||||
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" compat_patch_version "${raw_compat_version}")
|
||||
endif()
|
||||
|
||||
if(gp_regex_cmp_count GREATER 2)
|
||||
string(REGEX REPLACE "${gp_regex}" "\\3" raw_current_version "${candidate}")
|
||||
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" current_major_version "${raw_current_version}")
|
||||
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" current_minor_version "${raw_current_version}")
|
||||
string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" current_patch_version "${raw_current_version}")
|
||||
endif()
|
||||
|
||||
# Use the raw_item as the list entries returned by this function. Use the
|
||||
# gp_resolve_item function to resolve it to an actual full path file if
|
||||
# necessary.
|
||||
#
|
||||
set(item "${raw_item}")
|
||||
|
||||
# Add each item unless it is excluded:
|
||||
#
|
||||
set(add_item 1)
|
||||
|
||||
if("${item}" STREQUAL "${gp_install_id}")
|
||||
set(add_item 0)
|
||||
endif()
|
||||
|
||||
if(add_item AND ${exclude_system})
|
||||
set(type "")
|
||||
gp_resolved_file_type("${target}" "${item}" "${exepath}" "${dirs}" type)
|
||||
|
||||
if("${type}" STREQUAL "system")
|
||||
set(add_item 0)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(add_item)
|
||||
list(LENGTH ${prerequisites_var} list_length_before_append)
|
||||
gp_append_unique(${prerequisites_var} "${item}")
|
||||
list(LENGTH ${prerequisites_var} list_length_after_append)
|
||||
|
||||
if(${recurse})
|
||||
# If item was really added, this is the first time we have seen it.
|
||||
# Add it to unseen_prereqs so that we can recursively add *its*
|
||||
# prerequisites...
|
||||
#
|
||||
# But first: resolve its name to an absolute full path name such
|
||||
# that the analysis tools can simply accept it as input.
|
||||
#
|
||||
if(NOT list_length_before_append EQUAL list_length_after_append)
|
||||
gp_resolve_item("${target}" "${item}" "${exepath}" "${dirs}" resolved_item)
|
||||
set(unseen_prereqs ${unseen_prereqs} "${resolved_item}")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
if(verbose)
|
||||
message(STATUS "ignoring non-matching line: '${candidate}'")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
list(LENGTH ${prerequisites_var} prerequisites_var_length)
|
||||
if(prerequisites_var_length GREATER 0)
|
||||
list(SORT ${prerequisites_var})
|
||||
endif()
|
||||
if(${recurse})
|
||||
set(more_inputs ${unseen_prereqs})
|
||||
foreach(input ${more_inputs})
|
||||
get_prerequisites("${input}" ${prerequisites_var} ${exclude_system} ${recurse} "${exepath}" "${dirs}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
set(${prerequisites_var} ${${prerequisites_var}} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(list_prerequisites target)
|
||||
if("${ARGV1}" STREQUAL "")
|
||||
set(all 1)
|
||||
else()
|
||||
set(all "${ARGV1}")
|
||||
endif()
|
||||
|
||||
if("${ARGV2}" STREQUAL "")
|
||||
set(exclude_system 0)
|
||||
else()
|
||||
set(exclude_system "${ARGV2}")
|
||||
endif()
|
||||
|
||||
if("${ARGV3}" STREQUAL "")
|
||||
set(verbose 0)
|
||||
else()
|
||||
set(verbose "${ARGV3}")
|
||||
endif()
|
||||
|
||||
set(count 0)
|
||||
set(count_str "")
|
||||
set(print_count "${verbose}")
|
||||
set(print_prerequisite_type "${verbose}")
|
||||
set(print_target "${verbose}")
|
||||
set(type_str "")
|
||||
|
||||
get_filename_component(exepath "${target}" PATH)
|
||||
|
||||
set(prereqs "")
|
||||
get_prerequisites("${target}" prereqs ${exclude_system} ${all} "${exepath}" "")
|
||||
|
||||
if(print_target)
|
||||
message(STATUS "File '${target}' depends on:")
|
||||
endif()
|
||||
|
||||
foreach(d ${prereqs})
|
||||
math(EXPR count "${count} + 1")
|
||||
|
||||
if(print_count)
|
||||
set(count_str "${count}. ")
|
||||
endif()
|
||||
|
||||
if(print_prerequisite_type)
|
||||
gp_file_type("${target}" "${d}" type)
|
||||
set(type_str " (${type})")
|
||||
endif()
|
||||
|
||||
message(STATUS "${count_str}${d}${type_str}")
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(list_prerequisites_by_glob glob_arg glob_exp)
|
||||
message(STATUS "=============================================================================")
|
||||
message(STATUS "List prerequisites of executables matching ${glob_arg} '${glob_exp}'")
|
||||
message(STATUS "")
|
||||
file(${glob_arg} file_list ${glob_exp})
|
||||
foreach(f ${file_list})
|
||||
is_file_executable("${f}" is_f_executable)
|
||||
if(is_f_executable)
|
||||
message(STATUS "=============================================================================")
|
||||
list_prerequisites("${f}" ${ARGN})
|
||||
message(STATUS "")
|
||||
endif()
|
||||
endforeach()
|
||||
endfunction()
|
@ -2,6 +2,10 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>A Minecraft mod wants to access your camera.</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>A Minecraft mod wants to access your microphone.</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
|
@ -5,44 +5,46 @@ set(TEST_RESOURCE_PATH ${CMAKE_CURRENT_LIST_DIR})
|
||||
message(${TEST_RESOURCE_PATH})
|
||||
|
||||
function(add_unit_test name)
|
||||
set(options "")
|
||||
set(oneValueArgs DATA)
|
||||
set(multiValueArgs SOURCES LIBS)
|
||||
if(BUILD_TESTING)
|
||||
set(options "")
|
||||
set(oneValueArgs DATA)
|
||||
set(multiValueArgs SOURCES LIBS)
|
||||
|
||||
cmake_parse_arguments(OPT "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
|
||||
cmake_parse_arguments(OPT "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
|
||||
|
||||
if(WIN32)
|
||||
add_executable(${name}_test ${OPT_SOURCES} ${TEST_RESOURCE_PATH}/UnitTest/test.rc)
|
||||
else()
|
||||
add_executable(${name}_test ${OPT_SOURCES})
|
||||
endif()
|
||||
|
||||
if(NOT "${OPT_DATA}" STREQUAL "")
|
||||
set(TEST_DATA_PATH "${CMAKE_CURRENT_BINARY_DIR}/data")
|
||||
set(TEST_DATA_PATH_SRC "${CMAKE_CURRENT_SOURCE_DIR}/${OPT_DATA}")
|
||||
message("From ${TEST_DATA_PATH_SRC} to ${TEST_DATA_PATH}")
|
||||
string(REGEX REPLACE "[/\\:]" "_" DATA_TARGET_NAME "${TEST_DATA_PATH_SRC}")
|
||||
if(UNIX)
|
||||
# on unix we get the third / from the filename
|
||||
set(TEST_DATA_URL "file://${TEST_DATA_PATH}")
|
||||
if(WIN32)
|
||||
add_executable(${name}_test ${OPT_SOURCES} ${TEST_RESOURCE_PATH}/UnitTest/test.rc)
|
||||
else()
|
||||
# we don't on windows, so we have to add it ourselves
|
||||
set(TEST_DATA_URL "file:///${TEST_DATA_PATH}")
|
||||
add_executable(${name}_test ${OPT_SOURCES})
|
||||
endif()
|
||||
if(NOT TARGET "${DATA_TARGET_NAME}")
|
||||
add_custom_target(${DATA_TARGET_NAME})
|
||||
add_dependencies(${name}_test ${DATA_TARGET_NAME})
|
||||
add_custom_command(
|
||||
TARGET ${DATA_TARGET_NAME}
|
||||
COMMAND ${CMAKE_COMMAND} "-DTEST_DATA_URL=${TEST_DATA_URL}" -DSOURCE=${TEST_DATA_PATH_SRC} -DDESTINATION=${TEST_DATA_PATH} -P ${TEST_RESOURCE_PATH}/UnitTest/generate_test_data.cmake
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
if(NOT "${OPT_DATA}" STREQUAL "")
|
||||
set(TEST_DATA_PATH "${CMAKE_CURRENT_BINARY_DIR}/data")
|
||||
set(TEST_DATA_PATH_SRC "${CMAKE_CURRENT_SOURCE_DIR}/${OPT_DATA}")
|
||||
message("From ${TEST_DATA_PATH_SRC} to ${TEST_DATA_PATH}")
|
||||
string(REGEX REPLACE "[/\\:]" "_" DATA_TARGET_NAME "${TEST_DATA_PATH_SRC}")
|
||||
if(UNIX)
|
||||
# on unix we get the third / from the filename
|
||||
set(TEST_DATA_URL "file://${TEST_DATA_PATH}")
|
||||
else()
|
||||
# we don't on windows, so we have to add it ourselves
|
||||
set(TEST_DATA_URL "file:///${TEST_DATA_PATH}")
|
||||
endif()
|
||||
if(NOT TARGET "${DATA_TARGET_NAME}")
|
||||
add_custom_target(${DATA_TARGET_NAME})
|
||||
add_dependencies(${name}_test ${DATA_TARGET_NAME})
|
||||
add_custom_command(
|
||||
TARGET ${DATA_TARGET_NAME}
|
||||
COMMAND ${CMAKE_COMMAND} "-DTEST_DATA_URL=${TEST_DATA_URL}" -DSOURCE=${TEST_DATA_PATH_SRC} -DDESTINATION=${TEST_DATA_PATH} -P ${TEST_RESOURCE_PATH}/UnitTest/generate_test_data.cmake
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_link_libraries(${name}_test Qt5::Test ${OPT_LIBS})
|
||||
|
||||
target_include_directories(${name}_test PRIVATE "${TEST_RESOURCE_PATH}/UnitTest/")
|
||||
|
||||
add_test(NAME ${name} COMMAND ${name}_test WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
endif()
|
||||
|
||||
target_link_libraries(${name}_test Qt5::Test ${OPT_LIBS})
|
||||
|
||||
target_include_directories(${name}_test PRIVATE "${TEST_RESOURCE_PATH}/UnitTest/")
|
||||
|
||||
add_test(NAME ${name} COMMAND ${name}_test WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
endfunction()
|
||||
|
@ -14,7 +14,7 @@ BEGIN
|
||||
BEGIN
|
||||
BLOCK "000004b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "MultiMC Contributors"
|
||||
VALUE "CompanyName", "MultiMC & PolyMC Contributors"
|
||||
VALUE "FileDescription", "Testcase"
|
||||
VALUE "FileVersion", "1.0.0.0"
|
||||
VALUE "ProductName", "Launcher Testcase"
|
||||
|
@ -1,881 +0,0 @@
|
||||
# - Use Module for Java
|
||||
# This file provides functions for Java. It is assumed that FindJava.cmake
|
||||
# has already been loaded. See FindJava.cmake for information on how to
|
||||
# load Java into your CMake project.
|
||||
#
|
||||
# add_jar(TARGET_NAME SRC1 SRC2 .. SRCN RCS1 RCS2 .. RCSN)
|
||||
#
|
||||
# This command creates a <TARGET_NAME>.jar. It compiles the given source
|
||||
# files (SRC) and adds the given resource files (RCS) to the jar file.
|
||||
# If only resource files are given then just a jar file is created.
|
||||
#
|
||||
# Additional instructions:
|
||||
# To add compile flags to the target you can set these flags with
|
||||
# the following variable:
|
||||
#
|
||||
# set(CMAKE_JAVA_COMPILE_FLAGS -nowarn)
|
||||
#
|
||||
# To add a path or a jar file to the class path you can do this
|
||||
# with the CMAKE_JAVA_INCLUDE_PATH variable.
|
||||
#
|
||||
# set(CMAKE_JAVA_INCLUDE_PATH /usr/share/java/shibboleet.jar)
|
||||
#
|
||||
# To use a different output name for the target you can set it with:
|
||||
#
|
||||
# set(CMAKE_JAVA_TARGET_OUTPUT_NAME shibboleet.jar)
|
||||
# add_jar(foobar foobar.java)
|
||||
#
|
||||
# To use a different output directory than CMAKE_CURRENT_BINARY_DIR
|
||||
# you can set it with:
|
||||
#
|
||||
# set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${PROJECT_BINARY_DIR}/bin)
|
||||
#
|
||||
# To define an entry point in your jar you can set it with:
|
||||
#
|
||||
# set(CMAKE_JAVA_JAR_ENTRY_POINT com/examples/MyProject/Main)
|
||||
#
|
||||
# To add a VERSION to the target output name you can set it using
|
||||
# CMAKE_JAVA_TARGET_VERSION. This will create a jar file with the name
|
||||
# shibboleet-1.0.0.jar and will create a symlink shibboleet.jar
|
||||
# pointing to the jar with the version information.
|
||||
#
|
||||
# set(CMAKE_JAVA_TARGET_VERSION 1.2.0)
|
||||
# add_jar(shibboleet shibbotleet.java)
|
||||
#
|
||||
# If the target is a JNI library, utilize the following commands to
|
||||
# create a JNI symbolic link:
|
||||
#
|
||||
# set(CMAKE_JNI_TARGET TRUE)
|
||||
# set(CMAKE_JAVA_TARGET_VERSION 1.2.0)
|
||||
# add_jar(shibboleet shibbotleet.java)
|
||||
# install_jar(shibboleet ${LIB_INSTALL_DIR}/shibboleet)
|
||||
# install_jni_symlink(shibboleet ${JAVA_LIB_INSTALL_DIR})
|
||||
#
|
||||
# If a single target needs to produce more than one jar from its
|
||||
# java source code, to prevent the accumulation of duplicate class
|
||||
# files in subsequent jars, set/reset CMAKE_JAR_CLASSES_PREFIX prior
|
||||
# to calling the add_jar() function:
|
||||
#
|
||||
# set(CMAKE_JAR_CLASSES_PREFIX com/redhat/foo)
|
||||
# add_jar(foo foo.java)
|
||||
#
|
||||
# set(CMAKE_JAR_CLASSES_PREFIX com/redhat/bar)
|
||||
# add_jar(bar bar.java)
|
||||
#
|
||||
# Target Properties:
|
||||
# The add_jar() functions sets some target properties. You can get these
|
||||
# properties with the
|
||||
# get_property(TARGET <target_name> PROPERTY <propery_name>)
|
||||
# command.
|
||||
#
|
||||
# INSTALL_FILES The files which should be installed. This is used by
|
||||
# install_jar().
|
||||
# JNI_SYMLINK The JNI symlink which should be installed.
|
||||
# This is used by install_jni_symlink().
|
||||
# JAR_FILE The location of the jar file so that you can include
|
||||
# it.
|
||||
# CLASS_DIR The directory where the class files can be found. For
|
||||
# example to use them with javah.
|
||||
#
|
||||
# find_jar(<VAR>
|
||||
# name | NAMES name1 [name2 ...]
|
||||
# [PATHS path1 [path2 ... ENV var]]
|
||||
# [VERSIONS version1 [version2]]
|
||||
# [DOC "cache documentation string"]
|
||||
# )
|
||||
#
|
||||
# This command is used to find a full path to the named jar. A cache
|
||||
# entry named by <VAR> is created to stor the result of this command. If
|
||||
# the full path to a jar is found the result is stored in the variable
|
||||
# and the search will not repeated unless the variable is cleared. If
|
||||
# nothing is found, the result will be <VAR>-NOTFOUND, and the search
|
||||
# will be attempted again next time find_jar is invoked with the same
|
||||
# variable.
|
||||
# The name of the full path to a file that is searched for is specified
|
||||
# by the names listed after NAMES argument. Additional search locations
|
||||
# can be specified after the PATHS argument. If you require special a
|
||||
# version of a jar file you can specify it with the VERSIONS argument.
|
||||
# The argument after DOC will be used for the documentation string in
|
||||
# the cache.
|
||||
#
|
||||
# install_jar(TARGET_NAME DESTINATION)
|
||||
#
|
||||
# This command installs the TARGET_NAME files to the given DESTINATION.
|
||||
# It should be called in the same scope as add_jar() or it will fail.
|
||||
#
|
||||
# install_jni_symlink(TARGET_NAME DESTINATION)
|
||||
#
|
||||
# This command installs the TARGET_NAME JNI symlinks to the given
|
||||
# DESTINATION. It should be called in the same scope as add_jar()
|
||||
# or it will fail.
|
||||
#
|
||||
# create_javadoc(<VAR>
|
||||
# PACKAGES pkg1 [pkg2 ...]
|
||||
# [SOURCEPATH <sourcepath>]
|
||||
# [CLASSPATH <classpath>]
|
||||
# [INSTALLPATH <install path>]
|
||||
# [DOCTITLE "the documentation title"]
|
||||
# [WINDOWTITLE "the title of the document"]
|
||||
# [AUTHOR TRUE|FALSE]
|
||||
# [USE TRUE|FALSE]
|
||||
# [VERSION TRUE|FALSE]
|
||||
# )
|
||||
#
|
||||
# Create java documentation based on files or packages. For more
|
||||
# details please read the javadoc manpage.
|
||||
#
|
||||
# There are two main signatures for create_javadoc. The first
|
||||
# signature works with package names on a path with source files:
|
||||
#
|
||||
# Example:
|
||||
# create_javadoc(my_example_doc
|
||||
# PACKAGES com.exmaple.foo com.example.bar
|
||||
# SOURCEPATH "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
# CLASSPATH ${CMAKE_JAVA_INCLUDE_PATH}
|
||||
# WINDOWTITLE "My example"
|
||||
# DOCTITLE "<h1>My example</h1>"
|
||||
# AUTHOR TRUE
|
||||
# USE TRUE
|
||||
# VERSION TRUE
|
||||
# )
|
||||
#
|
||||
# The second signature for create_javadoc works on a given list of
|
||||
# files.
|
||||
#
|
||||
# create_javadoc(<VAR>
|
||||
# FILES file1 [file2 ...]
|
||||
# [CLASSPATH <classpath>]
|
||||
# [INSTALLPATH <install path>]
|
||||
# [DOCTITLE "the documentation title"]
|
||||
# [WINDOWTITLE "the title of the document"]
|
||||
# [AUTHOR TRUE|FALSE]
|
||||
# [USE TRUE|FALSE]
|
||||
# [VERSION TRUE|FALSE]
|
||||
# )
|
||||
#
|
||||
# Example:
|
||||
# create_javadoc(my_example_doc
|
||||
# FILES ${example_SRCS}
|
||||
# CLASSPATH ${CMAKE_JAVA_INCLUDE_PATH}
|
||||
# WINDOWTITLE "My example"
|
||||
# DOCTITLE "<h1>My example</h1>"
|
||||
# AUTHOR TRUE
|
||||
# USE TRUE
|
||||
# VERSION TRUE
|
||||
# )
|
||||
#
|
||||
# Both signatures share most of the options. These options are the
|
||||
# same as what you can find in the javadoc manpage. Please look at
|
||||
# the manpage for CLASSPATH, DOCTITLE, WINDOWTITLE, AUTHOR, USE and
|
||||
# VERSION.
|
||||
#
|
||||
# The documentation will be by default installed to
|
||||
#
|
||||
# ${CMAKE_INSTALL_PREFIX}/share/javadoc/<VAR>
|
||||
#
|
||||
# if you don't set the INSTALLPATH.
|
||||
#
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2010-2011 Andreas schneider <asn@redhat.com>
|
||||
# Copyright 2010 Ben Boeckel <ben.boeckel@kitware.com>
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
function (__java_copy_file src dest comment)
|
||||
add_custom_command(
|
||||
OUTPUT ${dest}
|
||||
COMMAND cmake -E copy_if_different
|
||||
ARGS ${src}
|
||||
${dest}
|
||||
DEPENDS ${src}
|
||||
COMMENT ${comment})
|
||||
endfunction (__java_copy_file src dest comment)
|
||||
|
||||
# define helper scripts
|
||||
set(_JAVA_CLASS_FILELIST_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/UseJavaClassFilelist.cmake)
|
||||
set(_JAVA_SYMLINK_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/UseJavaSymlinks.cmake)
|
||||
|
||||
function(add_jar _TARGET_NAME)
|
||||
set(_JAVA_SOURCE_FILES ${ARGN})
|
||||
|
||||
if (NOT DEFINED CMAKE_JAVA_TARGET_OUTPUT_DIR)
|
||||
set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
endif(NOT DEFINED CMAKE_JAVA_TARGET_OUTPUT_DIR)
|
||||
|
||||
if (CMAKE_JAVA_JAR_ENTRY_POINT)
|
||||
set(_ENTRY_POINT_OPTION e)
|
||||
set(_ENTRY_POINT_VALUE ${CMAKE_JAVA_JAR_ENTRY_POINT})
|
||||
endif (CMAKE_JAVA_JAR_ENTRY_POINT)
|
||||
|
||||
if (LIBRARY_OUTPUT_PATH)
|
||||
set(CMAKE_JAVA_LIBRARY_OUTPUT_PATH ${LIBRARY_OUTPUT_PATH})
|
||||
else (LIBRARY_OUTPUT_PATH)
|
||||
set(CMAKE_JAVA_LIBRARY_OUTPUT_PATH ${CMAKE_JAVA_TARGET_OUTPUT_DIR})
|
||||
endif (LIBRARY_OUTPUT_PATH)
|
||||
|
||||
set(CMAKE_JAVA_INCLUDE_PATH
|
||||
${CMAKE_JAVA_INCLUDE_PATH}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_JAVA_OBJECT_OUTPUT_PATH}
|
||||
${CMAKE_JAVA_LIBRARY_OUTPUT_PATH}
|
||||
)
|
||||
|
||||
if (WIN32 AND NOT CYGWIN AND NOT CMAKE_CROSSCOMPILING)
|
||||
set(CMAKE_JAVA_INCLUDE_FLAG_SEP ";")
|
||||
else ()
|
||||
set(CMAKE_JAVA_INCLUDE_FLAG_SEP ":")
|
||||
endif()
|
||||
|
||||
foreach (JAVA_INCLUDE_DIR ${CMAKE_JAVA_INCLUDE_PATH})
|
||||
set(CMAKE_JAVA_INCLUDE_PATH_FINAL "${CMAKE_JAVA_INCLUDE_PATH_FINAL}${CMAKE_JAVA_INCLUDE_FLAG_SEP}${JAVA_INCLUDE_DIR}")
|
||||
endforeach(JAVA_INCLUDE_DIR)
|
||||
|
||||
set(CMAKE_JAVA_CLASS_OUTPUT_PATH "${CMAKE_JAVA_TARGET_OUTPUT_DIR}${CMAKE_FILES_DIRECTORY}/${_TARGET_NAME}.dir")
|
||||
|
||||
set(_JAVA_TARGET_OUTPUT_NAME "${_TARGET_NAME}.jar")
|
||||
if (CMAKE_JAVA_TARGET_OUTPUT_NAME AND CMAKE_JAVA_TARGET_VERSION)
|
||||
set(_JAVA_TARGET_OUTPUT_NAME "${CMAKE_JAVA_TARGET_OUTPUT_NAME}-${CMAKE_JAVA_TARGET_VERSION}.jar")
|
||||
set(_JAVA_TARGET_OUTPUT_LINK "${CMAKE_JAVA_TARGET_OUTPUT_NAME}.jar")
|
||||
elseif (CMAKE_JAVA_TARGET_VERSION)
|
||||
set(_JAVA_TARGET_OUTPUT_NAME "${_TARGET_NAME}-${CMAKE_JAVA_TARGET_VERSION}.jar")
|
||||
set(_JAVA_TARGET_OUTPUT_LINK "${_TARGET_NAME}.jar")
|
||||
elseif (CMAKE_JAVA_TARGET_OUTPUT_NAME)
|
||||
set(_JAVA_TARGET_OUTPUT_NAME "${CMAKE_JAVA_TARGET_OUTPUT_NAME}.jar")
|
||||
endif (CMAKE_JAVA_TARGET_OUTPUT_NAME AND CMAKE_JAVA_TARGET_VERSION)
|
||||
# reset
|
||||
set(CMAKE_JAVA_TARGET_OUTPUT_NAME)
|
||||
|
||||
set(_JAVA_CLASS_FILES)
|
||||
set(_JAVA_COMPILE_FILES)
|
||||
set(_JAVA_DEPENDS)
|
||||
set(_JAVA_RESOURCE_FILES)
|
||||
foreach(_JAVA_SOURCE_FILE ${_JAVA_SOURCE_FILES})
|
||||
get_filename_component(_JAVA_EXT ${_JAVA_SOURCE_FILE} EXT)
|
||||
get_filename_component(_JAVA_FILE ${_JAVA_SOURCE_FILE} NAME_WE)
|
||||
get_filename_component(_JAVA_PATH ${_JAVA_SOURCE_FILE} PATH)
|
||||
get_filename_component(_JAVA_FULL ${_JAVA_SOURCE_FILE} ABSOLUTE)
|
||||
|
||||
file(RELATIVE_PATH _JAVA_REL_BINARY_PATH ${CMAKE_JAVA_TARGET_OUTPUT_DIR} ${_JAVA_FULL})
|
||||
file(RELATIVE_PATH _JAVA_REL_SOURCE_PATH ${CMAKE_CURRENT_SOURCE_DIR} ${_JAVA_FULL})
|
||||
string(LENGTH ${_JAVA_REL_BINARY_PATH} _BIN_LEN)
|
||||
string(LENGTH ${_JAVA_REL_SOURCE_PATH} _SRC_LEN)
|
||||
if (${_BIN_LEN} LESS ${_SRC_LEN})
|
||||
set(_JAVA_REL_PATH ${_JAVA_REL_BINARY_PATH})
|
||||
else (${_BIN_LEN} LESS ${_SRC_LEN})
|
||||
set(_JAVA_REL_PATH ${_JAVA_REL_SOURCE_PATH})
|
||||
endif (${_BIN_LEN} LESS ${_SRC_LEN})
|
||||
get_filename_component(_JAVA_REL_PATH ${_JAVA_REL_PATH} PATH)
|
||||
|
||||
if (_JAVA_EXT MATCHES ".java")
|
||||
list(APPEND _JAVA_COMPILE_FILES ${_JAVA_SOURCE_FILE})
|
||||
set(_JAVA_CLASS_FILE "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${_JAVA_REL_PATH}/${_JAVA_FILE}.class")
|
||||
set(_JAVA_CLASS_FILES ${_JAVA_CLASS_FILES} ${_JAVA_CLASS_FILE})
|
||||
|
||||
elseif (_JAVA_EXT MATCHES ".jar"
|
||||
OR _JAVA_EXT MATCHES ".war"
|
||||
OR _JAVA_EXT MATCHES ".ear"
|
||||
OR _JAVA_EXT MATCHES ".sar")
|
||||
list(APPEND CMAKE_JAVA_INCLUDE_PATH ${_JAVA_SOURCE_FILE})
|
||||
|
||||
elseif (_JAVA_EXT STREQUAL "")
|
||||
list(APPEND CMAKE_JAVA_INCLUDE_PATH ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}} ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}_CLASSPATH})
|
||||
list(APPEND _JAVA_DEPENDS ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}})
|
||||
|
||||
else (_JAVA_EXT MATCHES ".java")
|
||||
__java_copy_file(${CMAKE_CURRENT_SOURCE_DIR}/${_JAVA_SOURCE_FILE}
|
||||
${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${_JAVA_SOURCE_FILE}
|
||||
"Copying ${_JAVA_SOURCE_FILE} to the build directory")
|
||||
list(APPEND _JAVA_RESOURCE_FILES ${_JAVA_SOURCE_FILE})
|
||||
endif (_JAVA_EXT MATCHES ".java")
|
||||
endforeach(_JAVA_SOURCE_FILE)
|
||||
|
||||
# create an empty java_class_filelist
|
||||
if (NOT EXISTS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist)
|
||||
file(WRITE ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist "")
|
||||
endif()
|
||||
|
||||
if (_JAVA_COMPILE_FILES)
|
||||
# Compile the java files and create a list of class files
|
||||
add_custom_command(
|
||||
# NOTE: this command generates an artificial dependency file
|
||||
OUTPUT ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}
|
||||
COMMAND ${Java_JAVAC_EXECUTABLE}
|
||||
${CMAKE_JAVA_COMPILE_FLAGS}
|
||||
-classpath "${CMAKE_JAVA_INCLUDE_PATH_FINAL}"
|
||||
-d ${CMAKE_JAVA_CLASS_OUTPUT_PATH}
|
||||
${_JAVA_COMPILE_FILES}
|
||||
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}
|
||||
DEPENDS ${_JAVA_COMPILE_FILES}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMENT "Building Java objects for ${_TARGET_NAME}.jar"
|
||||
)
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-DCMAKE_JAVA_CLASS_OUTPUT_PATH=${CMAKE_JAVA_CLASS_OUTPUT_PATH}
|
||||
-DCMAKE_JAR_CLASSES_PREFIX="${CMAKE_JAR_CLASSES_PREFIX}"
|
||||
-P ${_JAVA_CLASS_FILELIST_SCRIPT}
|
||||
DEPENDS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
endif (_JAVA_COMPILE_FILES)
|
||||
|
||||
# create the jar file
|
||||
set(_JAVA_JAR_OUTPUT_PATH
|
||||
${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_NAME})
|
||||
if (CMAKE_JNI_TARGET)
|
||||
add_custom_command(
|
||||
OUTPUT ${_JAVA_JAR_OUTPUT_PATH}
|
||||
COMMAND ${Java_JAR_EXECUTABLE}
|
||||
-cf${_ENTRY_POINT_OPTION} ${_JAVA_JAR_OUTPUT_PATH} ${_ENTRY_POINT_VALUE}
|
||||
${_JAVA_RESOURCE_FILES} @java_class_filelist
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-D_JAVA_TARGET_DIR=${CMAKE_JAVA_TARGET_OUTPUT_DIR}
|
||||
-D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_TARGET_OUTPUT_NAME}
|
||||
-D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK}
|
||||
-P ${_JAVA_SYMLINK_SCRIPT}
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-D_JAVA_TARGET_DIR=${CMAKE_JAVA_TARGET_OUTPUT_DIR}
|
||||
-D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_JAR_OUTPUT_PATH}
|
||||
-D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK}
|
||||
-P ${_JAVA_SYMLINK_SCRIPT}
|
||||
DEPENDS ${_JAVA_RESOURCE_FILES} ${_JAVA_DEPENDS} ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist
|
||||
WORKING_DIRECTORY ${CMAKE_JAVA_CLASS_OUTPUT_PATH}
|
||||
COMMENT "Creating Java archive ${_JAVA_TARGET_OUTPUT_NAME}"
|
||||
)
|
||||
else ()
|
||||
add_custom_command(
|
||||
OUTPUT ${_JAVA_JAR_OUTPUT_PATH}
|
||||
COMMAND ${Java_JAR_EXECUTABLE}
|
||||
-cf${_ENTRY_POINT_OPTION} ${_JAVA_JAR_OUTPUT_PATH} ${_ENTRY_POINT_VALUE}
|
||||
${_JAVA_RESOURCE_FILES} @java_class_filelist
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-D_JAVA_TARGET_DIR=${CMAKE_JAVA_TARGET_OUTPUT_DIR}
|
||||
-D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_TARGET_OUTPUT_NAME}
|
||||
-D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK}
|
||||
-P ${_JAVA_SYMLINK_SCRIPT}
|
||||
WORKING_DIRECTORY ${CMAKE_JAVA_CLASS_OUTPUT_PATH}
|
||||
DEPENDS ${_JAVA_RESOURCE_FILES} ${_JAVA_DEPENDS} ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist
|
||||
COMMENT "Creating Java archive ${_JAVA_TARGET_OUTPUT_NAME}"
|
||||
)
|
||||
endif (CMAKE_JNI_TARGET)
|
||||
|
||||
# Add the target and make sure we have the latest resource files.
|
||||
add_custom_target(${_TARGET_NAME} ALL DEPENDS ${_JAVA_JAR_OUTPUT_PATH})
|
||||
|
||||
set_property(
|
||||
TARGET
|
||||
${_TARGET_NAME}
|
||||
PROPERTY
|
||||
INSTALL_FILES
|
||||
${_JAVA_JAR_OUTPUT_PATH}
|
||||
)
|
||||
|
||||
if (_JAVA_TARGET_OUTPUT_LINK)
|
||||
set_property(
|
||||
TARGET
|
||||
${_TARGET_NAME}
|
||||
PROPERTY
|
||||
INSTALL_FILES
|
||||
${_JAVA_JAR_OUTPUT_PATH}
|
||||
${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_LINK}
|
||||
)
|
||||
|
||||
if (CMAKE_JNI_TARGET)
|
||||
set_property(
|
||||
TARGET
|
||||
${_TARGET_NAME}
|
||||
PROPERTY
|
||||
JNI_SYMLINK
|
||||
${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_LINK}
|
||||
)
|
||||
endif (CMAKE_JNI_TARGET)
|
||||
endif (_JAVA_TARGET_OUTPUT_LINK)
|
||||
|
||||
set_property(
|
||||
TARGET
|
||||
${_TARGET_NAME}
|
||||
PROPERTY
|
||||
JAR_FILE
|
||||
${_JAVA_JAR_OUTPUT_PATH}
|
||||
)
|
||||
|
||||
set_property(
|
||||
TARGET
|
||||
${_TARGET_NAME}
|
||||
PROPERTY
|
||||
CLASSDIR
|
||||
${CMAKE_JAVA_CLASS_OUTPUT_PATH}
|
||||
)
|
||||
|
||||
endfunction(add_jar)
|
||||
|
||||
function(INSTALL_JAR _TARGET_NAME _DESTINATION)
|
||||
get_property(__FILES
|
||||
TARGET
|
||||
${_TARGET_NAME}
|
||||
PROPERTY
|
||||
INSTALL_FILES
|
||||
)
|
||||
|
||||
if (__FILES)
|
||||
install(
|
||||
FILES
|
||||
${__FILES}
|
||||
DESTINATION
|
||||
${_DESTINATION}
|
||||
)
|
||||
else (__FILES)
|
||||
message(SEND_ERROR "The target ${_TARGET_NAME} is not known in this scope.")
|
||||
endif (__FILES)
|
||||
endfunction(INSTALL_JAR _TARGET_NAME _DESTINATION)
|
||||
|
||||
function(INSTALL_JNI_SYMLINK _TARGET_NAME _DESTINATION)
|
||||
get_property(__SYMLINK
|
||||
TARGET
|
||||
${_TARGET_NAME}
|
||||
PROPERTY
|
||||
JNI_SYMLINK
|
||||
)
|
||||
|
||||
if (__SYMLINK)
|
||||
install(
|
||||
FILES
|
||||
${__SYMLINK}
|
||||
DESTINATION
|
||||
${_DESTINATION}
|
||||
)
|
||||
else (__SYMLINK)
|
||||
message(SEND_ERROR "The target ${_TARGET_NAME} is not known in this scope.")
|
||||
endif (__SYMLINK)
|
||||
endfunction(INSTALL_JNI_SYMLINK _TARGET_NAME _DESTINATION)
|
||||
|
||||
function (find_jar VARIABLE)
|
||||
set(_jar_names)
|
||||
set(_jar_files)
|
||||
set(_jar_versions)
|
||||
set(_jar_paths
|
||||
/usr/share/java/
|
||||
/usr/local/share/java/
|
||||
${Java_JAR_PATHS})
|
||||
set(_jar_doc "NOTSET")
|
||||
|
||||
set(_state "name")
|
||||
|
||||
foreach (arg ${ARGN})
|
||||
if (${_state} STREQUAL "name")
|
||||
if (${arg} STREQUAL "VERSIONS")
|
||||
set(_state "versions")
|
||||
elseif (${arg} STREQUAL "NAMES")
|
||||
set(_state "names")
|
||||
elseif (${arg} STREQUAL "PATHS")
|
||||
set(_state "paths")
|
||||
elseif (${arg} STREQUAL "DOC")
|
||||
set(_state "doc")
|
||||
else (${arg} STREQUAL "NAMES")
|
||||
set(_jar_names ${arg})
|
||||
if (_jar_doc STREQUAL "NOTSET")
|
||||
set(_jar_doc "Finding ${arg} jar")
|
||||
endif (_jar_doc STREQUAL "NOTSET")
|
||||
endif (${arg} STREQUAL "VERSIONS")
|
||||
elseif (${_state} STREQUAL "versions")
|
||||
if (${arg} STREQUAL "NAMES")
|
||||
set(_state "names")
|
||||
elseif (${arg} STREQUAL "PATHS")
|
||||
set(_state "paths")
|
||||
elseif (${arg} STREQUAL "DOC")
|
||||
set(_state "doc")
|
||||
else (${arg} STREQUAL "NAMES")
|
||||
set(_jar_versions ${_jar_versions} ${arg})
|
||||
endif (${arg} STREQUAL "NAMES")
|
||||
elseif (${_state} STREQUAL "names")
|
||||
if (${arg} STREQUAL "VERSIONS")
|
||||
set(_state "versions")
|
||||
elseif (${arg} STREQUAL "PATHS")
|
||||
set(_state "paths")
|
||||
elseif (${arg} STREQUAL "DOC")
|
||||
set(_state "doc")
|
||||
else (${arg} STREQUAL "VERSIONS")
|
||||
set(_jar_names ${_jar_names} ${arg})
|
||||
if (_jar_doc STREQUAL "NOTSET")
|
||||
set(_jar_doc "Finding ${arg} jar")
|
||||
endif (_jar_doc STREQUAL "NOTSET")
|
||||
endif (${arg} STREQUAL "VERSIONS")
|
||||
elseif (${_state} STREQUAL "paths")
|
||||
if (${arg} STREQUAL "VERSIONS")
|
||||
set(_state "versions")
|
||||
elseif (${arg} STREQUAL "NAMES")
|
||||
set(_state "names")
|
||||
elseif (${arg} STREQUAL "DOC")
|
||||
set(_state "doc")
|
||||
else (${arg} STREQUAL "VERSIONS")
|
||||
set(_jar_paths ${_jar_paths} ${arg})
|
||||
endif (${arg} STREQUAL "VERSIONS")
|
||||
elseif (${_state} STREQUAL "doc")
|
||||
if (${arg} STREQUAL "VERSIONS")
|
||||
set(_state "versions")
|
||||
elseif (${arg} STREQUAL "NAMES")
|
||||
set(_state "names")
|
||||
elseif (${arg} STREQUAL "PATHS")
|
||||
set(_state "paths")
|
||||
else (${arg} STREQUAL "VERSIONS")
|
||||
set(_jar_doc ${arg})
|
||||
endif (${arg} STREQUAL "VERSIONS")
|
||||
endif (${_state} STREQUAL "name")
|
||||
endforeach (arg ${ARGN})
|
||||
|
||||
if (NOT _jar_names)
|
||||
message(FATAL_ERROR "find_jar: No name to search for given")
|
||||
endif (NOT _jar_names)
|
||||
|
||||
foreach (jar_name ${_jar_names})
|
||||
foreach (version ${_jar_versions})
|
||||
set(_jar_files ${_jar_files} ${jar_name}-${version}.jar)
|
||||
endforeach (version ${_jar_versions})
|
||||
set(_jar_files ${_jar_files} ${jar_name}.jar)
|
||||
endforeach (jar_name ${_jar_names})
|
||||
|
||||
find_file(${VARIABLE}
|
||||
NAMES ${_jar_files}
|
||||
PATHS ${_jar_paths}
|
||||
DOC ${_jar_doc}
|
||||
NO_DEFAULT_PATH)
|
||||
endfunction (find_jar VARIABLE)
|
||||
|
||||
function(create_javadoc _target)
|
||||
set(_javadoc_packages)
|
||||
set(_javadoc_files)
|
||||
set(_javadoc_sourcepath)
|
||||
set(_javadoc_classpath)
|
||||
set(_javadoc_installpath "${CMAKE_INSTALL_PREFIX}/share/javadoc")
|
||||
set(_javadoc_doctitle)
|
||||
set(_javadoc_windowtitle)
|
||||
set(_javadoc_author FALSE)
|
||||
set(_javadoc_version FALSE)
|
||||
set(_javadoc_use FALSE)
|
||||
|
||||
set(_state "package")
|
||||
|
||||
foreach (arg ${ARGN})
|
||||
if (${_state} STREQUAL "package")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "CLASSPATH")
|
||||
set(_state "classpath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
set(_javadoc_packages ${arg})
|
||||
set(_state "packages")
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "packages")
|
||||
if (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "CLASSPATH")
|
||||
set(_state "classpath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
list(APPEND _javadoc_packages ${arg})
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "files")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "CLASSPATH")
|
||||
set(_state "classpath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
list(APPEND _javadoc_files ${arg})
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "sourcepath")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "CLASSPATH")
|
||||
set(_state "classpath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
list(APPEND _javadoc_sourcepath ${arg})
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "classpath")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
list(APPEND _javadoc_classpath ${arg})
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "installpath")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
set(_javadoc_installpath ${arg})
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "doctitle")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "CLASSPATH")
|
||||
set(_state "classpath")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
set(_javadoc_doctitle ${arg})
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "windowtitle")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "CLASSPATH")
|
||||
set(_state "classpath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
set(_javadoc_windowtitle ${arg})
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "author")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "CLASSPATH")
|
||||
set(_state "classpath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
set(_javadoc_author ${arg})
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "use")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "CLASSPATH")
|
||||
set(_state "classpath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
set(_javadoc_use ${arg})
|
||||
endif ()
|
||||
elseif (${_state} STREQUAL "version")
|
||||
if (${arg} STREQUAL "PACKAGES")
|
||||
set(_state "packages")
|
||||
elseif (${arg} STREQUAL "FILES")
|
||||
set(_state "files")
|
||||
elseif (${arg} STREQUAL "SOURCEPATH")
|
||||
set(_state "sourcepath")
|
||||
elseif (${arg} STREQUAL "CLASSPATH")
|
||||
set(_state "classpath")
|
||||
elseif (${arg} STREQUAL "INSTALLPATH")
|
||||
set(_state "installpath")
|
||||
elseif (${arg} STREQUAL "DOCTITLE")
|
||||
set(_state "doctitle")
|
||||
elseif (${arg} STREQUAL "WINDOWTITLE")
|
||||
set(_state "windowtitle")
|
||||
elseif (${arg} STREQUAL "AUTHOR")
|
||||
set(_state "author")
|
||||
elseif (${arg} STREQUAL "USE")
|
||||
set(_state "use")
|
||||
elseif (${arg} STREQUAL "VERSION")
|
||||
set(_state "version")
|
||||
else ()
|
||||
set(_javadoc_version ${arg})
|
||||
endif ()
|
||||
endif (${_state} STREQUAL "package")
|
||||
endforeach (arg ${ARGN})
|
||||
|
||||
set(_javadoc_builddir ${CMAKE_CURRENT_BINARY_DIR}/javadoc/${_target})
|
||||
set(_javadoc_options -d ${_javadoc_builddir})
|
||||
|
||||
if (_javadoc_sourcepath)
|
||||
set(_start TRUE)
|
||||
foreach(_path ${_javadoc_sourcepath})
|
||||
if (_start)
|
||||
set(_sourcepath ${_path})
|
||||
set(_start FALSE)
|
||||
else (_start)
|
||||
set(_sourcepath ${_sourcepath}:${_path})
|
||||
endif (_start)
|
||||
endforeach(_path ${_javadoc_sourcepath})
|
||||
set(_javadoc_options ${_javadoc_options} -sourcepath ${_sourcepath})
|
||||
endif (_javadoc_sourcepath)
|
||||
|
||||
if (_javadoc_classpath)
|
||||
set(_start TRUE)
|
||||
foreach(_path ${_javadoc_classpath})
|
||||
if (_start)
|
||||
set(_classpath ${_path})
|
||||
set(_start FALSE)
|
||||
else (_start)
|
||||
set(_classpath ${_classpath}:${_path})
|
||||
endif (_start)
|
||||
endforeach(_path ${_javadoc_classpath})
|
||||
set(_javadoc_options ${_javadoc_options} -classpath "${_classpath}")
|
||||
endif (_javadoc_classpath)
|
||||
|
||||
if (_javadoc_doctitle)
|
||||
set(_javadoc_options ${_javadoc_options} -doctitle '${_javadoc_doctitle}')
|
||||
endif (_javadoc_doctitle)
|
||||
|
||||
if (_javadoc_windowtitle)
|
||||
set(_javadoc_options ${_javadoc_options} -windowtitle '${_javadoc_windowtitle}')
|
||||
endif (_javadoc_windowtitle)
|
||||
|
||||
if (_javadoc_author)
|
||||
set(_javadoc_options ${_javadoc_options} -author)
|
||||
endif (_javadoc_author)
|
||||
|
||||
if (_javadoc_use)
|
||||
set(_javadoc_options ${_javadoc_options} -use)
|
||||
endif (_javadoc_use)
|
||||
|
||||
if (_javadoc_version)
|
||||
set(_javadoc_options ${_javadoc_options} -version)
|
||||
endif (_javadoc_version)
|
||||
|
||||
add_custom_target(${_target}_javadoc ALL
|
||||
COMMAND ${Java_JAVADOC_EXECUTABLE} ${_javadoc_options}
|
||||
${_javadoc_files}
|
||||
${_javadoc_packages}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
install(
|
||||
DIRECTORY ${_javadoc_builddir}
|
||||
DESTINATION ${_javadoc_installpath}
|
||||
)
|
||||
endfunction(create_javadoc)
|
@ -1,52 +0,0 @@
|
||||
#
|
||||
# This script create a list of compiled Java class files to be added to a
|
||||
# jar file. This avoids including cmake files which get created in the
|
||||
# binary directory.
|
||||
#
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2010-2011 Andreas schneider <asn@redhat.com>
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
if (CMAKE_JAVA_CLASS_OUTPUT_PATH)
|
||||
if (EXISTS "${CMAKE_JAVA_CLASS_OUTPUT_PATH}")
|
||||
|
||||
set(_JAVA_GLOBBED_FILES)
|
||||
if (CMAKE_JAR_CLASSES_PREFIX)
|
||||
foreach(JAR_CLASS_PREFIX ${CMAKE_JAR_CLASSES_PREFIX})
|
||||
message(STATUS "JAR_CLASS_PREFIX: ${JAR_CLASS_PREFIX}")
|
||||
|
||||
file(GLOB_RECURSE _JAVA_GLOBBED_TMP_FILES "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${JAR_CLASS_PREFIX}/*.class")
|
||||
if (_JAVA_GLOBBED_TMP_FILES)
|
||||
list(APPEND _JAVA_GLOBBED_FILES ${_JAVA_GLOBBED_TMP_FILES})
|
||||
endif (_JAVA_GLOBBED_TMP_FILES)
|
||||
endforeach(JAR_CLASS_PREFIX ${CMAKE_JAR_CLASSES_PREFIX})
|
||||
else()
|
||||
file(GLOB_RECURSE _JAVA_GLOBBED_FILES "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/*.class")
|
||||
endif (CMAKE_JAR_CLASSES_PREFIX)
|
||||
|
||||
set(_JAVA_CLASS_FILES)
|
||||
# file(GLOB_RECURSE foo RELATIVE) is broken so we need this.
|
||||
foreach(_JAVA_GLOBBED_FILE ${_JAVA_GLOBBED_FILES})
|
||||
file(RELATIVE_PATH _JAVA_CLASS_FILE ${CMAKE_JAVA_CLASS_OUTPUT_PATH} ${_JAVA_GLOBBED_FILE})
|
||||
set(_JAVA_CLASS_FILES ${_JAVA_CLASS_FILES}${_JAVA_CLASS_FILE}\n)
|
||||
endforeach(_JAVA_GLOBBED_FILE ${_JAVA_GLOBBED_FILES})
|
||||
|
||||
# write to file
|
||||
file(WRITE ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist ${_JAVA_CLASS_FILES})
|
||||
|
||||
else (EXISTS "${CMAKE_JAVA_CLASS_OUTPUT_PATH}")
|
||||
message(SEND_ERROR "FATAL: Java class output path doesn't exist")
|
||||
endif (EXISTS "${CMAKE_JAVA_CLASS_OUTPUT_PATH}")
|
||||
else (CMAKE_JAVA_CLASS_OUTPUT_PATH)
|
||||
message(SEND_ERROR "FATAL: Can't find CMAKE_JAVA_CLASS_OUTPUT_PATH")
|
||||
endif (CMAKE_JAVA_CLASS_OUTPUT_PATH)
|
@ -1,32 +0,0 @@
|
||||
#
|
||||
# Helper script for UseJava.cmake
|
||||
#
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2010-2011 Andreas schneider <asn@redhat.com>
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
|
||||
if (UNIX AND _JAVA_TARGET_OUTPUT_LINK)
|
||||
if (_JAVA_TARGET_OUTPUT_NAME)
|
||||
find_program(LN_EXECUTABLE
|
||||
NAMES
|
||||
ln
|
||||
)
|
||||
|
||||
execute_process(
|
||||
COMMAND ${LN_EXECUTABLE} -sf "${_JAVA_TARGET_OUTPUT_NAME}" "${_JAVA_TARGET_OUTPUT_LINK}"
|
||||
WORKING_DIRECTORY ${_JAVA_TARGET_DIR}
|
||||
)
|
||||
else (_JAVA_TARGET_OUTPUT_NAME)
|
||||
message(SEND_ERROR "FATAL: Can't find _JAVA_TARGET_OUTPUT_NAME")
|
||||
endif (_JAVA_TARGET_OUTPUT_NAME)
|
||||
endif (UNIX AND _JAVA_TARGET_OUTPUT_LINK)
|
40
flake.lock
generated
40
flake.lock
generated
@ -3,11 +3,11 @@
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1641205782,
|
||||
"narHash": "sha256-4jY7RCWUoZ9cKD8co0/4tFARpWB+57+r1bLLvXNJliY=",
|
||||
"lastModified": 1648199409,
|
||||
"narHash": "sha256-JwPKdC2PoVBkG6E+eWw3j6BMR6sL3COpYWfif7RVb8Y=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "b7547d3eed6f32d06102ead8991ec52ab0a4f1a7",
|
||||
"rev": "64a525ee38886ab9028e6f61790de0832aa3ef03",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -16,21 +16,6 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"locked": {
|
||||
"lastModified": 1638122382,
|
||||
"narHash": "sha256-sQzZzAbvKEqN9s0bzWuYmRaA03v40gaJ4+iL1LXjaeI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "74f7e4319258e287b0f9cb95426c9853b282730b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"libnbtplusplus": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
@ -49,16 +34,16 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1641528457,
|
||||
"narHash": "sha256-FyU9E63n1W7Ql4pMnhW2/rO9OftWZ37pLppn/c1aisY=",
|
||||
"lastModified": 1648219316,
|
||||
"narHash": "sha256-Ctij+dOi0ZZIfX5eMhgwugfvB+WZSrvVNAyAuANOsnQ=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "ff377a78794d412a35245e05428c8f95fef3951f",
|
||||
"rev": "30d3d79b7d3607d56546dd2a6b49e156ba0ec634",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixos-unstable",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
@ -66,15 +51,15 @@
|
||||
"quazip": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1633895098,
|
||||
"narHash": "sha256-+Of0M2IAoTf1CyC0teCpsyurv6xfqiBo84V49dSeNTA=",
|
||||
"owner": "multimc",
|
||||
"lastModified": 1643049383,
|
||||
"narHash": "sha256-LcJY6yd6GyeL7X5MP4L94diceM1TYespWByliBsjK98=",
|
||||
"owner": "stachenov",
|
||||
"repo": "quazip",
|
||||
"rev": "b1a72ac0bb5a732bf887a535ab75c6f9bedb6b6b",
|
||||
"rev": "09ec1d10c6d627f895109b21728dda000cbfa7d1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "multimc",
|
||||
"owner": "stachenov",
|
||||
"repo": "quazip",
|
||||
"type": "github"
|
||||
}
|
||||
@ -82,7 +67,6 @@
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"flake-utils": "flake-utils",
|
||||
"libnbtplusplus": "libnbtplusplus",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"quazip": "quazip"
|
||||
|
75
flake.nix
75
flake.nix
@ -1,55 +1,34 @@
|
||||
{
|
||||
description = "PolyMC flake";
|
||||
inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||
inputs.flake-utils.url = "github:numtide/flake-utils";
|
||||
inputs.flake-compat = {
|
||||
url = "github:edolstra/flake-compat";
|
||||
flake = false;
|
||||
};
|
||||
inputs.libnbtplusplus = {
|
||||
url = "github:multimc/libnbtplusplus";
|
||||
flake = false;
|
||||
};
|
||||
inputs.quazip = {
|
||||
url = "github:multimc/quazip";
|
||||
flake = false;
|
||||
description = "A custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once (Fork of MultiMC)";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
|
||||
flake-compat = { url = "github:edolstra/flake-compat"; flake = false; };
|
||||
libnbtplusplus = { url = "github:multimc/libnbtplusplus"; flake = false; };
|
||||
quazip = { url = "github:stachenov/quazip"; flake = false; };
|
||||
};
|
||||
|
||||
outputs = inputs@{ self, nixpkgs, flake-utils, libnbtplusplus, quazip, ... }:
|
||||
flake-utils.lib.eachSystem [ "x86_64-linux" "aarch64-linux" ] (system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
};
|
||||
outputs = { self, nixpkgs, libnbtplusplus, quazip, ... }:
|
||||
let
|
||||
# Generate a user-friendly version number.
|
||||
version = builtins.substring 0 8 self.lastModifiedDate;
|
||||
|
||||
packages = {
|
||||
polymc = pkgs.libsForQt5.callPackage ./packages/nix/polymc {
|
||||
inherit self;
|
||||
submoduleQuazip = quazip;
|
||||
submoduleNbt = libnbtplusplus;
|
||||
};
|
||||
};
|
||||
# System types to support (qtbase is currently broken for "aarch64-darwin")
|
||||
supportedSystems = [ "x86_64-linux" "x86_64-darwin" "aarch64-linux" ];
|
||||
|
||||
# 'nix flake check' fails
|
||||
overlay = (final: prev: rec {
|
||||
polymc = prev.libsForQt5.callPackage ./packages/nix/polymc {
|
||||
inherit self;
|
||||
submoduleQuazip = quazip;
|
||||
submoduleNbt = libnbtplusplus;
|
||||
};
|
||||
});
|
||||
# Helper function to generate an attrset '{ x86_64-linux = f "x86_64-linux"; ... }'.
|
||||
forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
|
||||
|
||||
apps = {
|
||||
polymc = flake-utils.lib.mkApp {
|
||||
name = "polymc";
|
||||
drv = packages.polymc;
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
inherit packages overlay apps;
|
||||
defaultPackage = packages.polymc;
|
||||
defaultApp = apps.polymc;
|
||||
}
|
||||
);
|
||||
# Nixpkgs instantiated for supported system types.
|
||||
pkgs = forAllSystems (system: nixpkgs.legacyPackages.${system});
|
||||
in
|
||||
{
|
||||
packages = forAllSystems (system: { polymc = pkgs.${system}.libsForQt5.callPackage ./packages/nix/polymc { inherit version self quazip libnbtplusplus; }; });
|
||||
defaultPackage = forAllSystems (system: self.packages.${system}.polymc);
|
||||
|
||||
apps = forAllSystems (system: { polymc = { type = "app"; program = "${self.defaultPackage.${system}}/bin/polymc"; }; });
|
||||
defaultApp = forAllSystems (system: self.apps.${system}.polymc);
|
||||
|
||||
overlay = final: prev: { polymc = self.defaultPackage.${final.system}; };
|
||||
};
|
||||
}
|
||||
|
@ -1,6 +1,43 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 Lenny McLennington <lenny@sneed.church>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "Application.h"
|
||||
#include "BuildConfig.h"
|
||||
|
||||
#include "net/PasteUpload.h"
|
||||
#include "ui/MainWindow.h"
|
||||
#include "ui/InstanceWindow.h"
|
||||
|
||||
@ -14,7 +51,7 @@
|
||||
#include "ui/pages/global/ProxyPage.h"
|
||||
#include "ui/pages/global/ExternalToolsPage.h"
|
||||
#include "ui/pages/global/AccountListPage.h"
|
||||
#include "ui/pages/global/PasteEEPage.h"
|
||||
#include "ui/pages/global/APIPage.h"
|
||||
#include "ui/pages/global/CustomCommandsPage.h"
|
||||
|
||||
#include "ui/themes/ITheme.h"
|
||||
@ -26,6 +63,7 @@
|
||||
#include "ui/setupwizard/SetupWizard.h"
|
||||
#include "ui/setupwizard/LanguageWizardPage.h"
|
||||
#include "ui/setupwizard/JavaWizardPage.h"
|
||||
#include "ui/setupwizard/PasteWizardPage.h"
|
||||
|
||||
#include "ui/dialogs/CustomMessageBox.h"
|
||||
|
||||
@ -45,6 +83,7 @@
|
||||
#include <QStringList>
|
||||
#include <QDebug>
|
||||
#include <QStyleFactory>
|
||||
#include <QWindow>
|
||||
|
||||
#include "InstanceList.h"
|
||||
|
||||
@ -187,30 +226,9 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
||||
setApplicationName(BuildConfig.LAUNCHER_NAME);
|
||||
setApplicationDisplayName(BuildConfig.LAUNCHER_DISPLAYNAME);
|
||||
setApplicationVersion(BuildConfig.printableVersionString());
|
||||
|
||||
setDesktopFileName(BuildConfig.LAUNCHER_DESKTOPFILENAME);
|
||||
startTime = QDateTime::currentDateTime();
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
{
|
||||
QFile osrelease("/proc/sys/kernel/osrelease");
|
||||
if (osrelease.open(QFile::ReadOnly | QFile::Text)) {
|
||||
QTextStream in(&osrelease);
|
||||
auto contents = in.readAll();
|
||||
if(
|
||||
contents.contains("WSL", Qt::CaseInsensitive) ||
|
||||
contents.contains("Microsoft", Qt::CaseInsensitive)
|
||||
) {
|
||||
showFatalErrorMessage(
|
||||
"Unsupported system detected!",
|
||||
"Linux-on-Windows distributions are not supported.\n\n"
|
||||
"Please use the Windows binary when playing on Windows."
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Don't quit on hiding the last window
|
||||
this->setQuitOnLastWindowClosed(false);
|
||||
|
||||
@ -283,14 +301,43 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_instanceIdToLaunch = args["launch"].toString();
|
||||
m_serverToJoin = args["server"].toString();
|
||||
m_profileToUse = args["profile"].toString();
|
||||
m_liveCheck = args["alive"].toBool();
|
||||
m_zipToImport = args["import"].toUrl();
|
||||
|
||||
// error if --launch is missing with --server or --profile
|
||||
if((!m_serverToJoin.isEmpty() || !m_profileToUse.isEmpty()) && m_instanceIdToLaunch.isEmpty())
|
||||
{
|
||||
std::cerr << "--server and --profile can only be used in combination with --launch!" << std::endl;
|
||||
m_status = Application::Failed;
|
||||
return;
|
||||
}
|
||||
|
||||
QString origcwdPath = QDir::currentPath();
|
||||
QString binPath = applicationDirPath();
|
||||
|
||||
{
|
||||
// Root path is used for updates and portable data
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||
QDir foo(FS::PathCombine(binPath, "..")); // typically portable-root or /usr
|
||||
m_rootPath = foo.absolutePath();
|
||||
#elif defined(Q_OS_WIN32)
|
||||
m_rootPath = binPath;
|
||||
#elif defined(Q_OS_MAC)
|
||||
QDir foo(FS::PathCombine(binPath, "../.."));
|
||||
m_rootPath = foo.absolutePath();
|
||||
// on macOS, touch the root to force Finder to reload the .app metadata (and fix any icon change issues)
|
||||
FS::updateTimestamp(m_rootPath);
|
||||
#endif
|
||||
|
||||
#ifdef LAUNCHER_JARS_LOCATION
|
||||
m_jarsPath = TOSTRING(LAUNCHER_JARS_LOCATION);
|
||||
#endif
|
||||
}
|
||||
|
||||
QString adjustedBy;
|
||||
QString dataPath;
|
||||
// change folder
|
||||
@ -299,24 +346,30 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
||||
{
|
||||
// the dir param. it makes multimc data path point to whatever the user specified
|
||||
// on command line
|
||||
adjustedBy += "Command line " + dirParam;
|
||||
adjustedBy = "Command line";
|
||||
dataPath = dirParam;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef LAUNCHER_LINUX_DATADIR
|
||||
QString xdgDataHome = QFile::decodeName(qgetenv("XDG_DATA_HOME"));
|
||||
if (xdgDataHome.isEmpty())
|
||||
xdgDataHome = QDir::homePath() + QLatin1String("/.local/share");
|
||||
dataPath = xdgDataHome + "/polymc";
|
||||
adjustedBy += "XDG standard " + dataPath;
|
||||
#elif defined(Q_OS_MAC)
|
||||
QDir foo(FS::PathCombine(applicationDirPath(), "../../Data"));
|
||||
QDir foo(FS::PathCombine(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation), ".."));
|
||||
dataPath = foo.absolutePath();
|
||||
adjustedBy += "Fallback to special Mac location " + dataPath;
|
||||
#else
|
||||
dataPath = applicationDirPath();
|
||||
adjustedBy += "Fallback to binary path " + dataPath;
|
||||
adjustedBy = "Persistent data path";
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
// TODO: this should be removed in a future version
|
||||
// TODO: provide a migration path similar to macOS migration
|
||||
QDir bar(FS::PathCombine(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation), "polymc"));
|
||||
if (bar.exists()) {
|
||||
dataPath = bar.absolutePath();
|
||||
adjustedBy = "Legacy data path";
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef Q_OS_MACOS
|
||||
if (QFile::exists(FS::PathCombine(m_rootPath, "portable.txt"))) {
|
||||
dataPath = m_rootPath;
|
||||
adjustedBy = "Portable data path";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -357,85 +410,8 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_instanceIdToLaunch.isEmpty() && !m_serverToJoin.isEmpty())
|
||||
{
|
||||
std::cerr << "--server can only be used in combination with --launch!" << std::endl;
|
||||
m_status = Application::Failed;
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_instanceIdToLaunch.isEmpty() && !m_profileToUse.isEmpty())
|
||||
{
|
||||
std::cerr << "--account can only be used in combination with --launch!" << std::endl;
|
||||
m_status = Application::Failed;
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(Q_OS_MAC)
|
||||
// move user data to new location if on macOS and it still exists in Contents/MacOS
|
||||
QDir fi(applicationDirPath());
|
||||
QString originalData = fi.absolutePath();
|
||||
// if the config file exists in Contents/MacOS, then user data is still there and needs to moved
|
||||
if (QFileInfo::exists(FS::PathCombine(originalData, BuildConfig.LAUNCHER_CONFIGFILE)))
|
||||
{
|
||||
if (!QFileInfo::exists(FS::PathCombine(originalData, "dontmovemacdata")))
|
||||
{
|
||||
QMessageBox::StandardButton askMoveDialogue;
|
||||
askMoveDialogue = QMessageBox::question(
|
||||
nullptr,
|
||||
BuildConfig.LAUNCHER_DISPLAYNAME,
|
||||
"Would you like to move application data to a new data location? It will improve the launcher's performance, but if you switch to older versions it will look like instances have disappeared. If you select no, you can migrate later in settings. You should select yes unless you're commonly switching between different versions (eg. develop and stable).",
|
||||
QMessageBox::Yes | QMessageBox::No,
|
||||
QMessageBox::Yes
|
||||
);
|
||||
if (askMoveDialogue == QMessageBox::Yes)
|
||||
{
|
||||
qDebug() << "On macOS and found config file in old location, moving user data...";
|
||||
QDir dir;
|
||||
QStringList dataFiles {
|
||||
"*.log", // Launcher log files: ${Launcher_Name}-@.log
|
||||
"accounts.json",
|
||||
"accounts",
|
||||
"assets",
|
||||
"cache",
|
||||
"icons",
|
||||
"instances",
|
||||
"libraries",
|
||||
"meta",
|
||||
"metacache",
|
||||
"mods",
|
||||
BuildConfig.LAUNCHER_CONFIGFILE,
|
||||
"themes",
|
||||
"translations"
|
||||
};
|
||||
QDirIterator files(originalData, dataFiles);
|
||||
while (files.hasNext()) {
|
||||
QString filePath(files.next());
|
||||
QString fileName(files.fileName());
|
||||
if (!dir.rename(filePath, FS::PathCombine(dataPath, fileName)))
|
||||
{
|
||||
qWarning() << "Failed to move " << fileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dataPath = originalData;
|
||||
QDir::setCurrent(dataPath);
|
||||
QFile file(originalData + "/dontmovemacdata");
|
||||
file.open(QIODevice::WriteOnly);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dataPath = originalData;
|
||||
QDir::setCurrent(dataPath);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Establish the mechanism for communication with an already running MultiMC that uses the same data path.
|
||||
* Establish the mechanism for communication with an already running PolyMC that uses the same data path.
|
||||
* If there is one, tell it what the user actually wanted to do and exit.
|
||||
* We want to initialize this before logging to avoid messing with the log of a potential already running copy.
|
||||
*/
|
||||
@ -520,24 +496,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
||||
qDebug() << "<> Log initialized.";
|
||||
}
|
||||
|
||||
// Set up paths
|
||||
{
|
||||
// Root path is used for updates.
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||
QDir foo(FS::PathCombine(binPath, ".."));
|
||||
m_rootPath = foo.absolutePath();
|
||||
#elif defined(Q_OS_WIN32)
|
||||
m_rootPath = binPath;
|
||||
#elif defined(Q_OS_MAC)
|
||||
QDir foo(FS::PathCombine(binPath, "../.."));
|
||||
m_rootPath = foo.absolutePath();
|
||||
// on macOS, touch the root to force Finder to reload the .app metadata (and fix any icon change issues)
|
||||
FS::updateTimestamp(m_rootPath);
|
||||
#endif
|
||||
|
||||
#ifdef MULTIMC_JARS_LOCATION
|
||||
m_jarsPath = TOSTRING(MULTIMC_JARS_LOCATION);
|
||||
#endif
|
||||
|
||||
qDebug() << BuildConfig.LAUNCHER_DISPLAYNAME << ", (c) 2013-2021 " << BuildConfig.LAUNCHER_COPYRIGHT;
|
||||
qDebug() << "Version : " << BuildConfig.printableVersionString();
|
||||
@ -566,26 +525,23 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
||||
qDebug() << "<> Paths set.";
|
||||
}
|
||||
|
||||
do // once
|
||||
if(m_liveCheck)
|
||||
{
|
||||
if(m_liveCheck)
|
||||
QFile check(liveCheckFile);
|
||||
if(check.open(QIODevice::WriteOnly | QIODevice::Truncate))
|
||||
{
|
||||
QFile check(liveCheckFile);
|
||||
if(!check.open(QIODevice::WriteOnly | QIODevice::Truncate))
|
||||
{
|
||||
qWarning() << "Could not open" << liveCheckFile << "for writing!";
|
||||
break;
|
||||
}
|
||||
auto payload = appID.toString().toUtf8();
|
||||
if(check.write(payload) != payload.size())
|
||||
if(check.write(payload) == payload.size())
|
||||
{
|
||||
check.close();
|
||||
} else {
|
||||
qWarning() << "Could not write into" << liveCheckFile << "!";
|
||||
check.remove();
|
||||
break;
|
||||
check.remove(); // also closes file!
|
||||
}
|
||||
check.close();
|
||||
} else {
|
||||
qWarning() << "Could not open" << liveCheckFile << "for writing!";
|
||||
}
|
||||
} while(false);
|
||||
}
|
||||
|
||||
// Initialize application settings
|
||||
{
|
||||
@ -595,15 +551,14 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
||||
m_settings->registerSetting("AutoUpdate", true);
|
||||
|
||||
// Theming
|
||||
m_settings->registerSetting("IconTheme", QString("multimc"));
|
||||
m_settings->registerSetting("IconTheme", QString("pe_colored"));
|
||||
m_settings->registerSetting("ApplicationTheme", QString("system"));
|
||||
|
||||
// Notifications
|
||||
m_settings->registerSetting("ShownNotifications", QString());
|
||||
|
||||
// Remembered state
|
||||
m_settings->registerSetting("LastUsedGroupForNewInstance", QString());
|
||||
|
||||
m_settings->registerSetting("MenuBarInsteadOfToolBar", false);
|
||||
|
||||
QString defaultMonospace;
|
||||
int defaultSize = 11;
|
||||
#ifdef Q_OS_WIN32
|
||||
@ -662,7 +617,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
||||
|
||||
// Memory
|
||||
m_settings->registerSetting({"MinMemAlloc", "MinMemoryAlloc"}, 512);
|
||||
m_settings->registerSetting({"MaxMemAlloc", "MaxMemoryAlloc"}, 1024);
|
||||
m_settings->registerSetting({"MaxMemAlloc", "MaxMemoryAlloc"}, 4096);
|
||||
m_settings->registerSetting("PermGen", 128);
|
||||
|
||||
// Java Settings
|
||||
@ -673,6 +628,8 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
||||
m_settings->registerSetting("JavaVendor", "");
|
||||
m_settings->registerSetting("LastHostname", "");
|
||||
m_settings->registerSetting("JvmArgs", "");
|
||||
m_settings->registerSetting("IgnoreJavaCompatibility", false);
|
||||
m_settings->registerSetting("IgnoreJavaWizard", false);
|
||||
|
||||
// Native library workarounds
|
||||
m_settings->registerSetting("UseNativeOpenAL", false);
|
||||
@ -686,6 +643,9 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
||||
// Minecraft launch method
|
||||
m_settings->registerSetting("MCLaunchMethod", "LauncherPart");
|
||||
|
||||
// Minecraft offline player name
|
||||
m_settings->registerSetting("LastOfflinePlayerName", "");
|
||||
|
||||
// Wrapper command for launch
|
||||
m_settings->registerSetting("WrapperCommand", "");
|
||||
|
||||
@ -714,8 +674,40 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
||||
|
||||
m_settings->registerSetting("UpdateDialogGeometry", "");
|
||||
|
||||
// paste.ee API key
|
||||
m_settings->registerSetting("PasteEEAPIKey", "multimc");
|
||||
// HACK: This code feels so stupid is there a less stupid way of doing this?
|
||||
{
|
||||
m_settings->registerSetting("PastebinURL", "");
|
||||
m_settings->registerSetting("PastebinType", PasteUpload::PasteType::Mclogs);
|
||||
m_settings->registerSetting("PastebinCustomAPIBase", "");
|
||||
|
||||
QString pastebinURL = m_settings->get("PastebinURL").toString();
|
||||
|
||||
bool userHadDefaultPastebin = pastebinURL == "https://0x0.st";
|
||||
if (!pastebinURL.isEmpty() && !userHadDefaultPastebin)
|
||||
{
|
||||
m_settings->set("PastebinType", PasteUpload::PasteType::NullPointer);
|
||||
m_settings->set("PastebinCustomAPIBase", pastebinURL);
|
||||
m_settings->reset("PastebinURL");
|
||||
}
|
||||
|
||||
bool ok;
|
||||
int pasteType = m_settings->get("PastebinType").toInt(&ok);
|
||||
// If PastebinType is invalid then reset the related settings.
|
||||
if (!ok || !(PasteUpload::PasteType::First <= pasteType && pasteType <= PasteUpload::PasteType::Last))
|
||||
{
|
||||
m_settings->reset("PastebinType");
|
||||
m_settings->reset("PastebinCustomAPIBase");
|
||||
}
|
||||
}
|
||||
// meta URL
|
||||
m_settings->registerSetting("MetaURLOverride", "");
|
||||
|
||||
m_settings->registerSetting("CloseAfterLaunch", false);
|
||||
m_settings->registerSetting("QuitAfterGameStop", false);
|
||||
|
||||
// Custom MSA credentials
|
||||
m_settings->registerSetting("MSAClientIDOverride", "");
|
||||
m_settings->registerSetting("CFKeyOverride", "");
|
||||
|
||||
// Init page provider
|
||||
{
|
||||
@ -728,7 +720,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
||||
m_globalSettingsProvider->addPage<ProxyPage>();
|
||||
m_globalSettingsProvider->addPage<ExternalToolsPage>();
|
||||
m_globalSettingsProvider->addPage<AccountListPage>();
|
||||
m_globalSettingsProvider->addPage<PasteEEPage>();
|
||||
m_globalSettingsProvider->addPage<APIPage>();
|
||||
}
|
||||
qDebug() << "<> Settings loaded.";
|
||||
}
|
||||
@ -854,6 +846,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
|
||||
m_metacache->addBase("ModpacksCHPacks", QDir("cache/ModpacksCHPacks").absolutePath());
|
||||
m_metacache->addBase("TechnicPacks", QDir("cache/TechnicPacks").absolutePath());
|
||||
m_metacache->addBase("FlamePacks", QDir("cache/FlamePacks").absolutePath());
|
||||
m_metacache->addBase("ModrinthPacks", QDir("cache/ModrinthPacks").absolutePath());
|
||||
m_metacache->addBase("root", QDir::currentPath());
|
||||
m_metacache->addBase("translations", QDir("translations").absolutePath());
|
||||
m_metacache->addBase("icons", QDir("cache/icons").absolutePath());
|
||||
@ -909,6 +902,10 @@ bool Application::createSetupWizard()
|
||||
{
|
||||
bool javaRequired = [&]()
|
||||
{
|
||||
bool ignoreJavaWizard = m_settings->get("IgnoreJavaWizard").toBool();
|
||||
if(ignoreJavaWizard) {
|
||||
return false;
|
||||
}
|
||||
QString currentHostName = QHostInfo::localHostName();
|
||||
QString oldHostName = settings()->get("LastHostname").toString();
|
||||
if (currentHostName != oldHostName)
|
||||
@ -930,7 +927,8 @@ bool Application::createSetupWizard()
|
||||
return true;
|
||||
return false;
|
||||
}();
|
||||
bool wizardRequired = javaRequired || languageRequired;
|
||||
bool pasteInterventionRequired = settings()->get("PastebinURL") != "";
|
||||
bool wizardRequired = javaRequired || languageRequired || pasteInterventionRequired;
|
||||
|
||||
if(wizardRequired)
|
||||
{
|
||||
@ -939,10 +937,16 @@ bool Application::createSetupWizard()
|
||||
{
|
||||
m_setupWizard->addPage(new LanguageWizardPage(m_setupWizard));
|
||||
}
|
||||
|
||||
if (javaRequired)
|
||||
{
|
||||
m_setupWizard->addPage(new JavaWizardPage(m_setupWizard));
|
||||
}
|
||||
|
||||
if (pasteInterventionRequired)
|
||||
{
|
||||
m_setupWizard->addPage(new PasteWizardPage(m_setupWizard));
|
||||
}
|
||||
connect(m_setupWizard, &QDialog::finished, this, &Application::setupWizardFinished);
|
||||
m_setupWizard->show();
|
||||
return true;
|
||||
@ -1125,6 +1129,15 @@ std::vector<ITheme *> Application::getValidApplicationThemes()
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Application::isFlatpak()
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
return QFile::exists("/.flatpak-info");
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Application::setApplicationTheme(const QString& name, bool initial)
|
||||
{
|
||||
auto systemPalette = qApp->palette();
|
||||
@ -1240,6 +1253,12 @@ bool Application::kill(InstancePtr instance)
|
||||
return true;
|
||||
}
|
||||
|
||||
void Application::closeCurrentWindow()
|
||||
{
|
||||
if (focusWindow())
|
||||
focusWindow()->close();
|
||||
}
|
||||
|
||||
void Application::addRunningInstance()
|
||||
{
|
||||
m_runningInstances ++;
|
||||
@ -1512,5 +1531,25 @@ QString Application::getJarsPath()
|
||||
{
|
||||
return FS::PathCombine(QCoreApplication::applicationDirPath(), "jars");
|
||||
}
|
||||
return m_jarsPath;
|
||||
return FS::PathCombine(m_rootPath, m_jarsPath);
|
||||
}
|
||||
|
||||
QString Application::getMSAClientID()
|
||||
{
|
||||
QString clientIDOverride = m_settings->get("MSAClientIDOverride").toString();
|
||||
if (!clientIDOverride.isEmpty()) {
|
||||
return clientIDOverride;
|
||||
}
|
||||
|
||||
return BuildConfig.MSA_CLIENT_ID;
|
||||
}
|
||||
|
||||
QString Application::getCurseKey()
|
||||
{
|
||||
QString keyOverride = m_settings->get("CFKeyOverride").toString();
|
||||
if (!keyOverride.isEmpty()) {
|
||||
return keyOverride;
|
||||
}
|
||||
|
||||
return BuildConfig.CURSEFORGE_API_KEY;
|
||||
}
|
||||
|
@ -1,3 +1,38 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QApplication>
|
||||
@ -69,6 +104,8 @@ public:
|
||||
|
||||
QIcon getThemedIcon(const QString& name);
|
||||
|
||||
bool isFlatpak();
|
||||
|
||||
void setIconTheme(const QString& name);
|
||||
|
||||
std::vector<ITheme *> getValidApplicationThemes();
|
||||
@ -117,6 +154,9 @@ public:
|
||||
|
||||
QString getJarsPath();
|
||||
|
||||
QString getMSAClientID();
|
||||
QString getCurseKey();
|
||||
|
||||
/// this is the root of the 'installation'. Used for automatic updates
|
||||
const QString &root() {
|
||||
return m_rootPath;
|
||||
@ -150,6 +190,7 @@ public slots:
|
||||
MinecraftAccountPtr accountToUse = nullptr
|
||||
);
|
||||
bool kill(InstancePtr instance);
|
||||
void closeCurrentWindow();
|
||||
|
||||
private slots:
|
||||
void on_windowClose();
|
||||
|
@ -1,16 +1,36 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* 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.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "BaseInstance.h"
|
||||
@ -39,6 +59,7 @@ BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr s
|
||||
m_settings->registerSetting("lastLaunchTime", 0);
|
||||
m_settings->registerSetting("totalTimePlayed", 0);
|
||||
m_settings->registerSetting("lastTimePlayed", 0);
|
||||
m_settings->registerSetting("InstanceType", "OneSix");
|
||||
|
||||
// Custom Commands
|
||||
auto commandSetting = m_settings->registerSetting({"OverrideCommands","OverrideLaunchCmd"}, false);
|
||||
|
@ -1,16 +1,36 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* 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.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
@ -37,6 +37,10 @@ set(CORE_SOURCES
|
||||
InstanceImportTask.h
|
||||
InstanceImportTask.cpp
|
||||
|
||||
# Mod downloading task
|
||||
ModDownloadTask.h
|
||||
ModDownloadTask.cpp
|
||||
|
||||
# Use tracking separate from memory management
|
||||
Usable.h
|
||||
|
||||
@ -140,6 +144,8 @@ set(LAUNCH_SOURCES
|
||||
launch/steps/TextPrint.h
|
||||
launch/steps/Update.cpp
|
||||
launch/steps/Update.h
|
||||
launch/steps/QuitAfterGameStop.cpp
|
||||
launch/steps/QuitAfterGameStop.h
|
||||
launch/LaunchStep.cpp
|
||||
launch/LaunchStep.h
|
||||
launch/LaunchTask.cpp
|
||||
@ -170,13 +176,6 @@ add_unit_test(DownloadTask
|
||||
DATA updater/testdata
|
||||
)
|
||||
|
||||
# Rarely used notifications
|
||||
set(NOTIFICATIONS_SOURCES
|
||||
# Notifications - short warning messages
|
||||
notifications/NotificationChecker.h
|
||||
notifications/NotificationChecker.cpp
|
||||
)
|
||||
|
||||
# Backend for the news bar... there's usually no news.
|
||||
set(NEWS_SOURCES
|
||||
# News System
|
||||
@ -221,7 +220,11 @@ set(MINECRAFT_SOURCES
|
||||
minecraft/auth/flows/Mojang.h
|
||||
minecraft/auth/flows/MSA.cpp
|
||||
minecraft/auth/flows/MSA.h
|
||||
minecraft/auth/flows/Offline.cpp
|
||||
minecraft/auth/flows/Offline.h
|
||||
|
||||
minecraft/auth/steps/OfflineStep.cpp
|
||||
minecraft/auth/steps/OfflineStep.h
|
||||
minecraft/auth/steps/EntitlementsStep.cpp
|
||||
minecraft/auth/steps/EntitlementsStep.h
|
||||
minecraft/auth/steps/GetSkinStep.cpp
|
||||
@ -232,6 +235,8 @@ set(MINECRAFT_SOURCES
|
||||
minecraft/auth/steps/MigrationEligibilityStep.h
|
||||
minecraft/auth/steps/MinecraftProfileStep.cpp
|
||||
minecraft/auth/steps/MinecraftProfileStep.h
|
||||
minecraft/auth/steps/MinecraftProfileStepMojang.cpp
|
||||
minecraft/auth/steps/MinecraftProfileStepMojang.h
|
||||
minecraft/auth/steps/MSAStep.cpp
|
||||
minecraft/auth/steps/MSAStep.h
|
||||
minecraft/auth/steps/XboxAuthorizationStep.cpp
|
||||
@ -278,13 +283,6 @@ set(MINECRAFT_SOURCES
|
||||
minecraft/launch/VerifyJavaInstall.cpp
|
||||
minecraft/launch/VerifyJavaInstall.h
|
||||
|
||||
minecraft/legacy/LegacyModList.h
|
||||
minecraft/legacy/LegacyModList.cpp
|
||||
minecraft/legacy/LegacyInstance.h
|
||||
minecraft/legacy/LegacyInstance.cpp
|
||||
minecraft/legacy/LegacyUpgradeTask.h
|
||||
minecraft/legacy/LegacyUpgradeTask.cpp
|
||||
|
||||
minecraft/GradleSpecifier.h
|
||||
minecraft/MinecraftInstance.cpp
|
||||
minecraft/MinecraftInstance.h
|
||||
@ -352,28 +350,30 @@ set(MINECRAFT_SOURCES
|
||||
|
||||
mojang/PackageManifest.h
|
||||
mojang/PackageManifest.cpp
|
||||
)
|
||||
minecraft/Agent.h)
|
||||
|
||||
add_unit_test(GradleSpecifier
|
||||
SOURCES minecraft/GradleSpecifier_test.cpp
|
||||
LIBS Launcher_logic
|
||||
)
|
||||
|
||||
add_executable(PackageManifest
|
||||
mojang/PackageManifest_test.cpp
|
||||
)
|
||||
target_link_libraries(PackageManifest
|
||||
Launcher_logic
|
||||
Qt5::Test
|
||||
)
|
||||
target_include_directories(PackageManifest
|
||||
PRIVATE ../cmake/UnitTest/
|
||||
)
|
||||
add_test(
|
||||
NAME PackageManifest
|
||||
COMMAND PackageManifest
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
if(BUILD_TESTING)
|
||||
add_executable(PackageManifest
|
||||
mojang/PackageManifest_test.cpp
|
||||
)
|
||||
target_link_libraries(PackageManifest
|
||||
Launcher_logic
|
||||
Qt5::Test
|
||||
)
|
||||
target_include_directories(PackageManifest
|
||||
PRIVATE ../cmake/UnitTest/
|
||||
)
|
||||
add_test(
|
||||
NAME PackageManifest
|
||||
COMMAND PackageManifest
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
add_unit_test(MojangVersionFormat
|
||||
SOURCES minecraft/MojangVersionFormat_test.cpp
|
||||
@ -415,6 +415,11 @@ set(TASKS_SOURCES
|
||||
tasks/SequentialTask.cpp
|
||||
)
|
||||
|
||||
add_unit_test(Task
|
||||
SOURCES tasks/Task_test.cpp
|
||||
LIBS Launcher_logic
|
||||
)
|
||||
|
||||
set(SETTINGS_SOURCES
|
||||
# Settings
|
||||
settings/INIFile.cpp
|
||||
@ -491,6 +496,16 @@ set(META_SOURCES
|
||||
meta/Index.h
|
||||
)
|
||||
|
||||
set(API_SOURCES
|
||||
modplatform/ModAPI.h
|
||||
|
||||
modplatform/flame/FlameAPI.h
|
||||
modplatform/modrinth/ModrinthAPI.h
|
||||
|
||||
modplatform/helpers/NetworkModAPI.h
|
||||
modplatform/helpers/NetworkModAPI.cpp
|
||||
)
|
||||
|
||||
set(FTB_SOURCES
|
||||
modplatform/legacy_ftb/PackFetchTask.h
|
||||
modplatform/legacy_ftb/PackFetchTask.cpp
|
||||
@ -506,12 +521,21 @@ set(FLAME_SOURCES
|
||||
# Flame
|
||||
modplatform/flame/FlamePackIndex.cpp
|
||||
modplatform/flame/FlamePackIndex.h
|
||||
modplatform/flame/FlameModIndex.cpp
|
||||
modplatform/flame/FlameModIndex.h
|
||||
modplatform/flame/PackManifest.h
|
||||
modplatform/flame/PackManifest.cpp
|
||||
modplatform/flame/FileResolvingTask.h
|
||||
modplatform/flame/FileResolvingTask.cpp
|
||||
)
|
||||
|
||||
set(MODRINTH_SOURCES
|
||||
modplatform/modrinth/ModrinthPackIndex.cpp
|
||||
modplatform/modrinth/ModrinthPackIndex.h
|
||||
modplatform/modrinth/ModrinthPackManifest.cpp
|
||||
modplatform/modrinth/ModrinthPackManifest.h
|
||||
)
|
||||
|
||||
set(MODPACKSCH_SOURCES
|
||||
modplatform/modpacksch/FTBPackInstallTask.h
|
||||
modplatform/modpacksch/FTBPackInstallTask.cpp
|
||||
@ -524,6 +548,8 @@ set(TECHNIC_SOURCES
|
||||
modplatform/technic/SingleZipPackInstallTask.cpp
|
||||
modplatform/technic/SolderPackInstallTask.h
|
||||
modplatform/technic/SolderPackInstallTask.cpp
|
||||
modplatform/technic/SolderPackManifest.h
|
||||
modplatform/technic/SolderPackManifest.cpp
|
||||
modplatform/technic/TechnicPackProcessor.h
|
||||
modplatform/technic/TechnicPackProcessor.cpp
|
||||
)
|
||||
@ -535,6 +561,8 @@ set(ATLAUNCHER_SOURCES
|
||||
modplatform/atlauncher/ATLPackInstallTask.h
|
||||
modplatform/atlauncher/ATLPackManifest.cpp
|
||||
modplatform/atlauncher/ATLPackManifest.h
|
||||
modplatform/atlauncher/ATLShareCode.cpp
|
||||
modplatform/atlauncher/ATLShareCode.h
|
||||
)
|
||||
|
||||
add_unit_test(Index
|
||||
@ -553,7 +581,6 @@ set(LOGIC_SOURCES
|
||||
${NET_SOURCES}
|
||||
${LAUNCH_SOURCES}
|
||||
${UPDATE_SOURCES}
|
||||
${NOTIFICATIONS_SOURCES}
|
||||
${NEWS_SOURCES}
|
||||
${MINECRAFT_SOURCES}
|
||||
${SCREENSHOTS_SOURCES}
|
||||
@ -564,8 +591,10 @@ set(LOGIC_SOURCES
|
||||
${TOOLS_SOURCES}
|
||||
${META_SOURCES}
|
||||
${ICONS_SOURCES}
|
||||
${API_SOURCES}
|
||||
${FTB_SOURCES}
|
||||
${FLAME_SOURCES}
|
||||
${MODRINTH_SOURCES}
|
||||
${MODPACKSCH_SOURCES}
|
||||
${TECHNIC_SOURCES}
|
||||
${ATLAUNCHER_SOURCES}
|
||||
@ -632,6 +661,8 @@ SET(LAUNCHER_SOURCES
|
||||
ui/setupwizard/JavaWizardPage.h
|
||||
ui/setupwizard/LanguageWizardPage.cpp
|
||||
ui/setupwizard/LanguageWizardPage.h
|
||||
ui/setupwizard/PasteWizardPage.cpp
|
||||
ui/setupwizard/PasteWizardPage.h
|
||||
|
||||
# GUI - themes
|
||||
ui/themes/FusionTheme.cpp
|
||||
@ -685,8 +716,6 @@ SET(LAUNCHER_SOURCES
|
||||
ui/pages/instance/OtherLogsPage.h
|
||||
ui/pages/instance/ServersPage.cpp
|
||||
ui/pages/instance/ServersPage.h
|
||||
ui/pages/instance/LegacyUpgradePage.cpp
|
||||
ui/pages/instance/LegacyUpgradePage.h
|
||||
ui/pages/instance/WorldListPage.cpp
|
||||
ui/pages/instance/WorldListPage.h
|
||||
|
||||
@ -707,13 +736,18 @@ SET(LAUNCHER_SOURCES
|
||||
ui/pages/global/LauncherPage.h
|
||||
ui/pages/global/ProxyPage.cpp
|
||||
ui/pages/global/ProxyPage.h
|
||||
ui/pages/global/PasteEEPage.cpp
|
||||
ui/pages/global/PasteEEPage.h
|
||||
ui/pages/global/APIPage.cpp
|
||||
ui/pages/global/APIPage.h
|
||||
|
||||
# GUI - platform pages
|
||||
ui/pages/modplatform/VanillaPage.cpp
|
||||
ui/pages/modplatform/VanillaPage.h
|
||||
|
||||
ui/pages/modplatform/ModPage.cpp
|
||||
ui/pages/modplatform/ModPage.h
|
||||
ui/pages/modplatform/ModModel.cpp
|
||||
ui/pages/modplatform/ModModel.h
|
||||
|
||||
ui/pages/modplatform/atlauncher/AtlFilterModel.cpp
|
||||
ui/pages/modplatform/atlauncher/AtlFilterModel.h
|
||||
ui/pages/modplatform/atlauncher/AtlListModel.cpp
|
||||
@ -739,6 +773,15 @@ SET(LAUNCHER_SOURCES
|
||||
ui/pages/modplatform/flame/FlameModel.h
|
||||
ui/pages/modplatform/flame/FlamePage.cpp
|
||||
ui/pages/modplatform/flame/FlamePage.h
|
||||
ui/pages/modplatform/flame/FlameModModel.cpp
|
||||
ui/pages/modplatform/flame/FlameModModel.h
|
||||
ui/pages/modplatform/flame/FlameModPage.cpp
|
||||
ui/pages/modplatform/flame/FlameModPage.h
|
||||
|
||||
ui/pages/modplatform/modrinth/ModrinthPage.cpp
|
||||
ui/pages/modplatform/modrinth/ModrinthPage.h
|
||||
ui/pages/modplatform/modrinth/ModrinthModel.cpp
|
||||
ui/pages/modplatform/modrinth/ModrinthModel.h
|
||||
|
||||
ui/pages/modplatform/technic/TechnicModel.cpp
|
||||
ui/pages/modplatform/technic/TechnicModel.h
|
||||
@ -748,6 +791,11 @@ SET(LAUNCHER_SOURCES
|
||||
ui/pages/modplatform/ImportPage.cpp
|
||||
ui/pages/modplatform/ImportPage.h
|
||||
|
||||
ui/pages/modplatform/modrinth/ModrinthModModel.cpp
|
||||
ui/pages/modplatform/modrinth/ModrinthModModel.h
|
||||
ui/pages/modplatform/modrinth/ModrinthModPage.cpp
|
||||
ui/pages/modplatform/modrinth/ModrinthModPage.h
|
||||
|
||||
# GUI - dialogs
|
||||
ui/dialogs/AboutDialog.cpp
|
||||
ui/dialogs/AboutDialog.h
|
||||
@ -769,23 +817,26 @@ SET(LAUNCHER_SOURCES
|
||||
ui/dialogs/LoginDialog.h
|
||||
ui/dialogs/MSALoginDialog.cpp
|
||||
ui/dialogs/MSALoginDialog.h
|
||||
ui/dialogs/OfflineLoginDialog.cpp
|
||||
ui/dialogs/OfflineLoginDialog.h
|
||||
ui/dialogs/NewComponentDialog.cpp
|
||||
ui/dialogs/NewComponentDialog.h
|
||||
ui/dialogs/NewInstanceDialog.cpp
|
||||
ui/dialogs/NewInstanceDialog.h
|
||||
ui/dialogs/NotificationDialog.cpp
|
||||
ui/dialogs/NotificationDialog.h
|
||||
ui/pagedialog/PageDialog.cpp
|
||||
ui/pagedialog/PageDialog.h
|
||||
ui/dialogs/ProgressDialog.cpp
|
||||
ui/dialogs/ProgressDialog.h
|
||||
ui/dialogs/ReviewMessageBox.cpp
|
||||
ui/dialogs/ReviewMessageBox.h
|
||||
ui/dialogs/UpdateDialog.cpp
|
||||
ui/dialogs/UpdateDialog.h
|
||||
ui/dialogs/VersionSelectDialog.cpp
|
||||
ui/dialogs/VersionSelectDialog.h
|
||||
ui/dialogs/SkinUploadDialog.cpp
|
||||
ui/dialogs/SkinUploadDialog.h
|
||||
|
||||
ui/dialogs/ModDownloadDialog.cpp
|
||||
ui/dialogs/ModDownloadDialog.h
|
||||
|
||||
# GUI - widgets
|
||||
ui/widgets/Common.cpp
|
||||
@ -810,6 +861,8 @@ SET(LAUNCHER_SOURCES
|
||||
ui/widgets/LogView.h
|
||||
ui/widgets/MCModInfoFrame.cpp
|
||||
ui/widgets/MCModInfoFrame.h
|
||||
ui/widgets/ModFilterWidget.cpp
|
||||
ui/widgets/ModFilterWidget.h
|
||||
ui/widgets/ModListView.cpp
|
||||
ui/widgets/ModListView.h
|
||||
ui/widgets/PageContainer.cpp
|
||||
@ -839,10 +892,11 @@ SET(LAUNCHER_SOURCES
|
||||
)
|
||||
|
||||
qt5_wrap_ui(LAUNCHER_UI
|
||||
ui/setupwizard/PasteWizardPage.ui
|
||||
ui/pages/global/AccountListPage.ui
|
||||
ui/pages/global/JavaPage.ui
|
||||
ui/pages/global/LauncherPage.ui
|
||||
ui/pages/global/PasteEEPage.ui
|
||||
ui/pages/global/APIPage.ui
|
||||
ui/pages/global/ProxyPage.ui
|
||||
ui/pages/global/MinecraftPage.ui
|
||||
ui/pages/global/ExternalToolsPage.ui
|
||||
@ -855,24 +909,25 @@ qt5_wrap_ui(LAUNCHER_UI
|
||||
ui/pages/instance/InstanceSettingsPage.ui
|
||||
ui/pages/instance/VersionPage.ui
|
||||
ui/pages/instance/WorldListPage.ui
|
||||
ui/pages/instance/LegacyUpgradePage.ui
|
||||
ui/pages/instance/ScreenshotsPage.ui
|
||||
ui/pages/modplatform/atlauncher/AtlOptionalModDialog.ui
|
||||
ui/pages/modplatform/atlauncher/AtlPage.ui
|
||||
ui/pages/modplatform/VanillaPage.ui
|
||||
ui/pages/modplatform/ModPage.ui
|
||||
ui/pages/modplatform/flame/FlamePage.ui
|
||||
ui/pages/modplatform/legacy_ftb/Page.ui
|
||||
ui/pages/modplatform/ImportPage.ui
|
||||
ui/pages/modplatform/ftb/FtbPage.ui
|
||||
ui/pages/modplatform/modrinth/ModrinthPage.ui
|
||||
ui/pages/modplatform/technic/TechnicPage.ui
|
||||
ui/widgets/InstanceCardWidget.ui
|
||||
ui/widgets/CustomCommands.ui
|
||||
ui/widgets/MCModInfoFrame.ui
|
||||
ui/widgets/ModFilterWidget.ui
|
||||
ui/dialogs/CopyInstanceDialog.ui
|
||||
ui/dialogs/ProfileSetupDialog.ui
|
||||
ui/dialogs/ProgressDialog.ui
|
||||
ui/dialogs/NewInstanceDialog.ui
|
||||
ui/dialogs/NotificationDialog.ui
|
||||
ui/dialogs/UpdateDialog.ui
|
||||
ui/dialogs/NewComponentDialog.ui
|
||||
ui/dialogs/ProfileSelectDialog.ui
|
||||
@ -880,9 +935,11 @@ qt5_wrap_ui(LAUNCHER_UI
|
||||
ui/dialogs/ExportInstanceDialog.ui
|
||||
ui/dialogs/IconPickerDialog.ui
|
||||
ui/dialogs/MSALoginDialog.ui
|
||||
ui/dialogs/OfflineLoginDialog.ui
|
||||
ui/dialogs/AboutDialog.ui
|
||||
ui/dialogs/LoginDialog.ui
|
||||
ui/dialogs/EditAccountDialog.ui
|
||||
ui/dialogs/ReviewMessageBox.ui
|
||||
)
|
||||
|
||||
qt5_add_resources(LAUNCHER_RESOURCES
|
||||
@ -908,9 +965,8 @@ endif()
|
||||
add_library(Launcher_logic STATIC ${LOGIC_SOURCES} ${LAUNCHER_SOURCES} ${LAUNCHER_UI} ${LAUNCHER_RESOURCES})
|
||||
target_link_libraries(Launcher_logic
|
||||
systeminfo
|
||||
Launcher_quazip
|
||||
Launcher_classparser
|
||||
${NBT_NAME}
|
||||
nbt++
|
||||
${ZLIB_LIBRARIES}
|
||||
optional-bare
|
||||
tomlc99
|
||||
@ -926,10 +982,10 @@ target_link_libraries(Launcher_logic
|
||||
)
|
||||
target_link_libraries(Launcher_logic
|
||||
Launcher_iconfix
|
||||
${QUAZIP_LIBRARIES}
|
||||
QuaZip::QuaZip
|
||||
hoedown
|
||||
Launcher_rainbow
|
||||
LocalPeer
|
||||
Launcher_rainbow
|
||||
)
|
||||
|
||||
target_link_libraries(Launcher_logic)
|
||||
@ -950,7 +1006,7 @@ if(DEFINED Launcher_APP_BINARY_DEFS)
|
||||
endif()
|
||||
|
||||
install(TARGETS ${Launcher_Name}
|
||||
BUNDLE DESTINATION ${BUNDLE_DEST_DIR} COMPONENT Runtime
|
||||
BUNDLE DESTINATION "." COMPONENT Runtime
|
||||
LIBRARY DESTINATION ${LIBRARY_DEST_DIR} COMPONENT Runtime
|
||||
RUNTIME DESTINATION ${BINARY_DEST_DIR} COMPONENT Runtime
|
||||
)
|
||||
@ -971,7 +1027,7 @@ if(INSTALL_BUNDLE STREQUAL "full")
|
||||
DIRECTORY "${QT_PLUGINS_DIR}/imageformats"
|
||||
DESTINATION ${PLUGIN_DEST_DIR}
|
||||
COMPONENT Runtime
|
||||
REGEX "tga|tiff|mng|webp" EXCLUDE
|
||||
REGEX "tga|tiff|mng" EXCLUDE
|
||||
)
|
||||
# Icon engines
|
||||
install(
|
||||
@ -1001,7 +1057,7 @@ if(INSTALL_BUNDLE STREQUAL "full")
|
||||
DIRECTORY "${QT_PLUGINS_DIR}/imageformats"
|
||||
DESTINATION ${PLUGIN_DEST_DIR}
|
||||
COMPONENT Runtime
|
||||
REGEX "tga|tiff|mng|webp" EXCLUDE
|
||||
REGEX "tga|tiff|mng" EXCLUDE
|
||||
REGEX "d\\." EXCLUDE
|
||||
REGEX "_debug\\." EXCLUDE
|
||||
REGEX "\\.dSYM" EXCLUDE
|
||||
|
@ -1,8 +1,43 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 dada513 <dada513@protonmail.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/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2022 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "DesktopServices.h"
|
||||
#include <QDir>
|
||||
#include <QDesktopServices>
|
||||
#include <QProcess>
|
||||
#include <QDebug>
|
||||
#include "Application.h"
|
||||
|
||||
/**
|
||||
* This shouldn't exist, but until QTBUG-9328 and other unreported bugs are fixed, it needs to be a thing.
|
||||
@ -84,7 +119,14 @@ bool openDirectory(const QString &path, bool ensureExists)
|
||||
return QDesktopServices::openUrl(QUrl::fromLocalFile(dir.absolutePath()));
|
||||
};
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||
return IndirectOpen(f);
|
||||
if(!APPLICATION->isFlatpak())
|
||||
{
|
||||
return IndirectOpen(f);
|
||||
}
|
||||
else
|
||||
{
|
||||
return f();
|
||||
}
|
||||
#else
|
||||
return f();
|
||||
#endif
|
||||
@ -98,7 +140,14 @@ bool openFile(const QString &path)
|
||||
return QDesktopServices::openUrl(QUrl::fromLocalFile(path));
|
||||
};
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||
return IndirectOpen(f);
|
||||
if(!APPLICATION->isFlatpak())
|
||||
{
|
||||
return IndirectOpen(f);
|
||||
}
|
||||
else
|
||||
{
|
||||
return f();
|
||||
}
|
||||
#else
|
||||
return f();
|
||||
#endif
|
||||
@ -109,10 +158,17 @@ bool openFile(const QString &application, const QString &path, const QString &wo
|
||||
qDebug() << "Opening file" << path << "using" << application;
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||
// FIXME: the pid here is fake. So if something depends on it, it will likely misbehave
|
||||
return IndirectOpen([&]()
|
||||
if(!APPLICATION->isFlatpak())
|
||||
{
|
||||
return QProcess::startDetached(application, QStringList() << path, workingDirectory);
|
||||
}, pid);
|
||||
return IndirectOpen([&]()
|
||||
{
|
||||
return QProcess::startDetached(application, QStringList() << path, workingDirectory);
|
||||
}, pid);
|
||||
}
|
||||
else
|
||||
{
|
||||
return QProcess::startDetached(application, QStringList() << path, workingDirectory, pid);
|
||||
}
|
||||
#else
|
||||
return QProcess::startDetached(application, QStringList() << path, workingDirectory, pid);
|
||||
#endif
|
||||
@ -122,11 +178,18 @@ bool run(const QString &application, const QStringList &args, const QString &wor
|
||||
{
|
||||
qDebug() << "Running" << application << "with args" << args.join(' ');
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||
if(!APPLICATION->isFlatpak())
|
||||
{
|
||||
// FIXME: the pid here is fake. So if something depends on it, it will likely misbehave
|
||||
return IndirectOpen([&]()
|
||||
{
|
||||
return QProcess::startDetached(application, args, workingDirectory);
|
||||
}, pid);
|
||||
}
|
||||
else
|
||||
{
|
||||
return QProcess::startDetached(application, args, workingDirectory, pid);
|
||||
}
|
||||
#else
|
||||
return QProcess::startDetached(application, args, workingDirectory, pid);
|
||||
#endif
|
||||
@ -140,7 +203,14 @@ bool openUrl(const QUrl &url)
|
||||
return QDesktopServices::openUrl(url);
|
||||
};
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||
return IndirectOpen(f);
|
||||
if(!APPLICATION->isFlatpak())
|
||||
{
|
||||
return IndirectOpen(f);
|
||||
}
|
||||
else
|
||||
{
|
||||
return f();
|
||||
}
|
||||
#else
|
||||
return f();
|
||||
#endif
|
||||
|
@ -42,7 +42,6 @@ void InstanceCopyTask::copyFinished()
|
||||
}
|
||||
// FIXME: shouldn't this be able to report errors?
|
||||
auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(m_stagingPath, "instance.cfg"));
|
||||
instanceSettings->registerSetting("InstanceType", "Legacy");
|
||||
|
||||
InstancePtr inst(new NullInstance(m_globalSettings, instanceSettings, m_stagingPath));
|
||||
inst->setName(m_instName);
|
||||
|
@ -9,6 +9,15 @@
|
||||
InstanceCreationTask::InstanceCreationTask(BaseVersionPtr version)
|
||||
{
|
||||
m_version = version;
|
||||
m_usingLoader = false;
|
||||
}
|
||||
|
||||
InstanceCreationTask::InstanceCreationTask(BaseVersionPtr version, QString loader, BaseVersionPtr loaderVersion)
|
||||
{
|
||||
m_version = version;
|
||||
m_usingLoader = true;
|
||||
m_loader = loader;
|
||||
m_loaderVersion = loaderVersion;
|
||||
}
|
||||
|
||||
void InstanceCreationTask::executeTask()
|
||||
@ -17,12 +26,12 @@ void InstanceCreationTask::executeTask()
|
||||
{
|
||||
auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(m_stagingPath, "instance.cfg"));
|
||||
instanceSettings->suspendSave();
|
||||
instanceSettings->registerSetting("InstanceType", "Legacy");
|
||||
instanceSettings->set("InstanceType", "OneSix");
|
||||
MinecraftInstance inst(m_globalSettings, instanceSettings, m_stagingPath);
|
||||
auto components = inst.getPackProfile();
|
||||
components->buildingFromScratch();
|
||||
components->setComponentVersion("net.minecraft", m_version->descriptor(), true);
|
||||
if(m_usingLoader)
|
||||
components->setComponentVersion(m_loader, m_loaderVersion->descriptor());
|
||||
inst.setName(m_instName);
|
||||
inst.setIconKey(m_instIcon);
|
||||
instanceSettings->resumeSave();
|
||||
|
@ -12,6 +12,7 @@ class InstanceCreationTask : public InstanceTask
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit InstanceCreationTask(BaseVersionPtr version);
|
||||
explicit InstanceCreationTask(BaseVersionPtr version, QString loader, BaseVersionPtr loaderVersion);
|
||||
|
||||
protected:
|
||||
//! Entry point for tasks.
|
||||
@ -19,4 +20,7 @@ protected:
|
||||
|
||||
private: /* data */
|
||||
BaseVersionPtr m_version;
|
||||
bool m_usingLoader;
|
||||
QString m_loader;
|
||||
BaseVersionPtr m_loaderVersion;
|
||||
};
|
||||
|
@ -1,43 +1,81 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* 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.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "InstanceImportTask.h"
|
||||
#include <QtConcurrentRun>
|
||||
#include "Application.h"
|
||||
#include "BaseInstance.h"
|
||||
#include "FileSystem.h"
|
||||
#include "Application.h"
|
||||
#include "MMCZip.h"
|
||||
#include "NullInstance.h"
|
||||
#include "settings/INISettingsObject.h"
|
||||
#include "icons/IconList.h"
|
||||
#include "icons/IconUtils.h"
|
||||
#include <QtConcurrentRun>
|
||||
#include "settings/INISettingsObject.h"
|
||||
|
||||
// FIXME: this does not belong here, it's Minecraft/Flame specific
|
||||
#include <quazip/quazipdir.h>
|
||||
#include "Json.h"
|
||||
#include "minecraft/MinecraftInstance.h"
|
||||
#include "minecraft/PackProfile.h"
|
||||
#include "modplatform/flame/FileResolvingTask.h"
|
||||
#include "modplatform/flame/PackManifest.h"
|
||||
#include "Json.h"
|
||||
#include <quazipdir.h>
|
||||
#include "modplatform/modrinth/ModrinthPackManifest.h"
|
||||
#include "modplatform/technic/TechnicPackProcessor.h"
|
||||
|
||||
#include "icons/IconList.h"
|
||||
#include "Application.h"
|
||||
#include "icons/IconList.h"
|
||||
#include "net/ChecksumValidator.h"
|
||||
|
||||
InstanceImportTask::InstanceImportTask(const QUrl sourceUrl)
|
||||
#include "ui/dialogs/CustomMessageBox.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
InstanceImportTask::InstanceImportTask(const QUrl sourceUrl, QWidget* parent)
|
||||
{
|
||||
m_sourceUrl = sourceUrl;
|
||||
m_parent = parent;
|
||||
}
|
||||
|
||||
bool InstanceImportTask::abort()
|
||||
{
|
||||
m_filesNetJob->abort();
|
||||
m_extractFuture.cancel();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void InstanceImportTask::executeTask()
|
||||
@ -101,6 +139,7 @@ void InstanceImportTask::processZipPack()
|
||||
QString mmcFound = MMCZip::findFolderOfFileInZip(m_packZip.get(), "instance.cfg");
|
||||
bool technicFound = QuaZipDir(m_packZip.get()).exists("/bin/modpack.jar") || QuaZipDir(m_packZip.get()).exists("/bin/version.json");
|
||||
QString flameFound = MMCZip::findFolderOfFileInZip(m_packZip.get(), "manifest.json");
|
||||
QString modrinthFound = MMCZip::findFolderOfFileInZip(m_packZip.get(), "modrinth.index.json");
|
||||
QString root;
|
||||
if(!mmcFound.isNull())
|
||||
{
|
||||
@ -124,6 +163,13 @@ void InstanceImportTask::processZipPack()
|
||||
root = flameFound;
|
||||
m_modpackType = ModpackType::Flame;
|
||||
}
|
||||
else if(!modrinthFound.isNull())
|
||||
{
|
||||
// process as Modrinth pack
|
||||
qDebug() << "Modrinth:" << modrinthFound;
|
||||
root = modrinthFound;
|
||||
m_modpackType = ModpackType::Modrinth;
|
||||
}
|
||||
if(m_modpackType == ModpackType::Unknown)
|
||||
{
|
||||
emitFailed(tr("Archive does not contain a recognized modpack type."));
|
||||
@ -180,15 +226,18 @@ void InstanceImportTask::extractFinished()
|
||||
|
||||
switch(m_modpackType)
|
||||
{
|
||||
case ModpackType::Flame:
|
||||
processFlame();
|
||||
return;
|
||||
case ModpackType::MultiMC:
|
||||
processMultiMC();
|
||||
return;
|
||||
case ModpackType::Technic:
|
||||
processTechnic();
|
||||
return;
|
||||
case ModpackType::Flame:
|
||||
processFlame();
|
||||
return;
|
||||
case ModpackType::Modrinth:
|
||||
processModrinth();
|
||||
return;
|
||||
case ModpackType::Unknown:
|
||||
emitFailed(tr("Archive does not contain a recognized modpack type."));
|
||||
return;
|
||||
@ -241,6 +290,7 @@ void InstanceImportTask::processFlame()
|
||||
|
||||
QString forgeVersion;
|
||||
QString fabricVersion;
|
||||
// TODO: is Quilt relevant here?
|
||||
for(auto &loader: pack.minecraft.modLoaders)
|
||||
{
|
||||
auto id = loader.id;
|
||||
@ -261,8 +311,6 @@ void InstanceImportTask::processFlame()
|
||||
|
||||
QString configPath = FS::PathCombine(m_stagingPath, "instance.cfg");
|
||||
auto instanceSettings = std::make_shared<INISettingsObject>(configPath);
|
||||
instanceSettings->registerSetting("InstanceType", "Legacy");
|
||||
instanceSettings->set("InstanceType", "OneSix");
|
||||
MinecraftInstance instance(m_globalSettings, instanceSettings, m_stagingPath);
|
||||
auto mcVersion = pack.minecraft.version;
|
||||
// Hack to correct some 'special sauce'...
|
||||
@ -285,7 +333,7 @@ void InstanceImportTask::processFlame()
|
||||
}
|
||||
else
|
||||
{
|
||||
logWarning(tr("Could not map recommended forge version for Minecraft %1").arg(mcVersion));
|
||||
logWarning(tr("Could not map recommended Forge version for Minecraft %1").arg(mcVersion));
|
||||
}
|
||||
}
|
||||
components->setComponentVersion("net.minecraftforge", forgeVersion);
|
||||
@ -422,7 +470,6 @@ void InstanceImportTask::processMultiMC()
|
||||
{
|
||||
QString configPath = FS::PathCombine(m_stagingPath, "instance.cfg");
|
||||
auto instanceSettings = std::make_shared<INISettingsObject>(configPath);
|
||||
instanceSettings->registerSetting("InstanceType", "Legacy");
|
||||
|
||||
NullInstance instance(m_globalSettings, instanceSettings, m_stagingPath);
|
||||
|
||||
@ -433,25 +480,174 @@ void InstanceImportTask::processMultiMC()
|
||||
instance.setName(m_instName);
|
||||
|
||||
// if the icon was specified by user, use that. otherwise pull icon from the pack
|
||||
if (m_instIcon != "default") {
|
||||
instance.setIconKey(m_instIcon);
|
||||
} else {
|
||||
m_instIcon = instance.iconKey();
|
||||
|
||||
auto importIconPath = IconUtils::findBestIconIn(instance.instanceRoot(), m_instIcon);
|
||||
if (!importIconPath.isNull() && QFile::exists(importIconPath)) {
|
||||
// import icon
|
||||
auto iconList = APPLICATION->icons();
|
||||
if (iconList->iconFileExists(m_instIcon)) {
|
||||
iconList->deleteIcon(m_instIcon);
|
||||
}
|
||||
iconList->installIcons({ importIconPath });
|
||||
}
|
||||
}
|
||||
emitSucceeded();
|
||||
}
|
||||
|
||||
void InstanceImportTask::processModrinth()
|
||||
{
|
||||
std::vector<Modrinth::File> files;
|
||||
QString minecraftVersion, fabricVersion, quiltVersion, forgeVersion;
|
||||
try {
|
||||
QString indexPath = FS::PathCombine(m_stagingPath, "modrinth.index.json");
|
||||
auto doc = Json::requireDocument(indexPath);
|
||||
auto obj = Json::requireObject(doc, "modrinth.index.json");
|
||||
int formatVersion = Json::requireInteger(obj, "formatVersion", "modrinth.index.json");
|
||||
if (formatVersion == 1) {
|
||||
auto game = Json::requireString(obj, "game", "modrinth.index.json");
|
||||
if (game != "minecraft") {
|
||||
throw JSONValidationError("Unknown game: " + game);
|
||||
}
|
||||
|
||||
auto jsonFiles = Json::requireIsArrayOf<QJsonObject>(obj, "files", "modrinth.index.json");
|
||||
bool had_optional = false;
|
||||
for (auto& obj : jsonFiles) {
|
||||
Modrinth::File file;
|
||||
file.path = Json::requireString(obj, "path");
|
||||
|
||||
auto env = Json::ensureObject(obj, "env");
|
||||
QString support = Json::ensureString(env, "client", "unsupported");
|
||||
if (support == "unsupported") {
|
||||
continue;
|
||||
} else if (support == "optional") {
|
||||
// TODO: Make a review dialog for choosing which ones the user wants!
|
||||
if (!had_optional) {
|
||||
had_optional = true;
|
||||
auto info = CustomMessageBox::selectable(
|
||||
m_parent, tr("Optional mod detected!"),
|
||||
tr("One or more mods from this modpack are optional. They will be downloaded, but disabled by default!"), QMessageBox::Information);
|
||||
info->exec();
|
||||
}
|
||||
|
||||
if (file.path.endsWith(".jar"))
|
||||
file.path += ".disabled";
|
||||
}
|
||||
|
||||
QJsonObject hashes = Json::requireObject(obj, "hashes");
|
||||
QString hash;
|
||||
QCryptographicHash::Algorithm hashAlgorithm;
|
||||
hash = Json::ensureString(hashes, "sha1");
|
||||
hashAlgorithm = QCryptographicHash::Sha1;
|
||||
if (hash.isEmpty()) {
|
||||
hash = Json::ensureString(hashes, "sha512");
|
||||
hashAlgorithm = QCryptographicHash::Sha512;
|
||||
if (hash.isEmpty()) {
|
||||
hash = Json::ensureString(hashes, "sha256");
|
||||
hashAlgorithm = QCryptographicHash::Sha256;
|
||||
if (hash.isEmpty()) {
|
||||
throw JSONValidationError("No hash found for: " + file.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
file.hash = QByteArray::fromHex(hash.toLatin1());
|
||||
file.hashAlgorithm = hashAlgorithm;
|
||||
// Do not use requireUrl, which uses StrictMode, instead use QUrl's default TolerantMode
|
||||
// (as Modrinth seems to incorrectly handle spaces)
|
||||
file.download = Json::requireString(Json::ensureArray(obj, "downloads").first(), "Download URL for " + file.path);
|
||||
if (!file.download.isValid() || !Modrinth::validateDownloadUrl(file.download)) {
|
||||
throw JSONValidationError("Download URL for " + file.path + " is not a correctly formatted URL");
|
||||
}
|
||||
files.push_back(file);
|
||||
}
|
||||
|
||||
auto dependencies = Json::requireObject(obj, "dependencies", "modrinth.index.json");
|
||||
for (auto it = dependencies.begin(), end = dependencies.end(); it != end; ++it) {
|
||||
QString name = it.key();
|
||||
if (name == "minecraft") {
|
||||
minecraftVersion = Json::requireString(*it, "Minecraft version");
|
||||
}
|
||||
else if (name == "fabric-loader") {
|
||||
fabricVersion = Json::requireString(*it, "Fabric Loader version");
|
||||
}
|
||||
else if (name == "quilt-loader") {
|
||||
quiltVersion = Json::requireString(*it, "Quilt Loader version");
|
||||
}
|
||||
else if (name == "forge") {
|
||||
forgeVersion = Json::requireString(*it, "Forge version");
|
||||
}
|
||||
else {
|
||||
throw JSONValidationError("Unknown dependency type: " + name);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw JSONValidationError(QStringLiteral("Unknown format version: %s").arg(formatVersion));
|
||||
}
|
||||
QFile::remove(indexPath);
|
||||
} catch (const JSONValidationError& e) {
|
||||
emitFailed(tr("Could not understand pack index:\n") + e.cause());
|
||||
return;
|
||||
}
|
||||
|
||||
QString overridePath = FS::PathCombine(m_stagingPath, "overrides");
|
||||
if (QFile::exists(overridePath)) {
|
||||
QString mcPath = FS::PathCombine(m_stagingPath, ".minecraft");
|
||||
if (!QFile::rename(overridePath, mcPath)) {
|
||||
emitFailed(tr("Could not rename the overrides folder:\n") + "overrides");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QString configPath = FS::PathCombine(m_stagingPath, "instance.cfg");
|
||||
auto instanceSettings = std::make_shared<INISettingsObject>(configPath);
|
||||
MinecraftInstance instance(m_globalSettings, instanceSettings, m_stagingPath);
|
||||
auto components = instance.getPackProfile();
|
||||
components->buildingFromScratch();
|
||||
components->setComponentVersion("net.minecraft", minecraftVersion, true);
|
||||
if (!fabricVersion.isEmpty())
|
||||
components->setComponentVersion("net.fabricmc.fabric-loader", fabricVersion, true);
|
||||
if (!quiltVersion.isEmpty())
|
||||
components->setComponentVersion("org.quiltmc.quilt-loader", quiltVersion, true);
|
||||
if (!forgeVersion.isEmpty())
|
||||
components->setComponentVersion("net.minecraftforge", forgeVersion, true);
|
||||
if (m_instIcon != "default")
|
||||
{
|
||||
instance.setIconKey(m_instIcon);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_instIcon = instance.iconKey();
|
||||
|
||||
auto importIconPath = IconUtils::findBestIconIn(instance.instanceRoot(), m_instIcon);
|
||||
if (!importIconPath.isNull() && QFile::exists(importIconPath))
|
||||
{
|
||||
// import icon
|
||||
auto iconList = APPLICATION->icons();
|
||||
if (iconList->iconFileExists(m_instIcon))
|
||||
{
|
||||
iconList->deleteIcon(m_instIcon);
|
||||
}
|
||||
iconList->installIcons({importIconPath});
|
||||
}
|
||||
instance.setIconKey("modrinth");
|
||||
}
|
||||
emitSucceeded();
|
||||
instance.setName(m_instName);
|
||||
instance.saveNow();
|
||||
|
||||
m_filesNetJob = new NetJob(tr("Mod download"), APPLICATION->network());
|
||||
for (auto &file : files)
|
||||
{
|
||||
auto path = FS::PathCombine(m_stagingPath, ".minecraft", file.path);
|
||||
qDebug() << "Will download" << file.download << "to" << path;
|
||||
auto dl = Net::Download::makeFile(file.download, path);
|
||||
dl->addValidator(new Net::ChecksumValidator(file.hashAlgorithm, file.hash));
|
||||
m_filesNetJob->addNetAction(dl);
|
||||
}
|
||||
connect(m_filesNetJob.get(), &NetJob::succeeded, this, [&]()
|
||||
{
|
||||
m_filesNetJob.reset();
|
||||
emitSucceeded();
|
||||
}
|
||||
);
|
||||
connect(m_filesNetJob.get(), &NetJob::failed, [&](const QString &reason)
|
||||
{
|
||||
m_filesNetJob.reset();
|
||||
emitFailed(reason);
|
||||
});
|
||||
connect(m_filesNetJob.get(), &NetJob::progress, [&](qint64 current, qint64 total)
|
||||
{
|
||||
setProgress(current, total);
|
||||
});
|
||||
setStatus(tr("Downloading mods..."));
|
||||
m_filesNetJob->start();
|
||||
}
|
||||
|
@ -1,16 +1,36 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* 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.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
@ -35,7 +55,10 @@ class InstanceImportTask : public InstanceTask
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit InstanceImportTask(const QUrl sourceUrl);
|
||||
explicit InstanceImportTask(const QUrl sourceUrl, QWidget* parent = nullptr);
|
||||
|
||||
bool canAbort() const override { return true; }
|
||||
bool abort() override;
|
||||
|
||||
protected:
|
||||
//! Entry point for tasks.
|
||||
@ -44,8 +67,9 @@ protected:
|
||||
private:
|
||||
void processZipPack();
|
||||
void processMultiMC();
|
||||
void processFlame();
|
||||
void processTechnic();
|
||||
void processFlame();
|
||||
void processModrinth();
|
||||
|
||||
private slots:
|
||||
void downloadSucceeded();
|
||||
@ -66,7 +90,11 @@ private: /* data */
|
||||
enum class ModpackType{
|
||||
Unknown,
|
||||
MultiMC,
|
||||
Technic,
|
||||
Flame,
|
||||
Technic
|
||||
Modrinth,
|
||||
} m_modpackType = ModpackType::Unknown;
|
||||
|
||||
//FIXME: nuke
|
||||
QWidget* m_parent;
|
||||
};
|
||||
|
@ -32,13 +32,16 @@
|
||||
#include "BaseInstance.h"
|
||||
#include "InstanceTask.h"
|
||||
#include "settings/INISettingsObject.h"
|
||||
#include "minecraft/legacy/LegacyInstance.h"
|
||||
#include "NullInstance.h"
|
||||
#include "minecraft/MinecraftInstance.h"
|
||||
#include "FileSystem.h"
|
||||
#include "ExponentialSeries.h"
|
||||
#include "WatchLock.h"
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
const static int GROUP_FILE_FORMAT_VERSION = 1;
|
||||
|
||||
InstanceList::InstanceList(SettingsObjectPtr settings, const QString & instDir, QObject *parent)
|
||||
@ -544,23 +547,8 @@ InstancePtr InstanceList::loadInstance(const InstanceId& id)
|
||||
auto instanceRoot = FS::PathCombine(m_instDir, id);
|
||||
auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(instanceRoot, "instance.cfg"));
|
||||
InstancePtr inst;
|
||||
|
||||
instanceSettings->registerSetting("InstanceType", "Legacy");
|
||||
|
||||
QString inst_type = instanceSettings->get("InstanceType").toString();
|
||||
|
||||
if (inst_type == "OneSix" || inst_type == "Nostalgia")
|
||||
{
|
||||
inst.reset(new MinecraftInstance(m_globalSettings, instanceSettings, instanceRoot));
|
||||
}
|
||||
else if (inst_type == "Legacy")
|
||||
{
|
||||
inst.reset(new LegacyInstance(m_globalSettings, instanceSettings, instanceRoot));
|
||||
}
|
||||
else
|
||||
{
|
||||
inst.reset(new NullInstance(m_globalSettings, instanceSettings, instanceRoot));
|
||||
}
|
||||
// TODO: Handle incompatible instances
|
||||
inst.reset(new MinecraftInstance(m_globalSettings, instanceSettings, instanceRoot));
|
||||
qDebug() << "Loaded instance " << inst->name() << " from " << inst->instanceRoot();
|
||||
return inst;
|
||||
}
|
||||
@ -867,13 +855,18 @@ Task * InstanceList::wrapInstanceTask(InstanceTask * task)
|
||||
QString InstanceList::getStagedInstancePath()
|
||||
{
|
||||
QString key = QUuid::createUuid().toString();
|
||||
QString relPath = FS::PathCombine("_LAUNCHER_TEMP/" , key);
|
||||
QString tempDir = ".LAUNCHER_TEMP/";
|
||||
QString relPath = FS::PathCombine(tempDir, key);
|
||||
QDir rootPath(m_instDir);
|
||||
auto path = FS::PathCombine(m_instDir, relPath);
|
||||
if(!rootPath.mkpath(relPath))
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
#ifdef Q_OS_WIN32
|
||||
auto tempPath = FS::PathCombine(m_instDir, tempDir);
|
||||
SetFileAttributesA(tempPath.toStdString().c_str(), FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
|
||||
#endif
|
||||
return path;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
#include "minecraft/MinecraftInstance.h"
|
||||
#include "minecraft/legacy/LegacyInstance.h"
|
||||
#include <FileSystem.h>
|
||||
#include "ui/pages/BasePage.h"
|
||||
#include "ui/pages/BasePageProvider.h"
|
||||
@ -14,7 +13,6 @@
|
||||
#include "ui/pages/instance/ScreenshotsPage.h"
|
||||
#include "ui/pages/instance/InstanceSettingsPage.h"
|
||||
#include "ui/pages/instance/OtherLogsPage.h"
|
||||
#include "ui/pages/instance/LegacyUpgradePage.h"
|
||||
#include "ui/pages/instance/WorldListPage.h"
|
||||
#include "ui/pages/instance/ServersPage.h"
|
||||
#include "ui/pages/instance/GameOptionsPage.h"
|
||||
@ -34,31 +32,20 @@ public:
|
||||
QList<BasePage *> values;
|
||||
values.append(new LogPage(inst));
|
||||
std::shared_ptr<MinecraftInstance> onesix = std::dynamic_pointer_cast<MinecraftInstance>(inst);
|
||||
if(onesix)
|
||||
{
|
||||
values.append(new VersionPage(onesix.get()));
|
||||
auto modsPage = new ModFolderPage(onesix.get(), onesix->loaderModList(), "mods", "loadermods", tr("Loader mods"), "Loader-mods");
|
||||
modsPage->setFilter("%1 (*.zip *.jar *.litemod)");
|
||||
values.append(modsPage);
|
||||
values.append(new CoreModFolderPage(onesix.get(), onesix->coreModList(), "coremods", "coremods", tr("Core mods"), "Core-mods"));
|
||||
values.append(new ResourcePackPage(onesix.get()));
|
||||
values.append(new TexturePackPage(onesix.get()));
|
||||
values.append(new ShaderPackPage(onesix.get()));
|
||||
values.append(new NotesPage(onesix.get()));
|
||||
values.append(new WorldListPage(onesix.get(), onesix->worldList()));
|
||||
values.append(new ServersPage(onesix));
|
||||
// values.append(new GameOptionsPage(onesix.get()));
|
||||
values.append(new ScreenshotsPage(FS::PathCombine(onesix->gameRoot(), "screenshots")));
|
||||
values.append(new InstanceSettingsPage(onesix.get()));
|
||||
}
|
||||
std::shared_ptr<LegacyInstance> legacy = std::dynamic_pointer_cast<LegacyInstance>(inst);
|
||||
if(legacy)
|
||||
{
|
||||
values.append(new LegacyUpgradePage(legacy));
|
||||
values.append(new NotesPage(legacy.get()));
|
||||
values.append(new WorldListPage(legacy.get(), legacy->worldList()));
|
||||
values.append(new ScreenshotsPage(FS::PathCombine(legacy->gameRoot(), "screenshots")));
|
||||
}
|
||||
values.append(new VersionPage(onesix.get()));
|
||||
auto modsPage = new ModFolderPage(onesix.get(), onesix->loaderModList(), "mods", "loadermods", tr("Mods"), "Loader-mods");
|
||||
modsPage->setFilter("%1 (*.zip *.jar *.litemod)");
|
||||
values.append(modsPage);
|
||||
values.append(new CoreModFolderPage(onesix.get(), onesix->coreModList(), "coremods", "coremods", tr("Core mods"), "Core-mods"));
|
||||
values.append(new ResourcePackPage(onesix.get()));
|
||||
values.append(new TexturePackPage(onesix.get()));
|
||||
values.append(new ShaderPackPage(onesix.get()));
|
||||
values.append(new NotesPage(onesix.get()));
|
||||
values.append(new WorldListPage(onesix.get(), onesix->worldList()));
|
||||
values.append(new ServersPage(onesix));
|
||||
// values.append(new GameOptionsPage(onesix.get()));
|
||||
values.append(new ScreenshotsPage(FS::PathCombine(onesix->gameRoot(), "screenshots")));
|
||||
values.append(new InstanceSettingsPage(onesix.get()));
|
||||
auto logMatcher = inst->getLogFileMatcher();
|
||||
if(logMatcher)
|
||||
{
|
||||
@ -74,3 +61,4 @@ public:
|
||||
protected:
|
||||
InstancePtr inst;
|
||||
};
|
||||
|
||||
|
@ -8,7 +8,7 @@ bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget *parent)
|
||||
|| jvmargs.contains("-XX-MaxHeapSize") || jvmargs.contains("-XX:InitialHeapSize"))
|
||||
{
|
||||
auto warnStr = QObject::tr(
|
||||
"You tried to manually set a JVM memory option (using \"-XX:PermSize\", \"-XX-MaxHeapSize\", \"-XX:InitialHeapSize\", \"-Xmx\" or \"-Xms\").\n"
|
||||
"You tried to manually set a JVM memory option (using \"-XX:PermSize\", \"-XX-MaxHeapSize\", \"-XX:InitialHeapSize\", \"-Xmx\" or \"-Xms\").\n"
|
||||
"There are dedicated boxes for these in the settings (Java tab, in the Memory group at the top).\n"
|
||||
"This message will be displayed until you remove them from the JVM arguments.");
|
||||
CustomMessageBox::selectable(
|
||||
@ -17,6 +17,17 @@ bool JavaCommon::checkJVMArgs(QString jvmargs, QWidget *parent)
|
||||
QMessageBox::Warning)->exec();
|
||||
return false;
|
||||
}
|
||||
// block lunacy with passing required version to the JVM
|
||||
if (jvmargs.contains(QRegExp("-version:.*"))) {
|
||||
auto warnStr = QObject::tr(
|
||||
"You tried to pass required Java version argument to the JVM (using \"-version:xxx\"). This is not safe and will not be allowed.\n"
|
||||
"This message will be displayed until you remove this from the JVM arguments.");
|
||||
CustomMessageBox::selectable(
|
||||
parent, QObject::tr("JVM arguments warning"),
|
||||
warnStr,
|
||||
QMessageBox::Warning)->exec();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -40,7 +51,7 @@ void JavaCommon::javaArgsWereBad(QWidget *parent, JavaCheckResult result)
|
||||
auto htmlError = result.errorLog;
|
||||
QString text;
|
||||
htmlError.replace('\n', "<br />");
|
||||
text += QObject::tr("The specified java binary didn't work with the arguments you provided:<br />");
|
||||
text += QObject::tr("The specified Java binary didn't work with the arguments you provided:<br />");
|
||||
text += QString("<font color=\"red\">%1</font>").arg(htmlError);
|
||||
CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
|
||||
}
|
||||
@ -49,8 +60,8 @@ void JavaCommon::javaBinaryWasBad(QWidget *parent, JavaCheckResult result)
|
||||
{
|
||||
QString text;
|
||||
text += QObject::tr(
|
||||
"The specified java binary didn't work.<br />You should use the auto-detect feature, "
|
||||
"or set the path to the java executable.<br />");
|
||||
"The specified Java binary didn't work.<br />You should use the auto-detect feature, "
|
||||
"or set the path to the Java executable.<br />");
|
||||
CustomMessageBox::selectable(parent, QObject::tr("Java test failure"), text, QMessageBox::Warning)->show();
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,38 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "LaunchController.h"
|
||||
#include "minecraft/auth/AccountList.h"
|
||||
#include "Application.h"
|
||||
@ -36,7 +71,10 @@ void LaunchController::executeTask()
|
||||
return;
|
||||
}
|
||||
|
||||
JavaCommon::checkJVMArgs(m_instance->settings()->get("JvmArgs").toString(), m_parentWidget);
|
||||
if(!JavaCommon::checkJVMArgs(m_instance->settings()->get("JvmArgs").toString(), m_parentWidget)) {
|
||||
emitFailed(tr("Invalid Java arguments specified. Please fix this first."));
|
||||
return;
|
||||
}
|
||||
|
||||
login();
|
||||
}
|
||||
@ -55,8 +93,8 @@ void LaunchController::decideAccount()
|
||||
auto reply = CustomMessageBox::selectable(
|
||||
m_parentWidget,
|
||||
tr("No Accounts"),
|
||||
tr("In order to play Minecraft, you must have at least one Mojang or Minecraft "
|
||||
"account logged in."
|
||||
tr("In order to play Minecraft, you must have at least one Mojang or Microsoft "
|
||||
"account logged in. "
|
||||
"Would you like to open the account manager to add an account now?"),
|
||||
QMessageBox::Information,
|
||||
QMessageBox::Yes | QMessageBox::No
|
||||
@ -116,6 +154,12 @@ void LaunchController::login() {
|
||||
m_session->wants_online = m_online;
|
||||
m_accountToUse->fillSession(m_session);
|
||||
|
||||
// Launch immediately in true offline mode
|
||||
if(m_accountToUse->isOffline()) {
|
||||
launchInstance();
|
||||
return;
|
||||
}
|
||||
|
||||
switch(m_accountToUse->accountState()) {
|
||||
case AccountState::Offline: {
|
||||
m_session->wants_online = false;
|
||||
@ -125,13 +169,14 @@ void LaunchController::login() {
|
||||
if(!m_session->wants_online) {
|
||||
// we ask the user for a player name
|
||||
bool ok = false;
|
||||
QString usedname = m_session->player_name;
|
||||
QString lastOfflinePlayerName = APPLICATION->settings()->get("LastOfflinePlayerName").toString();
|
||||
QString usedname = lastOfflinePlayerName.isEmpty() ? m_session->player_name : lastOfflinePlayerName;
|
||||
QString name = QInputDialog::getText(
|
||||
m_parentWidget,
|
||||
tr("Player name"),
|
||||
tr("Choose your offline mode player name."),
|
||||
QLineEdit::Normal,
|
||||
m_session->player_name,
|
||||
usedname,
|
||||
&ok
|
||||
);
|
||||
if (!ok)
|
||||
@ -142,6 +187,7 @@ void LaunchController::login() {
|
||||
if (name.length())
|
||||
{
|
||||
usedname = name;
|
||||
APPLICATION->settings()->set("LastOfflinePlayerName", usedname);
|
||||
}
|
||||
m_session->MakeOffline(usedname);
|
||||
// offline flavored game from here :3
|
||||
@ -222,6 +268,18 @@ void LaunchController::login() {
|
||||
emitFailed(errorString);
|
||||
return;
|
||||
}
|
||||
case AccountState::Disabled: {
|
||||
auto errorString = tr("The launcher's client identification has changed. Please remove this account and add it again.");
|
||||
QMessageBox::warning(
|
||||
m_parentWidget,
|
||||
tr("Client identification changed"),
|
||||
errorString,
|
||||
QMessageBox::StandardButton::Ok,
|
||||
QMessageBox::StandardButton::Ok
|
||||
);
|
||||
emitFailed(errorString);
|
||||
return;
|
||||
}
|
||||
case AccountState::Gone: {
|
||||
auto errorString = tr("The account no longer exists on the servers. It may have been migrated, in which case please add the new account you migrated this one to.");
|
||||
QMessageBox::warning(
|
||||
|
@ -1,3 +1,38 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <QObject>
|
||||
#include <BaseInstance.h>
|
||||
|
@ -14,14 +14,14 @@ if [[ $EUID -eq 0 ]]; then
|
||||
fi
|
||||
|
||||
|
||||
LAUNCHER_NAME=@Launcher_Name@
|
||||
LAUNCHER_NAME=@Launcher_APP_BINARY_NAME@
|
||||
LAUNCHER_DIR="$(dirname "$(readlink -f "$0")")"
|
||||
echo "Launcher Dir: ${LAUNCHER_DIR}"
|
||||
|
||||
# Set up env - filter out input LD_ variables but pass them in under different names
|
||||
export GAME_LIBRARY_PATH=${GAME_LIBRARY_PATH-${LD_LIBRARY_PATH}}
|
||||
export GAME_PRELOAD=${GAME_PRELOAD-${LD_PRELOAD}}
|
||||
export LD_LIBRARY_PATH="${LAUNCHER_DIR}/bin":$LAUNCHER_LIBRARY_PATH
|
||||
export LD_LIBRARY_PATH="${LAUNCHER_DIR}/lib@LIB_SUFFIX@":$LAUNCHER_LIBRARY_PATH
|
||||
export LD_PRELOAD=$LAUNCHER_PRELOAD
|
||||
export QT_PLUGIN_PATH="${LAUNCHER_DIR}/plugins"
|
||||
export QT_FONTPATH="${LAUNCHER_DIR}/fonts"
|
||||
|
@ -1,29 +1,48 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* 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.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <quazip.h>
|
||||
#include <quazipdir.h>
|
||||
#include <quazipfile.h>
|
||||
#include <JlCompress.h>
|
||||
#include <quazip/quazip.h>
|
||||
#include <quazip/quazipdir.h>
|
||||
#include <quazip/quazipfile.h>
|
||||
#include "MMCZip.h"
|
||||
#include "FileSystem.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
// ours
|
||||
bool MMCZip::mergeZipFiles(QuaZip *into, QFileInfo from, QSet<QString> &contained, const JlCompress::FilterFunction filter)
|
||||
bool MMCZip::mergeZipFiles(QuaZip *into, QFileInfo from, QSet<QString> &contained, const FilterFunction filter)
|
||||
{
|
||||
QuaZip modZip(from.filePath());
|
||||
modZip.open(QuaZip::mdUnzip);
|
||||
@ -74,6 +93,39 @@ bool MMCZip::mergeZipFiles(QuaZip *into, QFileInfo from, QSet<QString> &containe
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MMCZip::compressDirFiles(QuaZip *zip, QString dir, QFileInfoList files)
|
||||
{
|
||||
QDir directory(dir);
|
||||
if (!directory.exists()) return false;
|
||||
|
||||
for (auto e : files) {
|
||||
auto filePath = directory.relativeFilePath(e.absoluteFilePath());
|
||||
if( !JlCompress::compressFile(zip, e.absoluteFilePath(), filePath)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MMCZip::compressDirFiles(QString fileCompressed, QString dir, QFileInfoList files)
|
||||
{
|
||||
QuaZip zip(fileCompressed);
|
||||
QDir().mkpath(QFileInfo(fileCompressed).absolutePath());
|
||||
if(!zip.open(QuaZip::mdCreate)) {
|
||||
QFile::remove(fileCompressed);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto result = compressDirFiles(&zip, dir, files);
|
||||
|
||||
zip.close();
|
||||
if(zip.getZipError()!=0) {
|
||||
QFile::remove(fileCompressed);
|
||||
return false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ours
|
||||
bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const QList<Mod>& mods)
|
||||
{
|
||||
@ -122,13 +174,22 @@ bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const
|
||||
}
|
||||
else if (mod.type() == Mod::MOD_FOLDER)
|
||||
{
|
||||
// untested, but seems to be unused / not possible to reach
|
||||
// FIXME: buggy - does not work with addedFiles
|
||||
auto filename = mod.filename();
|
||||
QString what_to_zip = filename.absoluteFilePath();
|
||||
QDir dir(what_to_zip);
|
||||
dir.cdUp();
|
||||
QString parent_dir = dir.absolutePath();
|
||||
if (!JlCompress::compressSubDir(&zipOut, what_to_zip, parent_dir, addedFiles))
|
||||
auto files = QFileInfoList();
|
||||
MMCZip::collectFileListRecursively(what_to_zip, nullptr, &files, nullptr);
|
||||
|
||||
for (auto e : files) {
|
||||
if (addedFiles.contains(e.filePath()))
|
||||
files.removeAll(e);
|
||||
}
|
||||
|
||||
if (!MMCZip::compressDirFiles(&zipOut, parent_dir, files))
|
||||
{
|
||||
zipOut.close();
|
||||
QFile::remove(targetJarPath);
|
||||
@ -136,7 +197,7 @@ bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const
|
||||
return false;
|
||||
}
|
||||
qDebug() << "Adding folder " << filename.fileName() << " from "
|
||||
<< filename.absoluteFilePath();
|
||||
<< filename.absoluteFilePath();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -236,20 +297,40 @@ nonstd::optional<QStringList> MMCZip::extractSubDir(QuaZip *zip, const QString &
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
name.remove(0, subdir.size());
|
||||
QString absFilePath = directory.absoluteFilePath(name);
|
||||
auto original_name = name;
|
||||
|
||||
// Fix weird "folders with a single file get squashed" thing
|
||||
QString path;
|
||||
if(name.contains('/') && !name.endsWith('/')){
|
||||
path = name.section('/', 0, -2) + "/";
|
||||
FS::ensureFolderPathExists(path);
|
||||
|
||||
name = name.split('/').last();
|
||||
}
|
||||
|
||||
QString absFilePath;
|
||||
if(name.isEmpty())
|
||||
{
|
||||
absFilePath += "/";
|
||||
absFilePath = directory.absoluteFilePath(name) + "/";
|
||||
}
|
||||
else
|
||||
{
|
||||
absFilePath = directory.absoluteFilePath(path + name);
|
||||
}
|
||||
|
||||
if (!JlCompress::extractFile(zip, "", absFilePath))
|
||||
{
|
||||
qWarning() << "Failed to extract file" << name << "to" << absFilePath;
|
||||
qWarning() << "Failed to extract file" << original_name << "to" << absFilePath;
|
||||
JlCompress::removeFile(extracted);
|
||||
return nonstd::nullopt;
|
||||
}
|
||||
|
||||
extracted.append(absFilePath);
|
||||
qDebug() << "Extracted file" << name;
|
||||
QFile::setPermissions(absFilePath, QFileDevice::Permission::ReadUser | QFileDevice::Permission::WriteUser | QFileDevice::Permission::ExeUser);
|
||||
|
||||
qDebug() << "Extracted file" << name << "to" << absFilePath;
|
||||
} while (zip->goToNextFile());
|
||||
return extracted;
|
||||
}
|
||||
@ -310,3 +391,37 @@ bool MMCZip::extractFile(QString fileCompressed, QString file, QString target)
|
||||
}
|
||||
return MMCZip::extractRelFile(&zip, file, target);
|
||||
}
|
||||
|
||||
bool MMCZip::collectFileListRecursively(const QString& rootDir, const QString& subDir, QFileInfoList *files,
|
||||
MMCZip::FilterFunction excludeFilter) {
|
||||
QDir rootDirectory(rootDir);
|
||||
if (!rootDirectory.exists()) return false;
|
||||
|
||||
QDir directory;
|
||||
if (subDir == nullptr)
|
||||
directory = rootDirectory;
|
||||
else
|
||||
directory = QDir(subDir);
|
||||
|
||||
if (!directory.exists()) return false; // shouldn't ever happen
|
||||
|
||||
// recurse directories
|
||||
QFileInfoList entries = directory.entryInfoList(QDir::AllDirs | QDir::NoDotAndDotDot | QDir::Hidden);
|
||||
for (const auto& e: entries) {
|
||||
if (!collectFileListRecursively(rootDir, e.filePath(), files, excludeFilter))
|
||||
return false;
|
||||
}
|
||||
|
||||
// collect files
|
||||
entries = directory.entryInfoList(QDir::Files);
|
||||
for (const auto& e: entries) {
|
||||
QString relativeFilePath = rootDirectory.relativeFilePath(e.absoluteFilePath());
|
||||
if (excludeFilter && excludeFilter(relativeFilePath)) {
|
||||
qDebug() << "Skipping file " << relativeFilePath;
|
||||
continue;
|
||||
}
|
||||
|
||||
files->append(e.filePath()); // we want the original paths for MMCZip::compressDirFiles
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -1,16 +1,36 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* 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.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
@ -21,17 +41,36 @@
|
||||
#include "minecraft/mod/Mod.h"
|
||||
#include <functional>
|
||||
|
||||
#include <JlCompress.h>
|
||||
#include <quazip/JlCompress.h>
|
||||
#include <nonstd/optional>
|
||||
|
||||
namespace MMCZip
|
||||
{
|
||||
using FilterFunction = std::function<bool(const QString &)>;
|
||||
|
||||
/**
|
||||
* Merge two zip files, using a filter function
|
||||
*/
|
||||
bool mergeZipFiles(QuaZip *into, QFileInfo from, QSet<QString> &contained,
|
||||
const JlCompress::FilterFunction filter = nullptr);
|
||||
const FilterFunction filter = nullptr);
|
||||
|
||||
/**
|
||||
* Compress directory, by providing a list of files to compress
|
||||
* \param zip target archive
|
||||
* \param dir directory that will be compressed (to compress with relative paths)
|
||||
* \param files list of files to compress
|
||||
* \return true for success or false for failure
|
||||
*/
|
||||
bool compressDirFiles(QuaZip *zip, QString dir, QFileInfoList files);
|
||||
|
||||
/**
|
||||
* Compress directory, by providing a list of files to compress
|
||||
* \param fileCompressed target archive file
|
||||
* \param dir directory that will be compressed (to compress with relative paths)
|
||||
* \param files list of files to compress
|
||||
* \return true for success or false for failure
|
||||
*/
|
||||
bool compressDirFiles(QString fileCompressed, QString dir, QFileInfoList files);
|
||||
|
||||
/**
|
||||
* take a source jar, add mods to it, resulting in target jar
|
||||
@ -89,4 +128,13 @@ namespace MMCZip
|
||||
*/
|
||||
bool extractFile(QString fileCompressed, QString file, QString dir);
|
||||
|
||||
/**
|
||||
* Populate a QFileInfoList with a directory tree recursively, while allowing to excludeFilter what shouldn't be included.
|
||||
* \param rootDir directory to start off
|
||||
* \param subDir subdirectory, should be nullptr for first invocation
|
||||
* \param files resulting list of QFileInfo
|
||||
* \param excludeFilter function to excludeFilter which files shouldn't be included (returning true means to excude)
|
||||
* \return true for success or false for failure
|
||||
*/
|
||||
bool collectFileListRecursively(const QString &rootDir, const QString &subDir, QFileInfoList *files, FilterFunction excludeFilter);
|
||||
}
|
||||
|
39
launcher/ModDownloadTask.cpp
Normal file
39
launcher/ModDownloadTask.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
#include "ModDownloadTask.h"
|
||||
#include "Application.h"
|
||||
|
||||
ModDownloadTask::ModDownloadTask(const QUrl sourceUrl,const QString filename, const std::shared_ptr<ModFolderModel> mods)
|
||||
: m_sourceUrl(sourceUrl), mods(mods), filename(filename) {
|
||||
}
|
||||
|
||||
void ModDownloadTask::executeTask() {
|
||||
setStatus(tr("Downloading mod:\n%1").arg(m_sourceUrl.toString()));
|
||||
|
||||
m_filesNetJob.reset(new NetJob(tr("Mod download"), APPLICATION->network()));
|
||||
m_filesNetJob->addNetAction(Net::Download::makeFile(m_sourceUrl, mods->dir().absoluteFilePath(filename)));
|
||||
connect(m_filesNetJob.get(), &NetJob::succeeded, this, &ModDownloadTask::downloadSucceeded);
|
||||
connect(m_filesNetJob.get(), &NetJob::progress, this, &ModDownloadTask::downloadProgressChanged);
|
||||
connect(m_filesNetJob.get(), &NetJob::failed, this, &ModDownloadTask::downloadFailed);
|
||||
m_filesNetJob->start();
|
||||
}
|
||||
|
||||
void ModDownloadTask::downloadSucceeded()
|
||||
{
|
||||
emitSucceeded();
|
||||
m_filesNetJob.reset();
|
||||
}
|
||||
|
||||
void ModDownloadTask::downloadFailed(QString reason)
|
||||
{
|
||||
emitFailed(reason);
|
||||
m_filesNetJob.reset();
|
||||
}
|
||||
|
||||
void ModDownloadTask::downloadProgressChanged(qint64 current, qint64 total)
|
||||
{
|
||||
emit progress(current, total);
|
||||
}
|
||||
|
||||
bool ModDownloadTask::abort() {
|
||||
return m_filesNetJob->abort();
|
||||
}
|
||||
|
35
launcher/ModDownloadTask.h
Normal file
35
launcher/ModDownloadTask.h
Normal file
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
#include "QObjectPtr.h"
|
||||
#include "tasks/Task.h"
|
||||
#include "minecraft/mod/ModFolderModel.h"
|
||||
#include "net/NetJob.h"
|
||||
#include <QUrl>
|
||||
|
||||
|
||||
class ModDownloadTask : public Task {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ModDownloadTask(const QUrl sourceUrl, const QString filename, const std::shared_ptr<ModFolderModel> mods);
|
||||
const QString& getFilename() const { return filename; }
|
||||
|
||||
public slots:
|
||||
bool abort() override;
|
||||
protected:
|
||||
//! Entry point for tasks.
|
||||
void executeTask() override;
|
||||
|
||||
private:
|
||||
QUrl m_sourceUrl;
|
||||
NetJob::Ptr m_filesNetJob;
|
||||
const std::shared_ptr<ModFolderModel> mods;
|
||||
const QString filename;
|
||||
|
||||
void downloadProgressChanged(qint64 current, qint64 total);
|
||||
|
||||
void downloadFailed(QString reason);
|
||||
|
||||
void downloadSucceeded();
|
||||
};
|
||||
|
||||
|
||||
|
@ -93,7 +93,7 @@ void UpdateController::installUpdates()
|
||||
qDebug() << "Installing updates.";
|
||||
#ifdef Q_OS_WIN
|
||||
QString finishCmd = QApplication::applicationFilePath();
|
||||
#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||
#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined (Q_OS_OPENBSD)
|
||||
QString finishCmd = FS::PathCombine(m_root, BuildConfig.LAUNCHER_NAME);
|
||||
#elif defined Q_OS_MAC
|
||||
QString finishCmd = QApplication::applicationFilePath();
|
||||
@ -138,20 +138,6 @@ void UpdateController::installUpdates()
|
||||
}
|
||||
#endif
|
||||
QFileInfo destination (FS::PathCombine(m_root, op.destination));
|
||||
#ifdef Q_OS_WIN32
|
||||
if(QSysInfo::windowsVersion() < QSysInfo::WV_VISTA)
|
||||
{
|
||||
if(destination.fileName() == windowsExeName)
|
||||
{
|
||||
QDir rootDir(m_root);
|
||||
exeOrigin = rootDir.relativeFilePath(op.source);
|
||||
exePath = rootDir.relativeFilePath(op.destination);
|
||||
exeBackup = rootDir.relativeFilePath(FS::PathCombine(backupPath, destination.fileName()));
|
||||
useXPHack = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(destination.exists())
|
||||
{
|
||||
QString backupName = op.destination;
|
||||
|
@ -36,7 +36,7 @@ IconList::IconList(const QStringList &builtinPaths, QString path, QObject *paren
|
||||
auto file_info_list = instance_icons.entryInfoList(QDir::Files, QDir::Name);
|
||||
for (auto file_info : file_info_list)
|
||||
{
|
||||
builtinNames.insert(file_info.baseName());
|
||||
builtinNames.insert(file_info.completeBaseName());
|
||||
}
|
||||
}
|
||||
for(auto & builtinName : builtinNames)
|
||||
@ -51,6 +51,9 @@ IconList::IconList(const QStringList &builtinPaths, QString path, QObject *paren
|
||||
connect(m_watcher.get(), SIGNAL(fileChanged(QString)), SLOT(fileChanged(QString)));
|
||||
|
||||
directoryChanged(path);
|
||||
|
||||
// Forces the UI to update, so that lengthy icon names are shown properly from the start
|
||||
emit iconUpdated({});
|
||||
}
|
||||
|
||||
void IconList::directoryChanged(const QString &path)
|
||||
@ -94,7 +97,13 @@ void IconList::directoryChanged(const QString &path)
|
||||
{
|
||||
qDebug() << "Removing " << remove;
|
||||
QFileInfo rmfile(remove);
|
||||
QString key = rmfile.baseName();
|
||||
QString key = rmfile.completeBaseName();
|
||||
|
||||
QString suffix = rmfile.suffix();
|
||||
// The icon doesnt have a suffix, but it can have other .s in the name, so we account for those as well
|
||||
if (suffix != "jpeg" && suffix != "png" && suffix != "jpg" && suffix != "ico" && suffix != "svg" && suffix != "gif")
|
||||
key = rmfile.fileName();
|
||||
|
||||
int idx = getIconIndex(key);
|
||||
if (idx == -1)
|
||||
continue;
|
||||
@ -117,8 +126,15 @@ void IconList::directoryChanged(const QString &path)
|
||||
for (auto add : to_add)
|
||||
{
|
||||
qDebug() << "Adding " << add;
|
||||
|
||||
QFileInfo addfile(add);
|
||||
QString key = addfile.baseName();
|
||||
QString key = addfile.completeBaseName();
|
||||
|
||||
QString suffix = addfile.suffix();
|
||||
// The icon doesnt have a suffix, but it can have other .s in the name, so we account for those as well
|
||||
if (suffix != "jpeg" && suffix != "png" && suffix != "jpg" && suffix != "ico" && suffix != "svg" && suffix != "gif")
|
||||
key = addfile.fileName();
|
||||
|
||||
if (addIcon(key, QString(), addfile.filePath(), IconType::FileBased))
|
||||
{
|
||||
m_watcher->addPath(add);
|
||||
@ -133,7 +149,7 @@ void IconList::fileChanged(const QString &path)
|
||||
QFileInfo checkfile(path);
|
||||
if (!checkfile.exists())
|
||||
return;
|
||||
QString key = checkfile.baseName();
|
||||
QString key = checkfile.completeBaseName();
|
||||
int idx = getIconIndex(key);
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
@ -103,11 +103,15 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
|
||||
for(QString line : lines)
|
||||
{
|
||||
line = line.trimmed();
|
||||
// NOTE: workaround for GH-4125, where garbage is getting printed into stdout on bedrock linux
|
||||
if (line.contains("/bedrock/strata")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto parts = line.split('=', QString::SkipEmptyParts);
|
||||
if(parts.size() != 2 || parts[0].isEmpty() || parts[1].isEmpty())
|
||||
{
|
||||
success = false;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -125,7 +129,7 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status)
|
||||
auto os_arch = results["os.arch"];
|
||||
auto java_version = results["java.version"];
|
||||
auto java_vendor = results["java.vendor"];
|
||||
bool is_64 = os_arch == "x86_64" || os_arch == "amd64";
|
||||
bool is_64 = os_arch == "x86_64" || os_arch == "amd64" || os_arch == "aarch64" || os_arch == "arm64";
|
||||
|
||||
|
||||
result.validity = JavaCheckResult::Validity::Valid;
|
||||
|
@ -120,8 +120,8 @@ void JavaInstallList::updateListData(QList<BaseVersionPtr> versions)
|
||||
|
||||
bool sortJavas(BaseVersionPtr left, BaseVersionPtr right)
|
||||
{
|
||||
auto rleft = std::dynamic_pointer_cast<JavaInstall>(left);
|
||||
auto rright = std::dynamic_pointer_cast<JavaInstall>(right);
|
||||
auto rleft = std::dynamic_pointer_cast<JavaInstall>(right);
|
||||
auto rright = std::dynamic_pointer_cast<JavaInstall>(left);
|
||||
return (*rleft) > (*rright);
|
||||
}
|
||||
|
||||
@ -183,7 +183,7 @@ void JavaListLoadTask::javaCheckerFinished()
|
||||
JavaInstallPtr javaVersion(new JavaInstall());
|
||||
|
||||
javaVersion->id = result.javaVersion;
|
||||
javaVersion->arch = result.mojangPlatform;
|
||||
javaVersion->arch = result.realPlatform;
|
||||
javaVersion->path = result.path;
|
||||
candidates.append(javaVersion);
|
||||
|
||||
|
@ -77,14 +77,14 @@ QProcessEnvironment CleanEnviroment()
|
||||
qDebug() << "Env: ignoring" << key << value;
|
||||
continue;
|
||||
}
|
||||
// filter MultiMC-related things
|
||||
// filter PolyMC-related things
|
||||
if(key.startsWith("QT_"))
|
||||
{
|
||||
qDebug() << "Env: ignoring" << key << value;
|
||||
continue;
|
||||
}
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
|
||||
// Do not pass LD_* variables to java. They were intended for MultiMC
|
||||
// Do not pass LD_* variables to java. They were intended for PolyMC
|
||||
if(key.startsWith("LD_"))
|
||||
{
|
||||
qDebug() << "Env: ignoring" << key << value;
|
||||
@ -149,6 +149,21 @@ JavaInstallPtr JavaUtils::GetDefaultJava()
|
||||
return javaVersion;
|
||||
}
|
||||
|
||||
QStringList addJavasFromEnv(QList<QString> javas)
|
||||
{
|
||||
QByteArray env = qgetenv("POLYMC_JAVA_PATHS");
|
||||
#if defined(Q_OS_WIN32)
|
||||
QList<QString> javaPaths = QString::fromLocal8Bit(env).replace("\\", "/").split(QLatin1String(";"));
|
||||
#else
|
||||
QList<QString> javaPaths = QString::fromLocal8Bit(env).split(QLatin1String(":"));
|
||||
#endif
|
||||
for(QString i : javaPaths)
|
||||
{
|
||||
javas.append(i);
|
||||
};
|
||||
return javas;
|
||||
}
|
||||
|
||||
#if defined(Q_OS_WIN32)
|
||||
QList<JavaInstallPtr> JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString keyName, QString keyJavaDir, QString subkeySuffix)
|
||||
{
|
||||
@ -340,7 +355,7 @@ QList<QString> JavaUtils::FindJavaPaths()
|
||||
}
|
||||
}
|
||||
|
||||
return candidates;
|
||||
return addJavasFromEnv(candidates);
|
||||
}
|
||||
|
||||
#elif defined(Q_OS_MAC)
|
||||
@ -363,7 +378,7 @@ QList<QString> JavaUtils::FindJavaPaths()
|
||||
javas.append(systemLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Home/bin/java");
|
||||
javas.append(systemLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Commands/java");
|
||||
}
|
||||
return javas;
|
||||
return addJavasFromEnv(javas);
|
||||
}
|
||||
|
||||
#elif defined(Q_OS_LINUX)
|
||||
@ -402,14 +417,14 @@ QList<QString> JavaUtils::FindJavaPaths()
|
||||
scanJavaDir("/usr/lib/jvm");
|
||||
scanJavaDir("/usr/lib64/jvm");
|
||||
scanJavaDir("/usr/lib32/jvm");
|
||||
// javas stored in MultiMC's folder
|
||||
// javas stored in PolyMC's folder
|
||||
scanJavaDir("java");
|
||||
// manually installed JDKs in /opt
|
||||
scanJavaDir("/opt/jdk");
|
||||
scanJavaDir("/opt/jdks");
|
||||
// flatpak
|
||||
scanJavaDir("/app/jdk");
|
||||
return javas;
|
||||
return addJavasFromEnv(javas);
|
||||
}
|
||||
#else
|
||||
QList<QString> JavaUtils::FindJavaPaths()
|
||||
@ -419,6 +434,6 @@ QList<QString> JavaUtils::FindJavaPaths()
|
||||
QList<QString> javas;
|
||||
javas.append(this->GetDefaultJava()->path);
|
||||
|
||||
return javas;
|
||||
return addJavasFromEnv(javas);
|
||||
}
|
||||
#endif
|
||||
|
@ -1,18 +1,38 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* 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.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "launch/LaunchTask.h"
|
||||
@ -212,7 +232,7 @@ shared_qobject_ptr<LogModel> LaunchTask::getLogModel()
|
||||
m_logModel->setMaxLines(m_instance->getConsoleMaxLines());
|
||||
m_logModel->setStopOnOverflow(m_instance->shouldStopOnConsoleOverflow());
|
||||
// FIXME: should this really be here?
|
||||
m_logModel->setOverflowMessage(tr("MultiMC stopped watching the game log because the log length surpassed %1 lines.\n"
|
||||
m_logModel->setOverflowMessage(tr("Stopped watching the game log because the log length surpassed %1 lines.\n"
|
||||
"You may have to fix your mods because the game is still logging to files and"
|
||||
" likely wasting harddrive space at an alarming rate!").arg(m_logModel->getMaxLines()));
|
||||
}
|
||||
@ -277,4 +297,3 @@ QString LaunchTask::substituteVariables(const QString &cmd) const
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,36 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* 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.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "CheckJava.h"
|
||||
@ -87,14 +107,14 @@ void CheckJava::checkJavaFinished(JavaCheckResult result)
|
||||
// Error message displayed if java can't start
|
||||
emit logLine(QString("Could not start java:"), MessageLevel::Error);
|
||||
emit logLines(result.errorLog.split('\n'), MessageLevel::Error);
|
||||
emit logLine("\nCheck your MultiMC Java settings.", MessageLevel::Launcher);
|
||||
emit logLine(QString("\nCheck your Java settings."), MessageLevel::Launcher);
|
||||
printSystemInfo(false, false);
|
||||
emitFailed(QString("Could not start java!"));
|
||||
return;
|
||||
}
|
||||
case JavaCheckResult::Validity::ReturnedInvalidData:
|
||||
{
|
||||
emit logLine(QString("Java checker returned some invalid data MultiMC doesn't understand:"), MessageLevel::Error);
|
||||
emit logLine(QString("Java checker returned some invalid data we don't understand:"), MessageLevel::Error);
|
||||
emit logLines(result.outLog.split('\n'), MessageLevel::Warning);
|
||||
emit logLine("\nMinecraft might not start properly.", MessageLevel::Launcher);
|
||||
printSystemInfo(false, false);
|
||||
@ -104,7 +124,8 @@ void CheckJava::checkJavaFinished(JavaCheckResult result)
|
||||
case JavaCheckResult::Validity::Valid:
|
||||
{
|
||||
auto instance = m_parent->instance();
|
||||
printJavaInfo(result.javaVersion.toString(), result.mojangPlatform, result.javaVendor);
|
||||
printJavaInfo(result.javaVersion.toString(), result.realPlatform, result.javaVendor);
|
||||
printSystemInfo(true, result.is_64bit);
|
||||
instance->settings()->set("JavaVersion", result.javaVersion.toString());
|
||||
instance->settings()->set("JavaArchitecture", result.mojangPlatform);
|
||||
instance->settings()->set("JavaVendor", result.javaVendor);
|
||||
@ -117,8 +138,7 @@ void CheckJava::checkJavaFinished(JavaCheckResult result)
|
||||
|
||||
void CheckJava::printJavaInfo(const QString& version, const QString& architecture, const QString & vendor)
|
||||
{
|
||||
emit logLine(QString("Java is version %1, using %2-bit architecture, from %3.\n\n").arg(version, architecture, vendor), MessageLevel::Launcher);
|
||||
printSystemInfo(true, architecture == "64");
|
||||
emit logLine(QString("Java is version %1, using %2 architecture, from %3.\n\n").arg(version, architecture, vendor), MessageLevel::Launcher);
|
||||
}
|
||||
|
||||
void CheckJava::printSystemInfo(bool javaIsKnown, bool javaIs64bit)
|
||||
|
26
launcher/launch/steps/QuitAfterGameStop.cpp
Normal file
26
launcher/launch/steps/QuitAfterGameStop.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 dada513 <dada513@protonmail.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 "QuitAfterGameStop.h"
|
||||
#include <launch/LaunchTask.h>
|
||||
#include "Application.h"
|
||||
|
||||
void QuitAfterGameStop::executeTask()
|
||||
{
|
||||
APPLICATION->quit();
|
||||
}
|
35
launcher/launch/steps/QuitAfterGameStop.h
Normal file
35
launcher/launch/steps/QuitAfterGameStop.h
Normal file
@ -0,0 +1,35 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 dada513 <dada513@protonmail.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 <launch/LaunchStep.h>
|
||||
|
||||
class QuitAfterGameStop: public LaunchStep
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QuitAfterGameStop(LaunchTask *parent) :LaunchStep(parent){};
|
||||
virtual ~QuitAfterGameStop() {};
|
||||
|
||||
virtual void executeTask();
|
||||
virtual bool canAbort() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
@ -24,9 +24,11 @@ int main(int argc, char *argv[])
|
||||
return 42;
|
||||
#endif
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
|
||||
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
|
||||
QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
||||
#endif
|
||||
|
||||
// initialize Qt
|
||||
|
@ -75,7 +75,16 @@ Meta::BaseEntity::~BaseEntity()
|
||||
|
||||
QUrl Meta::BaseEntity::url() const
|
||||
{
|
||||
return QUrl(BuildConfig.META_URL).resolved(localFilename());
|
||||
auto s = APPLICATION->settings();
|
||||
QString metaOverride = s->get("MetaURLOverride").toString();
|
||||
if(metaOverride.isEmpty())
|
||||
{
|
||||
return QUrl(BuildConfig.META_URL).resolved(localFilename());
|
||||
}
|
||||
else
|
||||
{
|
||||
return QUrl(metaOverride).resolved(localFilename());
|
||||
}
|
||||
}
|
||||
|
||||
bool Meta::BaseEntity::loadLocalFile()
|
||||
|
36
launcher/minecraft/Agent.h
Normal file
36
launcher/minecraft/Agent.h
Normal file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include "Library.h"
|
||||
|
||||
class Agent;
|
||||
|
||||
typedef std::shared_ptr<Agent> AgentPtr;
|
||||
|
||||
class Agent {
|
||||
public:
|
||||
Agent(LibraryPtr library, QString &argument)
|
||||
{
|
||||
m_library = library;
|
||||
m_argument = argument;
|
||||
}
|
||||
|
||||
public: /* methods */
|
||||
|
||||
LibraryPtr library() {
|
||||
return m_library;
|
||||
}
|
||||
QString argument() {
|
||||
return m_argument;
|
||||
}
|
||||
|
||||
protected: /* data */
|
||||
|
||||
/// The library pointing to the jar this Java agent is contained within
|
||||
LibraryPtr m_library;
|
||||
|
||||
/// The argument to the Java agent, passed after an = if present
|
||||
QString m_argument;
|
||||
|
||||
};
|
@ -1,16 +1,36 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* 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.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <QFileInfo>
|
||||
@ -297,7 +317,7 @@ NetAction::Ptr AssetObject::getDownloadAction()
|
||||
auto rawHash = QByteArray::fromHex(hash.toLatin1());
|
||||
objectDL->addValidator(new Net::ChecksumValidator(QCryptographicHash::Sha1, rawHash));
|
||||
}
|
||||
objectDL->m_total_progress = size;
|
||||
objectDL->setProgress(objectDL->getProgress(), size);
|
||||
return objectDL;
|
||||
}
|
||||
return nullptr;
|
||||
|
@ -591,7 +591,7 @@ void ComponentUpdateTask::resolveDependencies(bool checkOnly)
|
||||
{
|
||||
component->m_version = "3.1.2";
|
||||
}
|
||||
else if (add.uid == "net.fabricmc.intermediary")
|
||||
else if (add.uid == "net.fabricmc.intermediary" || add.uid == "org.quiltmc.hashed")
|
||||
{
|
||||
auto minecraft = std::find_if(components.begin(), components.end(), [](ComponentPtr & cmp){
|
||||
return cmp->getID() == "net.minecraft";
|
||||
|
@ -124,7 +124,7 @@ struct GradleSpecifier
|
||||
}
|
||||
bool matchName(const GradleSpecifier & other) const
|
||||
{
|
||||
return other.artifactId() == artifactId() && other.groupId() == groupId();
|
||||
return other.artifactId() == artifactId() && other.groupId() == groupId() && other.classifier() == classifier();
|
||||
}
|
||||
bool operator==(const GradleSpecifier & other) const
|
||||
{
|
||||
|
@ -1,3 +1,38 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "LaunchProfile.h"
|
||||
#include <Version.h>
|
||||
|
||||
@ -7,11 +42,13 @@ void LaunchProfile::clear()
|
||||
m_minecraftVersionType.clear();
|
||||
m_minecraftAssets.reset();
|
||||
m_minecraftArguments.clear();
|
||||
m_addnJvmArguments.clear();
|
||||
m_tweakers.clear();
|
||||
m_mainClass.clear();
|
||||
m_appletClass.clear();
|
||||
m_libraries.clear();
|
||||
m_mavenFiles.clear();
|
||||
m_agents.clear();
|
||||
m_traits.clear();
|
||||
m_jarMods.clear();
|
||||
m_mainJar.reset();
|
||||
@ -45,6 +82,11 @@ void LaunchProfile::applyMinecraftArguments(const QString& minecraftArguments)
|
||||
applyString(minecraftArguments, this->m_minecraftArguments);
|
||||
}
|
||||
|
||||
void LaunchProfile::applyAddnJvmArguments(const QStringList& addnJvmArguments)
|
||||
{
|
||||
this->m_addnJvmArguments.append(addnJvmArguments);
|
||||
}
|
||||
|
||||
void LaunchProfile::applyMinecraftVersionType(const QString& type)
|
||||
{
|
||||
applyString(type, this->m_minecraftVersionType);
|
||||
@ -126,6 +168,11 @@ void LaunchProfile::applyMods(const QList<LibraryPtr>& mods)
|
||||
}
|
||||
}
|
||||
|
||||
void LaunchProfile::applyCompatibleJavaMajors(QList<int>& javaMajor)
|
||||
{
|
||||
m_compatibleJavaMajors.append(javaMajor);
|
||||
}
|
||||
|
||||
void LaunchProfile::applyLibrary(LibraryPtr library)
|
||||
{
|
||||
if(!library->isActive())
|
||||
@ -174,6 +221,22 @@ void LaunchProfile::applyMavenFile(LibraryPtr mavenFile)
|
||||
m_mavenFiles.append(Library::limitedCopy(mavenFile));
|
||||
}
|
||||
|
||||
void LaunchProfile::applyAgent(AgentPtr agent)
|
||||
{
|
||||
auto lib = agent->library();
|
||||
if(!lib->isActive())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(lib->isNative())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_agents.append(agent);
|
||||
}
|
||||
|
||||
const LibraryPtr LaunchProfile::getMainJar() const
|
||||
{
|
||||
return m_mainJar;
|
||||
@ -255,6 +318,11 @@ QString LaunchProfile::getMinecraftArguments() const
|
||||
return m_minecraftArguments;
|
||||
}
|
||||
|
||||
const QStringList & LaunchProfile::getAddnJvmArguments() const
|
||||
{
|
||||
return m_addnJvmArguments;
|
||||
}
|
||||
|
||||
const QList<LibraryPtr> & LaunchProfile::getJarMods() const
|
||||
{
|
||||
return m_jarMods;
|
||||
@ -275,6 +343,16 @@ const QList<LibraryPtr> & LaunchProfile::getMavenFiles() const
|
||||
return m_mavenFiles;
|
||||
}
|
||||
|
||||
const QList<AgentPtr> & LaunchProfile::getAgents() const
|
||||
{
|
||||
return m_agents;
|
||||
}
|
||||
|
||||
const QList<int> & LaunchProfile::getCompatibleJavaMajors() const
|
||||
{
|
||||
return m_compatibleJavaMajors;
|
||||
}
|
||||
|
||||
void LaunchProfile::getLibraryFiles(
|
||||
const QString& architecture,
|
||||
QStringList& jars,
|
||||
|
@ -1,6 +1,42 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <QString>
|
||||
#include "Library.h"
|
||||
#include "Agent.h"
|
||||
#include <ProblemProvider.h>
|
||||
|
||||
class LaunchProfile: public ProblemProvider
|
||||
@ -13,6 +49,7 @@ public: /* application of profile variables from patches */
|
||||
void applyMainClass(const QString& mainClass);
|
||||
void applyAppletClass(const QString& appletClass);
|
||||
void applyMinecraftArguments(const QString& minecraftArguments);
|
||||
void applyAddnJvmArguments(const QStringList& minecraftArguments);
|
||||
void applyMinecraftVersionType(const QString& type);
|
||||
void applyMinecraftAssets(MojangAssetIndexInfo::Ptr assets);
|
||||
void applyTraits(const QSet<QString> &traits);
|
||||
@ -21,6 +58,8 @@ public: /* application of profile variables from patches */
|
||||
void applyMods(const QList<LibraryPtr> &jarMods);
|
||||
void applyLibrary(LibraryPtr library);
|
||||
void applyMavenFile(LibraryPtr library);
|
||||
void applyAgent(AgentPtr agent);
|
||||
void applyCompatibleJavaMajors(QList<int>& javaMajor);
|
||||
void applyMainJar(LibraryPtr jar);
|
||||
void applyProblemSeverity(ProblemSeverity severity);
|
||||
/// clear the profile
|
||||
@ -33,12 +72,15 @@ public: /* getters for profile variables */
|
||||
QString getMinecraftVersionType() const;
|
||||
MojangAssetIndexInfo::Ptr getMinecraftAssets() const;
|
||||
QString getMinecraftArguments() const;
|
||||
const QStringList & getAddnJvmArguments() const;
|
||||
const QSet<QString> & getTraits() const;
|
||||
const QStringList & getTweakers() const;
|
||||
const QList<LibraryPtr> & getJarMods() const;
|
||||
const QList<LibraryPtr> & getLibraries() const;
|
||||
const QList<LibraryPtr> & getNativeLibraries() const;
|
||||
const QList<LibraryPtr> & getMavenFiles() const;
|
||||
const QList<AgentPtr> & getAgents() const;
|
||||
const QList<int> & getCompatibleJavaMajors() const;
|
||||
const LibraryPtr getMainJar() const;
|
||||
void getLibraryFiles(
|
||||
const QString & architecture,
|
||||
@ -69,6 +111,12 @@ private:
|
||||
*/
|
||||
QString m_minecraftArguments;
|
||||
|
||||
/**
|
||||
* Additional arguments to pass to the JVM in addition to those the user has configured,
|
||||
* memory settings, etc.
|
||||
*/
|
||||
QStringList m_addnJvmArguments;
|
||||
|
||||
/// A list of all tweaker classes
|
||||
QStringList m_tweakers;
|
||||
|
||||
@ -84,6 +132,9 @@ private:
|
||||
/// the list of maven files to be placed in the libraries folder, but not acted upon
|
||||
QList<LibraryPtr> m_mavenFiles;
|
||||
|
||||
/// the list of java agents to add to JVM arguments
|
||||
QList<AgentPtr> m_agents;
|
||||
|
||||
/// the main jar
|
||||
LibraryPtr m_mainJar;
|
||||
|
||||
@ -99,6 +150,9 @@ private:
|
||||
/// the list of mods
|
||||
QList<LibraryPtr> m_mods;
|
||||
|
||||
/// compatible java major versions
|
||||
QList<int> m_compatibleJavaMajors;
|
||||
|
||||
ProblemSeverity m_problemSeverity = ProblemSeverity::None;
|
||||
|
||||
};
|
||||
|
@ -156,7 +156,7 @@ public: /* methods */
|
||||
QStringList & failedLocalFiles, const QString & overridePath) const;
|
||||
|
||||
private: /* methods */
|
||||
/// the default storage prefix used by MultiMC
|
||||
/// the default storage prefix used by PolyMC
|
||||
static QString defaultStoragePrefix();
|
||||
|
||||
/// Get the prefix - root of the storage to be used
|
||||
@ -177,23 +177,23 @@ protected: /* data */
|
||||
/// DEPRECATED URL prefix of the maven repo where the file can be downloaded
|
||||
QString m_repositoryURL;
|
||||
|
||||
/// DEPRECATED: MultiMC-specific absolute URL. takes precedence over the implicit maven repo URL, if defined
|
||||
/// DEPRECATED: PolyMC-specific absolute URL. takes precedence over the implicit maven repo URL, if defined
|
||||
QString m_absoluteURL;
|
||||
|
||||
/// MultiMC extension - filename override
|
||||
/// PolyMC extension - filename override
|
||||
QString m_filename;
|
||||
|
||||
/// DEPRECATED MultiMC extension - display name
|
||||
/// DEPRECATED PolyMC extension - display name
|
||||
QString m_displayname;
|
||||
|
||||
/**
|
||||
* MultiMC-specific type hint - modifies how the library is treated
|
||||
* PolyMC-specific type hint - modifies how the library is treated
|
||||
*/
|
||||
QString m_hint;
|
||||
|
||||
/**
|
||||
* storage - by default the local libraries folder in multimc, but could be elsewhere
|
||||
* MultiMC specific, because of FTB.
|
||||
* storage - by default the local libraries folder in polymc, but could be elsewhere
|
||||
* PolyMC specific, because of FTB.
|
||||
*/
|
||||
QString m_storagePrefix;
|
||||
|
||||
@ -215,3 +215,4 @@ protected: /* data */
|
||||
/// MOJANG: container with Mojang style download info
|
||||
MojangLibraryDownloadInfo::Ptr m_mojangDownloads;
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,41 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MinecraftInstance.h"
|
||||
#include "BuildConfig.h"
|
||||
#include "minecraft/launch/CreateGameFolders.h"
|
||||
#include "minecraft/launch/ExtractNatives.h"
|
||||
#include "minecraft/launch/PrintInstanceInfo.h"
|
||||
@ -20,6 +57,7 @@
|
||||
#include "launch/steps/PreLaunchCommand.h"
|
||||
#include "launch/steps/TextPrint.h"
|
||||
#include "launch/steps/CheckJava.h"
|
||||
#include "launch/steps/QuitAfterGameStop.h"
|
||||
|
||||
#include "minecraft/launch/LauncherPartLaunch.h"
|
||||
#include "minecraft/launch/DirectJavaLaunch.h"
|
||||
@ -88,6 +126,7 @@ MinecraftInstance::MinecraftInstance(SettingsObjectPtr globalSettings, SettingsO
|
||||
|
||||
m_settings->registerOverride(globalSettings->getSetting("JavaPath"), javaOrLocation);
|
||||
m_settings->registerOverride(globalSettings->getSetting("JvmArgs"), javaOrArgs);
|
||||
m_settings->registerOverride(globalSettings->getSetting("IgnoreJavaCompatibility"), javaOrLocation);
|
||||
|
||||
// special!
|
||||
m_settings->registerPassthrough(globalSettings->getSetting("JavaTimestamp"), javaOrLocation);
|
||||
@ -124,18 +163,12 @@ MinecraftInstance::MinecraftInstance(SettingsObjectPtr globalSettings, SettingsO
|
||||
m_settings->registerSetting("JoinServerOnLaunch", false);
|
||||
m_settings->registerSetting("JoinServerOnLaunchAddress", "");
|
||||
|
||||
// DEPRECATED: Read what versions the user configuration thinks should be used
|
||||
m_settings->registerSetting({"IntendedVersion", "MinecraftVersion"}, "");
|
||||
m_settings->registerSetting("LWJGLVersion", "");
|
||||
m_settings->registerSetting("ForgeVersion", "");
|
||||
m_settings->registerSetting("LiteloaderVersion", "");
|
||||
// Miscellaneous
|
||||
auto miscellaneousOverride = m_settings->registerSetting("OverrideMiscellaneous", false);
|
||||
m_settings->registerOverride(globalSettings->getSetting("CloseAfterLaunch"), miscellaneousOverride);
|
||||
m_settings->registerOverride(globalSettings->getSetting("QuitAfterGameStop"), miscellaneousOverride);
|
||||
|
||||
m_components.reset(new PackProfile(this));
|
||||
m_components->setOldConfigVersion("net.minecraft", m_settings->get("IntendedVersion").toString());
|
||||
auto setting = m_settings->getSetting("LWJGLVersion");
|
||||
m_components->setOldConfigVersion("org.lwjgl", m_settings->get("LWJGLVersion").toString());
|
||||
m_components->setOldConfigVersion("net.minecraftforge", m_settings->get("ForgeVersion").toString());
|
||||
m_components->setOldConfigVersion("com.mumfrey.liteloader", m_settings->get("LiteloaderVersion").toString());
|
||||
}
|
||||
|
||||
void MinecraftInstance::saveNow()
|
||||
@ -303,6 +336,17 @@ QStringList MinecraftInstance::extraArguments() const
|
||||
list.append({"-Dfml.ignoreInvalidMinecraftCertificates=true",
|
||||
"-Dfml.ignorePatchDiscrepancies=true"});
|
||||
}
|
||||
auto addn = m_components->getProfile()->getAddnJvmArguments();
|
||||
if (!addn.isEmpty()) {
|
||||
list.append(addn);
|
||||
}
|
||||
auto agents = m_components->getProfile()->getAgents();
|
||||
for (auto agent : agents)
|
||||
{
|
||||
QStringList jar, temp1, temp2, temp3;
|
||||
agent->library()->getApplicableFiles(currentSystem, jar, temp1, temp2, temp3, getLocalLibraryPath());
|
||||
list.append("-javaagent:"+jar[0]+(agent->argument().isEmpty() ? "" : "="+agent->argument()));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@ -444,9 +488,8 @@ QStringList MinecraftInstance::processMinecraftArgs(
|
||||
}
|
||||
}
|
||||
|
||||
// blatant self-promotion.
|
||||
token_mapping["profile_name"] = token_mapping["version_name"] = "MultiMC5";
|
||||
|
||||
token_mapping["profile_name"] = name();
|
||||
token_mapping["version_name"] = profile->getMinecraftVersion();
|
||||
token_mapping["version_type"] = profile->getMinecraftVersionType();
|
||||
|
||||
QString absRootDir = QDir(gameRoot()).absolutePath();
|
||||
@ -946,6 +989,11 @@ shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPt
|
||||
{
|
||||
process->setCensorFilter(createCensorFilterFromSession(session));
|
||||
}
|
||||
if(m_settings->get("QuitAfterGameStop").toBool())
|
||||
{
|
||||
auto step = new QuitAfterGameStop(pptr);
|
||||
process->appendStep(step);
|
||||
}
|
||||
m_launchProcess = process;
|
||||
emit launchTaskChanged(m_launchProcess);
|
||||
return m_launchProcess;
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include <QUrl>
|
||||
|
||||
#include "tasks/Task.h"
|
||||
#include <quazip.h>
|
||||
#include <quazip/quazip.h>
|
||||
|
||||
#include "QObjectPtr.h"
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include "net/NetJob.h"
|
||||
#include "tasks/Task.h"
|
||||
#include "minecraft/VersionFilterData.h"
|
||||
#include <quazip.h>
|
||||
#include <quazip/quazip.h>
|
||||
|
||||
class MinecraftVersion;
|
||||
class MinecraftInstance;
|
||||
|
@ -1,3 +1,38 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MojangVersionFormat.h"
|
||||
#include "OneSixVersionFormat.h"
|
||||
#include "MojangDownloadInfo.h"
|
||||
@ -183,6 +218,15 @@ void MojangVersionFormat::readVersionProperties(const QJsonObject &in, VersionFi
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (in.contains("compatibleJavaMajors"))
|
||||
{
|
||||
for (auto compatible : requireArray(in.value("compatibleJavaMajors")))
|
||||
{
|
||||
out->compatibleJavaMajors.append(requireInteger(compatible));
|
||||
}
|
||||
}
|
||||
|
||||
if(in.contains("downloads"))
|
||||
{
|
||||
auto downloadsObj = requireObject(in, "downloads");
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "OneSixVersionFormat.h"
|
||||
#include <Json.h>
|
||||
#include "minecraft/Agent.h"
|
||||
#include "minecraft/ParseUtils.h"
|
||||
#include <minecraft/MojangVersionFormat.h>
|
||||
|
||||
@ -108,6 +109,14 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc
|
||||
}
|
||||
}
|
||||
|
||||
if (root.contains("+jvmArgs"))
|
||||
{
|
||||
for (auto arg : requireArray(root.value("+jvmArgs")))
|
||||
{
|
||||
out->addnJvmArguments.append(requireString(arg));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (root.contains("jarMods"))
|
||||
{
|
||||
@ -176,6 +185,21 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc
|
||||
readLibs("mavenFiles", out->mavenFiles);
|
||||
}
|
||||
|
||||
if(root.contains("+agents")) {
|
||||
for (auto agentVal : requireArray(root.value("+agents")))
|
||||
{
|
||||
QJsonObject agentObj = requireObject(agentVal);
|
||||
auto lib = libraryFromJson(*out, agentObj, filename);
|
||||
QString arg = "";
|
||||
if (agentObj.contains("argument"))
|
||||
{
|
||||
readString(agentObj, "argument", arg);
|
||||
}
|
||||
AgentPtr agent(new Agent(lib, arg));
|
||||
out->agents.append(agent);
|
||||
}
|
||||
}
|
||||
|
||||
// if we have mainJar, just use it
|
||||
if(root.contains("mainJar"))
|
||||
{
|
||||
|
@ -36,6 +36,13 @@
|
||||
#include "ComponentUpdateTask.h"
|
||||
|
||||
#include "Application.h"
|
||||
#include "modplatform/ModAPI.h"
|
||||
|
||||
static const QMap<QString, ModAPI::ModLoaderType> modloaderMapping{
|
||||
{"net.minecraftforge", ModAPI::Forge},
|
||||
{"net.fabricmc.fabric-loader", ModAPI::Fabric},
|
||||
{"org.quiltmc.quilt-loader", ModAPI::Quilt}
|
||||
};
|
||||
|
||||
PackProfile::PackProfile(MinecraftInstance * instance)
|
||||
: QAbstractListModel()
|
||||
@ -272,18 +279,6 @@ void PackProfile::save_internal()
|
||||
bool PackProfile::load()
|
||||
{
|
||||
auto filename = componentsFilePath();
|
||||
QFile componentsFile(filename);
|
||||
|
||||
// migrate old config to new one, if needed
|
||||
if(!componentsFile.exists())
|
||||
{
|
||||
if(!migratePreComponentConfig())
|
||||
{
|
||||
// FIXME: the user should be notified...
|
||||
qCritical() << "Failed to convert old pre-component config for instance" << d->m_instance->name();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// load the new component list and swap it with the current one...
|
||||
ComponentContainer newComponents;
|
||||
@ -369,239 +364,6 @@ void PackProfile::updateFailed(const QString& error)
|
||||
invalidateLaunchProfile();
|
||||
}
|
||||
|
||||
// NOTE this is really old stuff, and only needs to be used when loading the old hardcoded component-unaware format (loadPreComponentConfig).
|
||||
static void upgradeDeprecatedFiles(QString root, QString instanceName)
|
||||
{
|
||||
auto versionJsonPath = FS::PathCombine(root, "version.json");
|
||||
auto customJsonPath = FS::PathCombine(root, "custom.json");
|
||||
auto mcJson = FS::PathCombine(root, "patches" , "net.minecraft.json");
|
||||
|
||||
QString sourceFile;
|
||||
QString renameFile;
|
||||
|
||||
// convert old crap.
|
||||
if(QFile::exists(customJsonPath))
|
||||
{
|
||||
sourceFile = customJsonPath;
|
||||
renameFile = versionJsonPath;
|
||||
}
|
||||
else if(QFile::exists(versionJsonPath))
|
||||
{
|
||||
sourceFile = versionJsonPath;
|
||||
}
|
||||
if(!sourceFile.isEmpty() && !QFile::exists(mcJson))
|
||||
{
|
||||
if(!FS::ensureFilePathExists(mcJson))
|
||||
{
|
||||
qWarning() << "Couldn't create patches folder for" << instanceName;
|
||||
return;
|
||||
}
|
||||
if(!renameFile.isEmpty() && QFile::exists(renameFile))
|
||||
{
|
||||
if(!QFile::rename(renameFile, renameFile + ".old"))
|
||||
{
|
||||
qWarning() << "Couldn't rename" << renameFile << "to" << renameFile + ".old" << "in" << instanceName;
|
||||
return;
|
||||
}
|
||||
}
|
||||
auto file = ProfileUtils::parseJsonFile(QFileInfo(sourceFile), false);
|
||||
ProfileUtils::removeLwjglFromPatch(file);
|
||||
file->uid = "net.minecraft";
|
||||
file->version = file->minecraftVersion;
|
||||
file->name = "Minecraft";
|
||||
|
||||
Meta::Require needsLwjgl;
|
||||
needsLwjgl.uid = "org.lwjgl";
|
||||
file->requires.insert(needsLwjgl);
|
||||
|
||||
if(!ProfileUtils::saveJsonFile(OneSixVersionFormat::versionFileToJson(file), mcJson))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(!QFile::rename(sourceFile, sourceFile + ".old"))
|
||||
{
|
||||
qWarning() << "Couldn't rename" << sourceFile << "to" << sourceFile + ".old" << "in" << instanceName;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Migrate old layout to the component based one...
|
||||
* - Part of the version information is taken from `instance.cfg` (fed to this class from outside).
|
||||
* - Part is taken from the old order.json file.
|
||||
* - Part is loaded from loose json files in the instance's `patches` directory.
|
||||
*/
|
||||
bool PackProfile::migratePreComponentConfig()
|
||||
{
|
||||
// upgrade the very old files from the beginnings of MultiMC 5
|
||||
upgradeDeprecatedFiles(d->m_instance->instanceRoot(), d->m_instance->name());
|
||||
|
||||
QList<ComponentPtr> components;
|
||||
QSet<QString> loaded;
|
||||
|
||||
auto addBuiltinPatch = [&](const QString &uid, bool asDependency, const QString & emptyVersion, const Meta::Require & req, const Meta::Require & conflict)
|
||||
{
|
||||
auto jsonFilePath = FS::PathCombine(d->m_instance->instanceRoot(), "patches" , uid + ".json");
|
||||
auto intendedVersion = d->getOldConfigVersion(uid);
|
||||
// load up the base minecraft patch
|
||||
ComponentPtr component;
|
||||
if(QFile::exists(jsonFilePath))
|
||||
{
|
||||
if(intendedVersion.isEmpty())
|
||||
{
|
||||
intendedVersion = emptyVersion;
|
||||
}
|
||||
auto file = ProfileUtils::parseJsonFile(QFileInfo(jsonFilePath), false);
|
||||
// fix uid
|
||||
file->uid = uid;
|
||||
// if version is missing, add it from the outside.
|
||||
if(file->version.isEmpty())
|
||||
{
|
||||
file->version = intendedVersion;
|
||||
}
|
||||
// if this is a dependency (LWJGL), mark it also as volatile
|
||||
if(asDependency)
|
||||
{
|
||||
file->m_volatile = true;
|
||||
}
|
||||
// insert requirements if needed
|
||||
if(!req.uid.isEmpty())
|
||||
{
|
||||
file->requires.insert(req);
|
||||
}
|
||||
// insert conflicts if needed
|
||||
if(!conflict.uid.isEmpty())
|
||||
{
|
||||
file->conflicts.insert(conflict);
|
||||
}
|
||||
// FIXME: @QUALITY do not ignore return value
|
||||
ProfileUtils::saveJsonFile(OneSixVersionFormat::versionFileToJson(file), jsonFilePath);
|
||||
component = new Component(this, uid, file);
|
||||
component->m_version = intendedVersion;
|
||||
}
|
||||
else if(!intendedVersion.isEmpty())
|
||||
{
|
||||
auto metaVersion = APPLICATION->metadataIndex()->get(uid, intendedVersion);
|
||||
component = new Component(this, metaVersion);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
component->m_dependencyOnly = asDependency;
|
||||
component->m_important = !asDependency;
|
||||
components.append(component);
|
||||
};
|
||||
// TODO: insert depends and conflicts here if these are customized files...
|
||||
Meta::Require reqLwjgl;
|
||||
reqLwjgl.uid = "org.lwjgl";
|
||||
reqLwjgl.suggests = "2.9.1";
|
||||
Meta::Require conflictLwjgl3;
|
||||
conflictLwjgl3.uid = "org.lwjgl3";
|
||||
Meta::Require nullReq;
|
||||
addBuiltinPatch("org.lwjgl", true, "2.9.1", nullReq, conflictLwjgl3);
|
||||
addBuiltinPatch("net.minecraft", false, QString(), reqLwjgl, nullReq);
|
||||
|
||||
// first, collect all other file-based patches and load them
|
||||
QMap<QString, ComponentPtr> loadedComponents;
|
||||
QDir patchesDir(FS::PathCombine(d->m_instance->instanceRoot(),"patches"));
|
||||
for (auto info : patchesDir.entryInfoList(QStringList() << "*.json", QDir::Files))
|
||||
{
|
||||
// parse the file
|
||||
qDebug() << "Reading" << info.fileName();
|
||||
auto file = ProfileUtils::parseJsonFile(info, true);
|
||||
|
||||
// correct missing or wrong uid based on the file name
|
||||
QString uid = info.completeBaseName();
|
||||
|
||||
// ignore builtins, they've been handled already
|
||||
if (uid == "net.minecraft")
|
||||
continue;
|
||||
if (uid == "org.lwjgl")
|
||||
continue;
|
||||
|
||||
// handle horrible corner cases
|
||||
if(uid.isEmpty())
|
||||
{
|
||||
// if you have a file named '.json', make it just go away.
|
||||
// FIXME: @QUALITY do not ignore return value
|
||||
QFile::remove(info.absoluteFilePath());
|
||||
continue;
|
||||
}
|
||||
file->uid = uid;
|
||||
// FIXME: @QUALITY do not ignore return value
|
||||
ProfileUtils::saveJsonFile(OneSixVersionFormat::versionFileToJson(file), info.absoluteFilePath());
|
||||
|
||||
auto component = new Component(this, file->uid, file);
|
||||
auto version = d->getOldConfigVersion(file->uid);
|
||||
if(!version.isEmpty())
|
||||
{
|
||||
component->m_version = version;
|
||||
}
|
||||
loadedComponents[file->uid] = component;
|
||||
}
|
||||
// try to load the other 'hardcoded' patches (forge, liteloader), if they weren't loaded from files
|
||||
auto loadSpecial = [&](const QString & uid, int order)
|
||||
{
|
||||
auto patchVersion = d->getOldConfigVersion(uid);
|
||||
if(!patchVersion.isEmpty() && !loadedComponents.contains(uid))
|
||||
{
|
||||
auto patch = new Component(this, APPLICATION->metadataIndex()->get(uid, patchVersion));
|
||||
patch->setOrder(order);
|
||||
loadedComponents[uid] = patch;
|
||||
}
|
||||
};
|
||||
loadSpecial("net.minecraftforge", 5);
|
||||
loadSpecial("com.mumfrey.liteloader", 10);
|
||||
|
||||
// load the old order.json file, if present
|
||||
ProfileUtils::PatchOrder userOrder;
|
||||
ProfileUtils::readOverrideOrders(FS::PathCombine(d->m_instance->instanceRoot(), "order.json"), userOrder);
|
||||
|
||||
// now add all the patches by user sort order
|
||||
for (auto uid : userOrder)
|
||||
{
|
||||
// ignore builtins
|
||||
if (uid == "net.minecraft")
|
||||
continue;
|
||||
if (uid == "org.lwjgl")
|
||||
continue;
|
||||
// ordering has a patch that is gone?
|
||||
if(!loadedComponents.contains(uid))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
components.append(loadedComponents.take(uid));
|
||||
}
|
||||
|
||||
// is there anything left to sort? - this is used when there are leftover components that aren't part of the order.json
|
||||
if(!loadedComponents.isEmpty())
|
||||
{
|
||||
// inserting into multimap by order number as key sorts the patches and detects duplicates
|
||||
QMultiMap<int, ComponentPtr> files;
|
||||
auto iter = loadedComponents.begin();
|
||||
while(iter != loadedComponents.end())
|
||||
{
|
||||
files.insert((*iter)->getOrder(), *iter);
|
||||
iter++;
|
||||
}
|
||||
|
||||
// then just extract the patches and put them in the list
|
||||
for (auto order : files.keys())
|
||||
{
|
||||
const auto &values = files.values(order);
|
||||
for(auto &value: values)
|
||||
{
|
||||
// TODO: put back the insertion of problem messages here, so the user knows about the id duplication
|
||||
components.append(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
// new we have a complete list of components...
|
||||
return savePackProfile(componentsFilePath(), components);
|
||||
}
|
||||
|
||||
// END: save/load
|
||||
|
||||
void PackProfile::appendComponent(ComponentPtr component)
|
||||
@ -1169,15 +931,6 @@ std::shared_ptr<LaunchProfile> PackProfile::getProfile() const
|
||||
return d->m_profile;
|
||||
}
|
||||
|
||||
void PackProfile::setOldConfigVersion(const QString& uid, const QString& version)
|
||||
{
|
||||
if(version.isEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
d->m_oldConfigVersions[uid] = version;
|
||||
}
|
||||
|
||||
bool PackProfile::setComponentVersion(const QString& uid, const QString& version, bool important)
|
||||
{
|
||||
auto iter = d->componentIndex.find(uid);
|
||||
@ -1224,3 +977,20 @@ void PackProfile::disableInteraction(bool disable)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ModAPI::ModLoaderTypes PackProfile::getModLoaders()
|
||||
{
|
||||
ModAPI::ModLoaderTypes result = ModAPI::Unspecified;
|
||||
|
||||
QMapIterator<QString, ModAPI::ModLoaderType> i(modloaderMapping);
|
||||
|
||||
while (i.hasNext())
|
||||
{
|
||||
i.next();
|
||||
Component* c = getComponent(i.key());
|
||||
if (c != nullptr && c->isEnabled()) {
|
||||
result |= i.value();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "BaseVersion.h"
|
||||
#include "MojangDownloadInfo.h"
|
||||
#include "net/Mode.h"
|
||||
#include "modplatform/ModAPI.h"
|
||||
|
||||
class MinecraftInstance;
|
||||
struct PackProfileData;
|
||||
@ -117,6 +118,8 @@ public:
|
||||
// todo(merged): is this the best approach
|
||||
void appendComponent(ComponentPtr component);
|
||||
|
||||
ModAPI::ModLoaderTypes getModLoaders();
|
||||
|
||||
private:
|
||||
void scheduleSave();
|
||||
bool saveIsScheduled() const;
|
||||
@ -143,8 +146,6 @@ private:
|
||||
bool installCustomJar_internal(QString filepath);
|
||||
bool removeComponent_internal(ComponentPtr patch);
|
||||
|
||||
bool migratePreComponentConfig();
|
||||
|
||||
private: /* data */
|
||||
|
||||
std::unique_ptr<PackProfileData> d;
|
||||
|
@ -18,18 +18,6 @@ struct PackProfileData
|
||||
// the launch profile (volatile, temporary thing created on demand)
|
||||
std::shared_ptr<LaunchProfile> m_profile;
|
||||
|
||||
// version information migrated from instance.cfg file. Single use on migration!
|
||||
std::map<QString, QString> m_oldConfigVersions;
|
||||
QString getOldConfigVersion(const QString& uid) const
|
||||
{
|
||||
const auto iter = m_oldConfigVersions.find(uid);
|
||||
if(iter != m_oldConfigVersions.cend())
|
||||
{
|
||||
return (*iter).second;
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
// persistent list of components and related machinery
|
||||
ComponentContainer components;
|
||||
ComponentIndex componentIndex;
|
||||
|
@ -1,3 +1,39 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
|
||||
@ -20,7 +56,7 @@ void VersionFile::applyTo(LaunchProfile *profile)
|
||||
// Only real Minecraft can set those. Don't let anything override them.
|
||||
if (isMinecraftVersion(uid))
|
||||
{
|
||||
profile->applyMinecraftVersion(minecraftVersion);
|
||||
profile->applyMinecraftVersion(version);
|
||||
profile->applyMinecraftVersionType(type);
|
||||
// HACK: ignore assets from other version files than Minecraft
|
||||
// workaround for stupid assets issue caused by amazon:
|
||||
@ -32,10 +68,12 @@ void VersionFile::applyTo(LaunchProfile *profile)
|
||||
profile->applyMainClass(mainClass);
|
||||
profile->applyAppletClass(appletClass);
|
||||
profile->applyMinecraftArguments(minecraftArguments);
|
||||
profile->applyAddnJvmArguments(addnJvmArguments);
|
||||
profile->applyTweakers(addTweakers);
|
||||
profile->applyJarMods(jarMods);
|
||||
profile->applyMods(mods);
|
||||
profile->applyTraits(traits);
|
||||
profile->applyCompatibleJavaMajors(compatibleJavaMajors);
|
||||
|
||||
for (auto library : libraries)
|
||||
{
|
||||
@ -45,6 +83,10 @@ void VersionFile::applyTo(LaunchProfile *profile)
|
||||
{
|
||||
profile->applyMavenFile(mavenFile);
|
||||
}
|
||||
for (auto agent : agents)
|
||||
{
|
||||
profile->applyAgent(agent);
|
||||
}
|
||||
profile->applyProblemSeverity(getProblemSeverity());
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,38 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
@ -10,6 +45,7 @@
|
||||
#include "minecraft/Rule.h"
|
||||
#include "ProblemProvider.h"
|
||||
#include "Library.h"
|
||||
#include "Agent.h"
|
||||
#include <meta/JsonFormat.h>
|
||||
|
||||
class PackProfile;
|
||||
@ -27,19 +63,19 @@ public: /* methods */
|
||||
void applyTo(LaunchProfile* profile);
|
||||
|
||||
public: /* data */
|
||||
/// MultiMC: order hint for this version file if no explicit order is set
|
||||
/// PolyMC: order hint for this version file if no explicit order is set
|
||||
int order = 0;
|
||||
|
||||
/// MultiMC: human readable name of this package
|
||||
/// PolyMC: human readable name of this package
|
||||
QString name;
|
||||
|
||||
/// MultiMC: package ID of this package
|
||||
/// PolyMC: package ID of this package
|
||||
QString uid;
|
||||
|
||||
/// MultiMC: version of this package
|
||||
/// PolyMC: version of this package
|
||||
QString version;
|
||||
|
||||
/// MultiMC: DEPRECATED dependency on a Minecraft version
|
||||
/// PolyMC: DEPRECATED dependency on a Minecraft version
|
||||
QString dependsOnMinecraftVersion;
|
||||
|
||||
/// Mojang: DEPRECATED used to version the Mojang version format
|
||||
@ -51,12 +87,18 @@ public: /* data */
|
||||
/// Mojang: class to launch Minecraft with
|
||||
QString mainClass;
|
||||
|
||||
/// MultiMC: class to launch legacy Minecraft with (embed in a custom window)
|
||||
/// PolyMC: class to launch legacy Minecraft with (embed in a custom window)
|
||||
QString appletClass;
|
||||
|
||||
/// Mojang: Minecraft launch arguments (may contain placeholders for variable substitution)
|
||||
QString minecraftArguments;
|
||||
|
||||
/// PolyMC: Additional JVM launch arguments
|
||||
QStringList addnJvmArguments;
|
||||
|
||||
/// Mojang: list of compatible java majors
|
||||
QList<int> compatibleJavaMajors;
|
||||
|
||||
/// Mojang: type of the Minecraft version
|
||||
QString type;
|
||||
|
||||
@ -69,35 +111,38 @@ public: /* data */
|
||||
/// Mojang: DEPRECATED asset group to be used with Minecraft
|
||||
QString assets;
|
||||
|
||||
/// MultiMC: list of tweaker mod arguments for launchwrapper
|
||||
/// PolyMC: list of tweaker mod arguments for launchwrapper
|
||||
QStringList addTweakers;
|
||||
|
||||
/// Mojang: list of libraries to add to the version
|
||||
QList<LibraryPtr> libraries;
|
||||
|
||||
/// MultiMC: list of maven files to put in the libraries folder, but not in classpath
|
||||
/// PolyMC: list of maven files to put in the libraries folder, but not in classpath
|
||||
QList<LibraryPtr> mavenFiles;
|
||||
|
||||
/// PolyMC: list of agents to add to JVM arguments
|
||||
QList<AgentPtr> agents;
|
||||
|
||||
/// The main jar (Minecraft version library, normally)
|
||||
LibraryPtr mainJar;
|
||||
|
||||
/// MultiMC: list of attached traits of this version file - used to enable features
|
||||
/// PolyMC: list of attached traits of this version file - used to enable features
|
||||
QSet<QString> traits;
|
||||
|
||||
/// MultiMC: list of jar mods added to this version
|
||||
/// PolyMC: list of jar mods added to this version
|
||||
QList<LibraryPtr> jarMods;
|
||||
|
||||
/// MultiMC: list of mods added to this version
|
||||
/// PolyMC: list of mods added to this version
|
||||
QList<LibraryPtr> mods;
|
||||
|
||||
/**
|
||||
* MultiMC: set of packages this depends on
|
||||
* PolyMC: set of packages this depends on
|
||||
* NOTE: this is shared with the meta format!!!
|
||||
*/
|
||||
Meta::RequireSet requires;
|
||||
|
||||
/**
|
||||
* MultiMC: set of packages this conflicts with
|
||||
* PolyMC: set of packages this conflicts with
|
||||
* NOTE: this is shared with the meta format!!!
|
||||
*/
|
||||
Meta::RequireSet conflicts;
|
||||
@ -112,3 +157,4 @@ public:
|
||||
// Mojang: extended asset index download information
|
||||
std::shared_ptr<MojangAssetIndexInfo> mojangAssetIndex;
|
||||
};
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <QString>
|
||||
#include <QDebug>
|
||||
#include <QSaveFile>
|
||||
#include <QDirIterator>
|
||||
#include "World.h"
|
||||
|
||||
#include "GZip.h"
|
||||
@ -26,9 +27,9 @@
|
||||
#include <io/stream_reader.h>
|
||||
#include <tag_string.h>
|
||||
#include <tag_primitive.h>
|
||||
#include <quazip.h>
|
||||
#include <quazipfile.h>
|
||||
#include <quazipdir.h>
|
||||
#include <quazip/quazip.h>
|
||||
#include <quazip/quazipfile.h>
|
||||
#include <quazip/quazipdir.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
|
||||
@ -187,6 +188,26 @@ bool putLevelDatDataToFS(const QFileInfo &file, QByteArray & data)
|
||||
return f.commit();
|
||||
}
|
||||
|
||||
int64_t calculateWorldSize(const QFileInfo &file)
|
||||
{
|
||||
if (file.isFile() && file.suffix() == "zip")
|
||||
{
|
||||
return file.size();
|
||||
}
|
||||
else if(file.isDir())
|
||||
{
|
||||
QDirIterator it(file.absoluteFilePath(), QDir::Files, QDirIterator::Subdirectories);
|
||||
int64_t total = 0;
|
||||
while (it.hasNext())
|
||||
{
|
||||
total += it.fileInfo().size();
|
||||
it.next();
|
||||
}
|
||||
return total;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
World::World(const QFileInfo &file)
|
||||
{
|
||||
repath(file);
|
||||
@ -196,6 +217,7 @@ void World::repath(const QFileInfo &file)
|
||||
{
|
||||
m_containerFile = file;
|
||||
m_folderName = file.fileName();
|
||||
m_size = calculateWorldSize(file);
|
||||
if(file.isFile() && file.suffix() == "zip")
|
||||
{
|
||||
m_iconFile = QString();
|
||||
@ -482,6 +504,7 @@ void World::loadFromLevelDat(QByteArray data)
|
||||
if(randomSeed) {
|
||||
qDebug() << "Seed:" << *randomSeed;
|
||||
}
|
||||
qDebug() << "Size:" << m_size;
|
||||
qDebug() << "GameType:" << m_gameType.toLogString();
|
||||
}
|
||||
|
||||
|
@ -52,6 +52,10 @@ public:
|
||||
{
|
||||
return m_iconFile;
|
||||
}
|
||||
int64_t bytes() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
QDateTime lastPlayed() const
|
||||
{
|
||||
return m_lastPlayed;
|
||||
@ -105,6 +109,7 @@ protected:
|
||||
QString m_iconFile;
|
||||
QDateTime levelDatTime;
|
||||
QDateTime m_lastPlayed;
|
||||
int64_t m_size;
|
||||
int64_t m_randomSeed = 0;
|
||||
GameType m_gameType;
|
||||
bool is_valid = false;
|
||||
|
@ -14,7 +14,10 @@
|
||||
*/
|
||||
|
||||
#include "WorldList.h"
|
||||
|
||||
#include "Application.h"
|
||||
#include <FileSystem.h>
|
||||
#include <Qt>
|
||||
#include <QMimeData>
|
||||
#include <QUrl>
|
||||
#include <QUuid>
|
||||
@ -150,7 +153,7 @@ bool WorldList::resetIcon(int row)
|
||||
|
||||
int WorldList::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
return 3;
|
||||
return 4;
|
||||
}
|
||||
|
||||
QVariant WorldList::data(const QModelIndex &index, int role) const
|
||||
@ -164,6 +167,8 @@ QVariant WorldList::data(const QModelIndex &index, int role) const
|
||||
if (row < 0 || row >= worlds.size())
|
||||
return QVariant();
|
||||
|
||||
QLocale locale;
|
||||
|
||||
auto & world = worlds[row];
|
||||
switch (role)
|
||||
{
|
||||
@ -179,10 +184,23 @@ QVariant WorldList::data(const QModelIndex &index, int role) const
|
||||
case LastPlayedColumn:
|
||||
return world.lastPlayed();
|
||||
|
||||
case SizeColumn:
|
||||
return locale.formattedDataSize(world.bytes());
|
||||
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
case Qt::UserRole:
|
||||
switch (column)
|
||||
{
|
||||
case SizeColumn:
|
||||
return qVariantFromValue<qlonglong>(world.bytes());
|
||||
|
||||
default:
|
||||
return data(index, Qt::DisplayRole);
|
||||
}
|
||||
|
||||
case Qt::ToolTipRole:
|
||||
{
|
||||
return world.folderName();
|
||||
@ -207,6 +225,10 @@ QVariant WorldList::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
return world.lastPlayed();
|
||||
}
|
||||
case SizeRole:
|
||||
{
|
||||
return qVariantFromValue<qlonglong>(world.bytes());
|
||||
}
|
||||
case IconFileRole:
|
||||
{
|
||||
return world.iconFile();
|
||||
@ -229,6 +251,9 @@ QVariant WorldList::headerData(int section, Qt::Orientation orientation, int rol
|
||||
return tr("Game Mode");
|
||||
case LastPlayedColumn:
|
||||
return tr("Last Played");
|
||||
case SizeColumn:
|
||||
//: World size on disk
|
||||
return tr("Size");
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
@ -242,6 +267,8 @@ QVariant WorldList::headerData(int section, Qt::Orientation orientation, int rol
|
||||
return tr("Game mode of the world.");
|
||||
case LastPlayedColumn:
|
||||
return tr("Date and time the world was last played.");
|
||||
case SizeColumn:
|
||||
return tr("Size of the world on disk.");
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
|
@ -32,7 +32,8 @@ public:
|
||||
{
|
||||
NameColumn,
|
||||
GameModeColumn,
|
||||
LastPlayedColumn
|
||||
LastPlayedColumn,
|
||||
SizeColumn
|
||||
};
|
||||
|
||||
enum Roles
|
||||
@ -43,6 +44,7 @@ public:
|
||||
NameRole,
|
||||
GameModeRole,
|
||||
LastPlayedRole,
|
||||
SizeRole,
|
||||
IconFileRole
|
||||
};
|
||||
|
||||
|
@ -1,3 +1,38 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "AccountData.h"
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
@ -314,6 +349,8 @@ bool AccountData::resumeStateFromV3(QJsonObject data) {
|
||||
type = AccountType::MSA;
|
||||
} else if (typeS == "Mojang") {
|
||||
type = AccountType::Mojang;
|
||||
} else if (typeS == "Offline") {
|
||||
type = AccountType::Offline;
|
||||
} else {
|
||||
qWarning() << "Failed to parse account data: type is not recognized.";
|
||||
return false;
|
||||
@ -325,6 +362,10 @@ bool AccountData::resumeStateFromV3(QJsonObject data) {
|
||||
}
|
||||
|
||||
if(type == AccountType::MSA) {
|
||||
auto clientIDV = data.value("msa-client-id");
|
||||
if (clientIDV.isString()) {
|
||||
msaClientID = clientIDV.toString();
|
||||
} // leave msaClientID empty if it doesn't exist or isn't a string
|
||||
msaToken = tokenFromJSONV3(data, "msa");
|
||||
userToken = tokenFromJSONV3(data, "utoken");
|
||||
xboxApiToken = tokenFromJSONV3(data, "xrp-main");
|
||||
@ -358,11 +399,15 @@ QJsonObject AccountData::saveState() const {
|
||||
}
|
||||
else if (type == AccountType::MSA) {
|
||||
output["type"] = "MSA";
|
||||
output["msa-client-id"] = msaClientID;
|
||||
tokenToJSONV3(output, msaToken, "msa");
|
||||
tokenToJSONV3(output, userToken, "utoken");
|
||||
tokenToJSONV3(output, xboxApiToken, "xrp-main");
|
||||
tokenToJSONV3(output, mojangservicesToken, "xrp-mc");
|
||||
}
|
||||
else if (type == AccountType::Offline) {
|
||||
output["type"] = "Offline";
|
||||
}
|
||||
|
||||
tokenToJSONV3(output, yggdrasilToken, "ygg");
|
||||
profileToJSONV3(output, minecraftProfile, "profile");
|
||||
@ -371,7 +416,7 @@ QJsonObject AccountData::saveState() const {
|
||||
}
|
||||
|
||||
QString AccountData::userName() const {
|
||||
if(type != AccountType::Mojang) {
|
||||
if(type == AccountType::MSA) {
|
||||
return QString();
|
||||
}
|
||||
return yggdrasilToken.extra["userName"].toString();
|
||||
@ -427,6 +472,9 @@ QString AccountData::accountDisplayString() const {
|
||||
case AccountType::Mojang: {
|
||||
return userName();
|
||||
}
|
||||
case AccountType::Offline: {
|
||||
return userName();
|
||||
}
|
||||
case AccountType::MSA: {
|
||||
if(xboxApiToken.extra.contains("gtg")) {
|
||||
return xboxApiToken.extra["gtg"].toString();
|
||||
|
@ -1,3 +1,38 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <QString>
|
||||
#include <QByteArray>
|
||||
@ -38,7 +73,8 @@ struct MinecraftProfile {
|
||||
|
||||
enum class AccountType {
|
||||
MSA,
|
||||
Mojang
|
||||
Mojang,
|
||||
Offline
|
||||
};
|
||||
|
||||
enum class AccountState {
|
||||
@ -46,6 +82,7 @@ enum class AccountState {
|
||||
Offline,
|
||||
Working,
|
||||
Online,
|
||||
Disabled,
|
||||
Errored,
|
||||
Expired,
|
||||
Gone
|
||||
@ -80,6 +117,7 @@ struct AccountData {
|
||||
bool legacy = false;
|
||||
bool canMigrateToMSA = false;
|
||||
|
||||
QString msaClientID;
|
||||
Katabasis::Token msaToken;
|
||||
Katabasis::Token userToken;
|
||||
Katabasis::Token xboxApiToken;
|
||||
|
@ -1,16 +1,36 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* 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.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "AccountList.h"
|
||||
@ -291,6 +311,9 @@ QVariant AccountList::data(const QModelIndex &index, int role) const
|
||||
case AccountState::Expired: {
|
||||
return tr("Expired", "Account status");
|
||||
}
|
||||
case AccountState::Disabled: {
|
||||
return tr("Disabled", "Account status");
|
||||
}
|
||||
case AccountState::Gone: {
|
||||
return tr("Gone", "Account status");
|
||||
}
|
||||
@ -302,7 +325,7 @@ QVariant AccountList::data(const QModelIndex &index, int role) const
|
||||
}
|
||||
|
||||
case MigrationColumn: {
|
||||
if(account->isMSA()) {
|
||||
if(account->isMSA() || account->isOffline()) {
|
||||
return tr("N/A", "Can Migrate?");
|
||||
}
|
||||
if (account->canMigrate()) {
|
||||
|
@ -1,16 +1,36 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* 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.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
@ -24,7 +44,7 @@
|
||||
|
||||
/*!
|
||||
* List of available Mojang accounts.
|
||||
* This should be loaded in the background by MultiMC on startup.
|
||||
* This should be loaded in the background by PolyMC on startup.
|
||||
*/
|
||||
class AccountList : public QAbstractListModel
|
||||
{
|
||||
@ -158,3 +178,4 @@ protected:
|
||||
*/
|
||||
bool m_autosave = false;
|
||||
};
|
||||
|
||||
|
@ -1,16 +1,36 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* 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.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "AccountTask.h"
|
||||
@ -43,6 +63,8 @@ QString AccountTask::getStateMessage() const
|
||||
return tr("Authentication task succeeded.");
|
||||
case AccountTaskState::STATE_OFFLINE:
|
||||
return tr("Failed to contact the authentication server.");
|
||||
case AccountTaskState::STATE_DISABLED:
|
||||
return tr("Client ID has changed. New session needs to be created.");
|
||||
case AccountTaskState::STATE_FAILED_SOFT:
|
||||
return tr("Encountered an error during authentication.");
|
||||
case AccountTaskState::STATE_FAILED_HARD:
|
||||
@ -78,6 +100,12 @@ bool AccountTask::changeState(AccountTaskState newState, QString reason)
|
||||
emitFailed(reason);
|
||||
return false;
|
||||
}
|
||||
case AccountTaskState::STATE_DISABLED: {
|
||||
m_data->errorString = reason;
|
||||
m_data->accountState = AccountState::Disabled;
|
||||
emitFailed(reason);
|
||||
return false;
|
||||
}
|
||||
case AccountTaskState::STATE_FAILED_SOFT: {
|
||||
m_data->errorString = reason;
|
||||
m_data->accountState = AccountState::Errored;
|
||||
|
@ -1,16 +1,36 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* 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.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
@ -35,6 +55,7 @@ enum class AccountTaskState
|
||||
STATE_CREATED,
|
||||
STATE_WORKING,
|
||||
STATE_SUCCEEDED,
|
||||
STATE_DISABLED, //!< MSA Client ID has changed. Tell user to reloginn
|
||||
STATE_FAILED_SOFT, //!< soft failure. authentication went through partially
|
||||
STATE_FAILED_HARD, //!< hard failure. main tokens are invalid
|
||||
STATE_FAILED_GONE, //!< hard failure. main tokens are invalid, and the account no longer exists
|
||||
|
@ -44,7 +44,7 @@ void AuthRequest::onRequestFinished() {
|
||||
if (reply_ != qobject_cast<QNetworkReply *>(sender())) {
|
||||
return;
|
||||
}
|
||||
httpStatus_ = 200;
|
||||
httpStatus_ = reply_->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||
finish();
|
||||
}
|
||||
|
||||
|
@ -1,18 +1,38 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* 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.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Authors: Orochimarufan <orochimarufan.x3@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MinecraftAccount.h"
|
||||
@ -30,6 +50,7 @@
|
||||
|
||||
#include "flows/MSA.h"
|
||||
#include "flows/Mojang.h"
|
||||
#include "flows/Offline.h"
|
||||
|
||||
MinecraftAccount::MinecraftAccount(QObject* parent) : QObject(parent) {
|
||||
data.internalId = QUuid::createUuid().toString().remove(QRegExp("[{}-]"));
|
||||
@ -68,6 +89,23 @@ MinecraftAccountPtr MinecraftAccount::createBlankMSA()
|
||||
return account;
|
||||
}
|
||||
|
||||
MinecraftAccountPtr MinecraftAccount::createOffline(const QString &username)
|
||||
{
|
||||
MinecraftAccountPtr account = new MinecraftAccount();
|
||||
account->data.type = AccountType::Offline;
|
||||
account->data.yggdrasilToken.token = "offline";
|
||||
account->data.yggdrasilToken.validity = Katabasis::Validity::Certain;
|
||||
account->data.yggdrasilToken.issueInstant = QDateTime::currentDateTimeUtc();
|
||||
account->data.yggdrasilToken.extra["userName"] = username;
|
||||
account->data.yggdrasilToken.extra["clientToken"] = QUuid::createUuid().toString().remove(QRegExp("[{}-]"));
|
||||
account->data.minecraftEntitlement.ownsMinecraft = true;
|
||||
account->data.minecraftEntitlement.canPlayMinecraft = true;
|
||||
account->data.minecraftProfile.id = QUuid::createUuid().toString().remove(QRegExp("[{}-]"));
|
||||
account->data.minecraftProfile.name = username;
|
||||
account->data.minecraftProfile.validity = Katabasis::Validity::Certain;
|
||||
return account;
|
||||
}
|
||||
|
||||
|
||||
QJsonObject MinecraftAccount::saveToJson() const
|
||||
{
|
||||
@ -111,6 +149,16 @@ shared_qobject_ptr<AccountTask> MinecraftAccount::loginMSA() {
|
||||
return m_currentTask;
|
||||
}
|
||||
|
||||
shared_qobject_ptr<AccountTask> MinecraftAccount::loginOffline() {
|
||||
Q_ASSERT(m_currentTask.get() == nullptr);
|
||||
|
||||
m_currentTask.reset(new OfflineLogin(&data));
|
||||
connect(m_currentTask.get(), SIGNAL(succeeded()), SLOT(authSucceeded()));
|
||||
connect(m_currentTask.get(), SIGNAL(failed(QString)), SLOT(authFailed(QString)));
|
||||
emit activityChanged(true);
|
||||
return m_currentTask;
|
||||
}
|
||||
|
||||
shared_qobject_ptr<AccountTask> MinecraftAccount::refresh() {
|
||||
if(m_currentTask) {
|
||||
return m_currentTask;
|
||||
@ -119,6 +167,9 @@ shared_qobject_ptr<AccountTask> MinecraftAccount::refresh() {
|
||||
if(data.type == AccountType::MSA) {
|
||||
m_currentTask.reset(new MSASilent(&data));
|
||||
}
|
||||
else if(data.type == AccountType::Offline) {
|
||||
m_currentTask.reset(new OfflineRefresh(&data));
|
||||
}
|
||||
else {
|
||||
m_currentTask.reset(new MojangRefresh(&data));
|
||||
}
|
||||
@ -145,6 +196,9 @@ void MinecraftAccount::authFailed(QString reason)
|
||||
{
|
||||
switch (m_currentTask->taskState()) {
|
||||
case AccountTaskState::STATE_OFFLINE:
|
||||
case AccountTaskState::STATE_DISABLED: {
|
||||
// NOTE: user will need to fix this themselves.
|
||||
}
|
||||
case AccountTaskState::STATE_FAILED_SOFT: {
|
||||
// NOTE: this doesn't do much. There was an error of some sort.
|
||||
}
|
||||
|
@ -1,16 +1,36 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* 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.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
@ -41,7 +61,7 @@ Q_DECLARE_METATYPE(MinecraftAccountPtr)
|
||||
* A profile within someone's Mojang account.
|
||||
*
|
||||
* Currently, the profile system has not been implemented by Mojang yet,
|
||||
* but we might as well add some things for it in MultiMC right now so
|
||||
* but we might as well add some things for it in PolyMC right now so
|
||||
* we don't have to rip the code to pieces to add it later.
|
||||
*/
|
||||
struct AccountProfile
|
||||
@ -73,6 +93,8 @@ public: /* construction */
|
||||
|
||||
static MinecraftAccountPtr createBlankMSA();
|
||||
|
||||
static MinecraftAccountPtr createOffline(const QString &username);
|
||||
|
||||
static MinecraftAccountPtr loadFromJsonV2(const QJsonObject &json);
|
||||
static MinecraftAccountPtr loadFromJsonV3(const QJsonObject &json);
|
||||
|
||||
@ -89,6 +111,8 @@ public: /* manipulation */
|
||||
|
||||
shared_qobject_ptr<AccountTask> loginMSA();
|
||||
|
||||
shared_qobject_ptr<AccountTask> loginOffline();
|
||||
|
||||
shared_qobject_ptr<AccountTask> refresh();
|
||||
|
||||
shared_qobject_ptr<AccountTask> currentTask();
|
||||
@ -128,6 +152,10 @@ public: /* queries */
|
||||
return data.type == AccountType::MSA;
|
||||
}
|
||||
|
||||
bool isOffline() const {
|
||||
return data.type == AccountType::Offline;
|
||||
}
|
||||
|
||||
bool ownsMinecraft() const {
|
||||
return data.minecraftEntitlement.ownsMinecraft;
|
||||
}
|
||||
@ -149,6 +177,10 @@ public: /* queries */
|
||||
return "msa";
|
||||
}
|
||||
break;
|
||||
case AccountType::Offline: {
|
||||
return "offline";
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
return "unknown";
|
||||
}
|
||||
@ -198,3 +230,4 @@ slots:
|
||||
void authSucceeded();
|
||||
void authFailed(QString reason);
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "Parsers.h"
|
||||
#include "Json.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonArray>
|
||||
@ -94,7 +95,7 @@ bool parseXTokenResponse(QByteArray & data, Katabasis::Token &output, QString na
|
||||
return false;
|
||||
}
|
||||
if(!getString(obj.value("Token"), output.token)) {
|
||||
qWarning() << "User Token is not a timestamp";
|
||||
qWarning() << "User Token is not a string";
|
||||
return false;
|
||||
}
|
||||
auto arrayVal = obj.value("DisplayClaims").toObject().value("xui");
|
||||
@ -212,6 +213,180 @@ bool parseMinecraftProfile(QByteArray & data, MinecraftProfile &output) {
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
// these skin URLs are for the MHF_Steve and MHF_Alex accounts (made by a Mojang employee)
|
||||
// they are needed because the session server doesn't return skin urls for default skins
|
||||
static const QString SKIN_URL_STEVE = "http://textures.minecraft.net/texture/1a4af718455d4aab528e7a61f86fa25e6a369d1768dcb13f7df319a713eb810b";
|
||||
static const QString SKIN_URL_ALEX = "http://textures.minecraft.net/texture/83cee5ca6afcdb171285aa00e8049c297b2dbeba0efb8ff970a5677a1b644032";
|
||||
|
||||
bool isDefaultModelSteve(QString uuid) {
|
||||
// need to calculate *Java* hashCode of UUID
|
||||
// if number is even, skin/model is steve, otherwise it is alex
|
||||
|
||||
// just in case dashes are in the id
|
||||
uuid.remove('-');
|
||||
|
||||
if (uuid.size() != 32) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// qulonglong is guaranteed to be 64 bits
|
||||
// we need to use unsigned numbers to guarantee truncation below
|
||||
qulonglong most = uuid.left(16).toULongLong(nullptr, 16);
|
||||
qulonglong least = uuid.right(16).toULongLong(nullptr, 16);
|
||||
qulonglong xored = most ^ least;
|
||||
return ((static_cast<quint32>(xored >> 32)) ^ static_cast<quint32>(xored)) % 2 == 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Uses session server for skin/cape lookup instead of profile,
|
||||
because locked Mojang accounts cannot access profile endpoint
|
||||
(https://api.minecraftservices.com/minecraft/profile/)
|
||||
|
||||
ref: https://wiki.vg/Mojang_API#UUID_to_Profile_and_Skin.2FCape
|
||||
|
||||
{
|
||||
"id": "<profile identifier>",
|
||||
"name": "<player name>",
|
||||
"properties": [
|
||||
{
|
||||
"name": "textures",
|
||||
"value": "<base64 string>"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
decoded base64 "value":
|
||||
{
|
||||
"timestamp": <java time in ms>,
|
||||
"profileId": "<profile uuid>",
|
||||
"profileName": "<player name>",
|
||||
"textures": {
|
||||
"SKIN": {
|
||||
"url": "<player skin URL>"
|
||||
},
|
||||
"CAPE": {
|
||||
"url": "<player cape URL>"
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
bool parseMinecraftProfileMojang(QByteArray & data, MinecraftProfile &output) {
|
||||
qDebug() << "Parsing Minecraft profile...";
|
||||
#ifndef NDEBUG
|
||||
qDebug() << data;
|
||||
#endif
|
||||
|
||||
QJsonParseError jsonError;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(data, &jsonError);
|
||||
if(jsonError.error) {
|
||||
qWarning() << "Failed to parse response as JSON: " << jsonError.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
auto obj = Json::requireObject(doc, "mojang minecraft profile");
|
||||
if(!getString(obj.value("id"), output.id)) {
|
||||
qWarning() << "Minecraft profile id is not a string";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!getString(obj.value("name"), output.name)) {
|
||||
qWarning() << "Minecraft profile name is not a string";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto propsArray = obj.value("properties").toArray();
|
||||
QByteArray texturePayload;
|
||||
for( auto p : propsArray) {
|
||||
auto pObj = p.toObject();
|
||||
auto name = pObj.value("name");
|
||||
if (!name.isString() || name.toString() != "textures") {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto value = pObj.value("value");
|
||||
if (value.isString()) {
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
|
||||
texturePayload = QByteArray::fromBase64(value.toString().toUtf8(), QByteArray::AbortOnBase64DecodingErrors);
|
||||
#else
|
||||
texturePayload = QByteArray::fromBase64(value.toString().toUtf8());
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!texturePayload.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (texturePayload.isNull()) {
|
||||
qWarning() << "No texture payload data";
|
||||
return false;
|
||||
}
|
||||
|
||||
doc = QJsonDocument::fromJson(texturePayload, &jsonError);
|
||||
if(jsonError.error) {
|
||||
qWarning() << "Failed to parse response as JSON: " << jsonError.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
obj = Json::requireObject(doc, "session texture payload");
|
||||
auto textures = obj.value("textures");
|
||||
if (!textures.isObject()) {
|
||||
qWarning() << "No textures array in response";
|
||||
return false;
|
||||
}
|
||||
|
||||
Skin skinOut;
|
||||
// fill in default skin info ourselves, as this endpoint doesn't provide it
|
||||
bool steve = isDefaultModelSteve(output.id);
|
||||
skinOut.variant = steve ? "classic" : "slim";
|
||||
skinOut.url = steve ? SKIN_URL_STEVE : SKIN_URL_ALEX;
|
||||
// sadly we can't figure this out, but I don't think it really matters...
|
||||
skinOut.id = "00000000-0000-0000-0000-000000000000";
|
||||
Cape capeOut;
|
||||
auto tObj = textures.toObject();
|
||||
for (auto idx = tObj.constBegin(); idx != tObj.constEnd(); ++idx) {
|
||||
if (idx->isObject()) {
|
||||
if (idx.key() == "SKIN") {
|
||||
auto skin = idx->toObject();
|
||||
if (!getString(skin.value("url"), skinOut.url)) {
|
||||
qWarning() << "Skin url is not a string";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto maybeMeta = skin.find("metadata");
|
||||
if (maybeMeta != skin.end() && maybeMeta->isObject()) {
|
||||
auto meta = maybeMeta->toObject();
|
||||
// might not be present
|
||||
getString(meta.value("model"), skinOut.variant);
|
||||
}
|
||||
}
|
||||
else if (idx.key() == "CAPE") {
|
||||
auto cape = idx->toObject();
|
||||
if (!getString(cape.value("url"), capeOut.url)) {
|
||||
qWarning() << "Cape url is not a string";
|
||||
return false;
|
||||
}
|
||||
|
||||
// we don't know the cape ID as it is not returned from the session server
|
||||
// so just fake it - changing capes is probably locked anyway :(
|
||||
capeOut.alias = "cape";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output.skin = skinOut;
|
||||
if (capeOut.alias == "cape") {
|
||||
output.capes = QMap<QString, Cape>({{capeOut.alias, capeOut}});
|
||||
output.currentCape = capeOut.alias;
|
||||
}
|
||||
|
||||
output.validity = Katabasis::Validity::Certain;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parseMinecraftEntitlements(QByteArray & data, MinecraftEntitlement &output) {
|
||||
qDebug() << "Parsing Minecraft entitlements...";
|
||||
#ifndef NDEBUG
|
||||
|
@ -14,6 +14,7 @@ namespace Parsers
|
||||
bool parseMojangResponse(QByteArray &data, Katabasis::Token &output);
|
||||
|
||||
bool parseMinecraftProfile(QByteArray &data, MinecraftProfile &output);
|
||||
bool parseMinecraftProfileMojang(QByteArray &data, MinecraftProfile &output);
|
||||
bool parseMinecraftEntitlements(QByteArray &data, MinecraftEntitlement &output);
|
||||
bool parseRolloutResponse(QByteArray &data, bool& result);
|
||||
}
|
||||
|
@ -209,6 +209,28 @@ void Yggdrasil::processResponse(QJsonObject responseData) {
|
||||
m_data->yggdrasilToken.validity = Katabasis::Validity::Certain;
|
||||
m_data->yggdrasilToken.issueInstant = QDateTime::currentDateTimeUtc();
|
||||
|
||||
// Get UUID here since we need it for later
|
||||
auto profile = responseData.value("selectedProfile");
|
||||
if (!profile.isObject()) {
|
||||
changeState(AccountTaskState::STATE_FAILED_HARD, tr("Authentication server didn't send a selected profile."));
|
||||
return;
|
||||
}
|
||||
|
||||
auto profileObj = profile.toObject();
|
||||
for (auto i = profileObj.constBegin(); i != profileObj.constEnd(); ++i) {
|
||||
if (i.key() == "name" && i.value().isString()) {
|
||||
m_data->minecraftProfile.name = i->toString();
|
||||
}
|
||||
else if (i.key() == "id" && i.value().isString()) {
|
||||
m_data->minecraftProfile.id = i->toString();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_data->minecraftProfile.id.isEmpty()) {
|
||||
changeState(AccountTaskState::STATE_FAILED_HARD, tr("Authentication server didn't send a UUID in selected profile."));
|
||||
return;
|
||||
}
|
||||
|
||||
// We've made it through the minefield of possible errors. Return true to indicate that
|
||||
// we've succeeded.
|
||||
qDebug() << "Finished reading authentication response.";
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "Mojang.h"
|
||||
|
||||
#include "minecraft/auth/steps/YggdrasilStep.h"
|
||||
#include "minecraft/auth/steps/MinecraftProfileStep.h"
|
||||
#include "minecraft/auth/steps/MinecraftProfileStepMojang.h"
|
||||
#include "minecraft/auth/steps/MigrationEligibilityStep.h"
|
||||
#include "minecraft/auth/steps/GetSkinStep.h"
|
||||
|
||||
@ -10,7 +10,7 @@ MojangRefresh::MojangRefresh(
|
||||
QObject *parent
|
||||
) : AuthFlow(data, parent) {
|
||||
m_steps.append(new YggdrasilStep(m_data, QString()));
|
||||
m_steps.append(new MinecraftProfileStep(m_data));
|
||||
m_steps.append(new MinecraftProfileStepMojang(m_data));
|
||||
m_steps.append(new MigrationEligibilityStep(m_data));
|
||||
m_steps.append(new GetSkinStep(m_data));
|
||||
}
|
||||
@ -21,7 +21,7 @@ MojangLogin::MojangLogin(
|
||||
QObject *parent
|
||||
): AuthFlow(data, parent), m_password(password) {
|
||||
m_steps.append(new YggdrasilStep(m_data, m_password));
|
||||
m_steps.append(new MinecraftProfileStep(m_data));
|
||||
m_steps.append(new MinecraftProfileStepMojang(m_data));
|
||||
m_steps.append(new MigrationEligibilityStep(m_data));
|
||||
m_steps.append(new GetSkinStep(m_data));
|
||||
}
|
||||
|
17
launcher/minecraft/auth/flows/Offline.cpp
Normal file
17
launcher/minecraft/auth/flows/Offline.cpp
Normal file
@ -0,0 +1,17 @@
|
||||
#include "Offline.h"
|
||||
|
||||
#include "minecraft/auth/steps/OfflineStep.h"
|
||||
|
||||
OfflineRefresh::OfflineRefresh(
|
||||
AccountData *data,
|
||||
QObject *parent
|
||||
) : AuthFlow(data, parent) {
|
||||
m_steps.append(new OfflineStep(m_data));
|
||||
}
|
||||
|
||||
OfflineLogin::OfflineLogin(
|
||||
AccountData *data,
|
||||
QObject *parent
|
||||
) : AuthFlow(data, parent) {
|
||||
m_steps.append(new OfflineStep(m_data));
|
||||
}
|
22
launcher/minecraft/auth/flows/Offline.h
Normal file
22
launcher/minecraft/auth/flows/Offline.h
Normal file
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
#include "AuthFlow.h"
|
||||
|
||||
class OfflineRefresh : public AuthFlow
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit OfflineRefresh(
|
||||
AccountData *data,
|
||||
QObject *parent = 0
|
||||
);
|
||||
};
|
||||
|
||||
class OfflineLogin : public AuthFlow
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit OfflineLogin(
|
||||
AccountData *data,
|
||||
QObject *parent = 0
|
||||
);
|
||||
};
|
@ -50,7 +50,9 @@ void LauncherLoginStep::onRequestDone(
|
||||
auto requestor = qobject_cast<AuthRequest *>(QObject::sender());
|
||||
requestor->deleteLater();
|
||||
|
||||
#ifndef NDEBUG
|
||||
qDebug() << data;
|
||||
#endif
|
||||
if (error != QNetworkReply::NoError) {
|
||||
qWarning() << "Reply error:" << error;
|
||||
#ifndef NDEBUG
|
||||
|
@ -1,3 +1,38 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "MSAStep.h"
|
||||
|
||||
#include <QNetworkRequest>
|
||||
@ -12,9 +47,10 @@ using OAuth2 = Katabasis::DeviceFlow;
|
||||
using Activity = Katabasis::Activity;
|
||||
|
||||
MSAStep::MSAStep(AccountData* data, Action action) : AuthStep(data), m_action(action) {
|
||||
m_clientId = APPLICATION->getMSAClientID();
|
||||
OAuth2::Options opts;
|
||||
opts.scope = "XboxLive.signin offline_access";
|
||||
opts.clientIdentifier = BuildConfig.MSA_CLIENT_ID;
|
||||
opts.clientIdentifier = m_clientId;
|
||||
opts.authorizationUrl = "https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode";
|
||||
opts.accessTokenUrl = "https://login.microsoftonline.com/consumers/oauth2/v2.0/token";
|
||||
|
||||
@ -48,6 +84,10 @@ void MSAStep::rehydrate() {
|
||||
void MSAStep::perform() {
|
||||
switch(m_action) {
|
||||
case Refresh: {
|
||||
if (m_data->msaClientID != m_clientId) {
|
||||
emit hideVerificationUriAndCode();
|
||||
emit finished(AccountTaskState::STATE_DISABLED, tr("Microsoft user authentication failed - client identification has changed."));
|
||||
}
|
||||
m_oauth2->refresh();
|
||||
return;
|
||||
}
|
||||
@ -57,6 +97,7 @@ void MSAStep::perform() {
|
||||
m_oauth2->setExtraRequestParams(extraOpts);
|
||||
|
||||
*m_data = AccountData();
|
||||
m_data->msaClientID = m_clientId;
|
||||
m_oauth2->login();
|
||||
return;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user