Compare commits
593 Commits
continuous
...
continuous
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a656469f12 | ||
|
|
4f45df2293 | ||
|
|
af0d77caf7 | ||
|
|
3a6862f278 | ||
|
|
2ad482ee2f | ||
|
|
be0d31f408 | ||
|
|
7c8e2a598f | ||
|
|
820a001ced | ||
|
|
a5b68c5ed9 | ||
|
|
f37738f6f8 | ||
|
|
4cc009ac3e | ||
|
|
5100125fef | ||
|
|
1c0d145874 | ||
|
|
0e48f57247 | ||
|
|
f9ec8f0b85 | ||
|
|
a4614a00e9 | ||
|
|
0ba45d343e | ||
|
|
2c26601bee | ||
|
|
10ada3c141 | ||
|
|
4912e84d46 | ||
|
|
81c7ef20eb | ||
|
|
ac22de84bf | ||
|
|
70f6480a5f | ||
|
|
95bfb7cdf2 | ||
|
|
b22186b2f1 | ||
|
|
70e53f547b | ||
|
|
8047f8177b | ||
|
|
95bf2f03ad | ||
|
|
ca6de641a1 | ||
|
|
bb811310d2 | ||
|
|
cd881c079b | ||
|
|
2319d4caf9 | ||
|
|
ac412fc15e | ||
|
|
4f7a216191 | ||
|
|
d87cdd7ff8 | ||
|
|
2c53cc7e70 | ||
|
|
b7bb81fbe7 | ||
|
|
a767540a2b | ||
|
|
f1251e8767 | ||
|
|
c1c0c2761d | ||
|
|
c69a87fa89 | ||
|
|
bf7f952d0e | ||
|
|
6aecc45ce1 | ||
|
|
bfc10a732a | ||
|
|
67d1536127 | ||
|
|
56db9f73d8 | ||
|
|
250d425b34 | ||
|
|
99140fc7df | ||
|
|
2557d5acaa | ||
|
|
b14a1b664f | ||
|
|
56361b52e7 | ||
|
|
da1b9ad80d | ||
|
|
aec1213319 | ||
|
|
cb4540a877 | ||
|
|
613768c3f9 | ||
|
|
234a16d611 | ||
|
|
e468371394 | ||
|
|
671157ee20 | ||
|
|
4398de1dab | ||
|
|
dc09cf0c39 | ||
|
|
f4854dbcde | ||
|
|
25e206f5ae | ||
|
|
b3d3a15c3d | ||
|
|
92faa25670 | ||
|
|
3eed2769d5 | ||
|
|
6302553ee4 | ||
|
|
ae2808dff7 | ||
|
|
af69df15e1 | ||
|
|
98e4aae6bb | ||
|
|
3e921c829f | ||
|
|
e994cc0c8b | ||
|
|
cd26b1f279 | ||
|
|
24f05e3fc5 | ||
|
|
2bdeb05153 | ||
|
|
de4b635b19 | ||
|
|
ab744a8baf | ||
|
|
0aca03d343 | ||
|
|
eeca965b5d | ||
|
|
eb27dc639e | ||
|
|
af5c6d1196 | ||
|
|
0cce014c01 | ||
|
|
6111df486e | ||
|
|
7dc88f9417 | ||
|
|
e36486b73a | ||
|
|
000304ddde | ||
|
|
4c9b69af5f | ||
|
|
599b1b48ec | ||
|
|
4e23012950 | ||
|
|
6e69e1d67b | ||
|
|
7564e3c61f | ||
|
|
0543b861ca | ||
|
|
0d403a7117 | ||
|
|
928ce9d754 | ||
|
|
6cc3bed60a | ||
|
|
40dfd2e711 | ||
|
|
c554eef3b9 | ||
|
|
dc0648e812 | ||
|
|
3d762802ab | ||
|
|
21b0516724 | ||
|
|
cca1732245 | ||
|
|
fddf0200db | ||
|
|
6bb7bcd378 | ||
|
|
f37bbec78e | ||
|
|
50a8f23b43 | ||
|
|
f9fc26239b | ||
|
|
9f797ef705 | ||
|
|
a7671a8ac1 | ||
|
|
c807faf5b9 | ||
|
|
45dd15b064 | ||
|
|
7e50026100 | ||
|
|
05a258a5b4 | ||
|
|
902fa52cbd | ||
|
|
cc528d407d | ||
|
|
2267b2e4e6 | ||
|
|
7f5e62d03a | ||
|
|
e3bfdf4127 | ||
|
|
bf186b8178 | ||
|
|
907e02da8d | ||
|
|
2234f91c38 | ||
|
|
582fe9a2fc | ||
|
|
fa92a5fa0c | ||
|
|
342aa56144 | ||
|
|
e9440a8612 | ||
|
|
3e396bb55a | ||
|
|
72b8182af0 | ||
|
|
6022865cae | ||
|
|
1559b1b331 | ||
|
|
5db150e565 | ||
|
|
e823ba050a | ||
|
|
6f545f178e | ||
|
|
b598daf049 | ||
|
|
3f5ca210a0 | ||
|
|
f1e665b5b3 | ||
|
|
eb84efd260 | ||
|
|
90884a2d09 | ||
|
|
69e38c963d | ||
|
|
d7f4b21db7 | ||
|
|
6aa281bc59 | ||
|
|
e22dadc36f | ||
|
|
1bf5909023 | ||
|
|
ba71f114d9 | ||
|
|
c90d110096 | ||
|
|
05edde050d | ||
|
|
1c29490889 | ||
|
|
210f51d38c | ||
|
|
2e748c4aea | ||
|
|
375ff6296b | ||
|
|
026435865a | ||
|
|
216e680965 | ||
|
|
3fe77ec86c | ||
|
|
a88fea6ab3 | ||
|
|
78ef00a269 | ||
|
|
f9a9aedea5 | ||
|
|
53e59c2e73 | ||
|
|
fc3b8ae45d | ||
|
|
911b83a9d8 | ||
|
|
5276e46dc0 | ||
|
|
9fbd47bb4c | ||
|
|
b8ead38573 | ||
|
|
6a318d5000 | ||
|
|
71040c7ed5 | ||
|
|
c3531b6499 | ||
|
|
9c6f12f31c | ||
|
|
913d0eb693 | ||
|
|
7bff848592 | ||
|
|
72485da491 | ||
|
|
694472f4c1 | ||
|
|
735f4e2bcb | ||
|
|
9ebeb520fa | ||
|
|
dd52840a97 | ||
|
|
4ce03662d9 | ||
|
|
20320d8dfa | ||
|
|
f2ecdad5bb | ||
|
|
298842be32 | ||
|
|
15544cde26 | ||
|
|
a4ad537e59 | ||
|
|
7ba48e00bc | ||
|
|
bb620d1265 | ||
|
|
32e6f37c7e | ||
|
|
8f95535390 | ||
|
|
b2444f2480 | ||
|
|
37d6d75e69 | ||
|
|
97bdd9dba0 | ||
|
|
ffc8bf30d7 | ||
|
|
8209a8a681 | ||
|
|
34beb9666b | ||
|
|
6ccafbe297 | ||
|
|
a479099804 | ||
|
|
94791d3cb6 | ||
|
|
6555562e78 | ||
|
|
de790d6f59 | ||
|
|
cff0df60a9 | ||
|
|
c8b8e19ed3 | ||
|
|
2106556dec | ||
|
|
7221bd6049 | ||
|
|
ded38020d3 | ||
|
|
c6251174df | ||
|
|
177c132969 | ||
|
|
3fca1bb4d5 | ||
|
|
321e28c810 | ||
|
|
7fda58561f | ||
|
|
0cbb62b329 | ||
|
|
aa2e5eb3cc | ||
|
|
3d26ba1ed8 | ||
|
|
47c4844024 | ||
|
|
d457d7d093 | ||
|
|
43364ec2e9 | ||
|
|
14127c26f5 | ||
|
|
291f24a611 | ||
|
|
1abb16638f | ||
|
|
3e41e389c5 | ||
|
|
5aca143eba | ||
|
|
60fa855d47 | ||
|
|
22661fd446 | ||
|
|
61d8d5e12b | ||
|
|
a7f3c04baa | ||
|
|
296e642f09 | ||
|
|
75eb1f1e8b | ||
|
|
8f4a45baaa | ||
|
|
18aac5fd3d | ||
|
|
ca6ca8450b | ||
|
|
6ecaea3102 | ||
|
|
fa47ca0d2d | ||
|
|
8ce3b4ac93 | ||
|
|
a7ba705277 | ||
|
|
85a4d296f5 | ||
|
|
4dd8d89459 | ||
|
|
c564cc96c7 | ||
|
|
0e54200f34 | ||
|
|
fa75c33390 | ||
|
|
36cb3b2d89 | ||
|
|
2f3b03d27a | ||
|
|
f0deac206b | ||
|
|
5d0e473cf1 | ||
|
|
2174fe6d21 | ||
|
|
5d1e207337 | ||
|
|
87c209f1f9 | ||
|
|
ed5ea002d7 | ||
|
|
149593fea5 | ||
|
|
8c0f1d65ba | ||
|
|
bbf6f1c7b8 | ||
|
|
3b61e0bbd6 | ||
|
|
8d2986bc74 | ||
|
|
27a8adad22 | ||
|
|
64e774377b | ||
|
|
8ff469d466 | ||
|
|
a20e961892 | ||
|
|
8ba30a1c09 | ||
|
|
d570d6d6da | ||
|
|
882b573e70 | ||
|
|
54657c149b | ||
|
|
9054b11ebd | ||
|
|
71d31330f9 | ||
|
|
ea29699633 | ||
|
|
ccb8d611c6 | ||
|
|
f4d98c056e | ||
|
|
779adcd838 | ||
|
|
16e2ce0aeb | ||
|
|
7bfcd4cef0 | ||
|
|
c298635728 | ||
|
|
92e976952e | ||
|
|
a85bd0c864 | ||
|
|
0a5f175431 | ||
|
|
da6402ccc2 | ||
|
|
9d1b03d119 | ||
|
|
6cf0d7a871 | ||
|
|
d5a6a7ae60 | ||
|
|
185374f99f | ||
|
|
b9072e4642 | ||
|
|
06e5895d7a | ||
|
|
ac5be8156b | ||
|
|
8c12a8baed | ||
|
|
e615ff0e7f | ||
|
|
2e8fa60e96 | ||
|
|
a8ba9124dd | ||
|
|
f6e8a68b22 | ||
|
|
706cc16a86 | ||
|
|
a9fd508e47 | ||
|
|
90bd72d481 | ||
|
|
a2a3978de7 | ||
|
|
ea70989fd2 | ||
|
|
091228bcb3 | ||
|
|
9c49253388 | ||
|
|
eea804a4bf | ||
|
|
ecbfdb82f4 | ||
|
|
a1950ec7b0 | ||
|
|
6b56e13b60 | ||
|
|
d93bee0cbc | ||
|
|
5009db6aac | ||
|
|
c389736c2f | ||
|
|
66bdca63ee | ||
|
|
d3f455649e | ||
|
|
17ff80d85d | ||
|
|
407d0aa291 | ||
|
|
d13429a287 | ||
|
|
a84204fc75 | ||
|
|
292ace2d26 | ||
|
|
68a1fbdc2b | ||
|
|
d68f29737a | ||
|
|
a34edbd8e8 | ||
|
|
71e2d4ecd4 | ||
|
|
25656b532a | ||
|
|
1a791e8556 | ||
|
|
ccd31c6b27 | ||
|
|
6aeedf201c | ||
|
|
c9f8bdfcb0 | ||
|
|
3cf4901ad2 | ||
|
|
92de3ebc58 | ||
|
|
7aa9f23590 | ||
|
|
3d999269eb | ||
|
|
1e8e4825fa | ||
|
|
91bc372811 | ||
|
|
f9df96d70e | ||
|
|
8af0e2c8b4 | ||
|
|
a5191d8948 | ||
|
|
b2d8239829 | ||
|
|
34322f025b | ||
|
|
3e6b434733 | ||
|
|
8359cbe76c | ||
|
|
0e90e6285e | ||
|
|
2f5840f650 | ||
|
|
3b51a554dd | ||
|
|
5f0880d4a2 | ||
|
|
884a3c66ac | ||
|
|
c76752cc5f | ||
|
|
fc2888e107 | ||
|
|
674b4c1506 | ||
|
|
cddd50f1e9 | ||
|
|
6c9d5bc1fb | ||
|
|
ec23860238 | ||
|
|
14a2e34b7e | ||
|
|
29c8818557 | ||
|
|
7222830b28 | ||
|
|
9b0ad7daf0 | ||
|
|
73729827f4 | ||
|
|
97fa395a3b | ||
|
|
1cef8ea7af | ||
|
|
eda4e95607 | ||
|
|
a5f0ca38f1 | ||
|
|
bbbd7711c1 | ||
|
|
38e922557d | ||
|
|
4dec1785ed | ||
|
|
9f77b7dc46 | ||
|
|
5061a29f86 | ||
|
|
cb5dffd554 | ||
|
|
4eaa8ab40f | ||
|
|
2a82d265d6 | ||
|
|
f2392b5709 | ||
|
|
5620e7ab4c | ||
|
|
a76236ac5a | ||
|
|
d1c5862bab | ||
|
|
81400d0b01 | ||
|
|
a129f13e25 | ||
|
|
ec8b4c0a84 | ||
|
|
f1f726822c | ||
|
|
8982d55392 | ||
|
|
f499286a87 | ||
|
|
a3aaa87147 | ||
|
|
15a6971aca | ||
|
|
b1eb3390e3 | ||
|
|
74ad504377 | ||
|
|
8a0c2577ed | ||
|
|
a060d7aefd | ||
|
|
ccf342f4fe | ||
|
|
8b9a40ff1f | ||
|
|
425cc61c4c | ||
|
|
fe1fd5b024 | ||
|
|
0c8da36a0b | ||
|
|
2c5030ab45 | ||
|
|
9decba873b | ||
|
|
bda4c45504 | ||
|
|
f7aa8a0c90 | ||
|
|
4c15cceb32 | ||
|
|
3e4c5beb25 | ||
|
|
f84d865f4a | ||
|
|
2465782a3e | ||
|
|
7ba2209124 | ||
|
|
af6b434b71 | ||
|
|
052ea6a8bd | ||
|
|
448dc720ed | ||
|
|
75b15696f8 | ||
|
|
7fb113f610 | ||
|
|
0497e00ad2 | ||
|
|
9c50288bbb | ||
|
|
c5d4af802c | ||
|
|
340a8b5e0c | ||
|
|
bc1b86c19c | ||
|
|
b605cf603e | ||
|
|
fdc2ed8093 | ||
|
|
a27375d1f5 | ||
|
|
0e2abf9040 | ||
|
|
89430400d9 | ||
|
|
f1a9d408bf | ||
|
|
6529692244 | ||
|
|
51d11f8e86 | ||
|
|
c5397191e5 | ||
|
|
44426709f7 | ||
|
|
2d8f747e84 | ||
|
|
0dd5a60410 | ||
|
|
eec8129be4 | ||
|
|
934c5e018d | ||
|
|
d658d8cc78 | ||
|
|
ca9a3f0491 | ||
|
|
1510cb458f | ||
|
|
30cabb8107 | ||
|
|
64ee956618 | ||
|
|
39659644bf | ||
|
|
eb09af0b08 | ||
|
|
91a4ace12c | ||
|
|
2ad2e46b30 | ||
|
|
627444279f | ||
|
|
3550bdb30d | ||
|
|
c201b895eb | ||
|
|
72f1ac3780 | ||
|
|
d7dc3192de | ||
|
|
43ea65fffc | ||
|
|
a72d921c12 | ||
|
|
99b7d71824 | ||
|
|
67c73bdcbe | ||
|
|
8b1dbcf166 | ||
|
|
5f60095dc4 | ||
|
|
c7282b488b | ||
|
|
afa829d996 | ||
|
|
c06ea8d915 | ||
|
|
bf344282ec | ||
|
|
21f62910ac | ||
|
|
54552d93ef | ||
|
|
97455e7fd4 | ||
|
|
6087d43043 | ||
|
|
c1a96d3ff1 | ||
|
|
e27d20dfa3 | ||
|
|
890e12ec76 | ||
|
|
774d2ac28a | ||
|
|
960d724828 | ||
|
|
32aa1f91bf | ||
|
|
bd3634c815 | ||
|
|
eda0ac92cc | ||
|
|
546903ea05 | ||
|
|
4975001795 | ||
|
|
a078ad1f51 | ||
|
|
8307f671d4 | ||
|
|
241fab02b1 | ||
|
|
1bfee70477 | ||
|
|
eb51d17cd2 | ||
|
|
b5cb0b9f10 | ||
|
|
a955d1e957 | ||
|
|
2b2c967e85 | ||
|
|
c48d93e3ce | ||
|
|
8f257cc331 | ||
|
|
151e7fe37b | ||
|
|
add02dc6f9 | ||
|
|
d4c34abd6e | ||
|
|
1d81e611f0 | ||
|
|
6a0038e26a | ||
|
|
1d99f65e86 | ||
|
|
5e524bca60 | ||
|
|
cf3e56e275 | ||
|
|
ade560c601 | ||
|
|
62e3ba2126 | ||
|
|
674a4e5883 | ||
|
|
f911210b81 | ||
|
|
14eb07653c | ||
|
|
54b0cf9991 | ||
|
|
3ebcb08a97 | ||
|
|
23940f8590 | ||
|
|
687fb0123f | ||
|
|
6c91fdb0cd | ||
|
|
4832232fd6 | ||
|
|
185bce0489 | ||
|
|
f460aa63b0 | ||
|
|
22f8b6f9c3 | ||
|
|
0cb034afc2 | ||
|
|
d0464ef602 | ||
|
|
c3ebb84b97 | ||
|
|
11742efbc3 | ||
|
|
95af635ab4 | ||
|
|
1abec80191 | ||
|
|
93ebddfba3 | ||
|
|
5378494199 | ||
|
|
1b44d7733e | ||
|
|
694c630b44 | ||
|
|
7df1d4b9e2 | ||
|
|
b16037eabf | ||
|
|
bff7299f9b | ||
|
|
de196b1c58 | ||
|
|
a0eec8b85d | ||
|
|
c7e8ea2ffa | ||
|
|
1c1cf3d646 | ||
|
|
9759b80b78 | ||
|
|
94b2c0b443 | ||
|
|
ff8d17a5a8 | ||
|
|
aa23196a55 | ||
|
|
83b488c37e | ||
|
|
77abf621d7 | ||
|
|
f9d4ac2771 | ||
|
|
f076d84975 | ||
|
|
faf0b32a94 | ||
|
|
feb80e5997 | ||
|
|
004af02e99 | ||
|
|
8ad56eb085 | ||
|
|
578a77518f | ||
|
|
2457ecf226 | ||
|
|
8cd99885f1 | ||
|
|
684e229ac8 | ||
|
|
c0f1d8c647 | ||
|
|
c3b8696957 | ||
|
|
3ca413dbab | ||
|
|
92dc04ff3c | ||
|
|
ad6db91285 | ||
|
|
90a0f74087 | ||
|
|
4f7f5288a1 | ||
|
|
c23b4bfe61 | ||
|
|
4780f70ea2 | ||
|
|
98a04c7764 | ||
|
|
7da9772143 | ||
|
|
32def35408 | ||
|
|
952ccb1247 | ||
|
|
6f0fb594e7 | ||
|
|
f0b29bac1b | ||
|
|
7b5ff606bd | ||
|
|
3e22ee64ae | ||
|
|
c86c45503f | ||
|
|
ef75a4c28d | ||
|
|
bccd3f2271 | ||
|
|
7bbc3e8238 | ||
|
|
c34e0c66d9 | ||
|
|
e5d80878b8 | ||
|
|
1e075d25b7 | ||
|
|
d29e53481d | ||
|
|
d23a2fd2df | ||
|
|
f6f15cc204 | ||
|
|
4f2249ed8e | ||
|
|
9f322df498 | ||
|
|
b554d7e215 | ||
|
|
719093c10b | ||
|
|
c2da140ccc | ||
|
|
375998dffb | ||
|
|
787444f63d | ||
|
|
0c50076ff0 | ||
|
|
8ce01c38c7 | ||
|
|
cac6206984 | ||
|
|
a5c88bdda9 | ||
|
|
fc017286a6 | ||
|
|
20d4e3e719 | ||
|
|
4eaa32fc10 | ||
|
|
b7c025b167 | ||
|
|
f29c588e0f | ||
|
|
2065ef143a | ||
|
|
a5c02c85f0 | ||
|
|
9a8761f1d8 | ||
|
|
273990d292 | ||
|
|
0e27d8717c | ||
|
|
8a9b209db0 | ||
|
|
232d1f8583 | ||
|
|
6cfa5877a4 | ||
|
|
154df00f94 | ||
|
|
c5649c94d5 | ||
|
|
a1da10fe38 | ||
|
|
17a71ffc96 | ||
|
|
4609fbc0c5 | ||
|
|
d278d3bdd7 | ||
|
|
7811b60292 | ||
|
|
870fad5606 | ||
|
|
3e93aa459d | ||
|
|
626c5e44f6 | ||
|
|
c906aa0106 | ||
|
|
0a41b70e44 | ||
|
|
ea338adc46 | ||
|
|
5fa777578b | ||
|
|
5b9db5940b | ||
|
|
4b1b3aa13c | ||
|
|
2d51d23d89 | ||
|
|
b5b6dad39c | ||
|
|
a5619e9960 | ||
|
|
a75666a3cd | ||
|
|
49426721d8 | ||
|
|
04125284a3 | ||
|
|
1d4f7b2f94 | ||
|
|
38c82a3f76 | ||
|
|
785632a437 | ||
|
|
4be75af214 | ||
|
|
dcdca01e86 | ||
|
|
8b4b0479c8 | ||
|
|
c8bf7e5630 | ||
|
|
4987080e1e | ||
|
|
1d78e400ff | ||
|
|
2d1a885954 | ||
|
|
43ba2e747b | ||
|
|
eefb823ee2 | ||
|
|
a3c33e0fa9 | ||
|
|
16fe6b1b1a | ||
|
|
4275829bd5 | ||
|
|
1884f0a3ce |
12
.cirrus.yml
@@ -1,14 +1,13 @@
|
|||||||
task:
|
task:
|
||||||
name: freebsd-14-amd64
|
name: freebsd-14-amd64
|
||||||
freebsd_instance:
|
freebsd_instance:
|
||||||
image_family: freebsd-14-0
|
image_family: freebsd-14-2
|
||||||
setup_script:
|
setup_script:
|
||||||
- pkg update
|
- pkg update
|
||||||
- pkg install -y pkgconf git sdl2 python fontconfig opus
|
- pkg install -y pkgconf git sdl2 python fontconfig libvorbis opusfile bzip2 libbacktrace
|
||||||
- git submodule update --init --recursive
|
- git submodule update --init --recursive
|
||||||
test_script:
|
test_script:
|
||||||
- ./scripts/cirrus/build_freebsd.sh dedicated
|
- ./scripts/cirrus/build_freebsd.sh
|
||||||
- ./scripts/cirrus/build_freebsd.sh full
|
|
||||||
|
|
||||||
task:
|
task:
|
||||||
name: freebsd-15-amd64
|
name: freebsd-15-amd64
|
||||||
@@ -16,8 +15,7 @@ task:
|
|||||||
image_family: freebsd-15-0-snap
|
image_family: freebsd-15-0-snap
|
||||||
setup_script:
|
setup_script:
|
||||||
- pkg update
|
- pkg update
|
||||||
- pkg install -y pkgconf git sdl2 python fontconfig opus
|
- pkg install -y pkgconf git sdl2 python fontconfig libvorbis opusfile bzip2 libbacktrace
|
||||||
- git submodule update --init --recursive
|
- git submodule update --init --recursive
|
||||||
test_script:
|
test_script:
|
||||||
- ./scripts/cirrus/build_freebsd.sh dedicated
|
- ./scripts/cirrus/build_freebsd.sh
|
||||||
- ./scripts/cirrus/build_freebsd.sh full
|
|
||||||
|
|||||||
61
.github/workflows/c-cpp.yml
vendored
@@ -6,21 +6,8 @@ jobs:
|
|||||||
# steps:
|
# steps:
|
||||||
# - name: Cleanup
|
# - name: Cleanup
|
||||||
# run: rm -rf .* || true
|
# run: rm -rf .* || true
|
||||||
get_prev_runid:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
value: ${{ steps.do.outputs.value }}
|
|
||||||
steps:
|
|
||||||
- id: do
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
run: |
|
|
||||||
value=$(gh run -R ${{ github.repository }} list -b${{ github.ref_name }} -ssuccess -L1 --json databaseId -q'.[0].databaseId')
|
|
||||||
echo "Last run ID is $value"
|
|
||||||
echo "value=$value" >> "$GITHUB_OUTPUT"
|
|
||||||
build:
|
build:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
needs: get_prev_runid
|
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
@@ -28,35 +15,39 @@ jobs:
|
|||||||
include:
|
include:
|
||||||
# Linux build specifically want oldest Ubuntu as possible
|
# Linux build specifically want oldest Ubuntu as possible
|
||||||
# to be crossdistribution compatible, otherwise use ubuntu-latest
|
# to be crossdistribution compatible, otherwise use ubuntu-latest
|
||||||
- os: ubuntu-20.04
|
- os: ubuntu-22.04
|
||||||
targetos: linux
|
targetos: linux
|
||||||
targetarch: amd64
|
targetarch: amd64
|
||||||
- os: ubuntu-20.04
|
- os: ubuntu-22.04
|
||||||
targetos: linux
|
targetos: linux
|
||||||
targetarch: i386
|
targetarch: i386
|
||||||
- os: ubuntu-20.04
|
- os: ubuntu-22.04
|
||||||
targetos: linux
|
targetos: linux
|
||||||
targetarch: arm64
|
targetarch: arm64
|
||||||
cross: true
|
cross: true
|
||||||
- os: ubuntu-20.04
|
- os: ubuntu-22.04
|
||||||
targetos: linux
|
targetos: linux
|
||||||
targetarch: armhf
|
targetarch: armhf
|
||||||
cross: true
|
cross: true
|
||||||
- os: ubuntu-20.04
|
- os: ubuntu-24.04 # riscv64 would benefit from having latest compilers
|
||||||
targetos: linux
|
targetos: linux
|
||||||
targetarch: riscv64
|
targetarch: riscv64
|
||||||
cross: true
|
cross: true
|
||||||
- os: ubuntu-20.04
|
- os: ubuntu-22.04
|
||||||
targetos: linux
|
targetos: linux
|
||||||
targetarch: ppc64el
|
targetarch: ppc64el
|
||||||
cross: true
|
cross: true
|
||||||
# - os: ubuntu-aarch64-20.04
|
# - os: ubuntu-aarch64-22.04
|
||||||
# targetos: linux
|
# targetos: linux
|
||||||
# targetarch: aarch64
|
# targetarch: aarch64
|
||||||
- os: ubuntu-20.04
|
# - os: ubuntu-latest
|
||||||
|
# targetos: linux
|
||||||
|
# targetarch: e2k-8c
|
||||||
|
# cross: true
|
||||||
|
- os: ubuntu-latest
|
||||||
targetos: android
|
targetos: android
|
||||||
targetarch: multiarch
|
targetarch: multiarch
|
||||||
# - os: ubuntu-20.04
|
# - os: ubuntu-22.04
|
||||||
# targetos: motomagx
|
# targetos: motomagx
|
||||||
# targetarch: armv6
|
# targetarch: armv6
|
||||||
|
|
||||||
@@ -69,7 +60,7 @@ jobs:
|
|||||||
- os: windows-latest
|
- os: windows-latest
|
||||||
targetos: win32
|
targetos: win32
|
||||||
targetarch: amd64
|
targetarch: amd64
|
||||||
- os: windows-2019 # always use the oldest possible for 32-bit because of older compilers, and better support of certain legacy OSes
|
- os: windows-2022 # always use the oldest possible for 32-bit because of older compilers, and better support of certain legacy OSes
|
||||||
targetos: win32
|
targetos: win32
|
||||||
targetarch: i386
|
targetarch: i386
|
||||||
- os: macos-14 # arm64 as per github documentation
|
- os: macos-14 # arm64 as per github documentation
|
||||||
@@ -79,22 +70,16 @@ jobs:
|
|||||||
targetos: apple
|
targetos: apple
|
||||||
targetarch: amd64
|
targetarch: amd64
|
||||||
env:
|
env:
|
||||||
SDL_VERSION: 2.30.11
|
SDL_VERSION: 2.32.8
|
||||||
|
FFMPEG_VERSION: 7.1
|
||||||
GH_CPU_ARCH: ${{ matrix.targetarch }}
|
GH_CPU_ARCH: ${{ matrix.targetarch }}
|
||||||
|
GH_CPU_OS: ${{ matrix.targetos }}
|
||||||
GH_CROSSCOMPILING: ${{ matrix.cross }}
|
GH_CROSSCOMPILING: ${{ matrix.cross }}
|
||||||
WAFCACHE: ${{ github.workspace }}/wafcache/
|
|
||||||
WAFCACHE_EVICT_MAX_BYTES: 1000000 # github only gives 10gb for the whole repository
|
|
||||||
WAFCACHE_STATS: 1 # enable statistics in build log
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
- name: Restore cache
|
|
||||||
uses: actions/cache/restore@v4
|
|
||||||
with:
|
|
||||||
key: ${{ runner.os }}-${{ matrix.targetos }}-${{ matrix.targetarch }}-${{ needs.get_prev_runid.outputs.value }}
|
|
||||||
path: ${{ github.workspace }}/wafcache/
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: bash scripts/gha/deps_${{ matrix.targetos }}.sh
|
run: bash scripts/gha/deps_${{ matrix.targetos }}.sh
|
||||||
- name: Build engine
|
- name: Build engine
|
||||||
@@ -106,20 +91,15 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: artifact-${{ matrix.targetos }}-${{ matrix.targetarch }}
|
name: artifact-${{ matrix.targetos }}-${{ matrix.targetarch }}
|
||||||
path: artifacts/*
|
path: artifacts/*
|
||||||
- name: Save cache
|
|
||||||
uses: actions/cache/save@v4
|
|
||||||
with:
|
|
||||||
path: ${{ github.workspace }}/wafcache/
|
|
||||||
key: ${{ runner.os }}-${{ matrix.targetos }}-${{ matrix.targetarch }}-${{ github.run_id }}
|
|
||||||
|
|
||||||
flatpak:
|
flatpak:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
continue-on-error: true
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- app: su.xash.Engine.Compat.i386
|
- app: su.xash.Engine.Compat.i386
|
||||||
container:
|
container:
|
||||||
image: bilelmoussaoui/flatpak-github-actions:freedesktop-24.08
|
image: ghcr.io/flathub-infra/flatpak-github-actions:freedesktop-24.08
|
||||||
options: --privileged
|
options: --privileged
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
@@ -127,7 +107,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
- name: Build flatpak (Compat.i386)
|
- name: Build flatpak (Compat.i386)
|
||||||
uses: FWGS/flatpak-github-actions/flatpak-builder@v6.3
|
uses: FWGS/flatpak-github-actions/flatpak-builder@v6.5
|
||||||
with:
|
with:
|
||||||
bundle: ${{ matrix.app }}.flatpak
|
bundle: ${{ matrix.app }}.flatpak
|
||||||
manifest-path: scripts/flatpak/${{ matrix.app }}.yml
|
manifest-path: scripts/flatpak/${{ matrix.app }}.yml
|
||||||
@@ -146,7 +126,6 @@ jobs:
|
|||||||
--yes \
|
--yes \
|
||||||
--cleanup-tag \
|
--cleanup-tag \
|
||||||
--repo "$GITHUB_REPOSITORY" || true
|
--repo "$GITHUB_REPOSITORY" || true
|
||||||
sleep 20s
|
|
||||||
gh run download "$GITHUB_RUN_ID" \
|
gh run download "$GITHUB_RUN_ID" \
|
||||||
--dir artifacts/ \
|
--dir artifacts/ \
|
||||||
--repo "$GITHUB_REPOSITORY"
|
--repo "$GITHUB_REPOSITORY"
|
||||||
|
|||||||
11
.gitignore
vendored
@@ -222,7 +222,7 @@ publish/
|
|||||||
# Publish Web Output
|
# Publish Web Output
|
||||||
*.[Pp]ublish.xml
|
*.[Pp]ublish.xml
|
||||||
*.azurePubxml
|
*.azurePubxml
|
||||||
# TODO: Comment the next line if you want to checkin your web deploy settings
|
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||||
# but database connection strings (with potential passwords) will be unencrypted
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
*.pubxml
|
*.pubxml
|
||||||
*.publishproj
|
*.publishproj
|
||||||
@@ -345,3 +345,12 @@ enc_temp_folder/
|
|||||||
|
|
||||||
# ccls langauge server
|
# ccls langauge server
|
||||||
.ccls-*
|
.ccls-*
|
||||||
|
|
||||||
|
# JetBrains
|
||||||
|
.idea/
|
||||||
|
cmake-build-*
|
||||||
|
|
||||||
|
# some Android-specific build stuff
|
||||||
|
3rdparty/SDL
|
||||||
|
3rdparty/hlsdk-portable
|
||||||
|
!scripts/build-ninja.py
|
||||||
|
|||||||
12
.gitmodules
vendored
@@ -27,10 +27,16 @@
|
|||||||
url = https://github.com/FWGS/MultiEmulator
|
url = https://github.com/FWGS/MultiEmulator
|
||||||
[submodule "3rdparty/libogg/libogg"]
|
[submodule "3rdparty/libogg/libogg"]
|
||||||
path = 3rdparty/libogg/libogg
|
path = 3rdparty/libogg/libogg
|
||||||
url = https://gitlab.xiph.org/xiph/ogg.git
|
url = https://github.com/xiph/ogg.git
|
||||||
[submodule "3rdparty/vorbis/vorbis-src"]
|
[submodule "3rdparty/vorbis/vorbis-src"]
|
||||||
path = 3rdparty/vorbis/vorbis-src
|
path = 3rdparty/vorbis/vorbis-src
|
||||||
url = https://gitlab.xiph.org/xiph/vorbis.git
|
url = https://github.com/xiph/vorbis.git
|
||||||
[submodule "3rdparty/opusfile/opusfile"]
|
[submodule "3rdparty/opusfile/opusfile"]
|
||||||
path = 3rdparty/opusfile/opusfile
|
path = 3rdparty/opusfile/opusfile
|
||||||
url = https://gitlab.xiph.org/xiph/opusfile.git
|
url = https://github.com/xiph/opusfile.git
|
||||||
|
[submodule "3rdparty/libbacktrace/libbacktrace"]
|
||||||
|
path = 3rdparty/libbacktrace/libbacktrace
|
||||||
|
url = https://github.com/ianlancetaylor/libbacktrace
|
||||||
|
[submodule "3rdparty/maintui"]
|
||||||
|
path = 3rdparty/maintui
|
||||||
|
url = https://github.com/numas13/xash3d-maintui.git
|
||||||
|
|||||||
2
3rdparty/MultiEmulator
vendored
1
3rdparty/extras/wscript
vendored
@@ -25,5 +25,4 @@ def build(bld):
|
|||||||
name = 'extras.pk3',
|
name = 'extras.pk3',
|
||||||
files = srcdir.ant_glob('**/*'),
|
files = srcdir.ant_glob('**/*'),
|
||||||
relative_to = srcdir,
|
relative_to = srcdir,
|
||||||
compresslevel = 0,
|
|
||||||
install_path = install_path)
|
install_path = install_path)
|
||||||
|
|||||||
2
3rdparty/extras/xash-extras
vendored
2
3rdparty/gl-wes-v2
vendored
2
3rdparty/gl4es/gl4es
vendored
6
3rdparty/gl4es/wscript
vendored
@@ -13,10 +13,12 @@ def configure(conf):
|
|||||||
|
|
||||||
def build(bld):
|
def build(bld):
|
||||||
gl4es_srcdir = bld.path.find_node('gl4es/src')
|
gl4es_srcdir = bld.path.find_node('gl4es/src')
|
||||||
|
cflags = []
|
||||||
|
if bld.env.COMPILER_CC != 'msvc':
|
||||||
|
cflags += ['-w', '-fvisibility=hidden', '-std=gnu99']
|
||||||
bld.stlib(source = gl4es_srcdir.ant_glob(['gl/*.c', 'gl/*/*.c', 'glx/hardext.c']),
|
bld.stlib(source = gl4es_srcdir.ant_glob(['gl/*.c', 'gl/*/*.c', 'glx/hardext.c']),
|
||||||
target = 'gl4es',
|
target = 'gl4es',
|
||||||
includes = ['gl4es/src', 'gl4es/src/gl', 'gl4es/src/glx', 'gl4es/include'],
|
includes = ['gl4es/src', 'gl4es/src/gl', 'gl4es/src/glx', 'gl4es/include'],
|
||||||
defines = ['NOX11', 'NO_GBM', 'NO_INIT_CONSTRUCTOR', 'DEFAULT_ES=2', 'NOEGL', 'NO_LOADER', 'STATICLIB'],
|
defines = ['NOX11', 'NO_GBM', 'NO_INIT_CONSTRUCTOR', 'DEFAULT_ES=2', 'NOEGL', 'NO_LOADER', 'STATICLIB'],
|
||||||
cflags = ['-w', '-fvisibility=hidden', '-std=gnu99'],
|
cflags = cflags,
|
||||||
export_includes = '.')
|
export_includes = '.')
|
||||||
|
|||||||
1
3rdparty/libbacktrace/libbacktrace
vendored
Submodule
186
3rdparty/libbacktrace/wscript
vendored
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
#! /usr/bin/env python
|
||||||
|
# encoding: utf-8
|
||||||
|
|
||||||
|
from waflib import TaskGen
|
||||||
|
from waflib.Tools.c_config import DEFKEYS
|
||||||
|
|
||||||
|
FRAGMENT_ATOMIC='''int i;
|
||||||
|
int main(void) {
|
||||||
|
__atomic_load_n(&i, __ATOMIC_ACQUIRE);
|
||||||
|
__atomic_store_n(&i, 1, __ATOMIC_RELEASE);
|
||||||
|
return 0;
|
||||||
|
}'''
|
||||||
|
|
||||||
|
FRAGMENT_SYNC='''int i;
|
||||||
|
int main (void) {
|
||||||
|
__sync_bool_compare_and_swap (&i, i, i);
|
||||||
|
__sync_lock_test_and_set (&i, 1);
|
||||||
|
__sync_lock_release (&i);
|
||||||
|
return 0;
|
||||||
|
}'''
|
||||||
|
|
||||||
|
FRAGMENT_GETPAGESIZE='''#include <unistd.h>
|
||||||
|
int main(void) { return getpagesize() }'''
|
||||||
|
|
||||||
|
FRAGMENT_GETEXECNAME='''#include <stdlib.h>
|
||||||
|
int main(void) { return getexecname() != 0 }'''
|
||||||
|
|
||||||
|
FRAGMENT_STRNLEN='''#include <string.h>
|
||||||
|
int main(int argc, char **argv) { return (int)strnlen(argv[0], 10); }'''
|
||||||
|
|
||||||
|
FRAGMENT_DL_ITERATE_PHDR='''#include <%s>
|
||||||
|
int main(void) { return dl_iterate_phdr(0, 0); }'''
|
||||||
|
|
||||||
|
FRAGMENT_FCNTL='''#include <fcntl.h>
|
||||||
|
int main(void) { return fcntl(0, 0, 0); }'''
|
||||||
|
|
||||||
|
FRAGMENT_GETIPINFO='''#include "unwind.h"
|
||||||
|
struct _Unwind_Context *context;
|
||||||
|
int ip_before_insn = 0;
|
||||||
|
int main(void) { return _Unwind_GetIPInfo(context, &ip_before_insn); }'''
|
||||||
|
|
||||||
|
FRAGMENT_LOADQUERY='''#include <sys/ldr.h>
|
||||||
|
#include <sys/debug.h>
|
||||||
|
int main(void) { return loadquery(0, 0, 0); }'''
|
||||||
|
|
||||||
|
FRAGMENT_KERN_PROC='''#include <sys/sysctl.h>
|
||||||
|
#if !defined(%s) || !defined(KERN_PROC_PATHNAME)
|
||||||
|
#error
|
||||||
|
#endif
|
||||||
|
int main(void) { return 0; }'''
|
||||||
|
|
||||||
|
FRAGMENT_LSTAT='''#include <sys/stat.h>
|
||||||
|
struct stat st;
|
||||||
|
int main(int argc, char **argv) { return lstat(argv[0], &st); }'''
|
||||||
|
|
||||||
|
FRAGMENT_READLINK='''#include <unistd.h>
|
||||||
|
char buf[100];
|
||||||
|
int main(int argc, char **argv) { return readlink(argv[0], buf, sizeof(buf)); }'''
|
||||||
|
|
||||||
|
def options(opt):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def configure(conf):
|
||||||
|
# add unsupported platforms here
|
||||||
|
if conf.env.DEST_OS in ['nswitch', 'psvita', 'dos']:
|
||||||
|
conf.env.DISABLE_LIBBACKTRACE = True
|
||||||
|
return
|
||||||
|
|
||||||
|
# win32 has it's own dbghelp-based backtrace, that's why we ship PDBs
|
||||||
|
if conf.env.COMPILER_CC == 'msvc':
|
||||||
|
conf.env.DISABLE_LIBBACKTRACE = True
|
||||||
|
return
|
||||||
|
|
||||||
|
if not conf.path.find_dir('libbacktrace') or not conf.path.find_dir('libbacktrace/config'):
|
||||||
|
conf.fatal('Can\'t find libbacktrace submodule. Run `git submodule update --init --recursive`.')
|
||||||
|
return
|
||||||
|
|
||||||
|
conf.define('BACKTRACE_ELF_SIZE', 64 if conf.env.DEST_SIZEOF_VOID_P == 8 else 32)
|
||||||
|
conf.define('BACKTRACE_XCOFF_SIZE', 64 if conf.env.DEST_SIZEOF_VOID_P == 8 else 32)
|
||||||
|
conf.define('_ALL_SOURCE', 1)
|
||||||
|
conf.define('_GNU_SOURCE', 1)
|
||||||
|
conf.define('_POSIX_PTHREAD_SEMANTICS', 1)
|
||||||
|
conf.define('_TANDEM_SOURCE', 1)
|
||||||
|
conf.define('__EXTENSIONS__', 1)
|
||||||
|
conf.define('_DARWIN_USE_64_BIT_INODE', 1)
|
||||||
|
conf.define('_LARGE_FILES', 1)
|
||||||
|
conf.check_large_file(compiler='c', execute=False, mandatory=False) # sets _FILE_OFFSET_BITS
|
||||||
|
|
||||||
|
conf.env.CFLAGS_EXTRAFLAGS = conf.filter_cflags(['-funwind-tables', '-g'], [])
|
||||||
|
|
||||||
|
if conf.filter_cflags(['-frandom-seed=test'], []):
|
||||||
|
conf.env.HAVE_FRANDOM_SEED = True
|
||||||
|
|
||||||
|
def check_header(hdr):
|
||||||
|
return {'header_name':hdr, 'msg':'... %s header' % hdr, 'mandatory':False, 'id':hdr, 'compiler': 'c'}
|
||||||
|
|
||||||
|
def check_frag(frag, msg, define, **kw):
|
||||||
|
return dict({'fragment': frag, 'msg':'... %s' % msg, 'mandatory': False, 'compiler': 'c'}, **kw)
|
||||||
|
|
||||||
|
conf.multicheck(
|
||||||
|
check_header('dlfcn.h'),
|
||||||
|
check_header('inttypes.h'),
|
||||||
|
check_header('link.h'),
|
||||||
|
check_header('sys/link.h'),
|
||||||
|
check_header('mach-o/dyld.h'),
|
||||||
|
check_header('memory.h'),
|
||||||
|
check_header('stdint.h'),
|
||||||
|
check_header('stdlib.h'),
|
||||||
|
check_header('strings.h'),
|
||||||
|
check_header('string.h'),
|
||||||
|
check_header('sys/ldr.h'),
|
||||||
|
check_header('sys/mman.h'),
|
||||||
|
check_header('sys/stat.h'),
|
||||||
|
check_header('sys/types.h'),
|
||||||
|
check_header('tlhelp32.h'),
|
||||||
|
check_header('unistd.h'),
|
||||||
|
check_header('windows.h'),
|
||||||
|
|
||||||
|
check_frag(FRAGMENT_ATOMIC, '__atomic extensions', 'HAVE_ATOMIC_FUNCTIONS'),
|
||||||
|
check_frag(FRAGMENT_SYNC, ' __sync extensions', 'HAVE_SYNC_FUNCTIONS'),
|
||||||
|
check_frag(FRAGMENT_GETPAGESIZE, ' getpagesize function', 'HAVE_DECL_GETPAGESIZE'),
|
||||||
|
check_frag(FRAGMENT_STRNLEN, ' strnlen function', 'HAVE_DECL_STRNLEN'),
|
||||||
|
check_frag(FRAGMENT_DL_ITERATE_PHDR % 'link.h', ' dl_iterate_phdr function in link.h', 'HAVE_DL_ITERATE_PHDR', after_tests=['link.h']),
|
||||||
|
check_frag(FRAGMENT_DL_ITERATE_PHDR % 'sys/link.h', ' dl_iterate_phdr function in sys/link.h', 'HAVE_DL_ITERATE_PHDR', after_tests=['sys/link.h']),
|
||||||
|
check_frag(FRAGMENT_FCNTL, 'fnctl function', 'HAVE_FCNTL'),
|
||||||
|
check_frag(FRAGMENT_GETEXECNAME, 'getexecname function','HAVE_GETEXECNAME'),
|
||||||
|
check_frag(FRAGMENT_GETIPINFO, '_Unwind_GetIPInfo function', 'HAVE_GETIPINFO'),
|
||||||
|
check_frag(FRAGMENT_KERN_PROC % 'KERN_PROC', 'KERN_PROC and KERN_PROC_PATHNAME defines', 'HAVE_KERN_PROC'),
|
||||||
|
check_frag(FRAGMENT_KERN_PROC % 'KERN_PROC_ARGS', 'KERN_PROC_ARGS and KERN_PROC_PATHNAME defines', 'HAVE_KERN_PROC_ARGS'),
|
||||||
|
check_frag(FRAGMENT_LOADQUERY, 'loadquery function', 'HAVE_LOADQUERY'),
|
||||||
|
check_frag(FRAGMENT_LSTAT, 'lstat function', 'HAVE_LSTAT'),
|
||||||
|
check_frag(FRAGMENT_READLINK, 'readlink function', 'HAVE_READLINK'),
|
||||||
|
|
||||||
|
# {'lib':'lzma', 'define_name':'HAVE_LIBLZMA', 'uselib_store':'lzma', 'msg':'... lzma library', 'mandatory':False},
|
||||||
|
# {'lib':'z', 'define_name':'HAVE_ZLIB', 'uselib_store':'z', 'msg':'... zlib library', 'mandatory':False},
|
||||||
|
# {'lib':'zstd', 'define_name':'HAVE_ZSTD', 'uselib_store':'zstd', 'msg':'... zstd library', 'mandatory':False},
|
||||||
|
msg='Checking for in parallel'
|
||||||
|
)
|
||||||
|
|
||||||
|
conf.env[DEFKEYS].sort()
|
||||||
|
|
||||||
|
conf.write_config_header()
|
||||||
|
|
||||||
|
conf.define('BACKTRACE_SUPPORTED', 1)
|
||||||
|
conf.define('BACKTRACE_USES_MALLOC', 0)
|
||||||
|
conf.define('BACKTRACE_SUPPORTS_THREADS', 1)
|
||||||
|
conf.define('BACKTRACE_SUPPORTS_DATA', conf.env.DEST_BINFMT in ['elf', 'mac-o'])
|
||||||
|
|
||||||
|
conf.write_config_header('backtrace-supported.h')
|
||||||
|
|
||||||
|
@TaskGen.feature('frandomseed')
|
||||||
|
@TaskGen.after_method('propagate_uselib_vars')
|
||||||
|
def process_frandom_seed(ctx):
|
||||||
|
tasks = getattr(ctx, 'compiled_tasks', [])
|
||||||
|
|
||||||
|
for task in tasks:
|
||||||
|
out = task.outputs[0]
|
||||||
|
task.env.CFLAGS = list(task.env.CFLAGS) # need a copy
|
||||||
|
task.env.CFLAGS += ['-frandom-seed=%s' % out.path_from(out.ctx.bldnode)]
|
||||||
|
|
||||||
|
def build(bld):
|
||||||
|
if bld.env.DISABLE_LIBBACKTRACE:
|
||||||
|
return
|
||||||
|
|
||||||
|
# we specifically only want mmap-based allocators because calling malloc is not safe from signal handlers
|
||||||
|
sources = ['atomic.c', 'dwarf.c', 'fileline.c', 'posix.c', 'print.c', 'sort.c', 'state.c', 'backtrace.c', 'simple.c', 'mmap.c', 'mmapio.c']
|
||||||
|
|
||||||
|
if bld.env.DEST_BINFMT == 'pe':
|
||||||
|
sources += ['pecoff.c']
|
||||||
|
elif bld.env.DEST_BINFMT == 'mac-o':
|
||||||
|
sources += ['macho.c']
|
||||||
|
elif bld.env.DEST_BINFMT == 'elf':
|
||||||
|
sources += ['elf.c']
|
||||||
|
else:
|
||||||
|
sources += ['unknown.c']
|
||||||
|
|
||||||
|
task = bld.stlib(
|
||||||
|
source = ['libbacktrace/' + i for i in sources],
|
||||||
|
target = 'backtrace',
|
||||||
|
features = 'frandomseed' if bld.env.HAVE_FRANDOM_SEED else '',
|
||||||
|
use = 'EXTRAFLAGS lzma z zstd',
|
||||||
|
includes = '. libbacktrace/',
|
||||||
|
export_defines = 'HAVE_LIBBACKTRACE=1',
|
||||||
|
export_includes = 'libbacktrace/'
|
||||||
|
)
|
||||||
|
|
||||||
1
3rdparty/maintui
vendored
Submodule
2
3rdparty/mainui
vendored
2
3rdparty/nanogl
vendored
78
3rdparty/opus/wscript
vendored
@@ -23,6 +23,17 @@ int main (void) {
|
|||||||
int * array = alloca(foo);
|
int * array = alloca(foo);
|
||||||
}'''
|
}'''
|
||||||
|
|
||||||
|
FRAGMENT_LRINT='''#include <math.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
int main (int argc, char **argv) {
|
||||||
|
return lrint%s((%s)atof(argv[1]));
|
||||||
|
}'''
|
||||||
|
|
||||||
|
# assuming MSVC always enables NEON
|
||||||
|
FRAGMENT_NEON='''#if !defined __ARM_NEON__ && !defined _MSC_VER
|
||||||
|
#error
|
||||||
|
#endif'''
|
||||||
|
|
||||||
def options(opt):
|
def options(opt):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -31,15 +42,61 @@ def configure(conf):
|
|||||||
conf.fatal('Can\'t find opus submodule. Run `git submodule update --init --recursive`.')
|
conf.fatal('Can\'t find opus submodule. Run `git submodule update --init --recursive`.')
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if conf.check_cc(fragment=FRAGMENT_LRINT % ('', 'double'), msg = 'Checking for C99 lrint', use = 'M', mandatory = False):
|
||||||
|
conf.define('HAVE_LRINT', 1)
|
||||||
|
|
||||||
|
if conf.check_cc(fragment=FRAGMENT_LRINT % ('f', 'float'), msg = 'Checking for C99 lrintf', use = 'M', mandatory = False):
|
||||||
|
conf.define('HAVE_LRINTF', 1)
|
||||||
|
|
||||||
# Check for C99 variable-size arrays, or alloca() as fallback
|
# Check for C99 variable-size arrays, or alloca() as fallback
|
||||||
if conf.check_cc(fragment=FRAGMENT_VLA, msg = 'Checking for C99 VLA support', mandatory = False):
|
if conf.check_cc(fragment=FRAGMENT_VLA, msg = 'Checking for C99 VLA support', mandatory = False):
|
||||||
conf.define('VAR_ARRAYS', 1)
|
conf.define('VAR_ARRAYS', 1)
|
||||||
elif conf.check_cc(fragment=FRAGMENT_ALLOCA_H, msg = 'Checking for alloca in alloca.h header', mandatory = False):
|
elif conf.check_cc(fragment=FRAGMENT_ALLOCA_H, msg = 'Checking for alloca in alloca.h header', mandatory = False):
|
||||||
conf.define('USE_ALLOCA', 1)
|
conf.define('USE_ALLOCA', 1)
|
||||||
conf.define('HAVE_ALLOCA_H', 1)
|
conf.define('HAVE_ALLOCA_H', 1)
|
||||||
elif conf.check_cc(fragmenmt=FRAGMENT_STDLIB_H, msg = 'Checking for alloca.h in stdlib.h', mandatory = False):
|
elif conf.check_cc(fragment=FRAGMENT_STDLIB_H, msg = 'Checking for alloca.h in stdlib.h', mandatory = False):
|
||||||
conf.define('USE_ALLOCA', 1)
|
conf.define('USE_ALLOCA', 1)
|
||||||
|
|
||||||
|
if conf.env.DEST_CPU in ['thumb', 'arm']:
|
||||||
|
if conf.check(header_name='arm_neon.h', mandatory = False):
|
||||||
|
if conf.check(fragment=FRAGMENT_NEON, msg = 'Checking if compiler enabled NEON', mandatory = False):
|
||||||
|
conf.env.HAVE_NEON = True
|
||||||
|
conf.define('OPUS_ARM_MAY_HAVE_NEON_INTR', 1)
|
||||||
|
conf.define('OPUS_ARM_PRESUME_NEON', 1)
|
||||||
|
elif conf.env.DEST_CPU.startswith('x86'):
|
||||||
|
if conf.check(header_name='xmmintrin.h', mandatory = False):
|
||||||
|
if conf.env.COMPILER_CC != 'msvc':
|
||||||
|
conf.env.CFLAGS += ['-msse']
|
||||||
|
conf.define('OPUS_X86_MAY_HAVE_SSE', 1)
|
||||||
|
if conf.env.DEST_SIZEOF_VOID_P > 4:
|
||||||
|
conf.define('OPUS_X86_PRESUME_SSE', 1)
|
||||||
|
|
||||||
|
if conf.check(header_name='emmintrin.h', mandatory = False):
|
||||||
|
if conf.env.COMPILER_CC != 'msvc':
|
||||||
|
conf.env.CFLAGS += ['-msse2']
|
||||||
|
conf.define('OPUS_X86_MAY_HAVE_SSE2', 1)
|
||||||
|
if conf.env.DEST_SIZEOF_VOID_P > 4:
|
||||||
|
conf.define('OPUS_X86_PRESUME_SSE2', 1)
|
||||||
|
|
||||||
|
# on x86_64 we enable both SSE and SSE2, so RTCD can be disabled (it's actually doesn't even build with RTCD enabled)
|
||||||
|
if conf.env.DEST_SIZEOF_VOID_P == 4:
|
||||||
|
if conf.check(header_name='cpuid.h', mandatory=False):
|
||||||
|
conf.define('CPU_INFO_BY_C', 1)
|
||||||
|
else:
|
||||||
|
conf.define('CPU_INFO_BY_ASM', 1)
|
||||||
|
|
||||||
|
conf.define('OPUS_HAVE_RTCD', 1)
|
||||||
|
|
||||||
|
# if conf.check(header_name='smmintrin.h', mandatory = False):
|
||||||
|
# if conf.env.COMPILER_CC != 'msvc':
|
||||||
|
# conf.env.CFLAGS += ['-msse4.1']
|
||||||
|
# conf.define('OPUS_X86_MAY_HAVE_SSE4_1', 1)
|
||||||
|
|
||||||
|
# if conf.check(header_name='immintrin.h', mandatory = False):
|
||||||
|
# if conf.env.COMPILER_CC != 'msvc':
|
||||||
|
# conf.env.CFLAGS += ['-mavx']
|
||||||
|
# conf.define('OPUS_X86_MAY_HAVE_AVX', 1)
|
||||||
|
|
||||||
# TODO: ARM/x86 intrinsics detection
|
# TODO: ARM/x86 intrinsics detection
|
||||||
# TODO: maybe call autotools/cmake/meson instead?
|
# TODO: maybe call autotools/cmake/meson instead?
|
||||||
|
|
||||||
@@ -55,8 +112,23 @@ def build(bld):
|
|||||||
'opus/src/opus_compare.c',
|
'opus/src/opus_compare.c',
|
||||||
'opus/celt/opus_custom_demo.c'
|
'opus/celt/opus_custom_demo.c'
|
||||||
])
|
])
|
||||||
includes = ['opus/include/', 'opus/celt/', 'opus/silk/', 'opus/silk/float/']
|
|
||||||
defines = ['OPUS_BUILD', 'FLOAT_APPROX', 'PACKAGE_VERSION="1.4.0"', 'CUSTOM_MODES']
|
includes = ['opus', 'opus/include/', 'opus/celt/', 'opus/silk/', 'opus/silk/float/']
|
||||||
|
|
||||||
|
if bld.env.DEST_CPU in ['thumb', 'arm']:
|
||||||
|
if bld.env.HAVE_NEON:
|
||||||
|
sources += bld.path.ant_glob(['opus/silk/arm/*.c', 'opus/celt/arm/*.c'])
|
||||||
|
includes += ['opus/silk/arm', 'opus/celt/arm']
|
||||||
|
elif bld.env.DEST_CPU.startswith('x86'):
|
||||||
|
sources += ['opus/silk/x86/x86_silk_map.c',
|
||||||
|
'opus/celt/x86/pitch_sse.c',
|
||||||
|
'opus/celt/x86/pitch_sse2.c',
|
||||||
|
'opus/celt/x86/vq_sse2.c',
|
||||||
|
'opus/celt/x86/x86_celt_map.c',
|
||||||
|
'opus/celt/x86/x86cpu.c']
|
||||||
|
includes += ['opus/silk/x86', 'opus/celt/x86']
|
||||||
|
|
||||||
|
defines = ['OPUS_BUILD', 'FLOAT_APPROX', 'PACKAGE_VERSION="1.4.0"', 'CUSTOM_MODES', 'ENABLE_HARDENING']
|
||||||
|
|
||||||
bld.stlib(
|
bld.stlib(
|
||||||
source = sources,
|
source = sources,
|
||||||
|
|||||||
2
3rdparty/vgui_support
vendored
@@ -45,3 +45,8 @@
|
|||||||
Tags can be any: subsystem, simple feature name or even just a filename, without extension.
|
Tags can be any: subsystem, simple feature name or even just a filename, without extension.
|
||||||
Just keep them always same, it helps keep history clean and commit messages short.
|
Just keep them always same, it helps keep history clean and commit messages short.
|
||||||
|
|
||||||
|
## LLM-based tools usage.
|
||||||
|
|
||||||
|
While we wouldn't recommend using any LLM-based (also misleadingly called AI) tools, we understand that they are here to stay.
|
||||||
|
|
||||||
|
Whether you're reporting bug or contributing the code, you take complete authorship and responsibility over provided content and the same rules will apply to you as for everybody else, so validate the bug report or the patch before sending it.
|
||||||
|
|||||||
@@ -2,23 +2,27 @@
|
|||||||
|
|
||||||
On this page you can find links where you can support each developer individually, who has provided public sponsorship information.
|
On this page you can find links where you can support each developer individually, who has provided public sponsorship information.
|
||||||
|
|
||||||
### [a1batross](https://github.com/a1batross)
|
## [a1batross](https://github.com/a1batross)
|
||||||
|
|
||||||
* Initial Xash3D SDL2/Linux port author, Xash3D FWGS engine maintainer, creator of non-commercial Flying With Gauss organization.
|
Initial Xash3D SDL2/Linux port author, Xash3D FWGS engine maintainer, creator of non-commercial Flying With Gauss organization.
|
||||||
* Boosty page: https://boosty.to/a1ba
|
|
||||||
|
|
||||||
### [nekonomicon](https://github.com/nekonomicon)
|
* [Boosty page](https://boosty.to/a1ba)
|
||||||
|
|
||||||
* [hlsdk-portable](https://github.com/FWGS/hlsdk-portable), [mdldec](../utils/mdldec), [opensource-mods.md](opensource-mods.md) maintainer and Xash3D FWGS [contributor](https://github.com/FWGS/xash3d-fwgs/commits?author=nekonomicon) (*BSD/clang port, PNG support, etc).
|
## [nekonomicon](https://github.com/nekonomicon)
|
||||||
* Boosty page: https://boosty.to/nekonomicon
|
|
||||||
|
|
||||||
### [Velaron](https://github.com/Velaron)
|
[hlsdk-portable](https://github.com/FWGS/hlsdk-portable), [mdldec](../utils/mdldec), [opensource-mods.md](opensource-mods.md) maintainer and Xash3D FWGS [contributor](https://github.com/FWGS/xash3d-fwgs/commits?author=nekonomicon) (*BSD/clang port, PNG support, etc).
|
||||||
* [cs16-client](https://github.com/Velaron/cs16-client) & [tf15-client](https://github.com/Velaron/tf15-client) maintainer and Xash3D FWGS [contributor](https://github.com/FWGS/xash3d-fwgs/commits?author=Velaron) (Android port, voice chat, etc).
|
|
||||||
* BuyMeACoffee page: https://www.buymeacoffee.com/velaron
|
|
||||||
|
|
||||||
### [SNMetamorph](https://github.com/SNMetamorph)
|
* [Boosty page](https://boosty.to/nekonomicon)
|
||||||
* [PrimeXT](https://github.com/SNMetamorph/PrimeXT) & [GoldSrc Monitor](https://github.com/SNMetamorph/goldsrc-monitor) maintainer and Xash3D FWGS [contributor](https://github.com/FWGS/xash3d-fwgs/commits?author=SNMetamorph) (Windows port, voice chat, etc).
|
|
||||||
* BTC: `16GAzK3qei5AwBW7sggXp3yNcFHBtdpxXj`
|
## [Velaron](https://github.com/Velaron)
|
||||||
* ETH (ERC20): `0xb580eeca9756e3881f9d6d026e28db28eb72a383`
|
|
||||||
* USDT (ERC20): `0xb580eeca9756e3881f9d6d026e28db28eb72a383`
|
[cs16-client](https://github.com/Velaron/cs16-client) & [tf15-client](https://github.com/Velaron/tf15-client) maintainer and Xash3D FWGS [contributor](https://github.com/FWGS/xash3d-fwgs/commits?author=Velaron) (Android port, voice chat, etc).
|
||||||
* USDC (ERC20): `0xb580eeca9756e3881f9d6d026e28db28eb72a383`
|
|
||||||
|
* [Boosty page](https://boosty.to/velaron)
|
||||||
|
|
||||||
|
## [SNMetamorph](https://github.com/SNMetamorph)
|
||||||
|
|
||||||
|
[PrimeXT](https://github.com/SNMetamorph/PrimeXT) & [GoldSrc Monitor](https://github.com/SNMetamorph/goldsrc-monitor) maintainer and Xash3D FWGS [contributor](https://github.com/FWGS/xash3d-fwgs/commits?author=SNMetamorph) (Windows port, voice chat, etc).
|
||||||
|
|
||||||
|
* [Boosty page](https://boosty.to/snmetamorph)
|
||||||
|
* [Other donation methods](https://snmetamorph.github.io/donate)
|
||||||
|
|||||||
@@ -42,3 +42,6 @@ Issue #3: Some mods (like The Specialists, Tyrian, ...) already apply suffixes _
|
|||||||
Resolution: On x86 on **Win/Lin/Mac**, don't change anything. Otherwise, strip the _i?86 part and follow the usual scheme.
|
Resolution: On x86 on **Win/Lin/Mac**, don't change anything. Otherwise, strip the _i?86 part and follow the usual scheme.
|
||||||
|
|
||||||
See discussion: https://github.com/FWGS/xash3d-fwgs/issues/39
|
See discussion: https://github.com/FWGS/xash3d-fwgs/issues/39
|
||||||
|
|
||||||
|
Issue #4: When distributing game libraries on Android inside an APK, they couldn't be loaded.
|
||||||
|
Resolution: Enable `useLegacyPackaging` option in build.gradle, when distributing games in APK. Always force game libraries to have `lib` prefix on Android, regardless if they are packaged in APK or not..
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ For connecting to GoldSrc-based servers, use this command:
|
|||||||
connect ip:port gs
|
connect ip:port gs
|
||||||
```
|
```
|
||||||
|
|
||||||
But keep in mind, there are requirement for server to be able to accept connections from Xash3D-based clients: it should use Reunion or Dproto.
|
But keep in mind, there are requirement for server to be able to accept connections from Xash3D-based clients: it should use Reunion.
|
||||||
Without this requirement, you will just get "Steam validation rejected" error on connecting.
|
Without this requirement, you will just get "Steam validation rejected" error on connecting.
|
||||||
|
|
||||||
That is because proper authorization with Steam API is not implemented in engine yet (but we have plans on it).
|
That is because proper authorization with Steam API is not implemented in engine yet (but we have plans on it).
|
||||||
|
|||||||
BIN
Documentation/images/editor.jpg
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
Documentation/images/example1.jpg
Normal file
|
After Width: | Height: | Size: 82 KiB |
BIN
Documentation/images/example2.jpg
Normal file
|
After Width: | Height: | Size: 212 KiB |
BIN
Documentation/images/example3.jpg
Normal file
|
After Width: | Height: | Size: 400 KiB |
BIN
Documentation/images/example4.jpg
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
Documentation/images/example5.jpg
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
Documentation/images/touch-buttons.jpg
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
BIN
Documentation/images/touch-profiles.jpg
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
@@ -2,10 +2,19 @@
|
|||||||
|
|
||||||
|Name |Version |Why not working |What was made for that
|
|Name |Version |Why not working |What was made for that
|
||||||
|---- |------- |--------------- |----------------------
|
|---- |------- |--------------- |----------------------
|
||||||
|Blue Shift |The latest steam release |Uses vgui2 library which xash3d does not support |Recreated source code here: https://github.com/FWGS/hlsdk-xash3d/tree/bshift
|
|Area 51 |Update 1 |Uses outdated BSP31 map format and custom HLFX SDK libraries. |You can try [this tool](https://hlfx.ru/forum/showthread.php?threadid=5250) to convert maps but there no warranty if it works.
|
||||||
|Counter Strike |1.6(The latest steam release) |Uses vgui2 library which xash3d does not support |Some work on vgui2 support was made here: https://github.com/FWGS/xash3d/tree/vinterface
|
|Arrange Mod: Rebirth |v150 |No idea yet. |
|
||||||
|Counter Strike: Condition Zero |The latest steam release |Uses vgui2 library which xash3d does not support |Some work on vgui2 support was made here: https://github.com/FWGS/xash3d/tree/vinterface
|
|Blue Shift |The latest steam release |Uses vgui2 library which xash3d does not support. |Recreated source code here: https://github.com/FWGS/hlsdk-xash3d/tree/bshift.
|
||||||
|Counter Strike: Condition Zero - Deleted scenes |The latest steam release |Uses vgui2 library which xash3d does not support |Some work on vgui2 support was made here: https://github.com/FWGS/xash3d/tree/vinterface
|
|Counter Strike |Beta 6.5- |Uses an old WON HL 1.0.0.16- interface. |
|
||||||
|Day of Defeat |The latest steam release |Uses vgui2 library which xash3d does not support |Some work on vgui2 support was made here: https://github.com/FWGS/xash3d/tree/vinterface
|
| |1.4 |Has encrypted blob instead of normal client.dll. |You can try [this tool](https://aluigi.altervista.org/papers/hldlldec.zip) to decrypt client.dll but there no warranty if it works.
|
||||||
|Sven-Coop |5.0+ |Uses custom GoldSrc engine |
|
| |1.5 |Has encrypted blob instead of normal client.dll. |Decrypted blob here: https://csm.dev/threads/cs-1-5-client-dll-decrypted-patched-for-usage.38845.
|
||||||
|
| |1.6(The latest steam release) |Uses vgui2 library which xash3d does not support. |Some work on vgui2 support was made here: https://github.com/FWGS/xash3d/tree/vinterface. Recreated Client Source Code here: https://github.com/Velaron/cs16-client.
|
||||||
|
|Counter Strike: Condition Zero |The latest steam release |Uses vgui2 library which xash3d does not support. |Some work on vgui2 support was made here: https://github.com/FWGS/xash3d/tree/vinterface. Recreated Client Source Code here: https://github.com/Velaron/cs16-client.
|
||||||
|
|Counter Strike: Condition Zero - Deleted scenes |The latest steam release |Uses vgui2 library which xash3d does not support. Uses new sequences code on engine-side that was never used in any other mods before. |Some work on vgui2 support was made here: https://github.com/FWGS/xash3d/tree/vinterface.
|
||||||
|
|Day of Defeat |The latest steam release |Uses vgui2 library which xash3d does not support. |Some work on vgui2 support was made here: https://github.com/FWGS/xash3d/tree/vinterface.
|
||||||
|
|Half-Life: Extended |Day One demo |Uses many hooks to GoldSource engine and version check. |Just wait new version or use more old version.
|
||||||
|
|Icon of Hell |Beta 0.99 |Uses outdated BSP31 map format and paranoia 2 libraries. |You can try [this tool](https://hlfx.ru/forum/showthread.php?threadid=5250) to convert maps and use Paranoia 2: The Savior 1.51 libraries but there no warranty if it works.
|
||||||
|
|Paranoia 2: The Savior |All builds older 1.51 |Uses an old renderer interface and engine features. |
|
||||||
|
|Rebellion |1.0 |Uses an old WON HL 1.0.0.16- interface. |Recreated source code here: https://github.com/FWGS/hlsdk-xash3d/tree/rebellion.
|
||||||
|
|Sven-Coop |5.0+ |Uses custom GoldSrc engine. |
|
||||||
|
|Time Shadows |Beta 0.1 |Uses Direct3D renderer. |
|
||||||
|
|||||||
@@ -32,12 +32,18 @@ Version 1.9 mirrored on github - https://github.com/solidi/hl-mods/tree/master/c
|
|||||||
## Cold Ice Ressurection
|
## Cold Ice Ressurection
|
||||||
Mirrored on github - https://github.com/solidi/hl-mods/tree/master/cir
|
Mirrored on github - https://github.com/solidi/hl-mods/tree/master/cir
|
||||||
|
|
||||||
|
## Counter-Life
|
||||||
|
Available on ModDB - https://www.moddb.com/mods/counter-life/downloads/cl-version-1-source-code
|
||||||
|
|
||||||
## Cthulhu
|
## Cthulhu
|
||||||
Uploaded to github by Oleg Cherkasky - https://github.com/gunrunners-paradise/Cthulhu-HLmod-SDK
|
Uploaded to github by Oleg Cherkasky - https://github.com/gunrunners-paradise/Cthulhu-HLmod-SDK
|
||||||
|
|
||||||
## Deathmatch Classic
|
## Deathmatch Classic
|
||||||
Available in Valve's Half-Life repository - https://github.com/ValveSoftware/halflife/tree/master/dmc
|
Available in Valve's Half-Life repository - https://github.com/ValveSoftware/halflife/tree/master/dmc
|
||||||
|
|
||||||
|
## Delta Particles
|
||||||
|
Available on ModDB - https://www.moddb.com/mods/half-life-delta/downloads/delta-particles-full-sources-maps-and-c-code
|
||||||
|
|
||||||
## Earth Special Forces
|
## Earth Special Forces
|
||||||
Alpha 2.0 - https://www.gamers-desire.de/details/2830
|
Alpha 2.0 - https://www.gamers-desire.de/details/2830
|
||||||
|
|
||||||
@@ -121,6 +127,11 @@ Mirrored on github - https://github.com/nekonomicon/HeartOfEvil
|
|||||||
## Ingram Chillin' Mod
|
## Ingram Chillin' Mod
|
||||||
Official SourceForge repository - https://sourceforge.net/projects/icm-hl/
|
Official SourceForge repository - https://sourceforge.net/projects/icm-hl/
|
||||||
|
|
||||||
|
## Master Sword
|
||||||
|
Official github repository of Master Sword Classic - https://github.com/BerntA/MasterSwordClassic
|
||||||
|
|
||||||
|
Official github repository of Master Sword Rebirth - https://github.com/MSRevive/MasterSwordRebirth
|
||||||
|
|
||||||
## MechMod
|
## MechMod
|
||||||
Official github repository - https://github.com/vermagav/mechmod
|
Official github repository - https://github.com/vermagav/mechmod
|
||||||
|
|
||||||
@@ -199,7 +210,7 @@ Branch **redempt** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tr
|
|||||||
OpenAG by YaLTeR - https://github.com/YaLTeR/OpenAG
|
OpenAG by YaLTeR - https://github.com/YaLTeR/OpenAG
|
||||||
|
|
||||||
## Afraid of Monsters
|
## Afraid of Monsters
|
||||||
malortie's recreation - https://github.com/malortie/hl-aom
|
malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-aom
|
||||||
|
|
||||||
Branch **aom** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/aom
|
Branch **aom** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/aom
|
||||||
|
|
||||||
@@ -207,17 +218,17 @@ Branch **aom** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/a
|
|||||||
Reverse-engineered code: branch **aomdc** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/aomdc
|
Reverse-engineered code: branch **aomdc** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/aomdc
|
||||||
|
|
||||||
## Azure Sheep
|
## Azure Sheep
|
||||||
malortie's recreation - https://github.com/malortie/hl-asheep
|
malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-asheep
|
||||||
|
|
||||||
Reverse-engineered code: branch **asheep** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/asheep
|
Reverse-engineered code: branch **asheep** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/asheep
|
||||||
|
|
||||||
## Big Lolly
|
## Big Lolly
|
||||||
malortie's recreation - https://github.com/malortie/hl-biglolly
|
malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-biglolly
|
||||||
|
|
||||||
Branch **biglolly** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/biglolly
|
Branch **biglolly** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/biglolly
|
||||||
|
|
||||||
## Black Ops
|
## Black Ops
|
||||||
malortie's recreation - https://github.com/malortie/hl-blackops
|
malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-blackops
|
||||||
|
|
||||||
Branch **blackops** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/blackops
|
Branch **blackops** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/blackops
|
||||||
|
|
||||||
@@ -246,7 +257,7 @@ Recreation by lostgamer aka nillerusr - https://github.com/LostGamerHL/crack_lif
|
|||||||
Reverse-engineered code: branch **clcampaign** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/clcampaign
|
Reverse-engineered code: branch **clcampaign** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/clcampaign
|
||||||
|
|
||||||
## Escape from the Darkness
|
## Escape from the Darkness
|
||||||
malortie's recreation - https://github.com/malortie/hl-eftd
|
malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-eftd
|
||||||
|
|
||||||
Reverse-engineered code: branch **eftd** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/eftd
|
Reverse-engineered code: branch **eftd** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/eftd
|
||||||
|
|
||||||
@@ -277,7 +288,7 @@ Reverse-engineered code: branch **rebellion** in hlsdk-portable - https://github
|
|||||||
Branch **hl_urbicide** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/hl_urbicide
|
Branch **hl_urbicide** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/hl_urbicide
|
||||||
|
|
||||||
## Half-Life: Visitors
|
## Half-Life: Visitors
|
||||||
malortie's recreation - https://github.com/malortie/hl-visitors
|
malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-visitors
|
||||||
|
|
||||||
Reverse-engineered code: branch **visitors** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/visitors
|
Reverse-engineered code: branch **visitors** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/visitors
|
||||||
|
|
||||||
@@ -285,17 +296,17 @@ Reverse-engineered code: branch **visitors** in hlsdk-portable - https://github.
|
|||||||
Branch **half-secret** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/half-secret
|
Branch **half-secret** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/half-secret
|
||||||
|
|
||||||
## Night at the Office
|
## Night at the Office
|
||||||
malortie's recreation - https://github.com/malortie/hl-nato
|
malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-nato
|
||||||
|
|
||||||
Branch **noffice** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/noffice
|
Branch **noffice** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/noffice
|
||||||
|
|
||||||
## Poke 646
|
## Poke 646
|
||||||
malortie's recreation - https://github.com/malortie/hl-poke646
|
malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-poke646
|
||||||
|
|
||||||
Reverse-engineered code: branch **poke646** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/poke646
|
Reverse-engineered code: branch **poke646** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/poke646
|
||||||
|
|
||||||
## Poke 646: Vendetta
|
## Poke 646: Vendetta
|
||||||
malortie's recreation - https://github.com/malortie/hl-poke646-vendetta
|
malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-poke646-vendetta
|
||||||
|
|
||||||
Reverse-engineered code: branch **poke646_vendetta** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/poke646_vendetta
|
Reverse-engineered code: branch **poke646_vendetta** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/poke646_vendetta
|
||||||
|
|
||||||
@@ -312,19 +323,19 @@ Branch **sewer_beta** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable
|
|||||||
Reverse-engineered code by Velaron - https://github.com/Velaron/tf15-client
|
Reverse-engineered code by Velaron - https://github.com/Velaron/tf15-client
|
||||||
|
|
||||||
## The Gate
|
## The Gate
|
||||||
malortie's recreation - https://github.com/malortie/hl-thegate
|
malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-thegate
|
||||||
|
|
||||||
Reverse-engineered code: branch **thegate** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/thegate
|
Reverse-engineered code: branch **thegate** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/thegate
|
||||||
|
|
||||||
## They Hunger
|
## They Hunger
|
||||||
malortie's recreation - https://github.com/malortie/hl-theyhunger
|
malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-theyhunger
|
||||||
|
|
||||||
Reverse-engineered code: branch **theyhunger** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/theyhunger
|
Reverse-engineered code: branch **theyhunger** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/theyhunger
|
||||||
|
|
||||||
They Hunger: Tactical - https://www.moddb.com/mods/they-hunger-tactical/downloads/tht-source-code-documentation
|
They Hunger: Tactical - https://www.moddb.com/mods/they-hunger-tactical/downloads/tht-source-code-documentation
|
||||||
|
|
||||||
## Times of Troubles
|
## Times of Troubles
|
||||||
malortie's recreation - https://github.com/malortie/hl-tot
|
malortie's recreation - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-tot
|
||||||
|
|
||||||
Branch **tot** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/tot
|
Branch **tot** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/tot
|
||||||
|
|
||||||
@@ -346,7 +357,7 @@ Branch **dmc** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/d
|
|||||||
Branch **echoes** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/echoes
|
Branch **echoes** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/echoes
|
||||||
|
|
||||||
## Half-Life: Invasion
|
## Half-Life: Invasion
|
||||||
Port to HLSDK 2.4 by malortie - https://github.com/malortie/hl-invasion
|
Port to HLSDK 2.4 by malortie - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-invasion
|
||||||
|
|
||||||
Port to Linux by fmoraw - https://github.com/fmoraw/hlinvasion
|
Port to Linux by fmoraw - https://github.com/fmoraw/hlinvasion
|
||||||
|
|
||||||
@@ -365,7 +376,7 @@ Port to Linux - https://github.com/fmoraw/NS
|
|||||||
Version 1.2: branch **sohl1.2** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/sohl1.2
|
Version 1.2: branch **sohl1.2** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/sohl1.2
|
||||||
|
|
||||||
## Swiss Cheese Halloween 2002
|
## Swiss Cheese Halloween 2002
|
||||||
Just more playable version by malortie - https://github.com/malortie/hl-shall
|
Just more playable version by malortie - https://github.com/HL1-Mods-Reimplementations-and-Ports/hl-shall
|
||||||
|
|
||||||
Branch **halloween** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/halloween
|
Branch **halloween** in hlsdk-portable - https://github.com/FWGS/hlsdk-portable/tree/halloween
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,14 @@
|
|||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
1. Make sure your PSVita is [set up to run homebrew applications](https://vita.hacks.guide/).
|
1. Make sure your PSVita is [set up to run homebrew applications](https://vita.hacks.guide/).
|
||||||
2. Install [kubridge](https://github.com/TheOfficialFloW/kubridge/releases/) by copying `kubridge.suprx` to your taiHEN plugins folder (usually `ux0:/tai`) and add it to your `config.txt`, for example:
|
2. Install [kubridge](https://github.com/TheOfficialFloW/kubridge/releases/). It is recommended to use kubridge version `0.1`, because other versions aren't tested, we don't know are they suitable or not.
|
||||||
|
|
||||||
|
Worth to notice, we got reports that automatic plugins management app EasyPlugin have issues with installing kubridge plugin, so it's better to install it manually: by copying `kubridge.suprx` to your taiHEN plugins folder (usually `ux0:/tai`, but could be `ur0:/tai`) and add it to your `config.txt`, for example:
|
||||||
```
|
```
|
||||||
*KERNEL
|
*KERNEL
|
||||||
ux0:tai/kubridge.skprx
|
ux0:tai/kubridge.skprx
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Install `libshacccg.suprx` by following [this guide](https://cimmerian.gitbook.io/vita-troubleshooting-guide/shader-compiler/extract-libshacccg.suprx).
|
3. Install `libshacccg.suprx` by following [this guide](https://cimmerian.gitbook.io/vita-troubleshooting-guide/shader-compiler/extract-libshacccg.suprx).
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
As online community is growing, we don't want to keep bad or invalid servers on the Internet Games list. It's a common rules for all Xash3D server owners who are using default master server.
|
|
||||||
|
|
||||||
1. Breaking master server or clients is prohibited in any way. If you found a serious bug, contact us at contact 'at' fwgs.ru or post an issue at GitHub.
|
|
||||||
|
|
||||||
2. Changing settings, exploiting vulnerabilities of clients is prohibited in any way. If you found a serious bug, contact us at contact 'at' fwgs.ru or post an issue at GitHub.
|
|
||||||
|
|
||||||
2. Agressive advertisement and spam on other servers is prohibited in any way.
|
|
||||||
|
|
||||||
3. If your server is require downloading custom content, it should be available for everyone. Recommended way to deliver custom content is FastDL.
|
|
||||||
|
|
||||||
4. It's recommended to keep your server is up-to-date. You may use our public Debian/Ubuntu/Arch Linux [repository](https://github.com/FWGS/xash3d/wiki/How-to-set-up-a-Xash3D-Dedicated-Server-on-Debian-or-Ubuntu) to simplify updating process.
|
|
||||||
|
|
||||||
Just follow these rules to not get banned on our master server. Good luck, have fun!
|
|
||||||
|
|
||||||
|
|
||||||
149
Documentation/touch-controls.md
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
# Touch controls configuring
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
Thanks to mittorn, we have the ability to fully customize the controls in Xash3D. The new config allows you to not only add and change control buttons, but also create custom menus. There is also a built-in visual editor available, which simplifies the customization process without the need for manual file editing.
|
||||||
|
|
||||||
|
## Editor mode usage
|
||||||
|
|
||||||
|
1. Launch Xash3D and start the game.
|
||||||
|
2. To enter the edit mode, click on the gear icon (command `touch_enableedit`).
|
||||||
|
3. In the edit mode, the grid is displayed. The number of cells can be changed with the command `touch_grid_count` (default is 50). The grid can be disabled with the command `touch_grid_enable 0`.
|
||||||
|
|
||||||
|
*Touch controls layout editor*
|
||||||
|

|
||||||
|
|
||||||
|
*Touch profiles window*
|
||||||
|

|
||||||
|
|
||||||
|
*Touch buttons parameters window*
|
||||||
|

|
||||||
|
|
||||||
|
## Layout editor features
|
||||||
|
|
||||||
|
* **Moving buttons**: click on a button, drag it to the desired location, and release.
|
||||||
|
* **Resizing buttons**: place your first finger on the top left corner of the button, and use your second finger to resize it.
|
||||||
|
* **Hiding/showing buttons**: select the button (it will turn red), then use the menu:
|
||||||
|
* **Close**: closes the editing mode (`touch_disableedit`).
|
||||||
|
* **Reset**: resets the button to its default values.
|
||||||
|
* **Hide/Show**: hides or shows the button (`touch_hide <name>` / `touch_show <name>`).
|
||||||
|
|
||||||
|
## Working with configuration files / console
|
||||||
|
|
||||||
|
All changes made in the visual editor are automatically saved to the touch profile file. The files are located in the `touch_profiles` folder inside game directory. The file name depends on the selected profile.
|
||||||
|
|
||||||
|
### Common commands in configuration files
|
||||||
|
|
||||||
|
```
|
||||||
|
// Comment: lines starting with // are ignored.
|
||||||
|
|
||||||
|
// Swipe zones for movement. Specify how far you need to swipe to speed up.
|
||||||
|
// The default values are set to be optimal for a small swipe to immediately walk quickly.
|
||||||
|
touch_forwardzone "0.060000" ; touch_sidezone "0.060000"
|
||||||
|
|
||||||
|
// Sensitivity settings (pitch - horizontal, yaw - vertical).
|
||||||
|
touch_pitch ; touch_yaw
|
||||||
|
|
||||||
|
// Grid settings (see above).
|
||||||
|
touch_grid_count ; touch_grid_enable
|
||||||
|
|
||||||
|
// Draws a border around the button.
|
||||||
|
touch_set_stroke <thickness> <c> <v> <e> <t>
|
||||||
|
(<r> - red; <g> - green; <b> - blue; <a> - alpha/transparency)
|
||||||
|
|
||||||
|
// Show (1) or hide (0) client buttons.
|
||||||
|
touch_setclientonly
|
||||||
|
|
||||||
|
// Removes all buttons from the screen.
|
||||||
|
touch_removeall
|
||||||
|
|
||||||
|
// Shows all available buttons in the configuration file.
|
||||||
|
touch_list
|
||||||
|
|
||||||
|
// Saves the config after editing. You can specify a new file name.
|
||||||
|
touch_config_file command.cfg
|
||||||
|
```
|
||||||
|
|
||||||
|
*The full list of buttons in the standard `touch.cfg` file, displayed in the console when using `touch_list`.*
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
## Adding new buttons
|
||||||
|
|
||||||
|
To add a new button, use the console command:
|
||||||
|
|
||||||
|
```
|
||||||
|
touch_addbutton "digits" "touch/key_1.png" "toggle_digits" 0.340000 0.782222 0.400000 0.888889 255 255 255 100 0
|
||||||
|
```
|
||||||
|
|
||||||
|
### Parameters of `touch_addbutton` command
|
||||||
|
|
||||||
|
| Parameter | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| `"digits"` | Unique name of the button. |
|
||||||
|
| `"touch/key_1.png"` | Path to the icon file (`.png` format). If the icon is not needed, leave `""`. |
|
||||||
|
| `"toggle_digits"` | Command to execute after clicking (for example, `"buy"` for purchase). |
|
||||||
|
| `0.340000` | X coordinate of the upper-left corner of the button. |
|
||||||
|
| `0.782222` | Y coordinate of the upper-left corner of the button. |
|
||||||
|
| `0.400000` | X coordinate of the lower-right corner of the button. |
|
||||||
|
| `0.888889` | Y coordinate of the lower-right corner of the button. |
|
||||||
|
| `255 255 255` | Button color in RGB format. |
|
||||||
|
| `100` | Button transparency (0 - fully transparent, 255 - fully opaque). |
|
||||||
|
| `0` | Flags (see next section). |
|
||||||
|
|
||||||
|
## List of flags
|
||||||
|
|
||||||
|
Flags define the behavior of the button. Their values are powers of two:
|
||||||
|
|
||||||
|
| Flag | Value | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `TOUCH_FL_HIDE` | 1 | Hides the button (not displayed in the game, but visible in the editor). |
|
||||||
|
| `TOUCH_FL_NOEDIT` | 2 | Disables editing of the button in the editor. |
|
||||||
|
| `TOUCH_FL_CLIENT` | 4 | The button is client-side (not saved in the main control file). |
|
||||||
|
| `TOUCH_FL_MP` | 8 | The button is displayed only in multiplayer. |
|
||||||
|
| `TOUCH_FL_SP` | 16 | The button is displayed only in singleplayer. |
|
||||||
|
| `TOUCH_FL_DEF_SHOW` | 32 | The button is always displayed on startup. |
|
||||||
|
| `TOUCH_FL_DEF_HIDE` | 64 | The button is always hidden on startup. |
|
||||||
|
| `TOUCH_FL_DRAW_ADDITIVE` | 128 | The button colors are added together in blend mode. |
|
||||||
|
| `TOUCH_FL_STROKE` | 256 | Enables outline stroke around the button. |
|
||||||
|
|
||||||
|
Flags can be combined by adding their values together. For example, `5 = 1 + 4` is the combination of `TOUCH_FL_HIDE` and `TOUCH_FL_CLIENT` flags, which is a hidden client button.
|
||||||
|
|
||||||
|
*In the image below, the `spray`, `scores`, `messagemode` buttons are displayed simultaneously with the flag 8 and `loadquick`, `savequick` with the flag 16, and each is displayed in the corresponding game mode.*
|
||||||
|

|
||||||
|
|
||||||
|
## Useful commands
|
||||||
|
|
||||||
|
* `touch_hide <pattern>`: hides buttons by pattern.
|
||||||
|
* `touch_setcommand`: changes the command bound to a button.
|
||||||
|
* `touch_settexture`: quickly changes the button image.
|
||||||
|
* `touch_setcolor`: sets the button color.
|
||||||
|
* `touch_exportconfig`: exports the current configuration, including aspect ratio.
|
||||||
|
|
||||||
|
## Usage examples
|
||||||
|
|
||||||
|
* `touch_hide menu*` hides all buttons with names starting with `menu`.
|
||||||
|
* `touch_setcolor "attack" 255 160 0 128` changes the color of the primary fire button from opaque white to translucent orange, similar to the color of the HUD in Half-Life.
|
||||||
|
|
||||||
|
*Result of executing this command*
|
||||||
|

|
||||||
|
|
||||||
|
* Example of adding a new button with a custom icon (the `lastinv` command is used - quick change between weapons)
|
||||||
|

|
||||||
|
|
||||||
|
*View of this button in layout editor*
|
||||||
|

|
||||||
|
|
||||||
|
## Tips
|
||||||
|
|
||||||
|
* To prevent the `look` and `move` buttons from interfering with editing other elements, place them before the others in the configuration file.
|
||||||
|
* And vice versa, to make a button appear on top of others, place it at the end of the configuration file.
|
||||||
|
* You can assign commands to buttons that change other buttons, see the previous section "Usage examples".
|
||||||
|
* After editing each parameter of each individual button in the Touch Buttons section, do not forget to press Save, otherwise the applied parameters will not be saved.
|
||||||
|
* To create your own icon for the button, you can use any graphics editor (for Android, Photo Editor by iudesk is suitable). Saving conditions:
|
||||||
|
* Image format - `.png` with transparency (e.g. alpha channel)
|
||||||
|
* Aspect ratio / size - 1:1 / 256x256
|
||||||
|
* Path to the icons location - `touch/gfx` inside game directory.
|
||||||
|
|
||||||
|
### Additional links
|
||||||
|
* [Handy palette for selecting color in RGB format](https://www.rapidtables.com/web/color/RGB_Color.html)
|
||||||
32
README.md
@@ -1,6 +1,7 @@
|
|||||||
# Xash3D FWGS Engine <img align="right" width="128" height="128" src="https://github.com/FWGS/xash3d-fwgs/raw/master/game_launch/icon-xash-material.png" alt="Xash3D FWGS icon" />
|
# Xash3D FWGS Engine <img align="right" width="128" height="128" src="https://github.com/FWGS/xash3d-fwgs/raw/master/game_launch/icon-xash-material.png" alt="Xash3D FWGS icon" />
|
||||||
[](https://builds.sr.ht/~a1batross/xash3d-fwgs?) [](https://github.com/FWGS/xash3d-fwgs/actions/workflows/c-cpp.yml) [](https://cirrus-ci.com/github/FWGS/xash3d-fwgs) [](http://fwgsdiscord.mentality.rip/) \
|
[](https://github.com/FWGS/xash3d-fwgs/actions/workflows/c-cpp.yml) [](https://cirrus-ci.com/github/FWGS/xash3d-fwgs) \
|
||||||
[](https://github.com/FWGS/xash3d-fwgs/releases/latest) [](https://github.com/FWGS/xash3d-fwgs/releases/tag/continuous)
|
[](http://fwgsdiscord.mentality.rip/) [](https://t.me/flyingwithgauss) \
|
||||||
|
[](https://github.com/FWGS/xash3d-fwgs/releases/tag/continuous)
|
||||||
|
|
||||||
Xash3D ([pronounced](https://ipa-reader.com/?text=ks%C9%91%CA%82) `[ksɑʂ]`) FWGS is a game engine, aimed to provide compatibility with Half-Life Engine and extend it, as well as to give game developers well known workflow.
|
Xash3D ([pronounced](https://ipa-reader.com/?text=ks%C9%91%CA%82) `[ksɑʂ]`) FWGS is a game engine, aimed to provide compatibility with Half-Life Engine and extend it, as well as to give game developers well known workflow.
|
||||||
|
|
||||||
@@ -35,6 +36,11 @@ You still needed to copy `valve` directory as all game resources located there.
|
|||||||
|
|
||||||
For additional info, run Xash3D with `-help` command line key.
|
For additional info, run Xash3D with `-help` command line key.
|
||||||
|
|
||||||
|
### Android
|
||||||
|
0) Install the APK file.
|
||||||
|
1) Copy `valve` directory to a folder named `xash` in the Internal storage.
|
||||||
|
2) Run games from within the app.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
* Before sending an issue, check if someone already reported your issue. Make sure you're following "How To Ask Questions The Smart Way" guide by Eric Steven Raymond. Read more: http://www.catb.org/~esr/faqs/smart-questions.html.
|
* Before sending an issue, check if someone already reported your issue. Make sure you're following "How To Ask Questions The Smart Way" guide by Eric Steven Raymond. Read more: http://www.catb.org/~esr/faqs/smart-questions.html.
|
||||||
* Issues are accepted in both English and Russian.
|
* Issues are accepted in both English and Russian.
|
||||||
@@ -43,7 +49,7 @@ For additional info, run Xash3D with `-help` command line key.
|
|||||||
## Build instructions
|
## Build instructions
|
||||||
We are using Waf build system. If you have some Waf-related questions, I recommend you to read [Waf Book](https://waf.io/book/).
|
We are using Waf build system. If you have some Waf-related questions, I recommend you to read [Waf Book](https://waf.io/book/).
|
||||||
|
|
||||||
NOTE: NEVER USE GitHub's ZIP ARCHIVES. GitHub doesn't include external dependencies we're using!
|
**NOTE: NEVER USE GitHub's ZIP ARCHIVES. GitHub doesn't include external dependencies we're using!**
|
||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
If your CPU is x86 compatible and you're on Windows or Linux, we are building 32-bit code by default. This was done to maintain compatibility with Steam releases of Half-Life and based on it's engine games.
|
If your CPU is x86 compatible and you're on Windows or Linux, we are building 32-bit code by default. This was done to maintain compatibility with Steam releases of Half-Life and based on it's engine games.
|
||||||
@@ -65,21 +71,30 @@ This repository contains our fork of HLSDK and restored source code for Half-Lif
|
|||||||
* Only for 32-bit engine on 64-bit x86 operating system:
|
* Only for 32-bit engine on 64-bit x86 operating system:
|
||||||
* Enable i386 on your system: `$ sudo dpkg --add-architecture i386`.
|
* Enable i386 on your system: `$ sudo dpkg --add-architecture i386`.
|
||||||
* Install `aptitude` ([why?](https://github.com/FWGS/xash3d-fwgs/issues/1828#issuecomment-2415131759)): `$ sudo apt update && sudo apt upgrade && sudo apt install aptitude`
|
* Install `aptitude` ([why?](https://github.com/FWGS/xash3d-fwgs/issues/1828#issuecomment-2415131759)): `$ sudo apt update && sudo apt upgrade && sudo apt install aptitude`
|
||||||
* Install development tools: `$ sudo aptitude --without-recommends install git build-essential gcc-multilib g++-multilib libsdl2-dev:i386 libfontconfig-dev:i386 libfreetype-dev:i386 libopus-dev:i386 libbz2-dev:i386`.
|
* Install development tools: `$ sudo aptitude --without-recommends install git build-essential gcc-multilib g++-multilib libsdl2-dev:i386 libfreetype-dev:i386 libopus-dev:i386 libbz2-dev:i386 libvorbis-dev:i386 libopusfile-dev:i386 libogg-dev:i386`.
|
||||||
* Set PKG_CONFIG_PATH environment variable to point at 32-bit libraries: `$ export PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig`.
|
* Set PKG_CONFIG_PATH environment variable to point at 32-bit libraries: `$ export PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig`.
|
||||||
|
|
||||||
* For 64-bit engine on 64-bit x86 and other non-x86 systems:
|
* For 64-bit engine on 64-bit x86 and other non-x86 systems:
|
||||||
* Install development tools: `$ sudo apt install git build-essential python libsdl2-dev libfontconfig-dev libfreetype6-dev libopus-dev libbz2-dev`.
|
* Install development tools: `$ sudo apt install git build-essential python libsdl2-dev libfreetype6-dev libopus-dev libbz2-dev libvorbis-dev libopusfile-dev libogg-dev`.
|
||||||
|
|
||||||
* Clone this repostory: `$ git clone --recursive https://github.com/FWGS/xash3d-fwgs`.
|
* Clone this repostory: `$ git clone --recursive https://github.com/FWGS/xash3d-fwgs`.
|
||||||
|
|
||||||
##### RedHat/Fedora
|
##### RedHat/Fedora
|
||||||
* Only for 32-bit engine on 64-bit x86 operating system:
|
* Only for 32-bit engine on 64-bit x86 operating system:
|
||||||
* Install development tools: `$ sudo dnf install git gcc gcc-c++ glibc-devel.i686 SDL2-devel.i686 opus-devel.i686 fontconfig-devel.i686 freetype-devel.i686 bzip2-devel.i686`.
|
* Install development tools: `$ sudo dnf install git gcc gcc-c++ glibc-devel.i686 SDL2-devel.i686 opus-devel.i686 freetype-devel.i686 bzip2-devel.i686 libvorbis-devel.i686 opusfile-devel.i686 libogg-devel.i686`.
|
||||||
* Set PKG_CONFIG_PATH environment variable to point at 32-bit libraries: `$ export PKG_CONFIG_PATH=/usr/lib/pkgconfig`.
|
* Set PKG_CONFIG_PATH environment variable to point at 32-bit libraries: `$ export PKG_CONFIG_PATH=/usr/lib/pkgconfig`.
|
||||||
|
|
||||||
* For 64-bit engine on 64-bit x86 and other non-x86 systems:
|
* For 64-bit engine on 64-bit x86 and other non-x86 systems:
|
||||||
* Install development tools: `$ sudo dnf install git gcc gcc-c++ SDL2-devel opus-devel fontconfig-devel freetype-devel bzip2-devel`.
|
* Install development tools: `$ sudo dnf install git gcc gcc-c++ SDL2-devel opus-devel freetype-devel bzip2-devel libvorbis-devel opusfile-devel libogg-devel`.
|
||||||
|
|
||||||
|
* Clone this repostory: `$ git clone --recursive https://github.com/FWGS/xash3d-fwgs`.
|
||||||
|
|
||||||
|
#### Android (Windows/Linux/macOS)
|
||||||
|
* Install [Android Studio](https://developer.android.com/studio) (or the command line tools).
|
||||||
|
* Install [Python](https://python.org) (at least 2.7, latest is better).
|
||||||
|
* Install [Git](https://git-scm.com/download/win).
|
||||||
|
* Install [Ninja](https://ninja-build.org/).
|
||||||
|
* Install [CMake](https://cmake.org/) (for some dependencies).
|
||||||
|
|
||||||
* Clone this repostory: `$ git clone --recursive https://github.com/FWGS/xash3d-fwgs`.
|
* Clone this repostory: `$ git clone --recursive https://github.com/FWGS/xash3d-fwgs`.
|
||||||
|
|
||||||
@@ -99,3 +114,6 @@ If compiling 32-bit on amd64, make sure `PKG_CONFIG_PATH` from the previous step
|
|||||||
1) Configure build: `./waf configure` (you need to pass `-8` to compile 64-bit engine on 64-bit x86 processor).
|
1) Configure build: `./waf configure` (you need to pass `-8` to compile 64-bit engine on 64-bit x86 processor).
|
||||||
2) Compile: `./waf build`.
|
2) Compile: `./waf build`.
|
||||||
3) Install: `./waf install --destdir=/path/to/any/output/directory`.
|
3) Install: `./waf install --destdir=/path/to/any/output/directory`.
|
||||||
|
|
||||||
|
#### Android (Windows/Linux/macOS)
|
||||||
|
You can just open the `android` folder in Android Studio and build from here, or use `gradlew` to build from command line.
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.6)
|
|
||||||
|
|
||||||
# Only used to build Android project
|
|
||||||
|
|
||||||
project(XASH_ANDROID)
|
|
||||||
|
|
||||||
# armeabi-v7a requires cpufeatures library
|
|
||||||
include(AndroidNdkModules)
|
|
||||||
android_ndk_import_module_cpufeatures()
|
|
||||||
|
|
||||||
find_package(PythonInterp 2.7 REQUIRED)
|
|
||||||
|
|
||||||
get_filename_component(C_COMPILER_ID ${CMAKE_C_COMPILER} NAME_WE)
|
|
||||||
get_filename_component(CXX_COMPILER_ID ${CMAKE_CXX_COMPILER} NAME_WE)
|
|
||||||
|
|
||||||
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
|
|
||||||
set(BUILD_TYPE "debug")
|
|
||||||
else()
|
|
||||||
set(BUILD_TYPE "release")
|
|
||||||
list(APPEND WAF_EXTRA_ARGS --enable-poly-opt --enable-lto)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(CMAKE_SIZEOF_VOID_P MATCHES "8")
|
|
||||||
set(64BIT ON CACHE BOOL "" FORCE)
|
|
||||||
list(APPEND WAF_EXTRA_ARGS -8) # only required for x86 when testing this cmakelist under linux
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(CMAKE_VERBOSE_MAKEFILE ON)
|
|
||||||
|
|
||||||
set(WAF_CC "${CMAKE_C_COMPILER} --target=${CMAKE_C_COMPILER_TARGET}")
|
|
||||||
set(WAF_CXX "${CMAKE_CXX_COMPILER} --target=${CMAKE_CXX_COMPILER_TARGET}")
|
|
||||||
|
|
||||||
# not cleanest way to get upper directory
|
|
||||||
set(ENGINE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../")
|
|
||||||
|
|
||||||
execute_process(
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E env
|
|
||||||
CC=${WAF_CC} CXX=${WAF_CXX}
|
|
||||||
AR=${CMAKE_AR} STRIP=${CMAKE_STRIP}
|
|
||||||
${PYTHON_EXECUTABLE} waf configure -T ${BUILD_TYPE} ${WAF_EXTRA_ARGS} cmake
|
|
||||||
--check-c-compiler=${C_COMPILER_ID} --check-cxx-compiler=${CXX_COMPILER_ID}
|
|
||||||
-s "${ENGINE_SOURCE_DIR}/SDL" --skip-sdl2-sanity-check --enable-bundled-deps
|
|
||||||
WORKING_DIRECTORY "${ENGINE_SOURCE_DIR}"
|
|
||||||
)
|
|
||||||
|
|
||||||
add_subdirectory("${ENGINE_SOURCE_DIR}/3rdparty/hlsdk-portable" hlsdk-portable)
|
|
||||||
|
|
||||||
# try to build minimal SDL. Enable features as we're gonna use them
|
|
||||||
set(SDL_RENDER OFF)
|
|
||||||
set(SDL_POWER OFF)
|
|
||||||
set(SDL_VULKAN OFF)
|
|
||||||
set(SDL_DISKAUDIO OFF)
|
|
||||||
set(SDL_DUMMYAUDIO OFF)
|
|
||||||
set(SDL_DUMMYVIDEO OFF)
|
|
||||||
set(SDL_VULKAN OFF)
|
|
||||||
set(SDL_OFFSCREEN OFF)
|
|
||||||
set(SDL_STATIC OFF)
|
|
||||||
add_subdirectory("${ENGINE_SOURCE_DIR}/3rdparty/SDL" SDL)
|
|
||||||
add_subdirectory("${ENGINE_SOURCE_DIR}/" xash3d-fwgs)
|
|
||||||
add_subdirectory("${ENGINE_SOURCE_DIR}/3rdparty/mainui" mainui)
|
|
||||||
@@ -1,129 +1,140 @@
|
|||||||
|
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import java.time.Month
|
import java.time.Month
|
||||||
import java.time.temporal.ChronoUnit
|
import java.time.temporal.ChronoUnit
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("com.android.application")
|
alias(libs.plugins.android.application)
|
||||||
id("org.jetbrains.kotlin.android")
|
alias(libs.plugins.kotlin.android)
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "su.xash.engine"
|
namespace = "su.xash.engine"
|
||||||
ndkVersion = "27.2.12479018"
|
ndkVersion = "28.2.13676358"
|
||||||
|
compileSdk = 35
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "su.xash"
|
applicationId = "su.xash.engine"
|
||||||
applicationIdSuffix = "engine"
|
versionName = "0.21-" + getGitHash()
|
||||||
versionName = "0.21"
|
versionCode = getBuildNum()
|
||||||
versionCode = getBuildNum()
|
minSdk = 21
|
||||||
minSdk = 21
|
targetSdk = 35
|
||||||
targetSdk = 34
|
|
||||||
compileSdk = 34
|
|
||||||
|
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
val engineRoot = projectDir.parentFile.parent
|
||||||
abiFilters("armeabi-v7a", "arm64-v8a", "x86", "x86_64")
|
|
||||||
arguments("-DANDROID_USE_LEGACY_TOOLCHAIN_FILE=OFF")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
externalNativeBuild {
|
experimentalProperties["ninja.abiFilters"] = setOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64")
|
||||||
cmake {
|
experimentalProperties["ninja.path"] = File(engineRoot, "wscript").path
|
||||||
version = "3.22.1"
|
experimentalProperties["ninja.configure"] = "run-python"
|
||||||
path = file("CMakeLists.txt")
|
experimentalProperties["ninja.arguments"] = setOf(
|
||||||
}
|
File(engineRoot, "scripts/configure-ninja.py").path,
|
||||||
}
|
engineRoot,
|
||||||
|
"--variant=\${ndk.variantName}",
|
||||||
|
"--abi=\${ndk.abi}",
|
||||||
|
"--configuration-dir=\${ndk.buildRoot}",
|
||||||
|
"--ndk-version=\${ndk.moduleNdkVersion}",
|
||||||
|
"--min-sdk-version=\${ndk.minPlatform}",
|
||||||
|
"--ndk-root=${android.ndkDirectory}",
|
||||||
|
// shut up, fake options
|
||||||
|
"-p:Configuration=\${ndk.variantName}",
|
||||||
|
"-p:Platform=\${ndk.abi}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
sourceCompatibility = JavaVersion.VERSION_11
|
||||||
targetCompatibility = JavaVersion.VERSION_1_8
|
targetCompatibility = JavaVersion.VERSION_11
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlinOptions {
|
kotlin {
|
||||||
jvmTarget = "1.8"
|
compilerOptions {
|
||||||
}
|
jvmTarget = JvmTarget.JVM_11
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildFeatures {
|
||||||
debug {
|
viewBinding = true
|
||||||
isMinifyEnabled = false
|
buildConfig = true
|
||||||
isShrinkResources = false
|
}
|
||||||
isDebuggable = true
|
|
||||||
applicationIdSuffix = ".test"
|
|
||||||
proguardFiles(
|
|
||||||
getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
release {
|
lint {
|
||||||
isMinifyEnabled = true
|
abortOnError = false
|
||||||
isShrinkResources = true
|
}
|
||||||
proguardFiles(
|
|
||||||
getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
register("asan") {
|
/*
|
||||||
initWith(getByName("debug"))
|
androidResources {
|
||||||
}
|
noCompress += ""
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
register("continuous") {
|
packaging {
|
||||||
initWith(getByName("release"))
|
jniLibs {
|
||||||
applicationIdSuffix = ".test"
|
keepDebugSymbols.add("**/*.so")
|
||||||
}
|
useLegacyPackaging = true
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
getByName("main") {
|
getByName("main") {
|
||||||
assets.srcDirs("../../3rdparty/extras/xash-extras", "../moddb")
|
assets.srcDirs("../../3rdparty/extras/xash-extras")
|
||||||
java.srcDir("../../3rdparty/SDL/android-project/app/src/main/java")
|
java.srcDir("../../3rdparty/SDL/android-project/app/src/main/java")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lint {
|
buildTypes {
|
||||||
abortOnError = false
|
debug {
|
||||||
}
|
isMinifyEnabled = false
|
||||||
|
isShrinkResources = false
|
||||||
|
isDebuggable = true
|
||||||
|
applicationIdSuffix = ".test"
|
||||||
|
proguardFiles(
|
||||||
|
getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
buildFeatures {
|
release {
|
||||||
viewBinding = true
|
isMinifyEnabled = true
|
||||||
buildConfig = true
|
isShrinkResources = true
|
||||||
}
|
proguardFiles(
|
||||||
|
getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
androidResources {
|
register("asan") {
|
||||||
noCompress += ""
|
initWith(getByName("debug"))
|
||||||
}
|
}
|
||||||
|
|
||||||
packaging {
|
register("continuous") {
|
||||||
jniLibs {
|
initWith(getByName("release"))
|
||||||
useLegacyPackaging = true
|
applicationIdSuffix = ".test"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("com.google.android.material:material:1.11.0")
|
implementation(libs.material)
|
||||||
implementation("androidx.appcompat:appcompat:1.6.1")
|
|
||||||
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
|
|
||||||
implementation("androidx.navigation:navigation-fragment-ktx:2.7.7")
|
|
||||||
implementation("androidx.navigation:navigation-ui-ktx:2.7.7")
|
|
||||||
implementation("androidx.cardview:cardview:1.0.0")
|
|
||||||
implementation("androidx.annotation:annotation:1.7.1")
|
|
||||||
implementation("androidx.fragment:fragment-ktx:1.6.2")
|
|
||||||
implementation("androidx.preference:preference-ktx:1.2.1")
|
|
||||||
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
|
|
||||||
implementation("androidx.work:work-runtime-ktx:2.9.0")
|
|
||||||
// implementation "androidx.legacy:legacy-support-v4:1.0.0"
|
|
||||||
|
|
||||||
implementation("com.madgag.spongycastle:prov:1.58.0.0")
|
implementation(libs.appcompat)
|
||||||
implementation("in.dragonbra:javasteam:1.2.0")
|
implementation(libs.navigation.runtime.ktx)
|
||||||
|
implementation(libs.navigation.fragment.ktx)
|
||||||
|
implementation(libs.navigation.ui.ktx)
|
||||||
|
implementation(libs.preference.ktx)
|
||||||
|
implementation(libs.swiperefreshlayout)
|
||||||
|
|
||||||
implementation("ch.acra:acra-http:5.11.2")
|
implementation(libs.acra.http)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getBuildNum(): Int {
|
fun getBuildNum(): Int {
|
||||||
val now = LocalDateTime.now()
|
val now = LocalDateTime.now()
|
||||||
val releaseDate = LocalDateTime.of(2015, Month.APRIL, 1, 0, 0, 0)
|
val releaseDate = LocalDateTime.of(2015, Month.APRIL, 1, 0, 0, 0)
|
||||||
val qBuildNum = releaseDate.until(now, ChronoUnit.DAYS)
|
val qBuildNum = releaseDate.until(now, ChronoUnit.DAYS)
|
||||||
val minuteOfDay = now.hour * 60 + now.minute
|
val minuteOfDay = now.hour * 60 + now.minute
|
||||||
return (qBuildNum * 10000 + minuteOfDay).toInt()
|
return (qBuildNum * 10000 + minuteOfDay).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getGitHash(): String {
|
||||||
|
val process = ProcessBuilder("git", "rev-parse", "--short", "HEAD").directory(project.rootDir)
|
||||||
|
.redirectErrorStream(true).start()
|
||||||
|
return process.inputStream.bufferedReader().readText().trim()
|
||||||
}
|
}
|
||||||
|
|||||||
27
android/app/proguard-rules.pro
vendored
@@ -1,3 +1,25 @@
|
|||||||
|
# Add project specific ProGuard rules here.
|
||||||
|
# You can control the set of applied configuration files using the
|
||||||
|
# proguardFiles setting in build.gradle.
|
||||||
|
#
|
||||||
|
# For more details, see
|
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following
|
||||||
|
# and specify the fully qualified class name to the JavaScript interface
|
||||||
|
# class:
|
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||||
|
# public *;
|
||||||
|
#}
|
||||||
|
|
||||||
|
# Uncomment this to preserve the line number information for
|
||||||
|
# debugging stack traces.
|
||||||
|
#-keepattributes SourceFile,LineNumberTable
|
||||||
|
|
||||||
|
# If you keep the line number information, uncomment this to
|
||||||
|
# hide the original source file name.
|
||||||
|
#-renamesourcefileattribute SourceFile
|
||||||
|
|
||||||
-keep class su.xash.engine.XashActivity {
|
-keep class su.xash.engine.XashActivity {
|
||||||
java.lang.String loadAndroidID();
|
java.lang.String loadAndroidID();
|
||||||
java.lang.String getAndroidID();
|
java.lang.String getAndroidID();
|
||||||
@@ -87,3 +109,8 @@
|
|||||||
void hapticRun(int, float, int);
|
void hapticRun(int, float, int);
|
||||||
void hapticStop(int);
|
void hapticStop(int);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Unexpected reference to missing service class: META-INF/services/javax.annotation.processing.Processor.
|
||||||
|
-dontwarn javax.annotation.processing.Processor
|
||||||
|
-dontwarn javax.annotation.processing.AbstractProcessor
|
||||||
|
-dontwarn javax.annotation.processing.SupportedOptions
|
||||||
|
|||||||
3
android/app/run-python
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
exec python $@
|
||||||
1
android/app/run-python.bat
Normal file
@@ -0,0 +1 @@
|
|||||||
|
python %*
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name" translatable="false">Xash3D FWGS (Test)</string>
|
<string name="app_name" translatable="false">Xash3D FWGS (Test)</string>
|
||||||
<string name="authority" translatable="false">su.xash.engine.test.documents</string>
|
</resources>
|
||||||
</resources>
|
|
||||||
|
|||||||
@@ -1,101 +1,89 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
android:allowAudioPlaybackCapture="true"
|
||||||
android:allowAudioPlaybackCapture="true"
|
android:installLocation="preferExternal">
|
||||||
android:installLocation="preferExternal"
|
<!-- OpenGL ES 1.1 -->
|
||||||
tools:targetApi="q">
|
<uses-feature android:glEsVersion="0x00010000" />
|
||||||
<!-- OpenGL ES 1.1 -->
|
<!-- Touchscreen support -->
|
||||||
<uses-feature android:glEsVersion="0x00010000" />
|
<uses-feature
|
||||||
<!-- Touchscreen support -->
|
android:name="android.hardware.touchscreen"
|
||||||
<uses-feature
|
android:required="false" />
|
||||||
android:name="android.hardware.touchscreen"
|
<!-- Game controller support -->
|
||||||
android:required="false" />
|
<uses-feature
|
||||||
<!-- Game controller support -->
|
android:name="android.hardware.bluetooth"
|
||||||
<uses-feature
|
android:required="false" />
|
||||||
android:name="android.hardware.bluetooth"
|
<uses-feature
|
||||||
android:required="false" />
|
android:name="android.hardware.gamepad"
|
||||||
<uses-feature
|
android:required="false" />
|
||||||
android:name="android.hardware.gamepad"
|
<uses-feature
|
||||||
android:required="false" />
|
android:name="android.hardware.usb.host"
|
||||||
<uses-feature
|
android:required="false" />
|
||||||
android:name="android.hardware.usb.host"
|
<!-- External mouse input events -->
|
||||||
android:required="false" />
|
<uses-feature
|
||||||
<!-- External mouse input events -->
|
android:name="android.hardware.type.pc"
|
||||||
<uses-feature
|
android:required="false" />
|
||||||
android:name="android.hardware.type.pc"
|
<!-- Audio recording support -->
|
||||||
android:required="false" />
|
<uses-feature
|
||||||
<!-- Audio recording support -->
|
android:name="android.hardware.microphone"
|
||||||
<uses-feature
|
android:required="false" />
|
||||||
android:name="android.hardware.microphone"
|
<!-- Allow downloading to the external storage on Android 5.1 and older -->
|
||||||
android:required="false" />
|
<uses-permission
|
||||||
<!-- Allow downloading to the external storage on Android 5.1 and older -->
|
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||||
<uses-permission
|
android:maxSdkVersion="22" />
|
||||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
<uses-permission
|
||||||
android:maxSdkVersion="22" />
|
android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
|
android:maxSdkVersion="32" />
|
||||||
android:maxSdkVersion="32" />
|
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
|
||||||
<!-- Allow access to Bluetooth devices -->
|
<!-- Allow access to Bluetooth devices -->
|
||||||
<!-- Currently this is just for Steam Controller support and requires setting SDL_HINT_JOYSTICK_HIDAPI_STEAM -->
|
<!-- Currently this is just for Steam Controller support and requires setting SDL_HINT_JOYSTICK_HIDAPI_STEAM -->
|
||||||
<uses-permission
|
<uses-permission
|
||||||
android:name="android.permission.BLUETOOTH"
|
android:name="android.permission.BLUETOOTH"
|
||||||
android:maxSdkVersion="30" />
|
android:maxSdkVersion="30" />
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||||||
<!-- Allow access to the vibrator -->
|
<!-- Allow access to the vibrator -->
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
<!-- Allow recording audio -->
|
<!-- Allow recording audio -->
|
||||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||||
<!-- Allow internet access -->
|
<!-- Allow internet access -->
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<!-- Dedicated server -->
|
<!-- Dedicated server -->
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".MainApplication"
|
android:name=".MainApplication"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:roundIcon="@mipmap/ic_launcher"
|
android:roundIcon="@mipmap/ic_launcher"
|
||||||
android:theme="@style/Theme.App"
|
android:theme="@style/Theme.App"
|
||||||
android:usesCleartextTraffic="true">
|
android:usesCleartextTraffic="true"
|
||||||
<activity
|
android:requestLegacyExternalStorage="true">
|
||||||
android:name=".MainActivity"
|
<activity
|
||||||
android:exported="true">
|
android:name=".MainActivity"
|
||||||
<intent-filter>
|
android:exported="true">
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".XashActivity"
|
android:name=".XashActivity"
|
||||||
android:alwaysRetainTaskState="true"
|
android:alwaysRetainTaskState="true"
|
||||||
android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation|touchscreen"
|
android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation|touchscreen"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
android:preferMinimalPostProcessing="true"
|
android:preferMinimalPostProcessing="true"
|
||||||
android:windowSoftInputMode="adjustResize"
|
android:windowSoftInputMode="adjustResize">
|
||||||
tools:targetApi="r">
|
<intent-filter>
|
||||||
<intent-filter>
|
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
|
||||||
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
|
</intent-filter>
|
||||||
</intent-filter>
|
</activity>
|
||||||
</activity>
|
</application>
|
||||||
|
<queries>
|
||||||
<provider
|
<intent>
|
||||||
android:name=".XashDocumentsProvider"
|
<action android:name="su.xash.engine.MOD" />
|
||||||
android:authorities="@string/authority"
|
</intent>
|
||||||
android:exported="true"
|
</queries>
|
||||||
android:grantUriPermissions="true"
|
</manifest>
|
||||||
android:permission="android.permission.MANAGE_DOCUMENTS">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.content.action.DOCUMENTS_PROVIDER" />
|
|
||||||
</intent-filter>
|
|
||||||
</provider>
|
|
||||||
</application>
|
|
||||||
|
|
||||||
<queries>
|
|
||||||
<intent>
|
|
||||||
<action android:name="su.xash.engine.MOD" />
|
|
||||||
</intent>
|
|
||||||
</queries>
|
|
||||||
</manifest>
|
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
package su.xash.engine;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.FrameLayout;
|
|
||||||
|
|
||||||
public class AndroidBug5497Workaround {
|
|
||||||
// For more information, see https://code.google.com/p/android/issues/detail?id=5497
|
|
||||||
// To use this class, simply invoke assistActivity() on an Activity that already has its content view set.
|
|
||||||
|
|
||||||
public static void assistActivity(Activity activity) {
|
|
||||||
new AndroidBug5497Workaround(activity);
|
|
||||||
}
|
|
||||||
|
|
||||||
private View mChildOfContent;
|
|
||||||
private int usableHeightPrevious;
|
|
||||||
private FrameLayout.LayoutParams frameLayoutParams;
|
|
||||||
|
|
||||||
private AndroidBug5497Workaround(Activity activity) {
|
|
||||||
FrameLayout content = activity.findViewById(android.R.id.content);
|
|
||||||
mChildOfContent = content.getChildAt(0);
|
|
||||||
mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(this::possiblyResizeChildOfContent);
|
|
||||||
frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void possiblyResizeChildOfContent() {
|
|
||||||
int usableHeightNow = computeUsableHeight();
|
|
||||||
if (usableHeightNow != usableHeightPrevious) {
|
|
||||||
int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();
|
|
||||||
int heightDifference = usableHeightSansKeyboard - usableHeightNow;
|
|
||||||
if (heightDifference > (usableHeightSansKeyboard / 4)) {
|
|
||||||
// keyboard probably just became visible
|
|
||||||
frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
|
|
||||||
} else {
|
|
||||||
// keyboard probably just became hidden
|
|
||||||
frameLayoutParams.height = usableHeightSansKeyboard;
|
|
||||||
}
|
|
||||||
mChildOfContent.requestLayout();
|
|
||||||
usableHeightPrevious = usableHeightNow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int computeUsableHeight() {
|
|
||||||
Rect r = new Rect();
|
|
||||||
mChildOfContent.getWindowVisibleDisplayFrame(r);
|
|
||||||
return (r.bottom - r.top);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
package su.xash.engine
|
package su.xash.engine
|
||||||
|
|
||||||
class DedicatedActivity {
|
class DedicatedActivity {}
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import android.app.Service
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
|
|
||||||
class DedicatedService: Service() {
|
class DedicatedService : Service() {
|
||||||
override fun onBind(intent: Intent?): IBinder? {
|
override fun onBind(intent: Intent?): IBinder? {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,26 +10,26 @@ import androidx.navigation.ui.setupActionBarWithNavController
|
|||||||
import su.xash.engine.databinding.ActivityMainBinding
|
import su.xash.engine.databinding.ActivityMainBinding
|
||||||
|
|
||||||
class MainActivity : AppCompatActivity() {
|
class MainActivity : AppCompatActivity() {
|
||||||
private lateinit var binding: ActivityMainBinding
|
private lateinit var binding: ActivityMainBinding
|
||||||
private lateinit var appBarConfiguration: AppBarConfiguration
|
private lateinit var appBarConfiguration: AppBarConfiguration
|
||||||
private lateinit var navController: NavController
|
private lateinit var navController: NavController
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
|
|
||||||
setSupportActionBar(binding.toolbar)
|
setSupportActionBar(binding.toolbar)
|
||||||
|
|
||||||
val navHostFragment =
|
val navHostFragment =
|
||||||
supportFragmentManager.findFragmentById(R.id.fragmentContainerView) as NavHostFragment
|
supportFragmentManager.findFragmentById(R.id.fragmentContainerView) as NavHostFragment
|
||||||
navController = navHostFragment.navController
|
navController = navHostFragment.navController
|
||||||
appBarConfiguration = AppBarConfiguration(navController.graph)
|
appBarConfiguration = AppBarConfiguration(navController.graph)
|
||||||
setupActionBarWithNavController(navController, appBarConfiguration)
|
setupActionBarWithNavController(navController, appBarConfiguration)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSupportNavigateUp(): Boolean {
|
override fun onSupportNavigateUp(): Boolean {
|
||||||
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
|
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,26 +3,25 @@ package su.xash.engine
|
|||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.StrictMode
|
import android.os.StrictMode
|
||||||
import org.acra.config.httpSender
|
|
||||||
import org.acra.data.StringFormat
|
import org.acra.data.StringFormat
|
||||||
import org.acra.ktx.initAcra
|
import org.acra.ktx.initAcra
|
||||||
|
|
||||||
class MainApplication : Application() {
|
class MainApplication : Application() {
|
||||||
override fun attachBaseContext(base: Context?) {
|
override fun attachBaseContext(base: Context?) {
|
||||||
super.attachBaseContext(base)
|
super.attachBaseContext(base)
|
||||||
|
|
||||||
if (!BuildConfig.DEBUG) {
|
if (!BuildConfig.DEBUG) {
|
||||||
initAcra {
|
initAcra {
|
||||||
buildConfigClass = BuildConfig::class.java
|
buildConfigClass = BuildConfig::class.java
|
||||||
reportFormat = StringFormat.JSON
|
reportFormat = StringFormat.JSON
|
||||||
|
|
||||||
httpSender {
|
// httpSender {
|
||||||
uri = "http://bodis.pp.ua:5000/report"
|
// uri = "http://bodis.pp.ua:5000/report"
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// enable strict mode to detect memory leaks etc.
|
// enable strict mode to detect memory leaks etc.
|
||||||
StrictMode.enableDefaults();
|
StrictMode.enableDefaults();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import android.content.pm.ActivityInfo;
|
|||||||
import android.content.res.AssetManager;
|
import android.content.res.AssetManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Environment;
|
||||||
import android.provider.Settings.Secure;
|
import android.provider.Settings.Secure;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
@@ -12,137 +13,142 @@ import android.view.WindowManager;
|
|||||||
|
|
||||||
import org.libsdl.app.SDLActivity;
|
import org.libsdl.app.SDLActivity;
|
||||||
|
|
||||||
|
import su.xash.engine.util.AndroidBug5497Workaround;
|
||||||
|
|
||||||
public class XashActivity extends SDLActivity {
|
public class XashActivity extends SDLActivity {
|
||||||
private boolean mUseVolumeKeys;
|
private boolean mUseVolumeKeys;
|
||||||
private String mPackageName;
|
private String mPackageName;
|
||||||
private static final String TAG = "XashActivity";
|
private static final String TAG = "XashActivity";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
|
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
//getWindow().addFlags(WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES);
|
//getWindow().addFlags(WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES);
|
||||||
getWindow().getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
|
getWindow().getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
|
||||||
}
|
}
|
||||||
|
|
||||||
AndroidBug5497Workaround.assistActivity(this);
|
AndroidBug5497Workaround.assistActivity(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy()
|
public void onDestroy() {
|
||||||
{
|
super.onDestroy();
|
||||||
super.onDestroy();
|
|
||||||
|
|
||||||
// Now that we don't exit from native code, we need to exit here, resetting
|
// Now that we don't exit from native code, we need to exit here, resetting
|
||||||
// application state (actually global variables that we don't cleanup on exit)
|
// application state (actually global variables that we don't cleanup on exit)
|
||||||
//
|
//
|
||||||
// When the issue with global variables will be resolved, remove that exit() call
|
// When the issue with global variables will be resolved, remove that exit() call
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String[] getLibraries() {
|
protected String[] getLibraries() {
|
||||||
return new String[]{"SDL2", "xash"};
|
return new String[]{"SDL2", "xash"};
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("HardwareIds")
|
@SuppressLint("HardwareIds")
|
||||||
private String getAndroidID() {
|
private String getAndroidID() {
|
||||||
return Secure.getString(getContentResolver(), Secure.ANDROID_ID);
|
return Secure.getString(getContentResolver(), Secure.ANDROID_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("ApplySharedPref")
|
@SuppressLint("ApplySharedPref")
|
||||||
private void saveAndroidID(String id) {
|
private void saveAndroidID(String id) {
|
||||||
getSharedPreferences("xash_preferences", MODE_PRIVATE).edit().putString("xash_id", id).commit();
|
getSharedPreferences("xash_preferences", MODE_PRIVATE).edit().putString("xash_id", id).commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String loadAndroidID() {
|
private String loadAndroidID() {
|
||||||
return getSharedPreferences("xash_preferences", MODE_PRIVATE).getString("xash_id", "");
|
return getSharedPreferences("xash_preferences", MODE_PRIVATE).getString("xash_id", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getCallingPackage() {
|
public String getCallingPackage() {
|
||||||
if (mPackageName != null) {
|
if (mPackageName != null) {
|
||||||
return mPackageName;
|
return mPackageName;
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.getCallingPackage();
|
return super.getCallingPackage();
|
||||||
}
|
}
|
||||||
|
|
||||||
private AssetManager getAssets(boolean isEngine) {
|
private AssetManager getAssets(boolean isEngine) {
|
||||||
AssetManager am = null;
|
AssetManager am = null;
|
||||||
|
|
||||||
if (isEngine) {
|
if (isEngine) {
|
||||||
am = getAssets();
|
am = getAssets();
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
am = getPackageManager().getResourcesForApplication(getCallingPackage()).getAssets();
|
am = getPackageManager().getResourcesForApplication(getCallingPackage()).getAssets();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(TAG, "Unable to load mod assets!");
|
Log.e(TAG, "Unable to load mod assets!");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return am;
|
return am;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String[] getAssetsList(boolean isEngine, String path) {
|
private String[] getAssetsList(boolean isEngine, String path) {
|
||||||
AssetManager am = getAssets(isEngine);
|
AssetManager am = getAssets(isEngine);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return am.list(path);
|
return am.list(path);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new String[]{};
|
return new String[]{};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||||
if (SDLActivity.mBrokenLibraries) {
|
if (SDLActivity.mBrokenLibraries) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int keyCode = event.getKeyCode();
|
int keyCode = event.getKeyCode();
|
||||||
if (!mUseVolumeKeys) {
|
if (!mUseVolumeKeys) {
|
||||||
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||
|
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_CAMERA || keyCode == KeyEvent.KEYCODE_ZOOM_IN || keyCode == KeyEvent.KEYCODE_ZOOM_OUT) {
|
||||||
keyCode == KeyEvent.KEYCODE_VOLUME_UP ||
|
return false;
|
||||||
keyCode == KeyEvent.KEYCODE_CAMERA ||
|
}
|
||||||
keyCode == KeyEvent.KEYCODE_ZOOM_IN ||
|
}
|
||||||
keyCode == KeyEvent.KEYCODE_ZOOM_OUT) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return getWindow().superDispatchKeyEvent(event);
|
return getWindow().superDispatchKeyEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: REMOVE LATER, temporary launchers support?
|
// TODO: REMOVE LATER, temporary launchers support?
|
||||||
@Override
|
@Override
|
||||||
protected String[] getArguments() {
|
protected String[] getArguments() {
|
||||||
String gamedir = getIntent().getStringExtra("gamedir");
|
String gamedir = getIntent().getStringExtra("gamedir");
|
||||||
if (gamedir == null) gamedir = "valve";
|
if (gamedir == null) gamedir = "valve";
|
||||||
nativeSetenv("XASH3D_GAME", gamedir);
|
nativeSetenv("XASH3D_GAME", gamedir);
|
||||||
|
|
||||||
String gamelibdir = getIntent().getStringExtra("gamelibdir");
|
String gamelibdir = getIntent().getStringExtra("gamelibdir");
|
||||||
if (gamelibdir != null) nativeSetenv("XASH3D_GAMELIBDIR", gamelibdir);
|
if (gamelibdir != null) nativeSetenv("XASH3D_GAMELIBDIR", gamelibdir);
|
||||||
|
|
||||||
String pakfile = getIntent().getStringExtra("pakfile");
|
String pakfile = getIntent().getStringExtra("pakfile");
|
||||||
if (pakfile != null) nativeSetenv("XASH3D_EXTRAS_PAK2", pakfile);
|
if (pakfile != null) nativeSetenv("XASH3D_EXTRAS_PAK2", pakfile);
|
||||||
|
|
||||||
mUseVolumeKeys = getIntent().getBooleanExtra("usevolume", false);
|
String basedir = getIntent().getStringExtra("basedir");
|
||||||
mPackageName = getIntent().getStringExtra("package");
|
if (basedir != null) {
|
||||||
|
nativeSetenv("XASH3D_BASEDIR", basedir);
|
||||||
|
} else {
|
||||||
|
String rootPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/xash";
|
||||||
|
nativeSetenv("XASH3D_BASEDIR", rootPath);
|
||||||
|
}
|
||||||
|
|
||||||
String[] env = getIntent().getStringArrayExtra("env");
|
mUseVolumeKeys = getIntent().getBooleanExtra("usevolume", false);
|
||||||
if (env != null) {
|
mPackageName = getIntent().getStringExtra("package");
|
||||||
for (int i = 0; i < env.length; i += 2)
|
|
||||||
nativeSetenv(env[i], env[i + 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
String argv = getIntent().getStringExtra("argv");
|
String[] env = getIntent().getStringArrayExtra("env");
|
||||||
if (argv == null) argv = "-console -log";
|
if (env != null) {
|
||||||
return argv.split(" ");
|
for (int i = 0; i < env.length; i += 2)
|
||||||
}
|
nativeSetenv(env[i], env[i + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
String argv = getIntent().getStringExtra("argv");
|
||||||
|
if (argv == null) argv = "-console -log";
|
||||||
|
return argv.split(" ");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,253 +0,0 @@
|
|||||||
package su.xash.engine;
|
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.content.res.AssetFileDescriptor;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.database.MatrixCursor;
|
|
||||||
import android.graphics.Point;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.CancellationSignal;
|
|
||||||
import android.os.ParcelFileDescriptor;
|
|
||||||
import android.provider.DocumentsContract.Document;
|
|
||||||
import android.provider.DocumentsContract.Root;
|
|
||||||
import android.provider.DocumentsProvider;
|
|
||||||
import android.webkit.MimeTypeMap;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.KITKAT)
|
|
||||||
public class XashDocumentsProvider extends DocumentsProvider {
|
|
||||||
private static final String ALL_MIME_TYPES = "*/*";
|
|
||||||
private File mRootDir;
|
|
||||||
|
|
||||||
private static final String TAG = "XashDocumentsProvider";
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCreate() {
|
|
||||||
mRootDir = getContext().getExternalFilesDir(null);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String[] DEFAULT_ROOT_PROJECTION = new String[]{Root.COLUMN_ROOT_ID,
|
|
||||||
Root.COLUMN_MIME_TYPES,
|
|
||||||
Root.COLUMN_FLAGS,
|
|
||||||
Root.COLUMN_ICON,
|
|
||||||
Root.COLUMN_TITLE,
|
|
||||||
Root.COLUMN_SUMMARY,
|
|
||||||
Root.COLUMN_DOCUMENT_ID,
|
|
||||||
Root.COLUMN_AVAILABLE_BYTES};
|
|
||||||
|
|
||||||
private static final String[] DEFAULT_DOCUMENT_PROJECTION = new String[]{Document.COLUMN_DOCUMENT_ID,
|
|
||||||
Document.COLUMN_MIME_TYPE,
|
|
||||||
Document.COLUMN_DISPLAY_NAME,
|
|
||||||
Document.COLUMN_LAST_MODIFIED,
|
|
||||||
Document.COLUMN_FLAGS,
|
|
||||||
Document.COLUMN_SIZE};
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Cursor queryRoots(String[] projection) {
|
|
||||||
final MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_ROOT_PROJECTION);
|
|
||||||
|
|
||||||
final String appName = getContext().getString(R.string.app_name);
|
|
||||||
final String docId = getDocIdForFile(mRootDir);
|
|
||||||
|
|
||||||
int flags;
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_CREATE | Root.FLAG_SUPPORTS_SEARCH;
|
|
||||||
} else {
|
|
||||||
flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_CREATE | Root.FLAG_SUPPORTS_SEARCH | Root.FLAG_SUPPORTS_IS_CHILD;
|
|
||||||
}
|
|
||||||
|
|
||||||
final MatrixCursor.RowBuilder row = result.newRow();
|
|
||||||
row.add(Root.COLUMN_ROOT_ID, docId);
|
|
||||||
row.add(Root.COLUMN_DOCUMENT_ID, docId);
|
|
||||||
row.add(Root.COLUMN_SUMMARY, null);
|
|
||||||
row.add(Root.COLUMN_FLAGS, flags);
|
|
||||||
row.add(Root.COLUMN_TITLE, appName);
|
|
||||||
row.add(Root.COLUMN_MIME_TYPES, ALL_MIME_TYPES);
|
|
||||||
row.add(Root.COLUMN_AVAILABLE_BYTES, mRootDir.getFreeSpace());
|
|
||||||
row.add(Root.COLUMN_ICON, R.mipmap.ic_launcher);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Cursor queryDocument(String documentId, String[] projection) throws FileNotFoundException {
|
|
||||||
final MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION);
|
|
||||||
|
|
||||||
includeFile(result, documentId, null);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Cursor queryChildDocuments(String parentDocumentId, String[] projection, String sortOrder) throws FileNotFoundException {
|
|
||||||
final MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION);
|
|
||||||
|
|
||||||
final File parent = getFileForDocId(parentDocumentId);
|
|
||||||
final File[] filesList = parent.listFiles();
|
|
||||||
|
|
||||||
if (filesList != null) {
|
|
||||||
for (File file : filesList) {
|
|
||||||
includeFile(result, null, file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ParcelFileDescriptor openDocument(final String documentId, String mode, CancellationSignal signal) throws FileNotFoundException {
|
|
||||||
final File file = getFileForDocId(documentId);
|
|
||||||
|
|
||||||
final int accessMode = ParcelFileDescriptor.parseMode(mode);
|
|
||||||
|
|
||||||
return ParcelFileDescriptor.open(file, accessMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AssetFileDescriptor openDocumentThumbnail(String documentId, Point sizeHint, CancellationSignal signal) throws FileNotFoundException {
|
|
||||||
final File file = getFileForDocId(documentId);
|
|
||||||
|
|
||||||
final ParcelFileDescriptor pfd = ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
|
|
||||||
|
|
||||||
return new AssetFileDescriptor(pfd, 0, file.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String createDocument(String parentDocumentId, String mimeType, String displayName) throws FileNotFoundException {
|
|
||||||
File newFile = new File(parentDocumentId, displayName);
|
|
||||||
|
|
||||||
int noConflictId = 1;
|
|
||||||
|
|
||||||
while (newFile.exists()) {
|
|
||||||
newFile = new File(parentDocumentId, displayName + " (" + noConflictId++ + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
boolean succeeded;
|
|
||||||
|
|
||||||
if (Document.MIME_TYPE_DIR.equals(mimeType)) {
|
|
||||||
succeeded = newFile.mkdir();
|
|
||||||
} else {
|
|
||||||
succeeded = newFile.createNewFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!succeeded) {
|
|
||||||
throw new FileNotFoundException("Failed to create document with id " + newFile.getPath());
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new FileNotFoundException("Failed to create document with id " + newFile.getPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
return newFile.getPath();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deleteDocument(String documentId) throws FileNotFoundException {
|
|
||||||
File file = getFileForDocId(documentId);
|
|
||||||
|
|
||||||
if (file.isDirectory()) {
|
|
||||||
if (!deleteDirectory(file)) {
|
|
||||||
throw new FileNotFoundException("Failed to delete document with id " + documentId);
|
|
||||||
}
|
|
||||||
} else if (!file.delete()) {
|
|
||||||
throw new FileNotFoundException("Failed to delete document with id " + documentId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDocumentType(String documentId) throws FileNotFoundException {
|
|
||||||
File file = getFileForDocId(documentId);
|
|
||||||
|
|
||||||
return getMimeType(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isChildDocument(String parentDocumentId, String documentId) {
|
|
||||||
return documentId.startsWith(parentDocumentId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static File getFileForDocId(String docId) throws FileNotFoundException {
|
|
||||||
final File f = new File(docId);
|
|
||||||
|
|
||||||
if (!f.exists()) throw new FileNotFoundException(f.getAbsolutePath() + " not found");
|
|
||||||
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getDocIdForFile(File file) {
|
|
||||||
return file.getAbsolutePath();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getMimeType(File file) {
|
|
||||||
if (file.isDirectory()) {
|
|
||||||
return Document.MIME_TYPE_DIR;
|
|
||||||
} else {
|
|
||||||
final String name = file.getName();
|
|
||||||
final int lastDot = name.lastIndexOf('.');
|
|
||||||
|
|
||||||
if (lastDot >= 0) {
|
|
||||||
final String extension = name.substring(lastDot + 1).toLowerCase();
|
|
||||||
final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
|
|
||||||
|
|
||||||
if (mime != null) return mime;
|
|
||||||
}
|
|
||||||
|
|
||||||
return "application/octet-stream";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean deleteDirectory(File dir) {
|
|
||||||
final File[] allContents = dir.listFiles();
|
|
||||||
|
|
||||||
if (allContents != null) {
|
|
||||||
for (File file : allContents) {
|
|
||||||
deleteDirectory(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return dir.delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void includeFile(MatrixCursor result, String docId, File file) throws FileNotFoundException {
|
|
||||||
if (docId == null) {
|
|
||||||
docId = getDocIdForFile(file);
|
|
||||||
} else {
|
|
||||||
file = getFileForDocId(docId);
|
|
||||||
}
|
|
||||||
|
|
||||||
int flags = 0;
|
|
||||||
|
|
||||||
if (file.isDirectory()) {
|
|
||||||
if (file.canWrite()) {
|
|
||||||
flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
|
|
||||||
}
|
|
||||||
} else if (file.canWrite()) {
|
|
||||||
flags |= Document.FLAG_SUPPORTS_WRITE;
|
|
||||||
}
|
|
||||||
|
|
||||||
File parentFile = file.getParentFile();
|
|
||||||
if (parentFile != null && parentFile.canWrite()) {
|
|
||||||
flags |= Document.FLAG_SUPPORTS_DELETE;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String displayName = file.getName();
|
|
||||||
final String mimeType = getMimeType(file);
|
|
||||||
|
|
||||||
if (mimeType.startsWith("image/")) {
|
|
||||||
flags |= Document.FLAG_SUPPORTS_THUMBNAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
final MatrixCursor.RowBuilder row = result.newRow();
|
|
||||||
row.add(Document.COLUMN_DOCUMENT_ID, docId);
|
|
||||||
row.add(Document.COLUMN_DISPLAY_NAME, displayName);
|
|
||||||
row.add(Document.COLUMN_SIZE, file.length());
|
|
||||||
row.add(Document.COLUMN_MIME_TYPE, mimeType);
|
|
||||||
row.add(Document.COLUMN_LAST_MODIFIED, file.lastModified());
|
|
||||||
row.add(Document.COLUMN_FLAGS, flags);
|
|
||||||
row.add(Document.COLUMN_ICON, R.mipmap.ic_launcher);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -14,64 +14,57 @@ import su.xash.engine.ui.library.LibraryViewModel
|
|||||||
|
|
||||||
|
|
||||||
class GameAdapter(private val libraryViewModel: LibraryViewModel) :
|
class GameAdapter(private val libraryViewModel: LibraryViewModel) :
|
||||||
ListAdapter<Game, GameAdapter.GameViewHolder>(DiffCallback()) {
|
ListAdapter<Game, GameAdapter.GameViewHolder>(DiffCallback()) {
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GameAdapter.GameViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GameAdapter.GameViewHolder {
|
||||||
val binding = CardGameBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
val binding = CardGameBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||||
return GameViewHolder(binding)
|
return GameViewHolder(binding)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: GameAdapter.GameViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: GameAdapter.GameViewHolder, position: Int) {
|
||||||
return holder.bind(getItem(position))
|
return holder.bind(getItem(position))
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DiffCallback : DiffUtil.ItemCallback<Game>() {
|
private class DiffCallback : DiffUtil.ItemCallback<Game>() {
|
||||||
override fun areItemsTheSame(oldItem: Game, newItem: Game): Boolean {
|
override fun areItemsTheSame(oldItem: Game, newItem: Game): Boolean {
|
||||||
return oldItem.basedir.name == newItem.basedir.name
|
return oldItem.basedir.name == newItem.basedir.name
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun areContentsTheSame(oldItem: Game, newItem: Game): Boolean {
|
override fun areContentsTheSame(oldItem: Game, newItem: Game): Boolean {
|
||||||
return oldItem.basedir.name == newItem.basedir.name && oldItem.installed == newItem.installed
|
return oldItem.basedir.name == newItem.basedir.name
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class GameViewHolder(val binding: CardGameBinding) :
|
inner class GameViewHolder(val binding: CardGameBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root) {
|
RecyclerView.ViewHolder(binding.root) {
|
||||||
fun bind(game: Game) {
|
fun bind(game: Game) {
|
||||||
binding.apply {
|
binding.apply {
|
||||||
gameTitle.text = game.title
|
gameTitle.text = game.title
|
||||||
|
|
||||||
if (game.icon != null) {
|
if (game.icon != null) {
|
||||||
gameIcon.setImageBitmap(game.icon)
|
gameIcon.setImageBitmap(game.icon)
|
||||||
} else {
|
} else {
|
||||||
gameIcon.visibility = View.GONE
|
gameIcon.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game.cover != null) {
|
if (game.cover != null) {
|
||||||
gameCover.setImageBitmap(game.cover)
|
gameCover.setImageBitmap(game.cover)
|
||||||
} else {
|
} else {
|
||||||
gameCover.visibility = View.GONE
|
gameCover.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!game.installed) {
|
settingsButton.setOnClickListener {
|
||||||
launchButton.visibility = View.GONE
|
libraryViewModel.setSelectedGame(game)
|
||||||
settingsButton.visibility = View.GONE
|
it.findNavController()
|
||||||
progressIndicator.visibility = View.VISIBLE
|
.navigate(R.id.action_libraryFragment_to_gameSettingsFragment)
|
||||||
return
|
}
|
||||||
}
|
|
||||||
|
|
||||||
settingsButton.setOnClickListener {
|
root.setOnClickListener { libraryViewModel.startEngine(it.context, game) }
|
||||||
libraryViewModel.setSelectedGame(game)
|
launchButton.setOnClickListener {
|
||||||
it.findNavController()
|
libraryViewModel.startEngine(it.context, game)
|
||||||
.navigate(R.id.action_libraryFragment_to_gameSettingsFragment)
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
root.setOnClickListener { libraryViewModel.startEngine(it.context, game) }
|
}
|
||||||
launchButton.setOnClickListener {
|
}
|
||||||
libraryViewModel.startEngine(it.context, game)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,89 +1,90 @@
|
|||||||
package su.xash.engine.model
|
package su.xash.engine.model
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
import androidx.documentfile.provider.DocumentFile
|
|
||||||
import su.xash.engine.util.TGAReader
|
import su.xash.engine.util.TGAReader
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileInputStream
|
||||||
import java.util.Scanner
|
import java.util.Scanner
|
||||||
|
|
||||||
|
|
||||||
object BackgroundBitmap {
|
object BackgroundBitmap {
|
||||||
private const val BACKGROUND_ROWS = 3
|
private const val BACKGROUND_ROWS = 3
|
||||||
private const val BACKGROUND_COLUMNS = 4
|
private const val BACKGROUND_COLUMNS = 4
|
||||||
private const val BACKGROUND_WIDTH = 800
|
private const val BACKGROUND_WIDTH = 800
|
||||||
private const val BACKGROUND_HEIGHT = 600
|
private const val BACKGROUND_HEIGHT = 600
|
||||||
|
|
||||||
fun createBackground(ctx: Context, file: DocumentFile): Bitmap {
|
fun createBackground(file: File): Bitmap {
|
||||||
var bitmap =
|
var bitmap =
|
||||||
Bitmap.createBitmap(BACKGROUND_WIDTH, BACKGROUND_HEIGHT, Bitmap.Config.ARGB_8888)
|
Bitmap.createBitmap(BACKGROUND_WIDTH, BACKGROUND_HEIGHT, Bitmap.Config.ARGB_8888)
|
||||||
var canvas = Canvas(bitmap)
|
var canvas = Canvas(bitmap)
|
||||||
var x: Int
|
var x: Int
|
||||||
var y = 0
|
var y = 0
|
||||||
var width: Int
|
var width: Int
|
||||||
var height = 0
|
var height = 0
|
||||||
|
|
||||||
var bgLayout = file.findFile("resource")?.findFile("HD_BackgroundLayout.txt")
|
val resourceFolder = File(file, "resource")
|
||||||
if (bgLayout == null) {
|
var bgLayout = File(resourceFolder, "HD_BackgroundLayout.txt")
|
||||||
bgLayout = file.findFile("resource")?.findFile("BackgroundLayout.txt")
|
if (!bgLayout.exists()) {
|
||||||
}
|
bgLayout = File(resourceFolder, "BackgroundLayout.txt")
|
||||||
|
}
|
||||||
|
|
||||||
if (bgLayout == null) {
|
if (!bgLayout.exists()) {
|
||||||
val dir = file.findFile("resource")?.findFile("background")
|
val dir = File(resourceFolder, "background")
|
||||||
for (i in 0 until BACKGROUND_ROWS) {
|
for (i in 0 until BACKGROUND_ROWS) {
|
||||||
x = 0
|
x = 0
|
||||||
for (j in 0 until BACKGROUND_COLUMNS) {
|
for (j in 0 until BACKGROUND_COLUMNS) {
|
||||||
val filename = "${BACKGROUND_WIDTH}_${i + 1}_${'a' + j}_loading.tga"
|
val filename = "${BACKGROUND_WIDTH}_${i + 1}_${'a' + j}_loading.tga"
|
||||||
val bmpFile = dir?.findFile(filename)
|
val bmpFile = File(dir, filename)
|
||||||
val bmpImage = loadTga(ctx, bmpFile!!)
|
val bmpImage = loadTga(bmpFile)
|
||||||
|
|
||||||
canvas.drawBitmap(bmpImage, x.toFloat(), y.toFloat(), null)
|
canvas.drawBitmap(bmpImage, x.toFloat(), y.toFloat(), null)
|
||||||
x += bmpImage.width
|
x += bmpImage.width
|
||||||
height = bmpImage.height
|
height = bmpImage.height
|
||||||
|
|
||||||
}
|
}
|
||||||
y += height
|
y += height
|
||||||
}
|
}
|
||||||
return bitmap
|
return bitmap
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.contentResolver.openInputStream(bgLayout.uri).use { inputStream ->
|
FileInputStream(bgLayout).use { inputStream ->
|
||||||
Scanner(inputStream).use { scanner ->
|
Scanner(inputStream).use { scanner ->
|
||||||
while (scanner.hasNext()) {
|
while (scanner.hasNext()) {
|
||||||
when (val str = scanner.next()) {
|
when (val str = scanner.next()) {
|
||||||
"resolution" -> {
|
"resolution" -> {
|
||||||
width = scanner.nextInt()
|
width = scanner.nextInt()
|
||||||
height = scanner.nextInt()
|
height = scanner.nextInt()
|
||||||
bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
|
bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
|
||||||
canvas = Canvas(bitmap)
|
canvas = Canvas(bitmap)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
var bmpFile = file
|
var bmpFile = file
|
||||||
str.split("/").forEach { bmpFile = bmpFile.findFile(it)!! }
|
str.split("/").forEach { bmpFile = File(bmpFile, it) }
|
||||||
//skip
|
//skip
|
||||||
scanner.next()
|
scanner.next()
|
||||||
x = scanner.nextInt()
|
x = scanner.nextInt()
|
||||||
y = scanner.nextInt()
|
y = scanner.nextInt()
|
||||||
val bmp = loadTga(ctx, bmpFile)
|
val bmp = loadTga(bmpFile)
|
||||||
canvas.drawBitmap(bmp, x.toFloat(), y.toFloat(), null)
|
canvas.drawBitmap(bmp, x.toFloat(), y.toFloat(), null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return bitmap
|
return bitmap
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadTga(ctx: Context, file: DocumentFile): Bitmap {
|
private fun loadTga(file: File): Bitmap {
|
||||||
ctx.contentResolver.openInputStream(file.uri).use {
|
FileInputStream(file).use {
|
||||||
val buffer = it?.readBytes()
|
val buffer = it.readBytes()
|
||||||
val pixels = TGAReader.read(buffer, TGAReader.ARGB)
|
val pixels = TGAReader.read(buffer, TGAReader.ARGB)
|
||||||
|
|
||||||
val width = TGAReader.getWidth(buffer)
|
val width = TGAReader.getWidth(buffer)
|
||||||
val height = TGAReader.getHeight(buffer)
|
val height = TGAReader.getHeight(buffer)
|
||||||
|
|
||||||
return Bitmap.createBitmap(pixels, 0, width, width, height, Bitmap.Config.ARGB_8888)
|
return Bitmap.createBitmap(pixels, 0, width, width, height, Bitmap.Config.ARGB_8888)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,118 +5,123 @@ import android.content.Intent
|
|||||||
import android.content.pm.PackageInfo
|
import android.content.pm.PackageInfo
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.BitmapFactory
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.provider.MediaStore
|
|
||||||
import androidx.documentfile.provider.DocumentFile
|
|
||||||
import su.xash.engine.XashActivity
|
import su.xash.engine.XashActivity
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileInputStream
|
||||||
|
|
||||||
|
|
||||||
class Game(val ctx: Context, val basedir: DocumentFile, var installed: Boolean = true) {
|
class Game(val ctx: Context, val basedir: File) {
|
||||||
private var iconName = "game.ico"
|
private var iconName = "game.ico"
|
||||||
var title = "Unknown Game"
|
var title = "Unknown Game"
|
||||||
var icon: Bitmap? = null
|
var icon: Bitmap? = null
|
||||||
var cover: Bitmap? = null
|
var cover: Bitmap? = null
|
||||||
|
|
||||||
private val pref = ctx.getSharedPreferences(basedir.name, Context.MODE_PRIVATE)
|
private val pref = ctx.getSharedPreferences(basedir.name, Context.MODE_PRIVATE)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
basedir.findFile("gameinfo.txt")?.let {
|
val gameInfo = File(basedir, "gameinfo.txt")
|
||||||
parseGameInfo(it)
|
if (gameInfo.exists()) {
|
||||||
} ?: basedir.findFile("liblist.gam")?.let { parseGameInfo(it) }
|
parseGameInfo(gameInfo)
|
||||||
|
} else {
|
||||||
|
val libListGam = File(basedir, "liblist.gam")
|
||||||
|
if (libListGam.exists()) parseGameInfo(libListGam)
|
||||||
|
}
|
||||||
|
|
||||||
basedir.findFile(iconName)
|
val iconFile = File(basedir, iconName)
|
||||||
?.let { icon = MediaStore.Images.Media.getBitmap(ctx.contentResolver, it.uri) }
|
if (iconFile.exists()) {
|
||||||
|
icon = BitmapFactory.decodeFile(iconFile.path)
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cover = BackgroundBitmap.createBackground(ctx, basedir)
|
cover = BackgroundBitmap.createBackground(basedir)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun startEngine(ctx: Context) {
|
fun startEngine(ctx: Context) {
|
||||||
ctx.startActivity(Intent(ctx, XashActivity::class.java).apply {
|
ctx.startActivity(Intent(ctx, XashActivity::class.java).apply {
|
||||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||||
putExtra("gamedir", basedir.name)
|
putExtra("gamedir", basedir.name)
|
||||||
putExtra("argv", pref.getString("arguments", "-console -log"))
|
putExtra("argv", pref.getString("arguments", "-console -log"))
|
||||||
putExtra("usevolume", pref.getBoolean("use_volume_buttons", false))
|
putExtra("usevolume", pref.getBoolean("use_volume_buttons", false))
|
||||||
//.putExtra("gamelibdir", getGameLibDir(context))
|
putExtra("basedir", basedir.parent)
|
||||||
//.putExtra("package", getPackageName()) }
|
//.putExtra("gamelibdir", getGameLibDir(context))
|
||||||
})
|
//.putExtra("package", getPackageName()) }
|
||||||
}
|
})
|
||||||
|
}
|
||||||
|
|
||||||
private fun parseGameInfo(file: DocumentFile) {
|
private fun parseGameInfo(file: File) {
|
||||||
ctx.contentResolver.openInputStream(file.uri).use { inputStream ->
|
FileInputStream(file).use { inputStream ->
|
||||||
inputStream?.bufferedReader().use { reader ->
|
inputStream.bufferedReader().use { reader ->
|
||||||
reader?.forEachLine {
|
reader.forEachLine {
|
||||||
val tokens = it.split("\\s+".toRegex(), limit = 2)
|
val tokens = it.split("\\s+".toRegex(), limit = 2)
|
||||||
if (tokens.size >= 2) {
|
if (tokens.size >= 2) {
|
||||||
val k = tokens[0]
|
val k = tokens[0]
|
||||||
val v = tokens[1].trim('"')
|
val v = tokens[1].trim('"')
|
||||||
|
|
||||||
if (k == "title" || k == "game") title = v
|
if (k == "title" || k == "game") title = v
|
||||||
if (k == "icon") iconName = v
|
if (k == "icon") iconName = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getPackageName(): String? {
|
private fun getPackageName(): String? {
|
||||||
// return if (mDbEntry != null) {
|
// return if (mDbEntry != null) {
|
||||||
// mDbEntry.getPackageName()
|
// mDbEntry.getPackageName()
|
||||||
// } else null
|
// } else null
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getGameLibDir(ctx: Context): String? {
|
private fun getGameLibDir(ctx: Context): String? {
|
||||||
val pkgName = getPackageName()
|
val pkgName = getPackageName()
|
||||||
if (pkgName != null) {
|
if (pkgName != null) {
|
||||||
val pkgInfo: PackageInfo = try {
|
val pkgInfo: PackageInfo = try {
|
||||||
ctx.packageManager.getPackageInfo(pkgName, 0)
|
ctx.packageManager.getPackageInfo(pkgName, 0)
|
||||||
} catch (e: PackageManager.NameNotFoundException) {
|
} catch (e: PackageManager.NameNotFoundException) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
ctx.startActivity(
|
ctx.startActivity(
|
||||||
Intent(
|
Intent(
|
||||||
Intent.ACTION_VIEW, Uri.parse("market://details?id=$pkgName")
|
Intent.ACTION_VIEW, Uri.parse("market://details?id=$pkgName")
|
||||||
).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
||||||
)
|
)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
return pkgInfo.applicationInfo.nativeLibraryDir
|
return pkgInfo.applicationInfo?.nativeLibraryDir
|
||||||
}
|
}
|
||||||
return ctx.applicationInfo.nativeLibraryDir
|
return ctx.applicationInfo.nativeLibraryDir
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun getGames(ctx: Context, file: DocumentFile): List<Game> {
|
fun getGames(ctx: Context, file: File): List<Game> {
|
||||||
val games = mutableListOf<Game>()
|
val games = mutableListOf<Game>()
|
||||||
|
|
||||||
if (checkIfGamedir(file)) {
|
if (checkIfGamedir(file)) {
|
||||||
games.add(Game(ctx, file))
|
games.add(Game(ctx, file))
|
||||||
} else {
|
} else {
|
||||||
file.listFiles().forEach {
|
file.listFiles()?.forEach {
|
||||||
if (it.isDirectory) {
|
if (it.isDirectory) {
|
||||||
if (checkIfGamedir(it)) {
|
if (checkIfGamedir(it)) {
|
||||||
games.add(Game(ctx, it))
|
games.add(Game(ctx, it))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return games
|
return games
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkIfGamedir(file: DocumentFile): Boolean {
|
fun checkIfGamedir(file: File): Boolean {
|
||||||
// exclude unfinished downloads
|
if (File(file, "liblist.gam").exists()) return true
|
||||||
if (file.name?.startsWith('.') == true)
|
if (File(file, "gameinfo.txt").exists()) return true
|
||||||
return false
|
|
||||||
|
|
||||||
file.findFile("liblist.gam")?.let { return true }
|
return false
|
||||||
file.findFile("gameinfo.txt")?.let { return true }
|
}
|
||||||
return false
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intent intent = new Intent("su.xash.engine.MOD");
|
// Intent intent = new Intent("su.xash.engine.MOD");
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
package su.xash.engine.model
|
|
||||||
|
|
||||||
import org.json.JSONArray
|
|
||||||
import org.json.JSONObject
|
|
||||||
import java.io.InputStream
|
|
||||||
|
|
||||||
class ModDatabase(inputStream: InputStream) {
|
|
||||||
val entries = mutableListOf<Entry>()
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val VERSION = 1
|
|
||||||
|
|
||||||
fun getFilename(): String {
|
|
||||||
return "v${VERSION}.json"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
inputStream.bufferedReader().use {
|
|
||||||
val jsonArray = JSONArray(it.readText())
|
|
||||||
|
|
||||||
for (i in 0..<jsonArray.length()) {
|
|
||||||
entries.add(Entry(jsonArray.getJSONObject(i)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getByGameDir(gamedir: String): Entry? {
|
|
||||||
return entries.filter { it.gamedir.equals(gamedir) }.firstOrNull()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inner class Entry(jsonObject: JSONObject) {
|
|
||||||
var name: String? = null
|
|
||||||
var appid: Int? = null
|
|
||||||
var gamedir: String? = null
|
|
||||||
|
|
||||||
// TODO Depots
|
|
||||||
var pkgname: String? = null
|
|
||||||
|
|
||||||
init {
|
|
||||||
if (jsonObject.has("name")) {
|
|
||||||
name = jsonObject.getString("name");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (jsonObject.has("app_id")) {
|
|
||||||
appid = jsonObject.getInt("app_id");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (jsonObject.has("gamedir")) {
|
|
||||||
gamedir = jsonObject.getString("gamedir");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (jsonObject.has("package_name")) {
|
|
||||||
pkgname = jsonObject.getString("package_name");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,94 +1,110 @@
|
|||||||
package su.xash.engine.ui.library
|
package su.xash.engine.ui.library
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.os.Environment
|
||||||
|
import android.provider.Settings
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuInflater
|
import android.view.MenuInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.view.MenuProvider
|
import androidx.core.view.MenuProvider
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import kotlinx.coroutines.launch
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import su.xash.engine.BuildConfig
|
||||||
import su.xash.engine.R
|
import su.xash.engine.R
|
||||||
import su.xash.engine.adapters.GameAdapter
|
import su.xash.engine.adapters.GameAdapter
|
||||||
import su.xash.engine.databinding.FragmentLibraryBinding
|
import su.xash.engine.databinding.FragmentLibraryBinding
|
||||||
|
|
||||||
class LibraryFragment : Fragment(), MenuProvider {
|
class LibraryFragment : Fragment(), MenuProvider {
|
||||||
private var _binding: FragmentLibraryBinding? = null
|
private var _binding: FragmentLibraryBinding? = null
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
private val libraryViewModel: LibraryViewModel by activityViewModels()
|
private val libraryViewModel: LibraryViewModel by activityViewModels()
|
||||||
|
|
||||||
override fun onCreateView(
|
private val startActivityForResult =
|
||||||
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||||
): View? {
|
if (checkStoragePermissions()) {
|
||||||
_binding = FragmentLibraryBinding.inflate(inflater, container, false)
|
libraryViewModel.reloadGames(requireContext())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val adapter = GameAdapter(libraryViewModel)
|
private fun checkStoragePermissions(): Boolean {
|
||||||
binding.gamesList.adapter = adapter
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !Environment.isExternalStorageManager()) {
|
||||||
|
MaterialAlertDialogBuilder(requireContext()).apply {
|
||||||
|
setTitle(R.string.file_access_required)
|
||||||
|
setMessage(R.string.file_access_message)
|
||||||
|
setPositiveButton(android.R.string.ok) { _, _ ->
|
||||||
|
startActivityForResult.launch(
|
||||||
|
Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION).setData(
|
||||||
|
Uri.fromParts("package", BuildConfig.APPLICATION_ID, null)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
setCancelable(false)
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
|
||||||
requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED)
|
return false
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return binding.root
|
override fun onCreateView(
|
||||||
}
|
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
|
_binding = FragmentLibraryBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
val adapter = GameAdapter(libraryViewModel)
|
||||||
binding.swipeRefresh.setOnRefreshListener { libraryViewModel.reloadGames(requireContext()) }
|
binding.gamesList.adapter = adapter
|
||||||
|
|
||||||
libraryViewModel.isReloading.observe(viewLifecycleOwner) {
|
requireActivity().addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.RESUMED)
|
||||||
binding.swipeRefresh.isRefreshing = it
|
|
||||||
}
|
|
||||||
|
|
||||||
libraryViewModel.installedGames.observe(viewLifecycleOwner) {
|
return binding.root
|
||||||
(binding.gamesList.adapter as GameAdapter).submitList(it)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
libraryViewModel.workInfos.observe(viewLifecycleOwner) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
libraryViewModel.refreshDownloads(requireContext())
|
binding.swipeRefresh.setOnRefreshListener { libraryViewModel.reloadGames(requireContext()) }
|
||||||
}
|
|
||||||
|
|
||||||
libraryViewModel.downloads.observe(viewLifecycleOwner) {
|
libraryViewModel.isReloading.observe(viewLifecycleOwner) {
|
||||||
libraryViewModel.reloadGames(requireContext())
|
binding.swipeRefresh.isRefreshing = it
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroyView() {
|
libraryViewModel.installedGames.observe(viewLifecycleOwner) {
|
||||||
super.onDestroyView()
|
(binding.gamesList.adapter as GameAdapter).submitList(it)
|
||||||
_binding = null
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
|
if (checkStoragePermissions()) {
|
||||||
menuInflater.inflate(R.menu.menu_library, menu)
|
libraryViewModel.reloadGames(requireContext())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
|
override fun onDestroyView() {
|
||||||
when (menuItem.itemId) {
|
super.onDestroyView()
|
||||||
R.id.action_browse -> {
|
_binding = null
|
||||||
startActivity(
|
}
|
||||||
Intent(Intent.ACTION_VIEW).setDataAndType(
|
|
||||||
null, "vnd.android.document/directory"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
R.id.action_install -> {
|
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
|
||||||
findNavController().navigate(R.id.action_libraryFragment_to_setupFragment)
|
menuInflater.inflate(R.menu.menu_library, menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.action_settings -> {
|
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
|
||||||
findNavController().navigate(R.id.action_libraryFragment_to_appSettingsFragment)
|
when (menuItem.itemId) {
|
||||||
}
|
R.id.action_settings -> {
|
||||||
}
|
findNavController().navigate(R.id.action_libraryFragment_to_appSettingsFragment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,125 +3,53 @@ package su.xash.engine.ui.library
|
|||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.net.Uri
|
import android.os.Environment
|
||||||
import androidx.documentfile.provider.DocumentFile
|
|
||||||
import androidx.lifecycle.AndroidViewModel
|
import androidx.lifecycle.AndroidViewModel
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.preference.PreferenceManager
|
|
||||||
import androidx.work.Data
|
|
||||||
import androidx.work.OneTimeWorkRequestBuilder
|
|
||||||
import androidx.work.OutOfQuotaPolicy
|
|
||||||
import androidx.work.WorkInfo
|
|
||||||
import androidx.work.WorkManager
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import su.xash.engine.model.Game
|
import su.xash.engine.model.Game
|
||||||
import su.xash.engine.model.ModDatabase
|
import java.io.File
|
||||||
import su.xash.engine.workers.FileCopyWorker
|
|
||||||
import su.xash.engine.workers.KEY_FILE_URI
|
|
||||||
import java.util.Locale
|
|
||||||
|
|
||||||
const val TAG_INSTALL = "TAG_INSTALL"
|
|
||||||
|
|
||||||
class LibraryViewModel(application: Application) : AndroidViewModel(application) {
|
class LibraryViewModel(application: Application) : AndroidViewModel(application) {
|
||||||
val installedGames: LiveData<List<Game>> get() = _installedGames
|
val installedGames: LiveData<List<Game>> get() = _installedGames
|
||||||
private val _installedGames = MutableLiveData(emptyList<Game>())
|
private val _installedGames = MutableLiveData(emptyList<Game>())
|
||||||
|
|
||||||
val downloads: LiveData<List<Game>> get() = _downloads
|
val isReloading: LiveData<Boolean> get() = _isReloading
|
||||||
private val _downloads = MutableLiveData(emptyList<Game>())
|
private val _isReloading = MutableLiveData(false)
|
||||||
|
|
||||||
val isReloading: LiveData<Boolean> get() = _isReloading
|
val selectedItem: LiveData<Game> get() = _selectedItem
|
||||||
private val _isReloading = MutableLiveData(false)
|
private val _selectedItem = MutableLiveData<Game>()
|
||||||
|
|
||||||
private val workManager = WorkManager.getInstance(application.applicationContext)
|
private val appPreferences: SharedPreferences =
|
||||||
val workInfos: LiveData<List<WorkInfo>> = workManager.getWorkInfosByTagLiveData(TAG_INSTALL)
|
application.getSharedPreferences("app_preferences", Context.MODE_PRIVATE)
|
||||||
|
|
||||||
val selectedItem: LiveData<Game> get() = _selectedItem
|
fun reloadGames(ctx: Context) {
|
||||||
private val _selectedItem = MutableLiveData<Game>()
|
if (isReloading.value == true) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_isReloading.value = true
|
||||||
|
|
||||||
val appPreferences = application.getSharedPreferences("app_preferences", Context.MODE_PRIVATE)
|
viewModelScope.launch {
|
||||||
val modDb: ModDatabase
|
withContext(Dispatchers.IO) {
|
||||||
|
val rootPath = appPreferences.getString("game_path", null)
|
||||||
|
?: (Environment.getExternalStorageDirectory().absolutePath + "/xash")
|
||||||
|
val root = File(rootPath)
|
||||||
|
|
||||||
init {
|
_installedGames.postValue(Game.getGames(ctx, root))
|
||||||
modDb = application.assets.open(ModDatabase.getFilename()).use { ModDatabase(it) }
|
_isReloading.postValue(false)
|
||||||
reloadGames(application.applicationContext)
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun reloadGames(ctx: Context) {
|
fun setSelectedGame(game: Game) {
|
||||||
if (isReloading.value == true) {
|
_selectedItem.value = game
|
||||||
return
|
}
|
||||||
}
|
|
||||||
_isReloading.value = true
|
|
||||||
|
|
||||||
viewModelScope.launch {
|
fun startEngine(ctx: Context, game: Game) {
|
||||||
withContext(Dispatchers.IO) {
|
game.startEngine(ctx)
|
||||||
val games = mutableListOf<Game>()
|
}
|
||||||
val root = DocumentFile.fromFile(ctx.getExternalFilesDir(null)!!)
|
}
|
||||||
|
|
||||||
val installedGames = Game.getGames(ctx, root)
|
|
||||||
.filter { p -> _downloads.value?.any { p.basedir.name == it.basedir.name } == false }
|
|
||||||
|
|
||||||
games.addAll(installedGames)
|
|
||||||
downloads.value?.let { games.addAll(it) }
|
|
||||||
|
|
||||||
_installedGames.postValue(games)
|
|
||||||
_isReloading.postValue(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun refreshDownloads(ctx: Context) {
|
|
||||||
viewModelScope.launch {
|
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
val games = mutableListOf<Game>()
|
|
||||||
|
|
||||||
workInfos.value?.filter {
|
|
||||||
it.state == WorkInfo.State.RUNNING && !it.progress.getString(FileCopyWorker.Input)
|
|
||||||
.isNullOrEmpty()
|
|
||||||
}?.forEach {
|
|
||||||
val uri = Uri.parse(it.progress.getString(FileCopyWorker.Input))
|
|
||||||
val file = DocumentFile.fromTreeUri(ctx, uri)
|
|
||||||
games.addAll(Game.getGames(ctx, file!!))
|
|
||||||
games.forEach { g -> g.installed = false }
|
|
||||||
}
|
|
||||||
|
|
||||||
_downloads.postValue(games)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun installGame(uri: Uri) {
|
|
||||||
val data = Data.Builder().putString(KEY_FILE_URI, uri.toString()).build()
|
|
||||||
val request = OneTimeWorkRequestBuilder<FileCopyWorker>().run {
|
|
||||||
setInputData(data)
|
|
||||||
addTag(TAG_INSTALL)
|
|
||||||
build()
|
|
||||||
}
|
|
||||||
workManager.enqueue(request)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setSelectedGame(game: Game) {
|
|
||||||
_selectedItem.value = game
|
|
||||||
}
|
|
||||||
|
|
||||||
fun uninstallGame(game: Game) {
|
|
||||||
viewModelScope.launch {
|
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
game.installed = false
|
|
||||||
game.basedir.delete()
|
|
||||||
_installedGames.postValue(_installedGames.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun startEngine(ctx: Context, game: Game) {
|
|
||||||
game.startEngine(ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -8,24 +8,24 @@ import androidx.fragment.app.Fragment
|
|||||||
import su.xash.engine.databinding.FragmentAppSettingsBinding
|
import su.xash.engine.databinding.FragmentAppSettingsBinding
|
||||||
|
|
||||||
class AppSettingsFragment : Fragment() {
|
class AppSettingsFragment : Fragment() {
|
||||||
private var _binding: FragmentAppSettingsBinding? = null
|
private var _binding: FragmentAppSettingsBinding? = null
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
||||||
): View? {
|
): View {
|
||||||
_binding = FragmentAppSettingsBinding.inflate(inflater, container, false)
|
_binding = FragmentAppSettingsBinding.inflate(inflater, container, false)
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
childFragmentManager.beginTransaction()
|
childFragmentManager.beginTransaction()
|
||||||
.add(binding.settingsFragment.id, AppSettingsPreferenceFragment()).commit();
|
.add(binding.settingsFragment.id, AppSettingsPreferenceFragment()).commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
_binding = null
|
_binding = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import androidx.preference.PreferenceFragmentCompat
|
|||||||
import su.xash.engine.R
|
import su.xash.engine.R
|
||||||
|
|
||||||
class AppSettingsPreferenceFragment() : PreferenceFragmentCompat() {
|
class AppSettingsPreferenceFragment() : PreferenceFragmentCompat() {
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
preferenceManager.sharedPreferencesName = "app_preferences";
|
preferenceManager.sharedPreferencesName = "app_preferences";
|
||||||
setPreferencesFromResource(R.xml.app_preferences, rootKey);
|
setPreferencesFromResource(R.xml.app_preferences, rootKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,59 +6,52 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.navigation.fragment.findNavController
|
|
||||||
import su.xash.engine.R
|
|
||||||
import su.xash.engine.databinding.FragmentGameSettingsBinding
|
import su.xash.engine.databinding.FragmentGameSettingsBinding
|
||||||
import su.xash.engine.ui.library.LibraryViewModel
|
import su.xash.engine.ui.library.LibraryViewModel
|
||||||
|
|
||||||
class GameSettingsFragment : Fragment() {
|
class GameSettingsFragment : Fragment() {
|
||||||
private var _binding: FragmentGameSettingsBinding? = null
|
private var _binding: FragmentGameSettingsBinding? = null
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
private val libraryViewModel: LibraryViewModel by activityViewModels()
|
private val libraryViewModel: LibraryViewModel by activityViewModels()
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
||||||
): View? {
|
): View {
|
||||||
_binding = FragmentGameSettingsBinding.inflate(inflater, container, false)
|
_binding = FragmentGameSettingsBinding.inflate(inflater, container, false)
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
val game = libraryViewModel.selectedItem.value!!
|
val game = libraryViewModel.selectedItem.value!!
|
||||||
|
|
||||||
binding.gameCard.apply {
|
binding.gameCard.apply {
|
||||||
gameTitle.text = game.title
|
gameTitle.text = game.title
|
||||||
|
|
||||||
if (game.icon != null) {
|
if (game.icon != null) {
|
||||||
gameIcon.setImageBitmap(game.icon)
|
gameIcon.setImageBitmap(game.icon)
|
||||||
} else {
|
} else {
|
||||||
gameIcon.visibility = View.GONE
|
gameIcon.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game.cover != null) {
|
if (game.cover != null) {
|
||||||
gameCover.setImageBitmap(game.cover)
|
gameCover.setImageBitmap(game.cover)
|
||||||
} else {
|
} else {
|
||||||
gameCover.visibility = View.GONE
|
gameCover.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
buttonsContainer.visibility = View.GONE
|
buttonsContainer.visibility = View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
childFragmentManager.beginTransaction()
|
childFragmentManager.beginTransaction()
|
||||||
.add(binding.settingsFragment.id, GameSettingsPreferenceFragment(game))
|
.add(binding.settingsFragment.id, GameSettingsPreferenceFragment(game))
|
||||||
.commit();
|
.commit();
|
||||||
|
}
|
||||||
|
|
||||||
binding.bottomNavigation.menu.findItem(R.id.action_uninstall).setOnMenuItemClickListener {
|
override fun onDestroyView() {
|
||||||
libraryViewModel.uninstallGame(game)
|
super.onDestroyView()
|
||||||
findNavController().popBackStack()
|
_binding = null
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroyView() {
|
|
||||||
super.onDestroyView()
|
|
||||||
_binding = null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,33 +8,33 @@ import su.xash.engine.R
|
|||||||
import su.xash.engine.model.Game
|
import su.xash.engine.model.Game
|
||||||
|
|
||||||
class GameSettingsPreferenceFragment(val game: Game) : PreferenceFragmentCompat() {
|
class GameSettingsPreferenceFragment(val game: Game) : PreferenceFragmentCompat() {
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
preferenceManager.sharedPreferencesName = game.basedir.name;
|
preferenceManager.sharedPreferencesName = game.basedir.name;
|
||||||
setPreferencesFromResource(R.xml.game_preferences, rootKey);
|
setPreferencesFromResource(R.xml.game_preferences, rootKey);
|
||||||
|
|
||||||
val packageList = findPreference<ListPreference>("package_name")!!
|
val packageList = findPreference<ListPreference>("package_name")!!
|
||||||
packageList.entries = arrayOf(getString(R.string.app_name))
|
packageList.entries = arrayOf(getString(R.string.app_name))
|
||||||
packageList.entryValues = arrayOf(requireContext().packageName)
|
packageList.entryValues = arrayOf(requireContext().packageName)
|
||||||
|
|
||||||
if (packageList.value == null) {
|
if (packageList.value == null) {
|
||||||
packageList.setValueIndex(0);
|
packageList.setValueIndex(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
val separatePackages = findPreference<SwitchPreferenceCompat>("separate_libraries")!!
|
val separatePackages = findPreference<SwitchPreferenceCompat>("separate_libraries")!!
|
||||||
val clientPackage = findPreference<ListPreference>("client_package")!!
|
val clientPackage = findPreference<ListPreference>("client_package")!!
|
||||||
val serverPackage = findPreference<ListPreference>("server_package")!!
|
val serverPackage = findPreference<ListPreference>("server_package")!!
|
||||||
separatePackages.setOnPreferenceChangeListener { _, newValue ->
|
separatePackages.setOnPreferenceChangeListener { _, newValue ->
|
||||||
if (newValue == true) {
|
if (newValue == true) {
|
||||||
packageList.isVisible = false
|
packageList.isVisible = false
|
||||||
clientPackage.isVisible = true
|
clientPackage.isVisible = true
|
||||||
serverPackage.isVisible = true
|
serverPackage.isVisible = true
|
||||||
} else {
|
} else {
|
||||||
packageList.isVisible = true
|
packageList.isVisible = true
|
||||||
clientPackage.isVisible = false
|
clientPackage.isVisible = false
|
||||||
serverPackage.isVisible = false
|
serverPackage.isVisible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
package su.xash.engine.ui.setup
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.fragment.app.activityViewModels
|
|
||||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
|
||||||
import su.xash.engine.databinding.FragmentSetupBinding
|
|
||||||
import su.xash.engine.ui.setup.pages.LocationPageFragment
|
|
||||||
import su.xash.engine.ui.setup.pages.WelcomePageFragment
|
|
||||||
|
|
||||||
class SetupFragment : Fragment() {
|
|
||||||
private var _binding: FragmentSetupBinding? = null
|
|
||||||
private val binding get() = _binding!!
|
|
||||||
private val setupViewModel: SetupViewModel by activityViewModels()
|
|
||||||
|
|
||||||
private lateinit var setupPageAdapter: SetupPageAdapter
|
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
|
||||||
): View? {
|
|
||||||
_binding = FragmentSetupBinding.inflate(inflater, container, false)
|
|
||||||
return binding.root
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
setupPageAdapter = SetupPageAdapter(this)
|
|
||||||
binding.viewPager.isUserInputEnabled = false
|
|
||||||
binding.viewPager.adapter = setupPageAdapter
|
|
||||||
|
|
||||||
setupViewModel.pageNumber.observe(viewLifecycleOwner) {
|
|
||||||
binding.viewPager.setCurrentItem(it, true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroyView() {
|
|
||||||
super.onDestroyView()
|
|
||||||
_binding = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SetupPageAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) {
|
|
||||||
val pages = listOf(WelcomePageFragment(), LocationPageFragment())
|
|
||||||
override fun getItemCount(): Int = 2
|
|
||||||
override fun createFragment(position: Int): Fragment = pages[position]
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
package su.xash.engine.ui.setup
|
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import android.net.Uri
|
|
||||||
import androidx.documentfile.provider.DocumentFile
|
|
||||||
import androidx.lifecycle.AndroidViewModel
|
|
||||||
import androidx.lifecycle.LiveData
|
|
||||||
import androidx.lifecycle.MutableLiveData
|
|
||||||
import su.xash.engine.MainApplication
|
|
||||||
import su.xash.engine.model.Game
|
|
||||||
|
|
||||||
class SetupViewModel(application: Application) : AndroidViewModel(application) {
|
|
||||||
val pageNumber: LiveData<Int> get() = _pageNumber
|
|
||||||
private val _pageNumber = MutableLiveData(0)
|
|
||||||
|
|
||||||
fun checkIfGameDir(uri: Uri): Boolean {
|
|
||||||
val ctx = getApplication<MainApplication>().applicationContext
|
|
||||||
val file = DocumentFile.fromTreeUri(ctx, uri)!!
|
|
||||||
return Game.checkIfGamedir(file)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setPageNumber(pos: Int) {
|
|
||||||
_pageNumber.value = pos
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
package su.xash.engine.ui.setup.pages
|
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.fragment.app.activityViewModels
|
|
||||||
import androidx.navigation.fragment.findNavController
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|
||||||
import su.xash.engine.R
|
|
||||||
import su.xash.engine.databinding.PageLocationBinding
|
|
||||||
import su.xash.engine.ui.library.LibraryViewModel
|
|
||||||
import su.xash.engine.ui.setup.SetupViewModel
|
|
||||||
|
|
||||||
class LocationPageFragment : Fragment() {
|
|
||||||
private var _binding: PageLocationBinding? = null
|
|
||||||
private val binding get() = _binding!!
|
|
||||||
private val setupViewModel: SetupViewModel by activityViewModels()
|
|
||||||
private val libraryViewModel: LibraryViewModel by activityViewModels()
|
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
|
||||||
): View? {
|
|
||||||
_binding = PageLocationBinding.inflate(inflater, container, false)
|
|
||||||
return binding.root
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
binding.pageButton.setOnClickListener {
|
|
||||||
getGamesDirectory.launch(null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroyView() {
|
|
||||||
super.onDestroyView()
|
|
||||||
_binding = null
|
|
||||||
}
|
|
||||||
|
|
||||||
private val getGamesDirectory =
|
|
||||||
registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) {
|
|
||||||
it?.let {
|
|
||||||
if (!setupViewModel.checkIfGameDir(it)) {
|
|
||||||
MaterialAlertDialogBuilder(requireContext()).apply {
|
|
||||||
setTitle(R.string.error)
|
|
||||||
setMessage(R.string.setup_location_empty)
|
|
||||||
setPositiveButton(R.string.ok) { dialog, _ -> dialog.dismiss() }
|
|
||||||
show()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
requireContext().contentResolver.takePersistableUriPermission(it, Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
|
||||||
libraryViewModel.installGame(it)
|
|
||||||
findNavController().navigate(R.id.action_setupFragment_to_libraryFragment)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
package su.xash.engine.ui.setup.pages
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.fragment.app.activityViewModels
|
|
||||||
import su.xash.engine.databinding.PageWelcomeBinding
|
|
||||||
import su.xash.engine.ui.setup.SetupViewModel
|
|
||||||
|
|
||||||
class WelcomePageFragment : Fragment() {
|
|
||||||
private var _binding: PageWelcomeBinding? = null
|
|
||||||
private val binding get() = _binding!!
|
|
||||||
private val setupViewModel: SetupViewModel by activityViewModels()
|
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
|
||||||
): View? {
|
|
||||||
_binding = PageWelcomeBinding.inflate(inflater, container, false)
|
|
||||||
return binding.root
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
binding.pageButton.setOnClickListener {
|
|
||||||
setupViewModel.setPageNumber(1)
|
|
||||||
}
|
|
||||||
setupViewModel.setPageNumber(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroyView() {
|
|
||||||
super.onDestroyView()
|
|
||||||
_binding = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package su.xash.engine.util;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
|
||||||
|
public class AndroidBug5497Workaround {
|
||||||
|
// For more information, see https://code.google.com/p/android/issues/detail?id=5497
|
||||||
|
// To use this class, simply invoke assistActivity() on an Activity that already has its content view set.
|
||||||
|
|
||||||
|
public static void assistActivity(Activity activity) {
|
||||||
|
new AndroidBug5497Workaround(activity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private View mChildOfContent;
|
||||||
|
private int usableHeightPrevious;
|
||||||
|
private FrameLayout.LayoutParams frameLayoutParams;
|
||||||
|
|
||||||
|
private AndroidBug5497Workaround(Activity activity) {
|
||||||
|
FrameLayout content = activity.findViewById(android.R.id.content);
|
||||||
|
mChildOfContent = content.getChildAt(0);
|
||||||
|
mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(this::possiblyResizeChildOfContent);
|
||||||
|
frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void possiblyResizeChildOfContent() {
|
||||||
|
int usableHeightNow = computeUsableHeight();
|
||||||
|
if (usableHeightNow != usableHeightPrevious) {
|
||||||
|
int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();
|
||||||
|
int heightDifference = usableHeightSansKeyboard - usableHeightNow;
|
||||||
|
if (heightDifference > (usableHeightSansKeyboard / 4)) {
|
||||||
|
// keyboard probably just became visible
|
||||||
|
frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
|
||||||
|
} else {
|
||||||
|
// keyboard probably just became hidden
|
||||||
|
frameLayoutParams.height = usableHeightSansKeyboard;
|
||||||
|
}
|
||||||
|
mChildOfContent.requestLayout();
|
||||||
|
usableHeightPrevious = usableHeightNow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int computeUsableHeight() {
|
||||||
|
Rect r = new Rect();
|
||||||
|
mChildOfContent.getWindowVisibleDisplayFrame(r);
|
||||||
|
return (r.bottom - r.top);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
package su.xash.engine.workers
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.net.Uri
|
|
||||||
import androidx.documentfile.provider.DocumentFile
|
|
||||||
import androidx.work.CoroutineWorker
|
|
||||||
import androidx.work.WorkerParameters
|
|
||||||
import androidx.work.workDataOf
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
|
|
||||||
const val KEY_FILE_URI = "KEY_FILE_URI"
|
|
||||||
|
|
||||||
class FileCopyWorker(ctx: Context, params: WorkerParameters) : CoroutineWorker(ctx, params) {
|
|
||||||
companion object {
|
|
||||||
const val Input = "Input"
|
|
||||||
const val Progress = "Progress"
|
|
||||||
}
|
|
||||||
|
|
||||||
private var fileCount = 0
|
|
||||||
private var fileCopied = 0
|
|
||||||
|
|
||||||
override suspend fun doWork(): Result {
|
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
val fileUri = inputData.getString(KEY_FILE_URI)
|
|
||||||
setProgress(workDataOf(Input to fileUri))
|
|
||||||
|
|
||||||
val uri = Uri.parse(fileUri)
|
|
||||||
val source = DocumentFile.fromTreeUri(applicationContext, uri)
|
|
||||||
|
|
||||||
fileCount = source?.countDirFiles() ?: return@withContext Result.failure()
|
|
||||||
|
|
||||||
setProgress(workDataOf(Progress to 0f))
|
|
||||||
|
|
||||||
val gamedir = source.name!!
|
|
||||||
val externalFilesDir = DocumentFile.fromFile(applicationContext.getExternalFilesDir(null)!!)
|
|
||||||
|
|
||||||
// create a directory to store staged files
|
|
||||||
val target = externalFilesDir.createDirectory(".$gamedir")!!
|
|
||||||
|
|
||||||
source.copyDirTo(applicationContext, this@FileCopyWorker, target)
|
|
||||||
|
|
||||||
target.renameTo(gamedir)
|
|
||||||
|
|
||||||
setProgress(workDataOf(Progress to 1f))
|
|
||||||
}
|
|
||||||
return Result.success()
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun fileCopied(count: Int) {
|
|
||||||
if(count == 0)
|
|
||||||
return
|
|
||||||
|
|
||||||
fileCopied += count
|
|
||||||
val percentage: Float = fileCopied.toFloat() / fileCount.toFloat();
|
|
||||||
setProgress(workDataOf(Progress to percentage))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun DocumentFile.countDirFiles(): Int {
|
|
||||||
var count: Int = 0
|
|
||||||
|
|
||||||
listFiles().forEach {
|
|
||||||
if (it.isDirectory)
|
|
||||||
count += it.countDirFiles()
|
|
||||||
else
|
|
||||||
count++
|
|
||||||
}
|
|
||||||
|
|
||||||
return count
|
|
||||||
}
|
|
||||||
|
|
||||||
fun DocumentFile.copyFileTo(ctx: Context, file: DocumentFile) {
|
|
||||||
val outFile = file.createFile("application", name!!)!!
|
|
||||||
|
|
||||||
ctx.contentResolver.openOutputStream(outFile.uri).use { os ->
|
|
||||||
ctx.contentResolver.openInputStream(uri).use {
|
|
||||||
it?.copyTo(os!!)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun DocumentFile.copyDirTo(ctx: Context, worker: FileCopyWorker, dir: DocumentFile) {
|
|
||||||
var count: Int = 0
|
|
||||||
|
|
||||||
listFiles().forEach {
|
|
||||||
if (it.isDirectory) {
|
|
||||||
val outDir = dir.createDirectory(it.name!!)!!
|
|
||||||
it.copyDirTo(ctx, worker, outDir)
|
|
||||||
} else {
|
|
||||||
it.copyFileTo(ctx, dir)
|
|
||||||
count++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
worker.fileCopied(count)
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<vector android:height="24dp" android:tint="#000000"
|
|
||||||
android:viewportHeight="24" android:viewportWidth="24"
|
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<path android:fillColor="@android:color/white" android:pathData="M21,10h-8.35C11.83,7.67 9.61,6 7,6c-3.31,0 -6,2.69 -6,6s2.69,6 6,6c2.61,0 4.83,-1.67 5.65,-4H13l2,2l2,-2l2,2l4,-4.04L21,10zM7,15c-1.65,0 -3,-1.35 -3,-3c0,-1.65 1.35,-3 3,-3s3,1.35 3,3C10,13.65 8.65,15 7,15z"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<vector android:height="24dp" android:tint="#000000"
|
|
||||||
android:viewportHeight="24" android:viewportWidth="24"
|
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<path android:fillColor="@android:color/white" android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<item android:state_enabled="true">
|
|
||||||
<shape android:shape="rectangle">
|
|
||||||
<gradient android:endColor="#2D73FF" android:startColor="#06BFFF" />
|
|
||||||
<corners android:radius="4dp" />
|
|
||||||
</shape>
|
|
||||||
</item>
|
|
||||||
<item android:state_enabled="false">
|
|
||||||
<shape android:shape="rectangle">
|
|
||||||
<gradient android:endColor="#6D6D6D" android:startColor="#8F8F8F" />
|
|
||||||
<corners android:radius="4dp" />
|
|
||||||
</shape>
|
|
||||||
</item>
|
|
||||||
</selector>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="24"
|
|
||||||
android:viewportHeight="24">
|
|
||||||
<path
|
|
||||||
android:fillColor="#FF000000"
|
|
||||||
android:pathData="M12.004,2c-5.25,0 -9.556,4.05 -9.964,9.197l5.36,2.216c0.454,-0.31 1.002,-0.492 1.593,-0.492 0.053,0 0.104,0.003 0.157,0.005l2.384,-3.452v-0.049c0,-2.08 1.69,-3.77 3.77,-3.77 2.079,0 3.77,1.692 3.77,3.772s-1.692,3.771 -3.77,3.771h-0.087l-3.397,2.426c0,0.043 0.003,0.088 0.003,0.133 0,1.562 -1.262,2.83 -2.825,2.83 -1.362,0 -2.513,-0.978 -2.775,-2.273l-3.838,-1.589C3.573,18.922 7.427,22 12.005,22c5.522,0 9.998,-4.477 9.998,-10 0,-5.522 -4.477,-10 -9.999,-10zM7.078,16.667c0.218,0.452 0.595,0.832 1.094,1.041 1.081,0.45 2.328,-0.063 2.777,-1.145 0.22,-0.525 0.22,-1.1 0.004,-1.625 -0.215,-0.525 -0.625,-0.934 -1.147,-1.152 -0.52,-0.217 -1.075,-0.208 -1.565,-0.025l1.269,0.525c0.797,0.333 1.174,1.25 0.84,2.046 -0.33,0.797 -1.247,1.175 -2.044,0.843l-1.228,-0.508zM17.818,9.422c0,-1.385 -1.128,-2.512 -2.513,-2.512 -1.387,0 -2.512,1.127 -2.512,2.512 0,1.388 1.125,2.513 2.512,2.513 1.386,0 2.512,-1.125 2.512,-2.513zM15.31,7.53c1.04,0 1.888,0.845 1.888,1.888s-0.847,1.888 -1.888,1.888c-1.044,0 -1.888,-0.845 -1.888,-1.888s0.845,-1.888 1.888,-1.888z"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="295.46dp"
|
|
||||||
android:height="90.47dp"
|
|
||||||
android:viewportWidth="295.46"
|
|
||||||
android:viewportHeight="90.47">
|
|
||||||
<path
|
|
||||||
android:fillColor="#FF000000"
|
|
||||||
android:pathData="m45.08,1c-23.24,0 -42.28,17.92 -44.08,40.69l23.71,9.8c2.01,-1.37 4.44,-2.18 7.05,-2.18 0.23,0 0.47,0.01 0.7,0.02l10.54,-15.28c0,-0.07 0,-0.14 0,-0.22 0,-9.2 7.48,-16.68 16.68,-16.68 9.2,0 16.68,7.48 16.68,16.68s-7.48,16.68 -16.68,16.68c-0.13,0 -0.25,0 -0.38,-0.01l-15.04,10.73c0.01,0.19 0.01,0.39 0.01,0.59 0,6.91 -5.62,12.52 -12.52,12.52 -6.06,0 -11.13,-4.33 -12.28,-10.06l-16.96,-7.01c5.25,18.57 22.31,32.18 42.56,32.18 24.43,0 44.24,-19.81 44.24,-44.24 0,-24.43 -19.81,-44.24 -44.24,-44.24"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#FF000000"
|
|
||||||
android:pathData="m28.72,68.12 l-5.43,-2.24c0.96,2.01 2.63,3.68 4.84,4.61 4.78,1.99 10.3,-0.28 12.29,-5.06 0.96,-2.31 0.97,-4.87 0.01,-7.19 -0.95,-2.32 -2.76,-4.13 -5.07,-5.1 -2.3,-0.96 -4.76,-0.92 -6.93,-0.1l5.61,2.32c3.53,1.47 5.2,5.52 3.72,9.05 -1.47,3.53 -5.52,5.2 -9.05,3.72"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#FF000000"
|
|
||||||
android:pathData="m70.8,33.83c0,-6.13 -4.99,-11.12 -11.12,-11.12 -6.13,0 -11.12,4.99 -11.12,11.12 0,6.13 4.99,11.11 11.12,11.11 6.13,0 11.12,-4.99 11.12,-11.11m-19.45,-0.02c0,-4.61 3.74,-8.35 8.35,-8.35s8.35,3.74 8.35,8.35 -3.74,8.35 -8.35,8.35 -8.35,-3.74 -8.35,-8.35"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#FF000000"
|
|
||||||
android:pathData="m136.56,31.27 l-2.96,5.21c-2.28,-1.6 -5.38,-2.56 -8.08,-2.56 -3.09,0 -5,1.28 -5,3.57 0,2.78 3.39,3.43 8.44,5.24 5.42,1.92 8.54,4.17 8.54,9.14 0,6.79 -5.34,10.61 -13.02,10.61 -3.74,0 -8.26,-0.97 -11.73,-3.08l2.16,-5.78c2.82,1.49 6.19,2.37 9.2,2.37 4.05,0 5.98,-1.5 5.98,-3.7 0,-2.53 -2.94,-3.29 -7.68,-4.86 -5.4,-1.8 -9.15,-4.17 -9.15,-9.67 0,-6.2 4.96,-9.76 12.1,-9.76 4.98,0 8.98,1.58 11.2,3.26"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#FF000000"
|
|
||||||
android:pathData="m152.76,61.9v-27.34h-10.13v-5.99h27.21v5.99h-10.1v27.34z"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#FF000000"
|
|
||||||
android:pathData="m197.9,42.05v5.99h-13.36v7.82h15.5v6.04h-22.47v-33.33h22.47v5.97h-15.5v7.51z"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#FF000000"
|
|
||||||
android:pathData="m215.62,55.43 l-2.21,6.47h-7.32l12.49,-33.33h7.03l12.85,33.32h-7.56l-2.25,-6.47h-13.03zM222.07,36.52 L217.51,49.87h9.2z"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#FF000000"
|
|
||||||
android:pathData="m261.22,60.93 l-8.97,-19.3v20.27h-6.68v-33.33h6.67l11.2,24.06 10.8,-24.06h6.73v33.33h-6.68v-20.44l-9.12,19.47z"/>
|
|
||||||
<path
|
|
||||||
android:fillColor="#FF000000"
|
|
||||||
android:pathData="m294.46,32.78c0,2.86 -2.15,4.65 -4.61,4.65 -2.47,0 -4.62,-1.78 -4.62,-4.65 0,-2.86 2.15,-4.64 4.62,-4.64 2.46,0 4.61,1.77 4.61,4.64m-8.46,0c0,2.4 1.73,3.9 3.85,3.9 2.11,0 3.83,-1.5 3.83,-3.9 0,-2.4 -1.72,-3.88 -3.83,-3.88 -2.12,0 -3.85,1.5 -3.85,3.88m3.91,-2.37c1.2,0 1.6,0.63 1.6,1.32 0,0.63 -0.37,1.05 -0.82,1.26l1.07,2.01h-0.88l-0.9,-1.78h-0.93v1.78h-0.73v-4.58zM289.05,32.54h0.81c0.53,0 0.84,-0.33 0.84,-0.75 0,-0.42 -0.22,-0.69 -0.84,-0.69h-0.81v1.44z"/>
|
|
||||||
</vector>
|
|
||||||
@@ -1,35 +1,36 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_height="match_parent"
|
android:layout_width="match_parent"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
android:layout_height="match_parent"
|
||||||
|
android:fitsSystemWindows="true">
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/appBarLayout"
|
android:id="@+id/appBarLayout"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
<androidx.appcompat.widget.Toolbar
|
<androidx.appcompat.widget.Toolbar
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent" />
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
<androidx.fragment.app.FragmentContainerView
|
<androidx.fragment.app.FragmentContainerView
|
||||||
android:id="@+id/fragmentContainerView"
|
android:id="@+id/fragmentContainerView"
|
||||||
android:name="androidx.navigation.fragment.NavHostFragment"
|
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
app:defaultNavHost="true"
|
app:defaultNavHost="true"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/appBarLayout"
|
app:layout_constraintTop_toBottomOf="@id/appBarLayout"
|
||||||
app:navGraph="@navigation/nav_graph"
|
app:navGraph="@navigation/nav_graph"
|
||||||
tools:layout="@layout/fragment_library"/>
|
tools:layout="@layout/fragment_library" />
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|||||||
@@ -1,111 +1,98 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
style="@style/Widget.Material3.CardView.Filled"
|
style="@style/Widget.Material3.CardView.Filled"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp">
|
android:layout_marginTop="8dp">
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="128dp">
|
android:layout_height="128dp">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/gameCover"
|
android:id="@+id/gameCover"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
tools:src="@android:mipmap/sym_def_app_icon" />
|
tools:src="@android:mipmap/sym_def_app_icon" />
|
||||||
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
<com.google.android.material.card.MaterialCardView
|
||||||
style="@style/Widget.Material3.CardView.Filled"
|
style="@style/Widget.Material3.CardView.Filled"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="48dp"
|
android:layout_height="48dp"
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
app:contentPadding="10dp"
|
app:contentPadding="10dp"
|
||||||
app:layout_constrainedWidth="true"
|
app:layout_constrainedWidth="true"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@id/buttonsContainer"
|
app:layout_constraintEnd_toStartOf="@id/buttonsContainer"
|
||||||
app:layout_constraintHorizontal_bias="0"
|
app:layout_constraintHorizontal_bias="0"
|
||||||
app:layout_constraintStart_toStartOf="parent">
|
app:layout_constraintStart_toStartOf="parent">
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/gameIcon"
|
android:id="@+id/gameIcon"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_marginRight="8dp"
|
android:layout_marginRight="8dp"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@id/gameTitle"
|
app:layout_constraintEnd_toStartOf="@id/gameTitle"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:src="@android:mipmap/sym_def_app_icon" />
|
tools:src="@android:mipmap/sym_def_app_icon" />
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
android:id="@+id/gameTitle"
|
android:id="@+id/gameTitle"
|
||||||
style="@style/TextAppearance.Material3.TitleMedium"
|
style="@style/TextAppearance.Material3.TitleMedium"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
app:layout_constrainedWidth="true"
|
app:layout_constrainedWidth="true"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@id/gameIcon"
|
app:layout_constraintStart_toEndOf="@id/gameIcon"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:text="Game Title" />
|
tools:text="Game Title" />
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
</com.google.android.material.card.MaterialCardView>
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
<com.google.android.material.card.MaterialCardView
|
||||||
android:id="@+id/buttonsContainer"
|
android:id="@+id/buttonsContainer"
|
||||||
style="@style/Widget.Material3.CardView.Filled"
|
style="@style/Widget.Material3.CardView.Filled"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent">
|
app:layout_constraintEnd_toEndOf="parent">
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<com.google.android.material.progressindicator.CircularProgressIndicator
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/progressIndicator"
|
android:id="@+id/launchButton"
|
||||||
android:layout_width="wrap_content"
|
style="@style/Widget.Material3.Button.IconButton"
|
||||||
android:layout_height="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:indeterminate="true"
|
android:layout_height="match_parent"
|
||||||
android:padding="10dp"
|
app:icon="@drawable/ic_baseline_play_arrow_24"
|
||||||
android:visibility="gone"
|
app:layout_constraintEnd_toStartOf="@+id/settingsButton" />
|
||||||
app:indicatorSize="20dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/launchButton"
|
android:id="@+id/settingsButton"
|
||||||
style="@style/Widget.Material3.Button.IconButton"
|
style="@style/Widget.Material3.Button.IconButton"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
app:icon="@drawable/ic_baseline_play_arrow_24"
|
app:icon="@drawable/ic_baseline_settings_24"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/settingsButton" />
|
app:layout_constraintEnd_toEndOf="parent" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
<com.google.android.material.button.MaterialButton
|
</com.google.android.material.card.MaterialCardView>
|
||||||
android:id="@+id/settingsButton"
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
style="@style/Widget.Material3.Button.IconButton"
|
</com.google.android.material.card.MaterialCardView>
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
app:icon="@drawable/ic_baseline_settings_24"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent" />
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
</com.google.android.material.card.MaterialCardView>
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
</com.google.android.material.card.MaterialCardView>
|
|
||||||
|
|||||||
@@ -1,30 +1,45 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_height="wrap_content">
|
style="@style/Widget.Material3.CardView.Filled"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="8dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
<!-- <com.google.android.material.textfield.TextInputLayout-->
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
<!-- android:layout_width="match_parent"-->
|
android:layout_width="match_parent"
|
||||||
<!-- android:layout_height="wrap_content"-->
|
android:layout_height="wrap_content"
|
||||||
<!-- app:layout_constraintTop_toTopOf="parent"-->
|
android:padding="10dp">
|
||||||
<!-- app:layout_constraintBottom_toBottomOf="parent">-->
|
|
||||||
|
|
||||||
<!-- <com.google.android.material.textfield.TextInputEditText-->
|
<TextView
|
||||||
<!-- android:layout_width="match_parent"-->
|
android:id="@android:id/title"
|
||||||
<!-- android:layout_height="wrap_content" />-->
|
android:layout_width="match_parent"
|
||||||
<!-- </com.google.android.material.textfield.TextInputLayout>-->
|
android:layout_height="wrap_content"
|
||||||
<TextView
|
android:textAppearance="@style/TextAppearance.Material3.TitleMedium"
|
||||||
android:id="@android:id/title"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
android:layout_width="match_parent"
|
tools:text="EditText Preference" />
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
<TextView
|
||||||
android:textAppearance="@style/TextAppearance.Material3.TitleMedium"/>
|
android:id="@android:id/summary"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@android:id/title"
|
||||||
|
tools:text="Summary" />
|
||||||
|
|
||||||
|
<!-- <com.google.android.material.button.MaterialButton-->
|
||||||
|
<!-- style="@style/Widget.Material3.Button.IconButton"-->
|
||||||
|
<!-- android:layout_width="wrap_content"-->
|
||||||
|
<!-- android:layout_height="wrap_content"-->
|
||||||
|
<!-- app:icon="@drawable/baseline_edit_24"-->
|
||||||
|
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
|
||||||
|
<!-- app:layout_constraintEnd_toEndOf="parent"-->
|
||||||
|
<!-- app:layout_constraintTop_toTopOf="parent" />-->
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@android:id/summary"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:layout_constraintTop_toBottomOf="@android:id/title"
|
|
||||||
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"/>
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
@@ -1,14 +1,12 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
android:layout_width="match_parent"
|
||||||
android:layout_width="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:paddingHorizontal="8dp">
|
|
||||||
|
|
||||||
<androidx.fragment.app.FragmentContainerView
|
<androidx.fragment.app.FragmentContainerView
|
||||||
android:id="@+id/settingsFragment"
|
android:id="@+id/settingsFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:layout="@android:layout/list_content" />
|
tools:layout="@android:layout/list_content" />
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|||||||
@@ -1,39 +1,32 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<include
|
<include
|
||||||
android:id="@+id/gameCard"
|
android:id="@+id/gameCard"
|
||||||
layout="@layout/card_game"
|
layout="@layout/card_game"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="8dp"
|
android:layout_margin="8dp"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<com.google.android.material.card.MaterialCardView
|
<androidx.fragment.app.FragmentContainerView
|
||||||
style="@style/Widget.Material3.CardView.Filled"
|
android:id="@+id/settingsFragment"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="8dp"
|
app:layout_constraintTop_toBottomOf="@id/gameCard"
|
||||||
app:contentPadding="16dp"
|
tools:layout="@android:layout/list_content">
|
||||||
app:layout_constraintTop_toBottomOf="@id/gameCard">
|
|
||||||
|
|
||||||
<androidx.fragment.app.FragmentContainerView
|
</androidx.fragment.app.FragmentContainerView>
|
||||||
android:id="@+id/settingsFragment"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
tools:layout="@android:layout/list_content" />
|
|
||||||
|
|
||||||
</com.google.android.material.card.MaterialCardView>
|
<!-- <com.google.android.material.bottomnavigation.BottomNavigationView-->
|
||||||
|
<!-- android:id="@+id/bottomNavigation"-->
|
||||||
<com.google.android.material.bottomnavigation.BottomNavigationView
|
<!-- style="@style/Widget.MaterialComponents.BottomNavigationView.Colored"-->
|
||||||
android:id="@+id/bottomNavigation"
|
<!-- android:layout_width="match_parent"-->
|
||||||
style="@style/Widget.MaterialComponents.BottomNavigationView.Colored"
|
<!-- android:layout_height="wrap_content"-->
|
||||||
android:layout_width="match_parent"
|
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
|
||||||
android:layout_height="wrap_content"
|
<!-- app:menu="@menu/menu_game_settings" />-->
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
app:menu="@menu/menu_game_settings" />
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:id="@+id/swipeRefresh"
|
||||||
android:layout_height="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:id="@+id/swipeRefresh">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/gamesList"
|
android:id="@+id/gamesList"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
app:layoutManager="LinearLayoutManager"
|
android:clipToPadding="false"
|
||||||
android:clipToPadding="false"
|
android:paddingHorizontal="8dp"
|
||||||
android:paddingHorizontal="8dp"
|
app:layoutManager="LinearLayoutManager"
|
||||||
tools:listitem="@layout/card_game" />
|
tools:listitem="@layout/card_game" />
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<androidx.viewpager2.widget.ViewPager2
|
|
||||||
android:id="@+id/viewPager"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent" />
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="@color/steam_background"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:orientation="vertical"
|
|
||||||
tools:context=".fragment.SteamLoginFragment">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/imageView"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:src="@drawable/steam_logo"
|
|
||||||
app:tint="#C5C3C0" />
|
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
|
||||||
android:layout_width="320dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_horizontal"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
app:startIconDrawable="@drawable/ic_baseline_person_24">
|
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
|
||||||
android:id="@+id/steamLogin"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:hint="@string/username"
|
|
||||||
android:inputType="textEmailAddress" />
|
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
|
||||||
android:layout_width="320dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_horizontal"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
|
|
||||||
app:startIconDrawable="@drawable/ic_baseline_key_24">
|
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
|
||||||
android:id="@+id/steamPassword"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:hint="@string/password"
|
|
||||||
android:inputType="textPassword" />
|
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/loginButton"
|
|
||||||
style="@style/App.Theme.SteamButton"
|
|
||||||
android:layout_width="240dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center_horizontal"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:text="@string/login" />
|
|
||||||
</LinearLayout>
|
|
||||||
@@ -1,19 +1,20 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
<TextView
|
|
||||||
android:id="@android:id/title"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
android:textAppearance="@style/TextAppearance.Material3.TitleMedium"/>
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@android:id/summary"
|
android:id="@android:id/title"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintTop_toBottomOf="@android:id/title"
|
android:textAppearance="@style/TextAppearance.Material3.TitleMedium"
|
||||||
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"/>
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
<TextView
|
||||||
|
android:id="@android:id/summary"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"
|
||||||
|
app:layout_constraintTop_toBottomOf="@android:id/title" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/pagePic"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:layout_marginTop="64dp"
|
|
||||||
android:layout_marginBottom="32dp"
|
|
||||||
android:src="@drawable/ic_baseline_folder_open_24"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:layout_constraintBottom_toTopOf="@id/pageTitle"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/pageTitle"
|
|
||||||
style="@style/TextAppearance.Material3.TitleLarge"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:gravity="center"
|
|
||||||
android:paddingHorizontal="16dp"
|
|
||||||
android:text="@string/setup_location_title"
|
|
||||||
android:textStyle="bold"
|
|
||||||
app:layout_constraintBottom_toTopOf="@id/pageMessage"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/pagePic" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/pageMessage"
|
|
||||||
style="@style/TextAppearance.Material3.TitleMedium"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:gravity="center"
|
|
||||||
android:paddingHorizontal="16dp"
|
|
||||||
android:text="@string/setup_location_message"
|
|
||||||
app:layout_constraintBottom_toTopOf="@id/pageButton"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/pageTitle" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/pageButton"
|
|
||||||
android:layout_width="240dp"
|
|
||||||
android:layout_marginBottom="128dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/ok"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/pageMessage" />
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/pagePic"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:layout_marginTop="64dp"
|
|
||||||
android:layout_marginBottom="32dp"
|
|
||||||
android:src="@mipmap/ic_launcher"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:layout_constraintBottom_toTopOf="@id/pageTitle"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/pageTitle"
|
|
||||||
style="@style/TextAppearance.Material3.TitleLarge"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:gravity="center"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:paddingHorizontal="16dp"
|
|
||||||
android:text="@string/setup_welcome_title"
|
|
||||||
app:layout_constraintBottom_toTopOf="@id/pageMessage"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/pagePic" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/pageMessage"
|
|
||||||
style="@style/TextAppearance.Material3.TitleMedium"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:gravity="center"
|
|
||||||
android:paddingHorizontal="16dp"
|
|
||||||
android:text="@string/setup_welcome_message"
|
|
||||||
app:layout_constraintBottom_toTopOf="@id/pageButton"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/pageTitle" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/pageButton"
|
|
||||||
android:layout_width="240dp"
|
|
||||||
android:layout_marginBottom="128dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/next"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/pageMessage" />
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:padding="32dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/textView"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/steam_guard_code"
|
|
||||||
android:textAppearance="@style/TextAppearance.Material3.TitleLarge"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
|
||||||
android:id="@+id/textInputLayout"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/textView">
|
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
|
||||||
android:id="@+id/steamCode"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:hint="@string/steam_guard_code" />
|
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
@@ -1,23 +1,37 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_height="wrap_content">
|
style="@style/Widget.Material3.CardView.Filled"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="8dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
<TextView
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@android:id/title"
|
android:layout_width="match_parent"
|
||||||
android:layout_width="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:padding="10dp">
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
<TextView
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
android:id="@android:id/title"
|
||||||
android:textAppearance="@style/TextAppearance.Material3.TitleMedium"/>
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="@style/TextAppearance.Material3.TitleMedium"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="Switch preference" />
|
||||||
|
|
||||||
|
<com.google.android.material.materialswitch.MaterialSwitch
|
||||||
|
android:id="@+id/switchWidget"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
<com.google.android.material.materialswitch.MaterialSwitch
|
|
||||||
android:id="@+id/switchWidget"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
@@ -1,14 +1,9 @@
|
|||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_dedicated"
|
android:id="@+id/action_dedicated"
|
||||||
android:icon="@drawable/ic_baseline_terminal_24"
|
android:icon="@drawable/ic_baseline_terminal_24"
|
||||||
android:title="@string/dedicated_server"
|
android:title="@string/dedicated_server"
|
||||||
app:showAsAction="always|withText"
|
android:visible="false"
|
||||||
android:visible="false"/>
|
app:showAsAction="always|withText" />
|
||||||
<item
|
</menu>
|
||||||
android:id="@+id/action_uninstall"
|
|
||||||
android:icon="@drawable/ic_baseline_delete_24"
|
|
||||||
android:title="@string/uninstall"
|
|
||||||
app:showAsAction="always|withText" />
|
|
||||||
</menu>
|
|
||||||
|
|||||||
@@ -1,19 +1,8 @@
|
|||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_browse"
|
android:id="@+id/action_settings"
|
||||||
android:icon="@drawable/ic_baseline_folder_open_24"
|
android:icon="@drawable/ic_baseline_settings_24"
|
||||||
android:title="@string/browse"
|
android:title="@string/app_settings"
|
||||||
app:showAsAction="always|withText" />
|
app:showAsAction="always|withText" />
|
||||||
<item
|
</menu>
|
||||||
android:id="@+id/action_install"
|
|
||||||
android:icon="@drawable/ic_baseline_add_24"
|
|
||||||
android:title="@string/install"
|
|
||||||
app:showAsAction="always|withText" />
|
|
||||||
<item
|
|
||||||
android:id="@+id/action_settings"
|
|
||||||
android:icon="@drawable/ic_baseline_settings_24"
|
|
||||||
android:title="@string/app_settings"
|
|
||||||
app:showAsAction="always|withText"
|
|
||||||
android:visible="false"/>
|
|
||||||
</menu>
|
|
||||||
|
|||||||
@@ -1,38 +1,26 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
|
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
android:id="@+id/nav_graph"
|
||||||
android:id="@+id/nav_graph"
|
android:label="@string/library"
|
||||||
android:label="@string/library"
|
app:startDestination="@id/libraryFragment">
|
||||||
app:startDestination="@id/libraryFragment">
|
<fragment
|
||||||
<fragment
|
android:id="@+id/libraryFragment"
|
||||||
android:id="@+id/libraryFragment"
|
android:name="su.xash.engine.ui.library.LibraryFragment"
|
||||||
android:name="su.xash.engine.ui.library.LibraryFragment"
|
android:label="@string/library">
|
||||||
android:label="@string/library">
|
<action
|
||||||
<action
|
android:id="@+id/action_libraryFragment_to_gameSettingsFragment"
|
||||||
android:id="@+id/action_libraryFragment_to_setupFragment"
|
app:destination="@id/gameSettingsFragment" />
|
||||||
app:destination="@id/setupFragment" />
|
<action
|
||||||
<action
|
android:id="@+id/action_libraryFragment_to_appSettingsFragment"
|
||||||
android:id="@+id/action_libraryFragment_to_gameSettingsFragment"
|
app:destination="@id/appSettingsFragment" />
|
||||||
app:destination="@id/gameSettingsFragment" />
|
</fragment>
|
||||||
<action
|
<fragment
|
||||||
android:id="@+id/action_libraryFragment_to_appSettingsFragment"
|
android:id="@+id/gameSettingsFragment"
|
||||||
app:destination="@id/appSettingsFragment" />
|
android:name="su.xash.engine.ui.settings.GameSettingsFragment"
|
||||||
</fragment>
|
android:label="@string/game_settings" />
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/setupFragment"
|
android:id="@+id/appSettingsFragment"
|
||||||
android:name="su.xash.engine.ui.setup.SetupFragment"
|
android:name="su.xash.engine.ui.settings.AppSettingsFragment"
|
||||||
android:label="@string/setup" >
|
android:label="@string/app_settings" />
|
||||||
<action
|
</navigation>
|
||||||
android:id="@+id/action_setupFragment_to_libraryFragment"
|
|
||||||
app:destination="@id/libraryFragment" />
|
|
||||||
</fragment>
|
|
||||||
<fragment
|
|
||||||
android:id="@+id/gameSettingsFragment"
|
|
||||||
android:name="su.xash.engine.ui.settings.GameSettingsFragment"
|
|
||||||
android:label="@string/game_settings" />
|
|
||||||
<fragment
|
|
||||||
android:id="@+id/appSettingsFragment"
|
|
||||||
android:name="su.xash.engine.ui.settings.AppSettingsFragment"
|
|
||||||
android:label="@string/app_settings" />
|
|
||||||
</navigation>
|
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<string name="ok">Ok</string>
|
|
||||||
<string name="cancel">Cancelar</string>
|
|
||||||
</resources>
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<string name="cancel">Annulla</string>
|
|
||||||
<string name="ok">Ok</string>
|
|
||||||
</resources>
|
|
||||||
@@ -1,33 +1,14 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="ok">Ok</string>
|
<string name="library">Biblioteca</string>
|
||||||
<string name="cancel">Cancelar</string>
|
<string name="dedicated_server">Dedicado</string>
|
||||||
<string name="next">Próximo</string>
|
<string name="app_settings">Configurações</string>
|
||||||
<string name="browse">Navegar</string>
|
<string name="game_settings">Configurações do jogo</string>
|
||||||
<string name="install">Instalar</string>
|
<string name="game_settings_command_line">Argumentos de linha de comando</string>
|
||||||
<string name="library">Biblioteca</string>
|
<string name="game_settings_volume_buttons">Usar botões de volume no jogo</string>
|
||||||
<string name="steam_guard_code">Código do Steam Guard</string>
|
<string name="preferences_package_name">Bibliotecas de pacotes</string>
|
||||||
<string name="steam_login">Logar com Steam</string>
|
<string name="preferences_separate_libraries">Bibliotecas de pacotes separados</string>
|
||||||
<string name="login">Logar</string>
|
<string name="preferences_client_package">Pacotes de Cliente</string>
|
||||||
<string name="username">Usuário</string>
|
<string name="preferences_server_package">Pacotes de Servidor</string>
|
||||||
<string name="password">Senha</string>
|
<string name="preferences_use_icons">Usar ícones ao inves de imagens de fundo</string>
|
||||||
<string name="uninstall">Desinstalar</string>
|
|
||||||
<string name="dedicated_server">Dedicado</string>
|
|
||||||
<string name="error">Erro!</string>
|
|
||||||
<string name="setup">Configurar</string>
|
|
||||||
<string name="app_settings">Configurações</string>
|
|
||||||
<string name="game_settings">Configurações do jogo</string>
|
|
||||||
<string name="game_settings_command_line">Argumentos de linha de comando</string>
|
|
||||||
<string name="game_settings_volume_buttons">Usar botões de volume no jogo</string>
|
|
||||||
<string name="setup_welcome_title">Bem vindo ao Xash3D FWGS!</string>
|
|
||||||
<string name="setup_welcome_message">Agora, nós vamos guiá-lo durante o processo de instalação.</string>
|
|
||||||
<string name="setup_location_title">Jogos</string>
|
|
||||||
<string name="setup_location_message">Selecione a pasta onde seus jogos estão localizados.</string>
|
|
||||||
<string name="setup_location_empty">A pasta selecionada não contem nenhum jogo.</string>
|
|
||||||
<string name="setup_location_invalid">A pasta selecionada é invalida.</string>
|
|
||||||
<string name="preferences_package_name">Bibliotecas de pacotes</string>
|
|
||||||
<string name="preferences_separate_libraries">Bibliotecas de pacotes separados</string>
|
|
||||||
<string name="preferences_client_package">Pacotes de Cliente</string>
|
|
||||||
<string name="preferences_server_package">Pacotes de Servidor</string>
|
|
||||||
<string name="preferences_use_icons">Usar ícones ao inves de imagens de fundo</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1,33 +1,14 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="cancel">Отмена</string>
|
<string name="library">Библиотека</string>
|
||||||
<string name="ok">ОК</string>
|
<string name="dedicated_server">Выделенный</string>
|
||||||
<string name="next">Далее</string>
|
<string name="app_settings">Настройки</string>
|
||||||
<string name="browse">Обзор</string>
|
<string name="game_settings">Настройки игры</string>
|
||||||
<string name="install">Установить</string>
|
<string name="game_settings_command_line">Аргументы командной строки</string>
|
||||||
<string name="library">Библиотека</string>
|
<string name="game_settings_volume_buttons">Использовать кнопки громкости</string>
|
||||||
<string name="steam_guard_code">Код Steam Guard</string>
|
<string name="preferences_package_name">Пакет библиотек</string>
|
||||||
<string name="steam_login">Логин Steam</string>
|
<string name="preferences_separate_libraries">Библиотеки из отдельных пакетов</string>
|
||||||
<string name="login">Логин</string>
|
<string name="preferences_client_package">Пакет клиента</string>
|
||||||
<string name="username">Имя пользователя</string>
|
<string name="preferences_server_package">Пакет сервера</string>
|
||||||
<string name="password">Пароль</string>
|
<string name="preferences_use_icons">Использовать иконки вместо фона</string>
|
||||||
<string name="uninstall">Удалить</string>
|
</resources>
|
||||||
<string name="dedicated_server">Выделенный</string>
|
|
||||||
<string name="error">Ошибка!</string>
|
|
||||||
<string name="setup">Установка</string>
|
|
||||||
<string name="app_settings">Настройки</string>
|
|
||||||
<string name="game_settings">Настройки игры</string>
|
|
||||||
<string name="game_settings_command_line">Аргументы командной строки</string>
|
|
||||||
<string name="game_settings_volume_buttons">Использовать кнопки громкости</string>
|
|
||||||
<string name="setup_welcome_title">Добро пожаловать в Xash3D FWGS!</string>
|
|
||||||
<string name="setup_welcome_message">Теперь мы ознакомим вас с процессом установки.</string>
|
|
||||||
<string name="setup_location_title">Игры</string>
|
|
||||||
<string name="setup_location_message">Выберите папку, в которой находятся ваши игры.</string>
|
|
||||||
<string name="setup_location_empty">Выбранный каталог не содержит ни одной игры.</string>
|
|
||||||
<string name="setup_location_invalid">Выбранный каталог недопустим.</string>
|
|
||||||
<string name="preferences_package_name">Пакет библиотек</string>
|
|
||||||
<string name="preferences_separate_libraries">Библиотеки из отдельных пакетов</string>
|
|
||||||
<string name="preferences_client_package">Пакет клиента</string>
|
|
||||||
<string name="preferences_server_package">Пакет сервера</string>
|
|
||||||
<string name="preferences_use_icons">Использовать иконки вместо фона</string>
|
|
||||||
</resources>
|
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<string name="ok">Tamam</string>
|
|
||||||
<string name="cancel">İptal</string>
|
|
||||||
</resources>
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<string name="ok">Ок</string>
|
|
||||||
<string name="cancel">Скасувати</string>
|
|
||||||
</resources>
|
|
||||||
@@ -1,12 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<color name="valve_red">#F74843</color>
|
<color name="valve_red">#F74843</color>
|
||||||
<color name="steam_grey">#C5C3C0</color>
|
<color name="hl_orange">#FB7E14</color>
|
||||||
<color name="steam_background">#181A21</color>
|
<color name="black">#000000</color>
|
||||||
<color name="steam_dark_grey">#32353C</color>
|
<color name="hl_dark_grey">#151515</color>
|
||||||
<color name="hl_orange">#FB7E14</color>
|
<color name="hl_grey">#292929</color>
|
||||||
<color name="black">#000000</color>
|
|
||||||
<color name="hl_dark_grey">#151515</color>
|
|
||||||
<color name="hl_grey">#292929</color>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<color name="ic_launcher_background">#F74843</color>
|
<color name="ic_launcher_background">#F74843</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1,36 +1,19 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name" translatable="false">Xash3D FWGS</string>
|
<string name="app_name" translatable="false">Xash3D FWGS</string>
|
||||||
<string name="authority" translatable="false">su.xash.engine.documents</string>
|
<string name="library">Library</string>
|
||||||
<string name="cancel">Cancel</string>
|
<string name="dedicated_server">Dedicated</string>
|
||||||
<string name="ok">OK</string>
|
<string name="app_settings">Settings</string>
|
||||||
<string name="next">Next</string>
|
<string name="game_settings">Game Settings</string>
|
||||||
<string name="browse">Browse</string>
|
<string name="game_settings_command_line">Command-line arguments</string>
|
||||||
<string name="install">Install</string>
|
<string name="game_settings_volume_buttons">Use volume buttons in-game</string>
|
||||||
<string name="library">Library</string>
|
<string name="preferences_package_name">Libraries package</string>
|
||||||
<string name="steam_guard_code">Steam Guard Code</string>
|
<string name="preferences_separate_libraries">Libraries from separate packages</string>
|
||||||
<string name="steam_login">Steam Login</string>
|
<string name="preferences_client_package">Client package</string>
|
||||||
<string name="login">Login</string>
|
<string name="preferences_server_package">Server package</string>
|
||||||
<string name="username">Username</string>
|
<string name="preferences_use_icons">Use icons instead of backgrounds</string>
|
||||||
<string name="password">Password</string>
|
<string name="game_data_location">Game data location</string>
|
||||||
<string name="steam" translatable="false">Steam</string>
|
<string name="file_access_required">All-files access required</string>
|
||||||
<string name="uninstall">Uninstall</string>
|
<string name="file_access_message">All-files access is required for the app to function properly.</string>
|
||||||
<string name="dedicated_server">Dedicated</string>
|
<string name="select_current_directory">Select current directory</string>
|
||||||
<string name="error">Error!</string>
|
</resources>
|
||||||
<string name="setup">Setup</string>
|
|
||||||
<string name="app_settings">Settings</string>
|
|
||||||
<string name="game_settings">Game Settings</string>
|
|
||||||
<string name="game_settings_command_line">Command-line arguments</string>
|
|
||||||
<string name="game_settings_volume_buttons">Use volume buttons in-game</string>
|
|
||||||
<string name="setup_welcome_title">Welcome to Xash3D FWGS!</string>
|
|
||||||
<string name="setup_welcome_message">Now, we will guide you through the installation process.</string>
|
|
||||||
<string name="setup_location_title">Games</string>
|
|
||||||
<string name="setup_location_message">Select the folder, where your games are located.</string>
|
|
||||||
<string name="setup_location_empty">Selected directory doesn\'t contain any games.</string>
|
|
||||||
<string name="setup_location_invalid">Selected directory is invalid.</string>
|
|
||||||
<string name="preferences_package_name">Libraries package</string>
|
|
||||||
<string name="preferences_separate_libraries">Libraries from separate packages</string>
|
|
||||||
<string name="preferences_client_package">Client package</string>
|
|
||||||
<string name="preferences_server_package">Server package</string>
|
|
||||||
<string name="preferences_use_icons">Use icons instead of backgrounds</string>
|
|
||||||
</resources>
|
|
||||||
|
|||||||
@@ -1,14 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<style name="App.Theme.SteamButton" parent="@style/Widget.Material3.Button">
|
<style name="ShapeAppearance.App.MediumComponent" parent="ShapeAppearance.Material3.MediumComponent">
|
||||||
<item name="android:background">@drawable/steam_button_gradient</item>
|
<item name="cornerSize">4dp</item>
|
||||||
<item name="backgroundTint">@null</item>
|
</style>
|
||||||
<item name="android:textColor">#FFFFFF</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style name="ShapeAppearance.App.MediumComponent" parent="ShapeAppearance.Material3.MediumComponent">
|
|
||||||
<item name="cornerSize">4dp</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<style name="Theme.App" parent="Theme.Material3.Dark.NoActionBar">
|
|
||||||
<item name="colorPrimary">@color/hl_orange</item>
|
|
||||||
<item name="colorPrimaryDark">@color/hl_dark_grey</item>
|
|
||||||
<!-- <item name="colorPrimaryContainer">@color/valve_red</item>-->
|
|
||||||
<item name="colorSurface">@color/hl_grey</item>
|
|
||||||
<item name="colorSurfaceVariant">@color/hl_grey</item>
|
|
||||||
<item name="android:colorBackground">@color/hl_dark_grey</item>
|
|
||||||
<item name="colorControlNormal">@color/hl_orange</item>
|
|
||||||
<item name="colorOnPrimary">@color/hl_dark_grey</item>
|
|
||||||
<!-- <item name="colorOnPrimaryContainer">@android:color/white</item>-->
|
|
||||||
<!-- <item name="colorOnSurface">@android:color/white</item>-->
|
|
||||||
<!-- <item name="colorOnSurfaceVariant">@android:color/white</item>-->
|
|
||||||
|
|
||||||
<!-- <item name="shapeAppearanceMediumComponent">@style/ShapeAppearance.App.MediumComponent</item>-->
|
<style name="Theme.App" parent="Theme.Material3.Dark.NoActionBar">
|
||||||
</style>
|
<item name="colorPrimary">@color/hl_orange</item>
|
||||||
</resources>
|
<item name="colorPrimaryDark">@color/hl_dark_grey</item>
|
||||||
|
<!-- <item name="colorPrimaryContainer">@color/valve_red</item>-->
|
||||||
|
<item name="colorSurface">@color/hl_grey</item>
|
||||||
|
<item name="colorSurfaceVariant">@color/hl_grey</item>
|
||||||
|
<item name="android:colorBackground">@color/hl_dark_grey</item>
|
||||||
|
<item name="colorControlNormal">@color/hl_orange</item>
|
||||||
|
<item name="colorOnPrimary">@color/hl_dark_grey</item>
|
||||||
|
<!-- <item name="colorOnPrimaryContainer">@android:color/white</item>-->
|
||||||
|
<!-- <item name="colorOnSurface">@android:color/white</item>-->
|
||||||
|
<!-- <item name="colorOnSurfaceVariant">@android:color/white</item>-->
|
||||||
|
|
||||||
|
<!-- <item name="shapeAppearanceMediumComponent">@style/ShapeAppearance.App.MediumComponent</item>-->
|
||||||
|
</style>
|
||||||
|
</resources>
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
<SwitchPreferenceCompat
|
<Preference
|
||||||
app:key="use_icons"
|
app:key="game_path"
|
||||||
app:layout="@layout/switch_preference"
|
app:layout="@layout/edit_text_preference"
|
||||||
app:title="@string/preferences_use_icons" />
|
app:title="@string/game_data_location"
|
||||||
</PreferenceScreen>
|
android:summary="/storage/emulated/0/xash" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
app:key="use_icons"
|
||||||
|
app:layout="@layout/switch_preference"
|
||||||
|
app:title="@string/preferences_use_icons" />
|
||||||
|
</PreferenceScreen>
|
||||||
|
|||||||