Compare commits
1741 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
292a6aeab3 | ||
|
|
7fbfcf1a92 | ||
|
|
1bcb28a1ad | ||
|
|
d51b0f60a2 | ||
|
|
ab9880159e | ||
|
|
0f94634361 | ||
|
|
f1492cc829 | ||
|
|
0ecee529d7 | ||
|
|
e9bfd96dd9 | ||
|
|
fb9dcf77c6 | ||
|
|
33851c1cb6 | ||
|
|
494203ef5a | ||
|
|
74f76f7305 | ||
|
|
62dbbea083 | ||
|
|
538c52bc2a | ||
|
|
b62eb1845b | ||
|
|
7c45564979 | ||
|
|
f8d2425242 | ||
|
|
50cedfc699 | ||
|
|
f4f596ca0c | ||
|
|
85aab426c5 | ||
|
|
29ff5f152e | ||
|
|
8213a720a3 | ||
|
|
afe3e09a27 | ||
|
|
ae20fa17c9 | ||
|
|
a6c03e9928 | ||
|
|
864c751aea | ||
|
|
f931d5c442 | ||
|
|
55cec86e5f | ||
|
|
4ec8ef753a | ||
|
|
3f22e23565 | ||
|
|
a73dd5ef6a | ||
|
|
653a477060 | ||
|
|
44113d2536 | ||
|
|
1165d3bdd1 | ||
|
|
c73cdc49a4 | ||
|
|
4e3ecf9b6d | ||
|
|
a40363c1fb | ||
|
|
46dd5ecddd | ||
|
|
b765bcb51f | ||
|
|
26bd7116a1 | ||
|
|
4d2f0da1fc | ||
|
|
c2f585da95 | ||
|
|
327c3cd9ff | ||
|
|
c64ca2e54b | ||
|
|
85955ebf75 | ||
|
|
d749205427 | ||
|
|
438ceb1984 | ||
|
|
5acb5115b9 | ||
|
|
37dc9e60eb | ||
|
|
c2191df359 | ||
|
|
d08da1b3c8 | ||
|
|
36f425b8cd | ||
|
|
dc3c379049 | ||
|
|
4ff7d4c554 | ||
|
|
db13f39b30 | ||
|
|
5a9c49f8d4 | ||
|
|
8ee85f2c16 | ||
|
|
2081b63b56 | ||
|
|
94f1fbf4db | ||
|
|
ab8a8068e0 | ||
|
|
79d2b28d5b | ||
|
|
18dc488ab9 | ||
|
|
a9340b2642 | ||
|
|
670e06816b | ||
|
|
53349cbd1a | ||
|
|
1794c81b61 | ||
|
|
dbe9acb3d8 | ||
|
|
22915a91a1 | ||
|
|
1289897004 | ||
|
|
9692da12b4 | ||
|
|
e34a99b38c | ||
|
|
f79eae8b83 | ||
|
|
38288d5e6a | ||
|
|
2050516bf1 | ||
|
|
02f486ebf4 | ||
|
|
9edce9ad91 | ||
|
|
ac8d93d5b9 | ||
|
|
bee4536c1a | ||
|
|
da2206168b | ||
|
|
17f930ea6f | ||
|
|
f23348c6cb | ||
|
|
21cbcb0e04 | ||
|
|
925c7526ee | ||
|
|
30e3deb8e2 | ||
|
|
ee34dcf96e | ||
|
|
49d800ff27 | ||
|
|
15f30b532c | ||
|
|
df06010846 | ||
|
|
696b344ef5 | ||
|
|
e63d99763e | ||
|
|
60850610f9 | ||
|
|
e16179b797 | ||
|
|
784b914a43 | ||
|
|
b9933b1158 | ||
|
|
878b3798f3 | ||
|
|
bc0e9a09fc | ||
|
|
8c34c0de50 | ||
|
|
5a93bc6109 | ||
|
|
8125da7882 | ||
|
|
d699187006 | ||
|
|
cff29149db | ||
|
|
3926f27d33 | ||
|
|
9bc5f06a19 | ||
|
|
a70f76a34d | ||
|
|
4dcdf09a01 | ||
|
|
f26d35070e | ||
|
|
a04266df54 | ||
|
|
2ec6a6afbc | ||
|
|
49f5b527db | ||
|
|
00287612de | ||
|
|
4b18cc2cc6 | ||
|
|
b2ed5b9341 | ||
|
|
a30dd08cd1 | ||
|
|
7420a7c7ab | ||
|
|
3f9148fa62 | ||
|
|
8cc41fa222 | ||
|
|
f06fb8c32e | ||
|
|
6ee15122f9 | ||
|
|
c9843e08bd | ||
|
|
7b47c39e6b | ||
|
|
b26ab375b5 | ||
|
|
9c4da7fa68 | ||
|
|
d64a1c760b | ||
|
|
555213714f | ||
|
|
7f27141a16 | ||
|
|
a8227a964d | ||
|
|
a7a9aac23a | ||
|
|
1176cc98e3 | ||
|
|
a7622f58ae | ||
|
|
67814db6ad | ||
|
|
8959c2ff91 | ||
|
|
a6eb99d23c | ||
|
|
fd46baae21 | ||
|
|
273bab7856 | ||
|
|
8133198cc2 | ||
|
|
25976f3b87 | ||
|
|
f71277eb64 | ||
|
|
b30b319214 | ||
|
|
e411f11c0c | ||
|
|
e30a7fccf2 | ||
|
|
12a0414f61 | ||
|
|
44322a7d07 | ||
|
|
8d4a7c3374 | ||
|
|
29c1a479a4 | ||
|
|
ee6489fb69 | ||
|
|
87c977a3e6 | ||
|
|
54e55e7534 | ||
|
|
65ab37b819 | ||
|
|
873e3bd676 | ||
|
|
6b37051980 | ||
|
|
cf5c81f7e2 | ||
|
|
9d280f51df | ||
|
|
f26ed86973 | ||
|
|
38f1370d59 | ||
|
|
213e0ceb9a | ||
|
|
7688fc2b16 | ||
|
|
20b3d8bffa | ||
|
|
2e0ec6ae9e | ||
|
|
a170f072ff | ||
|
|
e7542afd1c | ||
|
|
71b444288b | ||
|
|
94271b866b | ||
|
|
6e591f5ace | ||
|
|
4802988bbb | ||
|
|
292b80cf37 | ||
|
|
5048e74c79 | ||
|
|
c3086e5249 | ||
|
|
bb658319cb | ||
|
|
14f1552ad7 | ||
|
|
61c8cfdca6 | ||
|
|
af526b9113 | ||
|
|
6df33005a7 | ||
|
|
e9cb602ab7 | ||
|
|
a13587e139 | ||
|
|
6979b56d8c | ||
|
|
3a2edf7ddd | ||
|
|
a643170426 | ||
|
|
4964cccff9 | ||
|
|
82535da861 | ||
|
|
f70fb212f7 | ||
|
|
588b56530e | ||
|
|
3ad4e2478e | ||
|
|
c118675369 | ||
|
|
8b0622ff5c | ||
|
|
900e5786b6 | ||
|
|
2535174e00 | ||
|
|
7398b48345 | ||
|
|
eed320b055 | ||
|
|
01d2582c44 | ||
|
|
536eb03b50 | ||
|
|
1b37c9da66 | ||
|
|
e253833b68 | ||
|
|
ae729bcd15 | ||
|
|
9be6134073 | ||
|
|
59e3b83d74 | ||
|
|
4bdddf1051 | ||
|
|
211e404687 | ||
|
|
4cde23f4fe | ||
|
|
dbb6e4713d | ||
|
|
8c2c33093b | ||
|
|
63aeef1ba0 | ||
|
|
51c4f3eae8 | ||
|
|
455b56749c | ||
|
|
673851ffbd | ||
|
|
20be8d0da3 | ||
|
|
967b0c1982 | ||
|
|
fcea407708 | ||
|
|
5168eb63aa | ||
|
|
4a8e0487bc | ||
|
|
e7f86f8687 | ||
|
|
f97766019a | ||
|
|
6aae0f952c | ||
|
|
b72959f257 | ||
|
|
64a427fa62 | ||
|
|
32a8800344 | ||
|
|
1c789111e8 | ||
|
|
0b8eddbf25 | ||
|
|
631b3eddfb | ||
|
|
98e6af87c1 | ||
|
|
639f0e2c1a | ||
|
|
ba6d0d20fc | ||
|
|
14a89f94a6 | ||
|
|
8307564336 | ||
|
|
fffb1031f7 | ||
|
|
0bda3c9f43 | ||
|
|
0f3bfd894e | ||
|
|
054d36baa0 | ||
|
|
8e1270dcdc | ||
|
|
fec7eb66ea | ||
|
|
7c550a1ce4 | ||
|
|
333147cfd5 | ||
|
|
d25781f36c | ||
|
|
75ff154eca | ||
|
|
49464451dd | ||
|
|
c0eaf29cb5 | ||
|
|
87d1aad3d1 | ||
|
|
6f4212ebc8 | ||
|
|
6a365be734 | ||
|
|
2e52db6e93 | ||
|
|
ece2897c37 | ||
|
|
4ee8c41abd | ||
|
|
66ef30449a | ||
|
|
edddba6991 | ||
|
|
bc7aa5539c | ||
|
|
7348737878 | ||
|
|
fd42c5b129 | ||
|
|
3bad8f5934 | ||
|
|
72fc1583be | ||
|
|
aac4334b37 | ||
|
|
6f4098a2d9 | ||
|
|
b50a7587da | ||
|
|
f7f871ffc1 | ||
|
|
2193aa11a4 | ||
|
|
1ec9aad47f | ||
|
|
fb51a31dd2 | ||
|
|
ef528a4f3a | ||
|
|
792f9790ea | ||
|
|
661c6c9ccf | ||
|
|
809c622ad4 | ||
|
|
a51e740040 | ||
|
|
c7befd1913 | ||
|
|
03e758a037 | ||
|
|
10f1365905 | ||
|
|
dfb9378297 | ||
|
|
94c848b0de | ||
|
|
b088fee0e8 | ||
|
|
e9ffa69412 | ||
|
|
5a7ba9ffea | ||
|
|
def4c05dbc | ||
|
|
309870517e | ||
|
|
0d462268e9 | ||
|
|
831db874e4 | ||
|
|
fdac36df9f | ||
|
|
ad9ce1265e | ||
|
|
16f637329f | ||
|
|
d9a44ee061 | ||
|
|
1ce76470c2 | ||
|
|
4e3897636d | ||
|
|
90848b8972 | ||
|
|
473c74e63b | ||
|
|
2e8c003572 | ||
|
|
641649c1aa | ||
|
|
8b2fa7e554 | ||
|
|
67e3a863cc | ||
|
|
f8424a9fac | ||
|
|
237239d466 | ||
|
|
2f4836b045 | ||
|
|
c15b95e2be | ||
|
|
d7f2e90984 | ||
|
|
dcc0ed27d8 | ||
|
|
debfbdc017 | ||
|
|
dd45519d21 | ||
|
|
d36ac86b2a | ||
|
|
ecf3417b45 | ||
|
|
53e5eb6748 | ||
|
|
851febf61d | ||
|
|
dac091cea4 | ||
|
|
efc764020a | ||
|
|
9c7b482a20 | ||
|
|
8f6c76e93a | ||
|
|
0e48559109 | ||
|
|
34b9f8d755 | ||
|
|
8cca316fb5 | ||
|
|
4ddac48f1e | ||
|
|
e9c266cd16 | ||
|
|
b0ed60c2f0 | ||
|
|
099c62672b | ||
|
|
6c82d448f7 | ||
|
|
033cfd34e5 | ||
|
|
c3eeb1e90f | ||
|
|
85aa352215 | ||
|
|
aa6b7fad1f | ||
|
|
43dbba1152 | ||
|
|
8dac16bfc4 | ||
|
|
72ba7d37e0 | ||
|
|
183429867a | ||
|
|
8a247bd8aa | ||
|
|
a198bfaecd | ||
|
|
c413a70c56 | ||
|
|
e5e8e6d9b5 | ||
|
|
f7b4c786d7 | ||
|
|
3bf8255581 | ||
|
|
fe3de55409 | ||
|
|
deb81ec6cd | ||
|
|
b85f1341c1 | ||
|
|
ab077bc48f | ||
|
|
884bdb0fe2 | ||
|
|
f63d82ce9b | ||
|
|
3ad7a8ce9d | ||
|
|
b916ef5ae9 | ||
|
|
9c2fbfcae6 | ||
|
|
1814bd3e1f | ||
|
|
070b7b6d12 | ||
|
|
a0fdb3e6d7 | ||
|
|
94d37544b2 | ||
|
|
0e9d024c5d | ||
|
|
de63462363 | ||
|
|
e39cc1ca15 | ||
|
|
ebb4f26777 | ||
|
|
571d6c6865 | ||
|
|
5cc62f7e90 | ||
|
|
280d14a595 | ||
|
|
3b0e7ce18f | ||
|
|
09e2e0e145 | ||
|
|
d128ca12c9 | ||
|
|
fc2bcc3fb6 | ||
|
|
89badd662b | ||
|
|
7b2a0e39be | ||
|
|
3c17a5b4a2 | ||
|
|
89b07422e7 | ||
|
|
095ba1905d | ||
|
|
36f2564d6a | ||
|
|
f1fc20d5a1 | ||
|
|
1747cb0b46 | ||
|
|
6531e605c2 | ||
|
|
263ed51369 | ||
|
|
a197120f57 | ||
|
|
49364f6f6d | ||
|
|
e7632b7f0b | ||
|
|
56779b9a5b | ||
|
|
124112259e | ||
|
|
01a68a2453 | ||
|
|
a1ece7da38 | ||
|
|
c1f409f9ad | ||
|
|
e1fcac1761 | ||
|
|
3e3b9128c3 | ||
|
|
73b0f13de0 | ||
|
|
f4f76cada3 | ||
|
|
51c31bf0b8 | ||
|
|
feaf363fd8 | ||
|
|
edda3b4e02 | ||
|
|
5fe5a484a3 | ||
|
|
e91220cdea | ||
|
|
e0516ebc51 | ||
|
|
2d2bc94747 | ||
|
|
2120774df5 | ||
|
|
e9c0f6df3b | ||
|
|
e1d203ba10 | ||
|
|
e3a41d7416 | ||
|
|
8b0080256c | ||
|
|
81c4980738 | ||
|
|
df9d280b1c | ||
|
|
f4c7832964 | ||
|
|
a36ad8a4b4 | ||
|
|
6207162a17 | ||
|
|
efdb1d475d | ||
|
|
ca3c02677e | ||
|
|
c32fad10e0 | ||
|
|
0d4126df41 | ||
|
|
41596444a3 | ||
|
|
55cb94f1d1 | ||
|
|
a100622a03 | ||
|
|
27d831ef6a | ||
|
|
0a8a88047c | ||
|
|
c6e01f8a59 | ||
|
|
1f7db94281 | ||
|
|
5d6abe46f5 | ||
|
|
b2d80ada34 | ||
|
|
9d95a5363f | ||
|
|
c85f7e49d7 | ||
|
|
2e88482344 | ||
|
|
91602ae7d6 | ||
|
|
ac4ebd871c | ||
|
|
1d67197df1 | ||
|
|
9375a4233b | ||
|
|
17fdccddfe | ||
|
|
a186c956f7 | ||
|
|
5e983ea936 | ||
|
|
8320c31f85 | ||
|
|
6d7b50bdd8 | ||
|
|
300ff4d5f8 | ||
|
|
3fa0c3923a | ||
|
|
8b97ebf945 | ||
|
|
6706715fb1 | ||
|
|
cc1be852bb | ||
|
|
35c82b81c8 | ||
|
|
357d421f5a | ||
|
|
5772661dfb | ||
|
|
f6c7b3109b | ||
|
|
0ea384f3e6 | ||
|
|
837a66befc | ||
|
|
6f0d6e473f | ||
|
|
a79ea9766a | ||
|
|
6578040e77 | ||
|
|
ecef37ac60 | ||
|
|
c96f7ecf11 | ||
|
|
d90a56ff40 | ||
|
|
bcd2e80821 | ||
|
|
2406c1a338 | ||
|
|
4646b525f3 | ||
|
|
ae561db9e3 | ||
|
|
ebf1d93422 | ||
|
|
b5ef37a713 | ||
|
|
85928b5b9c | ||
|
|
6ef5654bb6 | ||
|
|
0abffa26ee | ||
|
|
7e57ad8279 | ||
|
|
a87399a10f | ||
|
|
9034688502 | ||
|
|
cef8abe247 | ||
|
|
95496fc27c | ||
|
|
d8da6c08a0 | ||
|
|
7547a9227c | ||
|
|
f35d920801 | ||
|
|
7efe10a8a9 | ||
|
|
94fbefd901 | ||
|
|
88a276eed9 | ||
|
|
8bcd85d079 | ||
|
|
8729e50f1b | ||
|
|
ee8093fc50 | ||
|
|
5ff2951b5a | ||
|
|
4d0444ba2a | ||
|
|
f59aa5b19c | ||
|
|
00fa8227c3 | ||
|
|
ed74748994 | ||
|
|
0111102d25 | ||
|
|
c5afe3c769 | ||
|
|
1cfe0216ac | ||
|
|
ba6103bbc7 | ||
|
|
1f16ce835a | ||
|
|
09939a551f | ||
|
|
af13e30f95 | ||
|
|
b5c4b79eb8 | ||
|
|
5e8a111fed | ||
|
|
fe65ffa4d1 | ||
|
|
8677532629 | ||
|
|
559bdb612c | ||
|
|
5579743b6c | ||
|
|
e47bdbf6d0 | ||
|
|
845671ce07 | ||
|
|
07159b5eb7 | ||
|
|
cba08057cf | ||
|
|
9464f07a5a | ||
|
|
28ac5eaec4 | ||
|
|
11f313f6e7 | ||
|
|
ccfc282cfc | ||
|
|
46127b50f3 | ||
|
|
cb09af7e86 | ||
|
|
2c577da8fd | ||
|
|
2e9166c7df | ||
|
|
7be382a3ce | ||
|
|
7c57ffd2c6 | ||
|
|
bf43ba7bf4 | ||
|
|
c0f162716b | ||
|
|
61ce2e7117 | ||
|
|
8ce41242ed | ||
|
|
c7a60f5112 | ||
|
|
9fb1464176 | ||
|
|
488be0c748 | ||
|
|
1002baa6b1 | ||
|
|
0b9b49c360 | ||
|
|
0aea884052 | ||
|
|
3fb3bb3c11 | ||
|
|
8bc92e051e | ||
|
|
adc3dbaf57 | ||
|
|
193b0922cc | ||
|
|
abfaea19a5 | ||
|
|
3e52c75d0f | ||
|
|
552eea488d | ||
|
|
5983ed5bf3 | ||
|
|
ed9dc3719c | ||
|
|
8bb70222ce | ||
|
|
2f3df11220 | ||
|
|
bd55e16d6e | ||
|
|
e859ce8eb6 | ||
|
|
d11e9ac190 | ||
|
|
3551ab645a | ||
|
|
cc60cba1f2 | ||
|
|
fb84fda4de | ||
|
|
53b7d34649 | ||
|
|
2ecd0c654b | ||
|
|
482c0ca503 | ||
|
|
b6a47da3b0 | ||
|
|
819cb13d43 | ||
|
|
32ad8f6df1 | ||
|
|
58f79e25e9 | ||
|
|
d358ea37a8 | ||
|
|
2a6077cb65 | ||
|
|
d557725c82 | ||
|
|
6b01f0450b | ||
|
|
6a8d63a2cd | ||
|
|
375276ea1f | ||
|
|
72a653e532 | ||
|
|
59235e6a21 | ||
|
|
09490df85d | ||
|
|
a677f6d571 | ||
|
|
d4f09f6ff9 | ||
|
|
fccbae33db | ||
|
|
81baeea35b | ||
|
|
f4f3eff242 | ||
|
|
0b5145f290 | ||
|
|
0a72abb519 | ||
|
|
7cb660f955 | ||
|
|
3eff8c787d | ||
|
|
b9d81f44e6 | ||
|
|
93fbbfe2d1 | ||
|
|
e36ba04921 | ||
|
|
7054c16f6c | ||
|
|
b7b510f807 | ||
|
|
4054bd8a23 | ||
|
|
daea9dd83a | ||
|
|
b10e9de54c | ||
|
|
14abfef522 | ||
|
|
f391e97a62 | ||
|
|
fd68efec0c | ||
|
|
c0cdbd122e | ||
|
|
e397f0ca78 | ||
|
|
04a72f4d90 | ||
|
|
8b37a1dbfc | ||
|
|
b943dc1449 | ||
|
|
fd61abb375 | ||
|
|
735a626cf3 | ||
|
|
54c7dbd16e | ||
|
|
c5a5b01bfb | ||
|
|
7cbea84706 | ||
|
|
5fbbacbe11 | ||
|
|
4b8ec822fe | ||
|
|
cbfe1636ff | ||
|
|
cebe1c308a | ||
|
|
39fa555209 | ||
|
|
ed1f2c5837 | ||
|
|
1d68dd797c | ||
|
|
da71fc1a2c | ||
|
|
40b04cbded | ||
|
|
e537cbe29a | ||
|
|
b1e91686da | ||
|
|
5007c5e286 | ||
|
|
637c14fb6d | ||
|
|
ea918a44c4 | ||
|
|
5c73ddeaf8 | ||
|
|
b56fbc853d | ||
|
|
1a358582a5 | ||
|
|
2d14bc3b1b | ||
|
|
b1a0d0b94a | ||
|
|
d7d75e88d5 | ||
|
|
6c7a5c70f5 | ||
|
|
c45f83e896 | ||
|
|
ce0d054e6e | ||
|
|
c87dee4f3f | ||
|
|
fb720782b9 | ||
|
|
385523c826 | ||
|
|
c387e91f0d | ||
|
|
9c02b2c393 | ||
|
|
9306743001 | ||
|
|
a1f867c26d | ||
|
|
4090a91272 | ||
|
|
00144af296 | ||
|
|
225366ee02 | ||
|
|
cedcd94417 | ||
|
|
43ca13cdf2 | ||
|
|
8fd8efb2e3 | ||
|
|
f9856ec591 | ||
|
|
0dc068eabf | ||
|
|
c0815b787e | ||
|
|
3011e40972 | ||
|
|
47ced6ee40 | ||
|
|
db49f73bf5 | ||
|
|
b1a1d785de | ||
|
|
4529bf36d1 | ||
|
|
3150863b2c | ||
|
|
f1ef1a6c41 | ||
|
|
d76e841761 | ||
|
|
c5fee81b8a | ||
|
|
3d1ead98c3 | ||
|
|
dc4850502d | ||
|
|
8d057a2b55 | ||
|
|
a11e70c413 | ||
|
|
d32ba39c1d | ||
|
|
0c65c2cf17 | ||
|
|
88d56c451e | ||
|
|
ec6de638a2 | ||
|
|
17e3b40bf9 | ||
|
|
0aabad688b | ||
|
|
eff07204ea | ||
|
|
4a90be9bc7 | ||
|
|
90f6e9b60e | ||
|
|
8b0158b044 | ||
|
|
e9f6f3d953 | ||
|
|
2a6be9f9e6 | ||
|
|
31fc5961d8 | ||
|
|
412a8c4aec | ||
|
|
a0c5c90c8d | ||
|
|
22559131cc | ||
|
|
8b0b0759ef | ||
|
|
375c978eb4 | ||
|
|
3beef4df08 | ||
|
|
6198f0c9d3 | ||
|
|
5f45f612a3 | ||
|
|
adac1125e8 | ||
|
|
06f5441399 | ||
|
|
5fef7dc66b | ||
|
|
4b560c7d3d | ||
|
|
ecb3863410 | ||
|
|
eac4ddac4c | ||
|
|
987c5dc321 | ||
|
|
ec99687702 | ||
|
|
501d24ddfd | ||
|
|
2aab73220c | ||
|
|
4f7a4cbf95 | ||
|
|
3bf2c86b07 | ||
|
|
eadb19d386 | ||
|
|
ce7b7cbaf2 | ||
|
|
fa5b947442 | ||
|
|
11f1be0d2c | ||
|
|
4418dd2eab | ||
|
|
73d2a4405d | ||
|
|
8d766a8cc8 | ||
|
|
fe8d0434c5 | ||
|
|
ae59c2496e | ||
|
|
a19d519b4b | ||
|
|
f7097ec394 | ||
|
|
16e1e37fd9 | ||
|
|
48c9d401db | ||
|
|
37078ef962 | ||
|
|
5ad333703f | ||
|
|
26bdb57972 | ||
|
|
c34974a555 | ||
|
|
ffa76b238e | ||
|
|
ab4ded89e3 | ||
|
|
29e3d38c55 | ||
|
|
0df87a9f83 | ||
|
|
26758e18b2 | ||
|
|
e8926c334c | ||
|
|
501e498175 | ||
|
|
f8a35c5884 | ||
|
|
0b685d843e | ||
|
|
89700c1e2e | ||
|
|
b171d4bf19 | ||
|
|
e827fba754 | ||
|
|
fac858e3cb | ||
|
|
8290964c31 | ||
|
|
9f5ccf28df | ||
|
|
6536c49c3c | ||
|
|
59abaf6a7f | ||
|
|
2a1685a2cb | ||
|
|
a35c605e73 | ||
|
|
4dcb94e6a5 | ||
|
|
e946cc896a | ||
|
|
a1e8838aee | ||
|
|
9390f7fca9 | ||
|
|
7490809a42 | ||
|
|
bc7fb1e6d4 | ||
|
|
2ee1ef13ec | ||
|
|
7552199f5e | ||
|
|
73c80d0603 | ||
|
|
9964693050 | ||
|
|
c51133f2c3 | ||
|
|
da944c330b | ||
|
|
6b1f5232fa | ||
|
|
4aebee53ac | ||
|
|
7faa29e84b | ||
|
|
349f58b807 | ||
|
|
1f5763bdf0 | ||
|
|
3acaa1dd49 | ||
|
|
2e8b11de93 | ||
|
|
74c9f684e6 | ||
|
|
18722beebd | ||
|
|
6b7a300a2e | ||
|
|
1ce0a833e9 | ||
|
|
6e00010e9a | ||
|
|
9325a8c892 | ||
|
|
00481145b6 | ||
|
|
a918c09543 | ||
|
|
a06fca791a | ||
|
|
ef341932a3 | ||
|
|
2e272f9b18 | ||
|
|
1580e757ed | ||
|
|
ed0460747c | ||
|
|
fa8d83a21a | ||
|
|
5203985a25 | ||
|
|
351e4d3fc6 | ||
|
|
5079ce65ba | ||
|
|
47a04c66f1 | ||
|
|
53cc4584f4 | ||
|
|
3492f9a4ee | ||
|
|
0aef731a79 | ||
|
|
ca51ceba6a | ||
|
|
f9ebcb6b98 | ||
|
|
97b6672610 | ||
|
|
05cc25c761 | ||
|
|
d13cfd5ca8 | ||
|
|
4399eeb67f | ||
|
|
dd4d316a66 | ||
|
|
2f92dbe12c | ||
|
|
fab831f143 | ||
|
|
073b8cb9de | ||
|
|
b776587f2d | ||
|
|
70a2a2194f | ||
|
|
df8da0823a | ||
|
|
507cc7eb14 | ||
|
|
fa4d659c5b | ||
|
|
74d28ed997 | ||
|
|
dcad671568 | ||
|
|
0a18e9c1dc | ||
|
|
e949ed67ef | ||
|
|
478d003307 | ||
|
|
f656aea029 | ||
|
|
1e77cccf5a | ||
|
|
1a8681e15d | ||
|
|
d92e48e1aa | ||
|
|
be4a6abc81 | ||
|
|
770969ec5c | ||
|
|
24e014f326 | ||
|
|
a506f8785e | ||
|
|
f1c0d02bc3 | ||
|
|
b8a4e13284 | ||
|
|
d52e6467ac | ||
|
|
0779058ca5 | ||
|
|
712409b4e1 | ||
|
|
571d3bd5e2 | ||
|
|
26bbe781a0 | ||
|
|
2844c97170 | ||
|
|
32e246885b | ||
|
|
824deddb46 | ||
|
|
866fcebf2e | ||
|
|
27c7400f34 | ||
|
|
180ac925f7 | ||
|
|
bb115f1d2f | ||
|
|
6c465c7182 | ||
|
|
46be9a801c | ||
|
|
b8d0e5fee2 | ||
|
|
8f31048619 | ||
|
|
52b66db729 | ||
|
|
39e8e4a2ae | ||
|
|
8875710f3d | ||
|
|
858551411b | ||
|
|
4ed5e8a434 | ||
|
|
e0a170db92 | ||
|
|
fa17a5f745 | ||
|
|
dc59c9bf0c | ||
|
|
823fa259e9 | ||
|
|
47491fe749 | ||
|
|
c81327fdb5 | ||
|
|
a82b728d98 | ||
|
|
ec5b92dd7a | ||
|
|
8a0ff999bd | ||
|
|
7b18bcafd6 | ||
|
|
1931101545 | ||
|
|
ae3eab8320 | ||
|
|
5165cf20c8 | ||
|
|
2cb5acb9f9 | ||
|
|
605058522e | ||
|
|
431231c4ee | ||
|
|
41ca9fc251 | ||
|
|
1a25984e88 | ||
|
|
3df41090e4 | ||
|
|
1b73ded110 | ||
|
|
6fe2674f5b | ||
|
|
c3eb1369ac | ||
|
|
9c380e52d1 | ||
|
|
c2695b1180 | ||
|
|
d3884d764d | ||
|
|
f05d33969f | ||
|
|
f225e6cf75 | ||
|
|
4972081d8a | ||
|
|
331ad00758 | ||
|
|
b64fefa73c | ||
|
|
c5f73c5e26 | ||
|
|
022367c8d6 | ||
|
|
eac9edb13a | ||
|
|
d5a9f68575 | ||
|
|
3caba87924 | ||
|
|
f469d591b8 | ||
|
|
72e3a115d6 | ||
|
|
df854f333c | ||
|
|
23605b2a80 | ||
|
|
33fa870f04 | ||
|
|
f1e2b21d8f | ||
|
|
13aaab4798 | ||
|
|
0f08491f50 | ||
|
|
cfef1d62e6 | ||
|
|
d9e429bfb4 | ||
|
|
19593b5574 | ||
|
|
89abcdb17c | ||
|
|
89c7e58101 | ||
|
|
6d53262a9f | ||
|
|
bf5ca2f3cd | ||
|
|
23ffdabcc4 | ||
|
|
200cf00fe4 | ||
|
|
12c2214432 | ||
|
|
fa6b93fad2 | ||
|
|
942b7cbb43 | ||
|
|
88e0016e31 | ||
|
|
54dda96849 | ||
|
|
5bd5c8289c | ||
|
|
26998e912b | ||
|
|
02fd57f9a4 | ||
|
|
f76ca049cc | ||
|
|
f4ab932924 | ||
|
|
d77946a5ab | ||
|
|
0d190a4c80 | ||
|
|
a1a441d397 | ||
|
|
ba9ba01dfe | ||
|
|
ad19e11213 | ||
|
|
2ff09ef382 | ||
|
|
11fd512c5e | ||
|
|
7d6fa48a74 | ||
|
|
31b5114a8d | ||
|
|
1cd7b7e0c7 | ||
|
|
db5f99f3f6 | ||
|
|
156f0a10cb | ||
|
|
9c0c2416d6 | ||
|
|
858325e40d | ||
|
|
c7604672fc | ||
|
|
49f9644714 | ||
|
|
49fa5bf14a | ||
|
|
e540c9d58d | ||
|
|
9d6f51695a | ||
|
|
2bc5b39895 | ||
|
|
ec2f6e8490 | ||
|
|
472531d1b6 | ||
|
|
4fe235cdbd | ||
|
|
e3051d6427 | ||
|
|
84bd756cdf | ||
|
|
1a2981e5f1 | ||
|
|
cedd9ac79b | ||
|
|
94f7b9295d | ||
|
|
78ff767b9e | ||
|
|
762728c0a6 | ||
|
|
3e3448adb1 | ||
|
|
3b3803f57e | ||
|
|
26f7ee56ab | ||
|
|
877eeeab5d | ||
|
|
3a4b8738fc | ||
|
|
eb1d16740e | ||
|
|
f08ca83440 | ||
|
|
4d0ac56bd8 | ||
|
|
4697704763 | ||
|
|
4a66802b37 | ||
|
|
edfa7f0c41 | ||
|
|
88a2b25281 | ||
|
|
1884996e53 | ||
|
|
451b26fa93 | ||
|
|
4fe3b93fb0 | ||
|
|
51bf5890d3 | ||
|
|
23e768d629 | ||
|
|
e1fdca5f41 | ||
|
|
d3ff2823dc | ||
|
|
4e3dc99479 | ||
|
|
e45acac6b6 | ||
|
|
3456b8cf23 | ||
|
|
7b02351f11 | ||
|
|
f3f66e1873 | ||
|
|
ae8c062631 | ||
|
|
49c847f38a | ||
|
|
0070b8731d | ||
|
|
efd9feca0e | ||
|
|
36ae73316a | ||
|
|
a467d853b0 | ||
|
|
7a648f0c5e | ||
|
|
dabf9fc9cb | ||
|
|
f1fa3a4c9c | ||
|
|
cb6926e821 | ||
|
|
33e437f865 | ||
|
|
055892cd62 | ||
|
|
4da012c871 | ||
|
|
accd6cb143 | ||
|
|
46fd26a879 | ||
|
|
76d1c8e8bd | ||
|
|
5d33805a6f | ||
|
|
82445d2ba2 | ||
|
|
70fc67199f | ||
|
|
c41728b97c | ||
|
|
512ed02db2 | ||
|
|
5babe993df | ||
|
|
6ae1992329 | ||
|
|
00fb93a87f | ||
|
|
5338cca79b | ||
|
|
437eb9f793 | ||
|
|
23f5af93ce | ||
|
|
55f6e86a56 | ||
|
|
aa50c4466e | ||
|
|
1889ef2d8c | ||
|
|
3a96f63798 | ||
|
|
18db311712 | ||
|
|
000e9746ba | ||
|
|
90f6f6d68d | ||
|
|
b24f82d257 | ||
|
|
bbcc58f103 | ||
|
|
0c3cade976 | ||
|
|
d3bd8289ec | ||
|
|
7b670f229e | ||
|
|
b43e7902df | ||
|
|
7e2dc67c4e | ||
|
|
e56155f9a0 | ||
|
|
821f87b880 | ||
|
|
ecbcc6dcaa | ||
|
|
cd9adbdf7e | ||
|
|
6efa7f3c5b | ||
|
|
4031b65099 | ||
|
|
bc09210ada | ||
|
|
affb24fc11 | ||
|
|
b5870b3ae4 | ||
|
|
19df78dbe2 | ||
|
|
4131f3b2fe | ||
|
|
4c80deae25 | ||
|
|
c6eb703648 | ||
|
|
24598ac463 | ||
|
|
b98377d5cb | ||
|
|
08bf8ecc89 | ||
|
|
a5fb8575a6 | ||
|
|
f9315a127f | ||
|
|
22d0d55d79 | ||
|
|
50ab84af42 | ||
|
|
374aac7ff5 | ||
|
|
e8aa88b317 | ||
|
|
5ed2faebc4 | ||
|
|
0767b6e9cf | ||
|
|
174e609526 | ||
|
|
63111ed938 | ||
|
|
42298947cc | ||
|
|
427a92f0f3 | ||
|
|
4a0219e9da | ||
|
|
b7a1f16a9d | ||
|
|
5994edcf17 | ||
|
|
754e7741c7 | ||
|
|
4f428b0e5d | ||
|
|
d69f5ac18d | ||
|
|
72a45ef014 | ||
|
|
3162a531b7 | ||
|
|
02f6431109 | ||
|
|
af5ece3fe9 | ||
|
|
91980319d2 | ||
|
|
7d7e2f029d | ||
|
|
3827d8a5ce | ||
|
|
2941f11c54 | ||
|
|
9eed139cc9 | ||
|
|
ab55dde534 | ||
|
|
0bc372bf86 | ||
|
|
4c737e315e | ||
|
|
30f483245c | ||
|
|
8527594b3b | ||
|
|
12ec9b08bf | ||
|
|
3fed2ef08d | ||
|
|
d9b9586af3 | ||
|
|
6fda7393b3 | ||
|
|
5b716dcdf2 | ||
|
|
e88d8bb7b7 | ||
|
|
94433b0107 | ||
|
|
8ac43d5617 | ||
|
|
90e63341bd | ||
|
|
ed7bd69116 | ||
|
|
e34beb5775 | ||
|
|
95c3044a40 | ||
|
|
ab7c982589 | ||
|
|
92643a244e | ||
|
|
c51b0585a2 | ||
|
|
2f7bd0e083 | ||
|
|
594c47f08b | ||
|
|
94d5121a26 | ||
|
|
e86787c663 | ||
|
|
24ec6f154a | ||
|
|
c4abe1cf05 | ||
|
|
6f710f1f6b | ||
|
|
9a5edb9431 | ||
|
|
2a328356cd | ||
|
|
48fdb94343 | ||
|
|
67343b5680 | ||
|
|
a8fd35fd15 | ||
|
|
d9f93ec67e | ||
|
|
18e354d0ae | ||
|
|
09d24c542e | ||
|
|
9fcc1f5dc2 | ||
|
|
ff292cfabc | ||
|
|
76d6ff14c2 | ||
|
|
89522a8197 | ||
|
|
a2eacc0fd3 | ||
|
|
faccdb0ed7 | ||
|
|
b0815bcae6 | ||
|
|
c684b56124 | ||
|
|
dccde1a422 | ||
|
|
6cd99383b9 | ||
|
|
dc0ea4d828 | ||
|
|
ec1bacd1dd | ||
|
|
0ebb566645 | ||
|
|
7c3b01c911 | ||
|
|
1531762524 | ||
|
|
b79a66ce83 | ||
|
|
17d479bc93 | ||
|
|
5f59fdf471 | ||
|
|
a799afc19c | ||
|
|
24130cde74 | ||
|
|
bd179f817f | ||
|
|
fd72aa4fac | ||
|
|
eecf9f0726 | ||
|
|
9f212fc475 | ||
|
|
40ec3f14bf | ||
|
|
ad1df59c18 | ||
|
|
804cd04778 | ||
|
|
083664d858 | ||
|
|
c98721056d | ||
|
|
d2fe664fe5 | ||
|
|
ad35fc535e | ||
|
|
10bd3e1899 | ||
|
|
e4cce437d4 | ||
|
|
3a6b5c91d5 | ||
|
|
1b563c30c5 | ||
|
|
9cedaf18a8 | ||
|
|
e5152439ef | ||
|
|
1a68035131 | ||
|
|
5294503483 | ||
|
|
f2d05c1355 | ||
|
|
73e8631fcd | ||
|
|
29c260f7ce | ||
|
|
5318347ab2 | ||
|
|
40ddd2dfdb | ||
|
|
6548d5da80 | ||
|
|
aff4e0c2d0 | ||
|
|
55c9b8e322 | ||
|
|
9281344863 | ||
|
|
061806eb8f | ||
|
|
8067cb6e65 | ||
|
|
2bf51c2034 | ||
|
|
cbf63b8c19 | ||
|
|
f715a0c8a3 | ||
|
|
f7259f745f | ||
|
|
944e481f32 | ||
|
|
b409db3e29 | ||
|
|
6ae19f11ea | ||
|
|
eded461866 | ||
|
|
c1e40ebe1f | ||
|
|
406a4a3a91 | ||
|
|
896c8d1f5f | ||
|
|
a5ae6e0631 | ||
|
|
0e248f8b83 | ||
|
|
2ca29efd77 | ||
|
|
3c9e5d2f0f | ||
|
|
61288a17ac | ||
|
|
fff28fdcbf | ||
|
|
84cc58d30b | ||
|
|
1f043c7088 | ||
|
|
9a966cfad9 | ||
|
|
e235e07bb2 | ||
|
|
1ba2a1fae0 | ||
|
|
e87c85b75c | ||
|
|
bd351197b2 | ||
|
|
489d3abe65 | ||
|
|
5dea99f139 | ||
|
|
11f107d60b | ||
|
|
829994f5b5 | ||
|
|
61a8000bf1 | ||
|
|
a189927b22 | ||
|
|
b3f00a0681 | ||
|
|
8cc5785e86 | ||
|
|
827d09289d | ||
|
|
0ce00531a6 | ||
|
|
4962d855af | ||
|
|
ef47883262 | ||
|
|
7e25e31d33 | ||
|
|
a1d56e2921 | ||
|
|
a34ac84e00 | ||
|
|
e248e2966a | ||
|
|
540b19c141 | ||
|
|
aa493c41d5 | ||
|
|
637f844601 | ||
|
|
1815554070 | ||
|
|
05e66b2492 | ||
|
|
ae115c4908 | ||
|
|
28c456e4c5 | ||
|
|
2d12c6e282 | ||
|
|
7d8dd5ab09 | ||
|
|
adfbc7508e | ||
|
|
417eaa544f | ||
|
|
a502a509ed | ||
|
|
1a7909aaa4 | ||
|
|
0fea79a647 | ||
|
|
ed2d01df4d | ||
|
|
2e31a4e2c1 | ||
|
|
e56898fff4 | ||
|
|
7671066548 | ||
|
|
87cd49a291 | ||
|
|
8fd31f3190 | ||
|
|
60d06c92f6 | ||
|
|
f1cd8bac20 | ||
|
|
6020ff7ee1 | ||
|
|
b99e253715 | ||
|
|
003cad94a0 | ||
|
|
cb55bd3612 | ||
|
|
2ec8a2719e | ||
|
|
e65727937c | ||
|
|
a1f3cb9270 | ||
|
|
3b85b20020 | ||
|
|
36a1b6bb93 | ||
|
|
29f7badbfb | ||
|
|
5e7421ab24 | ||
|
|
8325a8ba02 | ||
|
|
9b93a28ddb | ||
|
|
ad798850c6 | ||
|
|
92264ed37e | ||
|
|
9ce029b35d | ||
|
|
127f091728 | ||
|
|
454256d455 | ||
|
|
6300dd6737 | ||
|
|
ce8c6e0283 | ||
|
|
50e558644a | ||
|
|
1592e1c0ce | ||
|
|
d155dacadc | ||
|
|
ba7bda0b04 | ||
|
|
c7787d1390 | ||
|
|
a7d0d4892f | ||
|
|
463f1c540e | ||
|
|
079c348948 | ||
|
|
c50388a358 | ||
|
|
b637d79c50 | ||
|
|
5a6ab4f781 | ||
|
|
2a16229056 | ||
|
|
7652a1dbc5 | ||
|
|
6d4071f42c | ||
|
|
6cd49334d7 | ||
|
|
5aeea48413 | ||
|
|
7632647e1d | ||
|
|
41a56fba20 | ||
|
|
1600dc4f84 | ||
|
|
46cff62796 | ||
|
|
c33fe2e928 | ||
|
|
cac4ca96d5 | ||
|
|
cc89986a94 | ||
|
|
5a0c286ff4 | ||
|
|
3237de7e33 | ||
|
|
37d6f477c4 | ||
|
|
0f90f53f53 | ||
|
|
9d5953c9f5 | ||
|
|
dc8d727bdb | ||
|
|
90adb1c627 | ||
|
|
3be36f826c | ||
|
|
dc268285b0 | ||
|
|
7464cf7420 | ||
|
|
30c9956acd | ||
|
|
7cc579fd61 | ||
|
|
709ba2d4f7 | ||
|
|
a6cce0c043 | ||
|
|
152e795c32 | ||
|
|
89a78bf43b | ||
|
|
1e9e310922 | ||
|
|
840cad23b8 | ||
|
|
93817c5d3a | ||
|
|
470f8aed5b | ||
|
|
e9ee866c60 | ||
|
|
463bd4ef51 | ||
|
|
c8192ef7e3 | ||
|
|
6ed3c5d365 | ||
|
|
c53ed4650d | ||
|
|
ca60a13bb4 | ||
|
|
96a83533dd | ||
|
|
99521e4d76 | ||
|
|
299abeb25d | ||
|
|
454dacea6b | ||
|
|
54f55ee257 | ||
|
|
84b08ef64a | ||
|
|
bd3a9eb345 | ||
|
|
a937ccb07c | ||
|
|
7a2d38f2f1 | ||
|
|
370a0fad11 | ||
|
|
ec49868d27 | ||
|
|
25d1956da0 | ||
|
|
af486998d2 | ||
|
|
5229643761 | ||
|
|
4fd4de7d52 | ||
|
|
8e467e8239 | ||
|
|
04c6ea2e66 | ||
|
|
b6182b4913 | ||
|
|
ce92fedf09 | ||
|
|
9eff3e1aa9 | ||
|
|
012ed17208 | ||
|
|
33c0cf33d9 | ||
|
|
2bad1c0226 | ||
|
|
65506ba7e1 | ||
|
|
c93380dcf2 | ||
|
|
7849ba16f5 | ||
|
|
b755d745c5 | ||
|
|
c23a4be440 | ||
|
|
f89b5d0a34 | ||
|
|
2ffb31f00d | ||
|
|
99acb17d90 | ||
|
|
565dfb4b81 | ||
|
|
24f31dd92a | ||
|
|
63bcdb1019 | ||
|
|
5b2e70cda0 | ||
|
|
d97b18e633 | ||
|
|
6678864555 | ||
|
|
1f589901d6 | ||
|
|
1afdfccf3b | ||
|
|
5bd745a188 | ||
|
|
1ac69035ed | ||
|
|
9bc6b7b0f7 | ||
|
|
49bc941dd7 | ||
|
|
4037124c57 | ||
|
|
fc908bb92c | ||
|
|
c1c0010126 | ||
|
|
9cdeeb4c94 | ||
|
|
a84fa8ac0c | ||
|
|
6a7d62b38d | ||
|
|
40be7c9fc1 | ||
|
|
6006026deb | ||
|
|
00b6261a1c | ||
|
|
ce9d5f78e2 | ||
|
|
e75aca9236 | ||
|
|
683f9fd13b | ||
|
|
18e1cec611 | ||
|
|
4d47ca26db | ||
|
|
42d41eb0f7 | ||
|
|
fea1d35d08 | ||
|
|
2414f87a86 | ||
|
|
15ed114e87 | ||
|
|
f7037e3ecb | ||
|
|
75bd0a5ff7 | ||
|
|
c3a5964f17 | ||
|
|
9bd8870ef9 | ||
|
|
cb6f595cc3 | ||
|
|
9aa96b4d03 | ||
|
|
0765b6770f | ||
|
|
761417833e | ||
|
|
e5ab4df3dc | ||
|
|
12345a67e8 | ||
|
|
440cc21d8c | ||
|
|
173d71b04f | ||
|
|
6df837f9ba | ||
|
|
eea53ee9ef | ||
|
|
7fb65f5144 | ||
|
|
d352c9e8ca | ||
|
|
e5cc8ef97c | ||
|
|
af63a6ca09 | ||
|
|
a13e8d98e1 | ||
|
|
5136889c3e | ||
|
|
a7e5147104 | ||
|
|
017d81a8c6 | ||
|
|
77436644aa | ||
|
|
31ba30d101 | ||
|
|
cc6191cef2 | ||
|
|
9aa28c3e3f | ||
|
|
055d27a9f6 | ||
|
|
140e19dffe | ||
|
|
002ff639a0 | ||
|
|
826694793c | ||
|
|
4699b9be7a | ||
|
|
ec9ce77ace | ||
|
|
22c52171d9 | ||
|
|
cff1363050 | ||
|
|
48924e3364 | ||
|
|
79c4b1cb27 | ||
|
|
b1bfcfb190 | ||
|
|
7ab2dac645 | ||
|
|
702fe0ba24 | ||
|
|
755bc35d09 | ||
|
|
a7e93ad8f9 | ||
|
|
7bbc10acc3 | ||
|
|
690e1b7f8a | ||
|
|
ca4f2a2aeb | ||
|
|
531b5d58ba | ||
|
|
aedbc88e3c | ||
|
|
f9cbd8fa61 | ||
|
|
a614c050e7 | ||
|
|
931bf29c47 | ||
|
|
313981f30e | ||
|
|
3996804e71 | ||
|
|
673e6dec8d | ||
|
|
f8771a260c | ||
|
|
39531aba0e | ||
|
|
a635671276 | ||
|
|
144bdaa301 | ||
|
|
444f5ad446 | ||
|
|
32aa4794d0 | ||
|
|
618698aab3 | ||
|
|
b610a21b37 | ||
|
|
945027295a | ||
|
|
830eb19420 | ||
|
|
cb22591182 | ||
|
|
8c061ec070 | ||
|
|
4a9cd78d1d | ||
|
|
0f4e835f6c | ||
|
|
39939076e7 | ||
|
|
d51de3fa55 | ||
|
|
f1811bbbc6 | ||
|
|
04f34a00fa | ||
|
|
d89f8da5a2 | ||
|
|
b8850b2aae | ||
|
|
f4b2db89ec | ||
|
|
5a09f27c6a | ||
|
|
214b39ce8f | ||
|
|
a327b460bb | ||
|
|
ddf2fc5a74 | ||
|
|
2bd2fd7ef7 | ||
|
|
baca029fd0 | ||
|
|
0f180ff979 | ||
|
|
86e748dd93 | ||
|
|
bd94b5dd2e | ||
|
|
31feef398f | ||
|
|
49a8f72151 | ||
|
|
675e3bb08b | ||
|
|
aae4db7ebf | ||
|
|
80617c24f1 | ||
|
|
61eca643d4 | ||
|
|
b6a0767d03 | ||
|
|
d428f9c4c0 | ||
|
|
09b4021e23 | ||
|
|
f48ed1212b | ||
|
|
117febba6d | ||
|
|
fc65975252 | ||
|
|
7517c36b36 | ||
|
|
d5bd392cff | ||
|
|
4cccd8f6d9 | ||
|
|
bd1182ab39 | ||
|
|
a25252714d | ||
|
|
adbf61a06b | ||
|
|
b44739e33c | ||
|
|
340b026951 | ||
|
|
30bf3afc1d | ||
|
|
119f9ec6dd | ||
|
|
3a24d094c9 | ||
|
|
dba6e1210e | ||
|
|
b25234e431 | ||
|
|
f633d9b3bf | ||
|
|
4fa0602af9 | ||
|
|
8ee985928e | ||
|
|
98def7b879 | ||
|
|
6f8815200e | ||
|
|
4a0b633970 | ||
|
|
32c1baf887 | ||
|
|
d2d5f81782 | ||
|
|
04c89a26ed | ||
|
|
b1fb365f22 | ||
|
|
fc69d55314 | ||
|
|
ee3f29c569 | ||
|
|
f599acda6b | ||
|
|
8510d648aa | ||
|
|
33d7b6f67b | ||
|
|
9ca4961841 | ||
|
|
a1f50a0c4f | ||
|
|
5e4b08a8f5 | ||
|
|
57947441ce | ||
|
|
f1515c5063 | ||
|
|
ec10f36839 | ||
|
|
05b28b8269 | ||
|
|
9c421218b8 | ||
|
|
2de8f02814 | ||
|
|
9efbc47f78 | ||
|
|
dffb89390e | ||
|
|
74dae9316e | ||
|
|
acdd18f8df | ||
|
|
14b4ea7eb1 | ||
|
|
6eddbd1ecf | ||
|
|
6bda05a5fc | ||
|
|
8c278d6555 | ||
|
|
bc493d624f | ||
|
|
127a85ea89 | ||
|
|
dc8c9832d2 | ||
|
|
ed65d5da44 | ||
|
|
b13d0a222b | ||
|
|
dcd30d34da | ||
|
|
0a5ca4fcf4 | ||
|
|
9879420d31 | ||
|
|
1639f4297e | ||
|
|
fe7357bca2 | ||
|
|
3e17d24250 | ||
|
|
28bbb79e60 | ||
|
|
6c896c36bf | ||
|
|
78da1157ab | ||
|
|
21a9266c8f | ||
|
|
e724cbfa63 | ||
|
|
985b5a68fe | ||
|
|
f6bcb8d1ab | ||
|
|
41fa422160 | ||
|
|
5b57b238c3 | ||
|
|
4a47ed7f43 | ||
|
|
b89e7639cd | ||
|
|
c8c7d3ef2e | ||
|
|
1760041e56 | ||
|
|
4239bb325d | ||
|
|
8e4bbeff28 | ||
|
|
cc9e7289c6 | ||
|
|
6a8c7c10a6 | ||
|
|
df6127f528 | ||
|
|
c63252946a | ||
|
|
60140bdc1e | ||
|
|
558ced7497 | ||
|
|
403e820f55 | ||
|
|
d681fbd507 | ||
|
|
bcb1f5db6c | ||
|
|
20b85f7567 | ||
|
|
387e48cca8 | ||
|
|
ad0c6b7a55 | ||
|
|
92c136d4c3 | ||
|
|
321c676fd0 | ||
|
|
1aa582383c | ||
|
|
a1cdf756ab | ||
|
|
163ac96cd7 | ||
|
|
08c774e818 | ||
|
|
c229b1c60c | ||
|
|
422b6d56f7 | ||
|
|
e84360efe9 | ||
|
|
44882e5418 | ||
|
|
a2568c486e | ||
|
|
53cf31fe15 | ||
|
|
7eb702545b | ||
|
|
a139b273c9 | ||
|
|
650bd0bfb9 | ||
|
|
9e021ce7e3 | ||
|
|
4125f2a0e0 | ||
|
|
10c95c68d8 | ||
|
|
8996d4e09b | ||
|
|
3b4354fbe5 | ||
|
|
95ee0c60ca | ||
|
|
1f4e45eca6 | ||
|
|
b80afc2c79 | ||
|
|
9455b5628e | ||
|
|
12623012ed | ||
|
|
3f82c7459a | ||
|
|
385d12e159 | ||
|
|
e6f30956db | ||
|
|
b744cc7452 | ||
|
|
85442810f3 | ||
|
|
74007827f9 | ||
|
|
da100bea60 | ||
|
|
0f449d05aa | ||
|
|
e7e5ececa6 | ||
|
|
0833d4dd56 | ||
|
|
1fa039d331 | ||
|
|
50d02a8058 | ||
|
|
170da33755 | ||
|
|
912a8f9f2c | ||
|
|
7e7f336ccb | ||
|
|
d4cf8503cd | ||
|
|
168983c972 | ||
|
|
1fbf83c562 | ||
|
|
b3da731e1f | ||
|
|
26bc9514d7 | ||
|
|
65f151bbef | ||
|
|
545c68f122 | ||
|
|
d4bfe17a72 | ||
|
|
2a7733e61f | ||
|
|
d658c18566 | ||
|
|
ac97dfd8c4 | ||
|
|
f1cdbc339b | ||
|
|
74cf6ef598 | ||
|
|
8f71606fad | ||
|
|
3ad3da3680 | ||
|
|
2aacadaa82 | ||
|
|
ae33070507 | ||
|
|
e1b29f2985 | ||
|
|
215e8da87d | ||
|
|
2772351a3d | ||
|
|
969c3fd18e | ||
|
|
f62aac1c77 | ||
|
|
8d1a73c339 | ||
|
|
71d7004d0c | ||
|
|
47e01693c5 | ||
|
|
09c5cdb6a2 | ||
|
|
cae1026fee | ||
|
|
393a834891 | ||
|
|
260d2a5f42 | ||
|
|
f9ff9eb6fb | ||
|
|
f7d247fb2c | ||
|
|
3db4e9071f | ||
|
|
6ec46aec1f | ||
|
|
4d91bde49c | ||
|
|
dbb28788d9 | ||
|
|
7ca647b763 | ||
|
|
85d54292b2 | ||
|
|
5a3d519bab | ||
|
|
5edbe16e18 | ||
|
|
8a06ef1322 | ||
|
|
0568c8f841 | ||
|
|
0ad8c85cc4 | ||
|
|
0de67936c1 | ||
|
|
3f2a8dbb61 | ||
|
|
e830fd9bef | ||
|
|
c66607d09d | ||
|
|
fa9ac8c8ab | ||
|
|
ada0bd4012 | ||
|
|
a06a46b498 | ||
|
|
b746be4c67 | ||
|
|
45b4b3a6f8 | ||
|
|
fddac90db2 | ||
|
|
e704b25bc8 | ||
|
|
de00e21835 | ||
|
|
efb9f4ca2d | ||
|
|
ea25f2e854 | ||
|
|
1bdaf14eb5 | ||
|
|
d9c2e0f342 | ||
|
|
4df819b7ee | ||
|
|
5ffac3bc3e | ||
|
|
9dd9ef923c | ||
|
|
097bae35ab | ||
|
|
7221893e30 | ||
|
|
723bb9d942 | ||
|
|
6e134ab290 | ||
|
|
e989411074 | ||
|
|
0ee41f262e | ||
|
|
d1f8560aaf | ||
|
|
be462e0e28 | ||
|
|
56d73ea9a2 | ||
|
|
62926fc13f | ||
|
|
a1eb62a176 | ||
|
|
cf17272196 | ||
|
|
4b1464d6ad | ||
|
|
50dc476ceb | ||
|
|
1ae3f9f319 | ||
|
|
677a26cac1 | ||
|
|
4cb7e552ea | ||
|
|
cd069c016b | ||
|
|
4006551afe | ||
|
|
50f0723fb8 | ||
|
|
6768662f1d | ||
|
|
275266c85f | ||
|
|
f51808a000 | ||
|
|
7a4c027d0f | ||
|
|
117232687a | ||
|
|
3ee70d021a | ||
|
|
066471df33 | ||
|
|
0a2d904ce5 | ||
|
|
4a3a555326 | ||
|
|
e6b7edc180 | ||
|
|
9284aa39d5 | ||
|
|
b8450b6acd | ||
|
|
c5c939df63 | ||
|
|
0d74ad8cbf | ||
|
|
8b84b97cf0 | ||
|
|
e77097de2d | ||
|
|
3b229c9933 | ||
|
|
d350c18999 | ||
|
|
07969f2395 | ||
|
|
dc236d6ec1 | ||
|
|
90585fbb4f | ||
|
|
6c7cd80bb3 | ||
|
|
ba830aee5a | ||
|
|
86d15fe239 | ||
|
|
57b7c4785a | ||
|
|
4a7bcbfd38 | ||
|
|
4f30edd960 | ||
|
|
d3bf2271fc | ||
|
|
ba3d418260 | ||
|
|
0ae2225d9e | ||
|
|
7ff400ba1b | ||
|
|
55e7831c57 | ||
|
|
21826f2091 | ||
|
|
1fc1e132cb | ||
|
|
a4515e8eae | ||
|
|
821a15ecaa | ||
|
|
9c172e2010 | ||
|
|
1335a892b1 | ||
|
|
be75468100 | ||
|
|
f645d68ff2 | ||
|
|
c061b51a52 | ||
|
|
14a8be793c | ||
|
|
aa4acfe3d7 | ||
|
|
932b401aa9 | ||
|
|
e86664ddd2 | ||
|
|
fb7664ea3c | ||
|
|
e7b57c161d | ||
|
|
c0d27ee01d | ||
|
|
61050ec861 | ||
|
|
d344385aa3 | ||
|
|
fc5b63282f | ||
|
|
6191382a39 | ||
|
|
644d7aaa6d | ||
|
|
9e7f5b50aa | ||
|
|
0cfb275480 | ||
|
|
9c9e8269b6 | ||
|
|
a60f9ffc61 | ||
|
|
a7f0c08a94 | ||
|
|
a30777086d | ||
|
|
16269ee144 | ||
|
|
fdd1174d8b | ||
|
|
879fe24b62 | ||
|
|
1515a34ac1 | ||
|
|
798a50bc0c | ||
|
|
ec31b0361e | ||
|
|
48bec22982 | ||
|
|
42398fcd17 | ||
|
|
877db870d2 | ||
|
|
da33aa7ef9 | ||
|
|
92d9f47b83 | ||
|
|
a218d84931 | ||
|
|
b0c4719cb6 | ||
|
|
1248a8edf6 | ||
|
|
7eaa286a7a | ||
|
|
d534dacf18 | ||
|
|
7c2fd66929 | ||
|
|
5f601b53b2 | ||
|
|
23ee5cf982 | ||
|
|
f3fd986512 | ||
|
|
8c5548801f | ||
|
|
91d7e0f1f9 | ||
|
|
d63b5acd6e | ||
|
|
b155d8825f | ||
|
|
44dc150f66 | ||
|
|
75ddef9b02 | ||
|
|
7a17c74762 | ||
|
|
6ad1321048 | ||
|
|
c090476925 | ||
|
|
3a15e5c6bc | ||
|
|
e6716613cc | ||
|
|
362bf03e5d | ||
|
|
dcd37391fe | ||
|
|
44d178bb89 | ||
|
|
4c8c6ead28 | ||
|
|
0e5b952ea6 | ||
|
|
4a626043b8 | ||
|
|
6356cba581 | ||
|
|
26c690595e | ||
|
|
4d9852234a | ||
|
|
e9b52cdd55 | ||
|
|
99ffd3dc95 | ||
|
|
8dbcac7afc | ||
|
|
f8f0e0ca45 | ||
|
|
c891501579 | ||
|
|
244873f2fd | ||
|
|
33687254cd | ||
|
|
2db0b24002 | ||
|
|
76c95abf09 | ||
|
|
05dde993fd | ||
|
|
f6cfde2b56 | ||
|
|
af555a2089 | ||
|
|
4c6e18f5b8 | ||
|
|
491c62e8a7 | ||
|
|
d0d3ea080d | ||
|
|
8142eb8235 | ||
|
|
47959cddef | ||
|
|
357b9af52f | ||
|
|
4f17319836 | ||
|
|
1889889f01 | ||
|
|
bfa9d5b12e | ||
|
|
e1a73fa4ab | ||
|
|
5f8f03137c | ||
|
|
2a327ef4c9 | ||
|
|
5f08542009 | ||
|
|
1163591f8f | ||
|
|
6dd27c8799 | ||
|
|
7b84d92c4a | ||
|
|
fd53fe1cc3 | ||
|
|
9c284e6b8e | ||
|
|
f1f724f6e3 | ||
|
|
75a977fc39 | ||
|
|
059779a29a | ||
|
|
49a0b56b74 | ||
|
|
e38babe3c2 | ||
|
|
5cca594f7d | ||
|
|
0aeab7ef69 | ||
|
|
a8e92871c2 | ||
|
|
6f3cef7e1d | ||
|
|
21dfec3b93 | ||
|
|
b988715c2c | ||
|
|
ba82be7a89 | ||
|
|
d5d06a3452 | ||
|
|
3906bf9725 | ||
|
|
da74b29f21 | ||
|
|
b2a8b7dc97 | ||
|
|
3728927586 | ||
|
|
1c9d8728f2 | ||
|
|
55201311c7 | ||
|
|
bc1c70bd0c | ||
|
|
214015dfe9 | ||
|
|
36a7b93d80 | ||
|
|
fb6167ec6d | ||
|
|
8d9ae53e0e | ||
|
|
d057ab061b | ||
|
|
f30b1b70f6 | ||
|
|
8457cc5eff | ||
|
|
c9a48eb832 | ||
|
|
a9605a6888 | ||
|
|
3380c3c70e | ||
|
|
42fe91ad91 | ||
|
|
cf9fa6e055 | ||
|
|
3ba5b4296a | ||
|
|
68824eaa1b | ||
|
|
eed3a80fc1 | ||
|
|
63fa31bde1 | ||
|
|
61c2b943cf | ||
|
|
2e3f43674f | ||
|
|
9eb3ed4273 | ||
|
|
7b192433b7 | ||
|
|
ac261a0bfd | ||
|
|
4a15e277aa | ||
|
|
a2cbc49bb1 | ||
|
|
5d317b6d94 | ||
|
|
95d4430064 | ||
|
|
01025d5b4d | ||
|
|
8303d85b6c | ||
|
|
5e296f5d3a | ||
|
|
5560ef47c0 | ||
|
|
dbdd0a77a1 | ||
|
|
c269cbedac | ||
|
|
f36074376b | ||
|
|
a38e46a970 | ||
|
|
bad48db4d5 | ||
|
|
9c7ef72b8f | ||
|
|
431f6930ce | ||
|
|
007a7fb077 | ||
|
|
374f0a0841 | ||
|
|
6aed33a5d7 | ||
|
|
963394c558 | ||
|
|
341631a8e1 | ||
|
|
11de406065 | ||
|
|
654c98b969 | ||
|
|
4af85f4076 | ||
|
|
a22d36b485 | ||
|
|
da1017e61e | ||
|
|
5cd3b40add | ||
|
|
17e526bcfe | ||
|
|
7e2aaabd19 |
82
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
82
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
|
|
@ -4,51 +4,75 @@ body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: >-
|
value: >-
|
||||||
**Note: This issue tracker is not intended for support requests!** If you need help with crashes or other issues, then
|
**Need help?** Ask on [Discord](https://discord.gg/rN9Y7caguP) instead of opening an issue.
|
||||||
you should [ask on our Discord server](https://discord.gg/rN9Y7caguP) instead. Unless you are certain that you
|
|
||||||
have found a defect, and you are able to point to where the problem is, you should not open an issue.
|
|
||||||
<br><br>
|
|
||||||
Additionally, please make sure you have done the following:
|
|
||||||
|
|
||||||
- **Have you ensured that all of your mods (including ModernFix) are up-to-date?** The latest version of ModernFix
|
**Issues that do not meet the requirements below (or are otherwise impossible to address with the given info) will be closed without investigation.**
|
||||||
can always be found [on Modrinth](https://modrinth.com/mod/modernfix).
|
- type: checkboxes
|
||||||
|
id: confirmations
|
||||||
- **Have you used the [search tool](https://github.com/embeddedt/ModernFix/issues) to check whether your issue
|
attributes:
|
||||||
has already been reported?** If it has been, then consider adding more information to the existing issue instead.
|
label: Checklist
|
||||||
|
options:
|
||||||
- **Have you determined the minimum set of instructions to reproduce the issue?** If your problem only occurs
|
- label: I am reporting a defect, not asking for help
|
||||||
with other mods installed, then you should narrow down exactly which mods are causing the issue. Please do not
|
required: true
|
||||||
provide your entire list of mods to us and expect that we will be able to figure out the problem.
|
- label: I have searched existing issues and this has not been reported
|
||||||
|
required: true
|
||||||
|
- label: I have reduced my mod list to the minimum required to reproduce this issue (see below)
|
||||||
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: description
|
id: description
|
||||||
attributes:
|
attributes:
|
||||||
label: Bug Description
|
label: Bug Description
|
||||||
description: >-
|
description: >-
|
||||||
Use this section to describe the issue you are experiencing in as much depth as possible. The description should
|
Describe the issue in detail. Be sure to include what you expected to happen and what actually happened.
|
||||||
explain what behavior you were expecting, and why you believe the issue to be a bug. If the issue you are reporting
|
validations:
|
||||||
only occurs with specific mods installed, then provide the name and version of each mod.
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: minimal-mods
|
||||||
|
attributes:
|
||||||
|
label: Minimal Mod List
|
||||||
|
description: >-
|
||||||
|
List ONLY the mods required to reproduce this issue. Maintainers have debugging tools that help them
|
||||||
|
locate problems quickly, but these generally don't work well in modpacks or large mod sets.
|
||||||
|
A minimal list should typically contain fewer than 10 mods.
|
||||||
|
|
||||||
**Hint:** If you have any screenshots, videos, or other information that you feel is necessary to
|
Reports with large mod lists will likely be closed without investigation, unless the problem is very clear.
|
||||||
explain the issue, you can attach them here.
|
|
||||||
|
If you don't know which mods are causing your problem, use binary search:
|
||||||
|
|
||||||
|
1. Remove half your mods
|
||||||
|
|
||||||
|
2. Test if the issue still occurs
|
||||||
|
|
||||||
|
3. If yes, remove half again. If no, restore the last removed half and repeat from step 1.
|
||||||
|
|
||||||
|
4. Repeat until only the necessary mods remain
|
||||||
|
placeholder: "- ModernFix 5.x.x\n- SomeMod 1.2.3"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: description-reproduction-steps
|
id: description-reproduction-steps
|
||||||
attributes:
|
attributes:
|
||||||
label: Reproduction Steps
|
label: Reproduction Steps
|
||||||
description: >-
|
description: >-
|
||||||
Provide as much information as possible on how to reproduce this bug. Make sure your instructions are as clear and
|
Provide clear steps to reproduce the bug. Each step should be a single concrete action.
|
||||||
concise as possible, because other people will need to be able to follow your guide in order to re-create the issue.
|
|
||||||
|
Maintainers are busy and need to be able to quickly replicate your problem. Your reproduction steps should be
|
||||||
**Hint:** A common way to fill this section out is to write a step-by-step guide.
|
clear enough for someone who is unfamiliar with your mods to follow in 5 minutes or less (not counting time
|
||||||
|
to launch the game).
|
||||||
|
|
||||||
|
Providing vague steps is likely to result in the issue being closed.
|
||||||
|
|
||||||
|
placeholder: "1. \n2. \n3. "
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: log-file
|
id: diagnostic-info
|
||||||
attributes:
|
attributes:
|
||||||
label: Log File
|
label: Diagnostic Info
|
||||||
description: >-
|
description: >-
|
||||||
**Hint:** You can usually find the log files within the folder `.minecraft/logs`. Most often, you will want the `latest.log`
|
Drag and drop `latest.log` from `.minecraft/logs/` for the session where the issue occurred.
|
||||||
file, since that file belongs to the last played session of the game.
|
Do not paste log text inline. Issues without a valid `latest.log` will be closed.
|
||||||
placeholder: >-
|
|
||||||
Drag-and-drop the log file here.
|
If a crash occurred, also attach the relevant file from `.minecraft/crash-reports/`.
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
|
||||||
115
.github/workflows/gradle.yml
vendored
115
.github/workflows/gradle.yml
vendored
|
|
@ -11,31 +11,124 @@ on:
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
concurrency:
|
||||||
|
group: release-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Repository
|
- name: Checkout Repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Set up JDK 17
|
- name: Set up JDK 21
|
||||||
uses: actions/setup-java@v4
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
java-version: 17
|
java-version: 21
|
||||||
check-latest: true
|
check-latest: true
|
||||||
|
- name: Check if release branch
|
||||||
|
id: check_branch
|
||||||
|
if: github.event_name == 'push'
|
||||||
|
run: |
|
||||||
|
if [[ "${{ github.ref }}" =~ ^refs/heads/[0-9]+\. ]]; then
|
||||||
|
echo "is_release=true" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "is_release=false" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
- name: Setup Gradle
|
- name: Setup Gradle
|
||||||
uses: gradle/actions/setup-gradle@v3
|
uses: gradle/actions/setup-gradle@v4
|
||||||
with:
|
with:
|
||||||
cache-read-only: ${{ !startsWith(github.ref, 'refs/heads/1.') }}
|
cache-read-only: ${{ steps.check_branch.outputs.is_release != 'true' }}
|
||||||
gradle-home-cache-cleanup: true
|
gradle-home-cache-cleanup: true
|
||||||
- name: Setup project Loom cache
|
- name: Remove tags for release on other versions
|
||||||
uses: actions/cache@v4
|
if: steps.check_branch.outputs.is_release == 'true'
|
||||||
with:
|
run: ./scripts/tagcleaner.sh
|
||||||
path: |
|
|
||||||
.gradle/loom-cache
|
|
||||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/gradle.properties', '**/*.gradle*', '**/gradle-wrapper.properties') }}
|
|
||||||
restore-keys: ${{ runner.os }}-gradle-
|
|
||||||
- name: Build ModernFix using Gradle
|
- name: Build ModernFix using Gradle
|
||||||
run: ./gradlew build
|
run: ./gradlew build
|
||||||
|
- name: Run mixin audit
|
||||||
|
run: timeout 60 xvfb-run ./gradlew runAuditClient
|
||||||
|
- name: Publish mod to CurseForge & Modrinth
|
||||||
|
if: steps.check_branch.outputs.is_release == 'true'
|
||||||
|
run: ./gradlew publishMods copyJarToBin
|
||||||
|
env:
|
||||||
|
CURSEFORGE_TOKEN: ${{ secrets.CURSEFORGE_TOKEN }}
|
||||||
|
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
|
||||||
|
- name: Capture mod version
|
||||||
|
if: steps.check_branch.outputs.is_release == 'true'
|
||||||
|
run: |
|
||||||
|
echo "MOD_VERSION=$(./gradlew properties -q | grep '^version:' | awk '{print $2}')" >> $GITHUB_ENV
|
||||||
|
echo "MC_VERSION=$(grep '^minecraft_version=' gradle.properties | cut -d= -f2)" >> $GITHUB_ENV
|
||||||
|
- name: Comment on fixed issues
|
||||||
|
if: steps.check_branch.outputs.is_release == 'true'
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const { execSync } = require('child_process');
|
||||||
|
|
||||||
|
const branch = context.ref.replace('refs/heads/', '');
|
||||||
|
const { data: runs } = await github.rest.actions.listWorkflowRuns({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
workflow_id: 'gradle.yml',
|
||||||
|
branch,
|
||||||
|
status: 'success',
|
||||||
|
per_page: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
const logArgs = runs.workflow_runs.length > 0
|
||||||
|
? `${runs.workflow_runs[0].head_sha}..${context.sha}`
|
||||||
|
: `-1 ${context.sha}`;
|
||||||
|
const log = execSync(`git log ${logArgs} --format=%s%n%b`, { encoding: 'utf8' });
|
||||||
|
|
||||||
|
const issueNumbers = new Set();
|
||||||
|
const pattern = /(?:fix(?:es|ed)?|close[sd]?|resolve[sd]?)\s+#(\d+)/gi;
|
||||||
|
let match;
|
||||||
|
while ((match = pattern.exec(log)) !== null) {
|
||||||
|
issueNumbers.add(parseInt(match[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (issueNumbers.size === 0) {
|
||||||
|
console.log('No fixed issues found in commits');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MARKER = '<!-- modernfix-fix-tracker -->';
|
||||||
|
const modVersion = process.env.MOD_VERSION;
|
||||||
|
const mcVersion = process.env.MC_VERSION;
|
||||||
|
const newLine = `- ${modVersion} for Minecraft ${mcVersion}`;
|
||||||
|
|
||||||
|
for (const issueNumber of issueNumbers) {
|
||||||
|
try {
|
||||||
|
const { data: comments } = await github.rest.issues.listComments({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: issueNumber,
|
||||||
|
per_page: 100
|
||||||
|
});
|
||||||
|
|
||||||
|
const existing = comments.find(c => c.body.includes(MARKER));
|
||||||
|
if (existing) {
|
||||||
|
await github.rest.issues.updateComment({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
comment_id: existing.id,
|
||||||
|
body: existing.body + `\n${newLine}`
|
||||||
|
});
|
||||||
|
console.log(`Updated comment on issue #${issueNumber}`);
|
||||||
|
} else {
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: issueNumber,
|
||||||
|
body: `${MARKER}\nThe fix for this issue has been released in the following versions of ModernFix:\n${newLine}`
|
||||||
|
});
|
||||||
|
console.log(`Created comment on issue #${issueNumber}`);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`Could not comment on #${issueNumber}: ${e.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
- name: Upload Artifacts to GitHub
|
- name: Upload Artifacts to GitHub
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
|
|
|
||||||
41
.github/workflows/release.yml
vendored
41
.github/workflows/release.yml
vendored
|
|
@ -1,41 +0,0 @@
|
||||||
name: Release ModernFix Artifacts
|
|
||||||
|
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types:
|
|
||||||
- published
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
release:
|
|
||||||
if: github.repository_owner == 'embeddedt'
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
steps:
|
|
||||||
- name: Checkout Repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Set up JDK 17
|
|
||||||
uses: actions/setup-java@v4
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: 17
|
|
||||||
check-latest: true
|
|
||||||
- name: Remove tags for release on other versions
|
|
||||||
run: ./scripts/tagcleaner.sh
|
|
||||||
- name: Build and publish mod to CurseForge & Modrinth
|
|
||||||
run: ./gradlew publishToModSites copyJarToBin
|
|
||||||
env:
|
|
||||||
CURSEFORGE_TOKEN: ${{ secrets.CURSEFORGE_TOKEN }}
|
|
||||||
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
|
|
||||||
- name: Upload assets to GitHub
|
|
||||||
uses: AButler/upload-release-assets@v3.0
|
|
||||||
with:
|
|
||||||
files: 'bin/*'
|
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- name: Add changelog to release
|
|
||||||
uses: irongut/EditRelease@v1.2.0
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
id: ${{ github.event.release.id }}
|
|
||||||
replacebody: true
|
|
||||||
files: "CHANGELOG.md"
|
|
||||||
|
|
@ -2,16 +2,15 @@ ModernFix is a standard Minecraft-style Gradle project powered by Architectury L
|
||||||
run the `build` task (e.g. via `./gradlew build`). You can also use `./gradlew forge:build` or `./gradlew fabric:build`
|
run the `build` task (e.g. via `./gradlew build`). You can also use `./gradlew forge:build` or `./gradlew fabric:build`
|
||||||
to build for just one loader (e.g. when debugging and wanting to rebuild quickly).
|
to build for just one loader (e.g. when debugging and wanting to rebuild quickly).
|
||||||
|
|
||||||
You must use Java 17 to develop ModernFix as the toolchain requires it. Nonetheless, the 1.16 mod JARs will work on
|
You must use Java 21 to develop ModernFix as the toolchain requires it. Nonetheless, the built 1.20.1 JAR is still
|
||||||
a Minecraft instance with Java 8.
|
compatible with Java 17.
|
||||||
|
|
||||||
## Submitting pull requests
|
## Submitting pull requests
|
||||||
|
|
||||||
Code or documentation contributions are welcome. Please keep the following points in mind:
|
Code or documentation contributions are welcome. Please keep the following points in mind:
|
||||||
|
|
||||||
* This project supports many Minecraft versions. Ideally, contributions should be made to the oldest relevant MC version.
|
* This project supports many Minecraft versions. Ideally, contributions should be made to the oldest relevant MC version (currently 1.20)
|
||||||
For instance, a PR optimizing new worldgen should be made to 1.18 (not 1.19 or 1.20) while a PR optimizing something
|
and then they will be ported forward.
|
||||||
like recipes should be made to 1.16 (the oldest supported version).
|
|
||||||
|
|
||||||
This somewhat unconventional policy ensures that all supported versions are treated equal when it comes to development,
|
This somewhat unconventional policy ensures that all supported versions are treated equal when it comes to development,
|
||||||
rather than the onus being on other modders and players to backport changes that are needed. Changes to older versions are
|
rather than the onus being on other modders and players to backport changes that are needed. Changes to older versions are
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
plugins {
|
plugins {
|
||||||
id 'com.github.johnrengelman.shadow'
|
id 'com.gradleup.shadow' version '8.3.9'
|
||||||
id 'java-library'
|
id 'java-library'
|
||||||
id 'com.diffplug.spotless'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
|
|
@ -31,7 +30,6 @@ dependencies {
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType(JavaCompile) {
|
tasks.withType(JavaCompile) {
|
||||||
options.compilerArgs += '--enable-preview'
|
|
||||||
options.release = 17
|
options.release = 17
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -44,6 +42,7 @@ shadowJar {
|
||||||
// shadowJar bug
|
// shadowJar bug
|
||||||
include '*.jar'
|
include '*.jar'
|
||||||
include 'META-INF/services/javax.annotation.processing.Processor'
|
include 'META-INF/services/javax.annotation.processing.Processor'
|
||||||
|
include 'META-INF/gradle/incremental.annotation.processors'
|
||||||
include 'org/spongepowered/asm/mixin/Mixin.class'
|
include 'org/spongepowered/asm/mixin/Mixin.class'
|
||||||
include 'org/fury_phoenix/**/*'
|
include 'org/fury_phoenix/**/*'
|
||||||
include {it.getName() == 'OnlyIn.class'}
|
include {it.getName() == 'OnlyIn.class'}
|
||||||
|
|
@ -52,9 +51,4 @@ shadowJar {
|
||||||
include {it.getName() == 'EnvType.class'}
|
include {it.getName() == 'EnvType.class'}
|
||||||
}
|
}
|
||||||
|
|
||||||
spotless {
|
|
||||||
java {
|
|
||||||
removeUnusedImports()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
version = '1.1.4'
|
version = '1.1.4'
|
||||||
|
|
|
||||||
|
|
@ -90,24 +90,19 @@ public class ClientMixinValidator {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean targetsClient(Object classTarget) {
|
private boolean targetsClient(Object classTarget) {
|
||||||
return switch (classTarget) {
|
if (classTarget instanceof TypeElement te) {
|
||||||
case TypeElement te ->
|
return isClientMarked(te);
|
||||||
isClientMarked(te);
|
} else if (classTarget instanceof TypeMirror tm) {
|
||||||
case TypeMirror tm -> {
|
var el = types.asElement(tm);
|
||||||
var el = types.asElement(tm);
|
return el != null ? targetsClient(el) : warn("TypeMirror of " + tm);
|
||||||
yield el != null ? targetsClient(el) : warn("TypeMirror of " + tm);
|
} else if (classTarget instanceof String s) {
|
||||||
}
|
var te = elemUtils.getTypeElement(toSourceString(s.split("\\$")[0]));
|
||||||
// If you're using a dollar sign in class names you are insane
|
return te != null ? targetsClient(te) : warn(s);
|
||||||
case String s -> {
|
} else {
|
||||||
var te =
|
throw new IllegalArgumentException("Unhandled type: "
|
||||||
elemUtils.getTypeElement(toSourceString(s.split("\\$")[0]));
|
|
||||||
yield te != null ? targetsClient(te) : warn(s);
|
|
||||||
}
|
|
||||||
default ->
|
|
||||||
throw new IllegalArgumentException("Unhandled type: "
|
|
||||||
+ classTarget.getClass() + "\n" + "Stringified contents: "
|
+ classTarget.getClass() + "\n" + "Stringified contents: "
|
||||||
+ classTarget.toString());
|
+ classTarget.toString());
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isClientMarked(TypeElement te) {
|
private boolean isClientMarked(TypeElement te) {
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ import javax.annotation.processing.Processor;
|
||||||
import javax.annotation.processing.RoundEnvironment;
|
import javax.annotation.processing.RoundEnvironment;
|
||||||
import javax.annotation.processing.SupportedAnnotationTypes;
|
import javax.annotation.processing.SupportedAnnotationTypes;
|
||||||
import javax.annotation.processing.SupportedOptions;
|
import javax.annotation.processing.SupportedOptions;
|
||||||
import javax.annotation.processing.SupportedSourceVersion;
|
|
||||||
import javax.lang.model.SourceVersion;
|
import javax.lang.model.SourceVersion;
|
||||||
import javax.lang.model.element.Element;
|
import javax.lang.model.element.Element;
|
||||||
import javax.lang.model.element.TypeElement;
|
import javax.lang.model.element.TypeElement;
|
||||||
|
|
@ -26,7 +25,6 @@ import org.fury_phoenix.mixinAp.config.MixinConfig;
|
||||||
|
|
||||||
@SupportedAnnotationTypes({"org.spongepowered.asm.mixin.Mixin", "org.embeddedt.modernfix.annotation.ClientOnlyMixin"})
|
@SupportedAnnotationTypes({"org.spongepowered.asm.mixin.Mixin", "org.embeddedt.modernfix.annotation.ClientOnlyMixin"})
|
||||||
@SupportedOptions({"rootProject.name", "project.name", "org.fury_phoenix.mixinAp.validator.debug"})
|
@SupportedOptions({"rootProject.name", "project.name", "org.fury_phoenix.mixinAp.validator.debug"})
|
||||||
@SupportedSourceVersion(SourceVersion.RELEASE_17)
|
|
||||||
@AutoService(Processor.class)
|
@AutoService(Processor.class)
|
||||||
public class MixinProcessor extends AbstractProcessor {
|
public class MixinProcessor extends AbstractProcessor {
|
||||||
|
|
||||||
|
|
@ -38,6 +36,11 @@ public class MixinProcessor extends AbstractProcessor {
|
||||||
|
|
||||||
private final Map<String, List<String>> mixinConfigList = new HashMap<>();
|
private final Map<String, List<String>> mixinConfigList = new HashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SourceVersion getSupportedSourceVersion() {
|
||||||
|
return SourceVersion.latest();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -77,7 +80,7 @@ public class MixinProcessor extends AbstractProcessor {
|
||||||
List<String> mixins =
|
List<String> mixins =
|
||||||
annotatedMixins.stream()
|
annotatedMixins.stream()
|
||||||
.map(TypeElement.class::cast)
|
.map(TypeElement.class::cast)
|
||||||
.map(TypeElement::toString)
|
.map(e -> processingEnv.getElementUtils().getBinaryName(e).toString())
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
mixinConfigList.putIfAbsent(aliases.get(annotation.getSimpleName().toString()), mixins);
|
mixinConfigList.putIfAbsent(aliases.get(annotation.getSimpleName().toString()), mixins);
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ public record MixinConfig(
|
||||||
@SerializedName("package")
|
@SerializedName("package")
|
||||||
String packageName,
|
String packageName,
|
||||||
String plugin,
|
String plugin,
|
||||||
String compatabilityLevel,
|
String compatibilityLevel,
|
||||||
@SerializedName("mixins")
|
@SerializedName("mixins")
|
||||||
List<String> commonMixins,
|
List<String> commonMixins,
|
||||||
@SerializedName("client")
|
@SerializedName("client")
|
||||||
|
|
@ -25,7 +25,7 @@ public record MixinConfig(
|
||||||
InjectorOptions injectors, OverwriteOptions overwrites
|
InjectorOptions injectors, OverwriteOptions overwrites
|
||||||
) {
|
) {
|
||||||
public MixinConfig(String packageName, List<String> commonMixins, List<String> clientMixins) {
|
public MixinConfig(String packageName, List<String> commonMixins, List<String> clientMixins) {
|
||||||
this(true, "0.8", packageName, "org.embeddedt.modernfix.core.ModernFixMixinPlugin", "JAVA_8",
|
this(true, "0.8", packageName, "org.embeddedt.modernfix.core.ModernFixMixinPlugin", "JAVA_17",
|
||||||
commonMixins, clientMixins, InjectorOptions.DEFAULT, OverwriteOptions.DEFAULT);
|
commonMixins, clientMixins, InjectorOptions.DEFAULT, OverwriteOptions.DEFAULT);
|
||||||
}
|
}
|
||||||
public record InjectorOptions(int defaultRequire) {
|
public record InjectorOptions(int defaultRequire) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
org.fury_phoenix.mixinAp.annotation.MixinProcessor,aggregating
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
plugins {
|
|
||||||
id 'modernfix.common-conventions'
|
|
||||||
id 'java-library'
|
|
||||||
}
|
|
||||||
|
|
||||||
version = '1.1.0'
|
|
||||||
10
annotations/build.gradle.kts
Normal file
10
annotations/build.gradle.kts
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
plugins {
|
||||||
|
id("java")
|
||||||
|
}
|
||||||
|
|
||||||
|
version = "1.1.0"
|
||||||
|
|
||||||
|
java {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
package org.embeddedt.modernfix.annotation;
|
||||||
|
|
||||||
|
public enum FeatureLevel {
|
||||||
|
GA, BETA;
|
||||||
|
|
||||||
|
public boolean isAtLeast(FeatureLevel required) {
|
||||||
|
return this.ordinal() >= required.ordinal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
package org.embeddedt.modernfix.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.CLASS)
|
||||||
|
@Target({ElementType.TYPE, ElementType.PACKAGE})
|
||||||
|
public @interface RequiresFeatureLevel {
|
||||||
|
FeatureLevel value() default FeatureLevel.GA;
|
||||||
|
}
|
||||||
|
|
@ -6,7 +6,7 @@ import java.lang.annotation.RetentionPolicy;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
@Retention(RetentionPolicy.CLASS)
|
@Retention(RetentionPolicy.CLASS)
|
||||||
@Target(ElementType.TYPE)
|
@Target({ElementType.TYPE, ElementType.PACKAGE})
|
||||||
public @interface RequiresMod {
|
public @interface RequiresMod {
|
||||||
String value() default "";
|
String value() default "";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
67
build.gradle
67
build.gradle
|
|
@ -1,67 +0,0 @@
|
||||||
plugins {
|
|
||||||
id "architectury-plugin" version "3.4-SNAPSHOT"
|
|
||||||
id "dev.architectury.loom" version "1.6-SNAPSHOT" apply false
|
|
||||||
id "maven-publish"
|
|
||||||
id 'com.matthewprenger.cursegradle' version '1.4.0' apply false
|
|
||||||
id 'com.palantir.git-version' version '1.0.0'
|
|
||||||
id 'org.ajoberstar.grgit' version '5.2.0'
|
|
||||||
id 'se.bjurr.gitchangelog.git-changelog-gradle-plugin' version '1.79.0'
|
|
||||||
id "com.modrinth.minotaur" version "2.+" apply false
|
|
||||||
id("com.diffplug.spotless") version "6.18.0" apply false
|
|
||||||
id 'modernfix.common-conventions' apply false
|
|
||||||
}
|
|
||||||
|
|
||||||
architectury {
|
|
||||||
minecraft = rootProject.minecraft_version
|
|
||||||
}
|
|
||||||
|
|
||||||
ext.archives_base_name = 'modernfix'
|
|
||||||
|
|
||||||
apply plugin: 'modernfix.common-conventions'
|
|
||||||
|
|
||||||
tasks.withType(JavaCompile).configureEach {
|
|
||||||
// ensure that the encoding is set to UTF-8, no matter what the system default is
|
|
||||||
// this fixes some edge cases with special characters not displaying correctly
|
|
||||||
// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html
|
|
||||||
// If Javadoc is generated, this must be specified in that task too.
|
|
||||||
options.encoding = "UTF-8"
|
|
||||||
|
|
||||||
// The Minecraft launcher currently installs Java 8 for users, so your mod probably wants to target Java 8 too
|
|
||||||
// JDK 9 introduced a new way of specifying this that will make sure no newer classes or methods are used.
|
|
||||||
// We'll use that if it's available, but otherwise we'll use the older option.
|
|
||||||
def targetVersion = 8
|
|
||||||
/*
|
|
||||||
if (JavaVersion.current().isJava9Compatible()) {
|
|
||||||
options.release = targetVersion
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register('generateChangelog', se.bjurr.gitchangelog.plugin.gradle.GitChangelogTask) {
|
|
||||||
def details = versionDetails();
|
|
||||||
def theVersionRef
|
|
||||||
if (details.commitDistance > 0) {
|
|
||||||
theVersionRef = details.lastTag;
|
|
||||||
} else {
|
|
||||||
def secondLastTagCmd = "git describe --abbrev=0 " + details.lastTag + "^"
|
|
||||||
def secondLastTag = secondLastTagCmd.execute().text.trim()
|
|
||||||
theVersionRef = secondLastTag;
|
|
||||||
}
|
|
||||||
|
|
||||||
fromRef = theVersionRef
|
|
||||||
|
|
||||||
file = new File("${rootDir}/CHANGELOG.md");
|
|
||||||
templateContent = new File("${rootDir}/gradle/changelog.mustache").getText('UTF-8').replace("[[modernFixVersionRef]]", theVersionRef);
|
|
||||||
toCommit = "HEAD";
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register('checkCleanTag') {
|
|
||||||
doLast {
|
|
||||||
def details = versionDetails()
|
|
||||||
if (!details.isCleanTag || versionDetails().commitDistance != 0) {
|
|
||||||
throw new GradleException('Not a clean tree.')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
println "ModernFix: " + version
|
|
||||||
210
build.gradle.kts
Normal file
210
build.gradle.kts
Normal file
|
|
@ -0,0 +1,210 @@
|
||||||
|
plugins {
|
||||||
|
id("net.neoforged.moddev.legacyforge") version("2.0.134")
|
||||||
|
id("me.modmuss50.mod-publish-plugin") version("1.1.0")
|
||||||
|
}
|
||||||
|
|
||||||
|
val minecraft_version = rootProject.properties["minecraft_version"].toString()
|
||||||
|
|
||||||
|
group = "org.embeddedt"
|
||||||
|
|
||||||
|
val gitVersion = providers.of(GitVersionSource::class) {
|
||||||
|
parameters {
|
||||||
|
minecraftVersion.set(minecraft_version)
|
||||||
|
projectDir.set(rootProject.layout.projectDirectory)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
version = gitVersion.get()
|
||||||
|
|
||||||
|
base.archivesName = "modernfix-forge"
|
||||||
|
|
||||||
|
legacyForge {
|
||||||
|
enable {
|
||||||
|
forgeVersion = rootProject.properties["forge_version"].toString()
|
||||||
|
isDisableRecompilation = System.getenv("CI") == "true"
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.properties["parchment_version"]?.let { parchmentVer ->
|
||||||
|
parchment {
|
||||||
|
minecraftVersion = minecraft_version
|
||||||
|
mappingsVersion = parchmentVer.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
runs {
|
||||||
|
create("client") {
|
||||||
|
client()
|
||||||
|
}
|
||||||
|
create("server") {
|
||||||
|
server()
|
||||||
|
}
|
||||||
|
create("auditClient") {
|
||||||
|
client()
|
||||||
|
jvmArguments.addAll("-Dmodernfix.auditAndExit=true", "-Djava.awt.headless=true")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mods {
|
||||||
|
create("modernfix") {
|
||||||
|
sourceSet(sourceSets.main.get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mixin {
|
||||||
|
add(sourceSets.main.get(), "modernfix.refmap.json")
|
||||||
|
config("modernfix-modernfix.mixins.json")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named<Jar>("jar") {
|
||||||
|
manifest.attributes(mapOf(
|
||||||
|
"MixinConfigs" to "modernfix-modernfix.mixins.json",
|
||||||
|
"Specification-Version" to "1",
|
||||||
|
"Implementation-Title" to project.name,
|
||||||
|
"Implementation-Version" to version
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
val curSourceCompatLevel = JavaVersion.VERSION_17
|
||||||
|
sourceCompatibility = curSourceCompatLevel
|
||||||
|
targetCompatibility = curSourceCompatLevel
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
exclusiveContent {
|
||||||
|
forRepository {
|
||||||
|
maven {
|
||||||
|
// location of the maven that hosts JEI files
|
||||||
|
name = "Progwml6 maven"
|
||||||
|
url = uri("https://dvs1.progwml6.com/files/maven/")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
forRepository {
|
||||||
|
maven {
|
||||||
|
name = "ModMaven"
|
||||||
|
url = uri("https://modmaven.dev")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filter {
|
||||||
|
includeGroup("mezz.jei")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exclusiveContent {
|
||||||
|
forRepository {
|
||||||
|
maven("https://cursemaven.com")
|
||||||
|
}
|
||||||
|
filter {
|
||||||
|
includeGroup("curse.maven")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val embed by configurations.creating {
|
||||||
|
isCanBeConsumed = false
|
||||||
|
isCanBeResolved = true
|
||||||
|
isTransitive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":annotations"))
|
||||||
|
embed(project(":annotations"))
|
||||||
|
"additionalRuntimeClasspath"(project(":annotations"))
|
||||||
|
annotationProcessor(project(path = ":annotation-processor", configuration = "shadow"))
|
||||||
|
|
||||||
|
val mixinextrasVersion = rootProject.properties["mixinextras_version"].toString()
|
||||||
|
implementation("io.github.llamalad7:mixinextras-common:${mixinextrasVersion}")
|
||||||
|
annotationProcessor("net.fabricmc:sponge-mixin:0.12.5+mixin.0.8.5")
|
||||||
|
annotationProcessor("io.github.llamalad7:mixinextras-common:${mixinextrasVersion}")
|
||||||
|
implementation("io.github.llamalad7:mixinextras-forge:${mixinextrasVersion}")
|
||||||
|
"jarJar"("io.github.llamalad7:mixinextras-forge:${mixinextrasVersion}")
|
||||||
|
|
||||||
|
val jei_version = rootProject.properties["jei_version"].toString()
|
||||||
|
modCompileOnly("mezz.jei:jei-${minecraft_version}-forge:${jei_version}")
|
||||||
|
modCompileOnly("curse.maven:spark-361579:${rootProject.properties["spark_version"].toString()}")
|
||||||
|
modCompileOnly("curse.maven:ctm-267602:${rootProject.properties["ctm_version"].toString()}")
|
||||||
|
modCompileOnly("curse.maven:ldlib-626676:${rootProject.properties["ldlib_version"].toString()}")
|
||||||
|
modCompileOnly("curse.maven:supermartijncore-454372:4455391")
|
||||||
|
modCompileOnly("curse.maven:patchouli-306770:6164575")
|
||||||
|
modCompileOnly("curse.maven:cofhcore-69162:5374122")
|
||||||
|
modCompileOnly("curse.maven:resourcefullib-570073:5659871")
|
||||||
|
modCompileOnly("curse.maven:kubejs-238086:5853326")
|
||||||
|
modCompileOnly("curse.maven:terrablender-563928:6290448")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named<Jar>("jar") {
|
||||||
|
from(embed.map { if (it.isDirectory) it else zipTree(it) })
|
||||||
|
}
|
||||||
|
|
||||||
|
// For the AP
|
||||||
|
tasks.withType<JavaCompile>().configureEach {
|
||||||
|
if (!name.lowercase().contains("test")) {
|
||||||
|
options.compilerArgs.addAll(
|
||||||
|
listOf(
|
||||||
|
"-ArootProject.name=${rootProject.name}",
|
||||||
|
"-Aproject.name=${project.name}"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
main {
|
||||||
|
resources.srcDir(
|
||||||
|
layout.buildDirectory.dir("generated/sources/annotationProcessor/java/main/resources")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named<ProcessResources>("processResources") {
|
||||||
|
dependsOn(tasks.named("compileJava"))
|
||||||
|
|
||||||
|
inputs.property("version", project.version)
|
||||||
|
|
||||||
|
filesMatching("META-INF/mods.toml") {
|
||||||
|
expand("version" to project.version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val finalJarTask = "reobfJar"
|
||||||
|
|
||||||
|
tasks.register<Copy>("copyJarNameConsistent") {
|
||||||
|
from(tasks.named<Jar>(finalJarTask).get().outputs.files)
|
||||||
|
into(project.file("build/libs"))
|
||||||
|
rename { _ -> "modernfix-" + project.name + "-latest.jar" }
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register<Copy>("copyJarToBin") {
|
||||||
|
from(tasks.named<Jar>(finalJarTask).get().outputs.files)
|
||||||
|
into(rootProject.file("bin"))
|
||||||
|
mustRunAfter(tasks.named("copyJarNameConsistent"))
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named("build") {
|
||||||
|
dependsOn("copyJarToBin", "copyJarNameConsistent")
|
||||||
|
}
|
||||||
|
|
||||||
|
publishMods {
|
||||||
|
file.set(tasks.named<Jar>(finalJarTask).flatMap { it.archiveFile })
|
||||||
|
displayName.set(tasks.named<Jar>(finalJarTask).flatMap { it.archiveFileName })
|
||||||
|
changelog = "Please check the [GitHub wiki](https://github.com/embeddedt/ModernFix/wiki/Changelog) for major changes."
|
||||||
|
type = STABLE
|
||||||
|
|
||||||
|
modLoaders.add("forge")
|
||||||
|
|
||||||
|
curseforge {
|
||||||
|
projectId = "790626"
|
||||||
|
projectSlug = "modernfix"
|
||||||
|
accessToken = providers.environmentVariable("CURSEFORGE_TOKEN")
|
||||||
|
minecraftVersions.add(minecraft_version)
|
||||||
|
}
|
||||||
|
modrinth {
|
||||||
|
projectId = "nmDcB62a"
|
||||||
|
accessToken = providers.environmentVariable("MODRINTH_TOKEN")
|
||||||
|
minecraftVersions.add(minecraft_version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named("publishMods") {
|
||||||
|
dependsOn(finalJarTask)
|
||||||
|
}
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
plugins {
|
|
||||||
id 'groovy-gradle-plugin'
|
|
||||||
}
|
|
||||||
7
buildSrc/build.gradle.kts
Normal file
7
buildSrc/build.gradle.kts
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
plugins {
|
||||||
|
`kotlin-dsl`
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
@ -1,137 +0,0 @@
|
||||||
plugins {
|
|
||||||
id 'java'
|
|
||||||
id 'architectury-plugin'
|
|
||||||
id 'maven-publish'
|
|
||||||
id 'com.diffplug.spotless'
|
|
||||||
}
|
|
||||||
|
|
||||||
spotless {
|
|
||||||
java {
|
|
||||||
removeUnusedImports()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
architectury {
|
|
||||||
compileOnly()
|
|
||||||
}
|
|
||||||
|
|
||||||
group = 'org.embeddedt'
|
|
||||||
// extract base version from tag, generate other metadata ourselves
|
|
||||||
def details = versionDetails()
|
|
||||||
def plusIndex = details.lastTag.indexOf("+")
|
|
||||||
if(plusIndex == -1) {
|
|
||||||
plusIndex = details.lastTag.length()
|
|
||||||
}
|
|
||||||
def baseVersion = details.lastTag.substring(0, plusIndex)
|
|
||||||
def dirtyMarker = grgit.status().clean ? "" : ".dirty"
|
|
||||||
def commitHashMarker = details.commitDistance > 0 ? ("." + details.gitHash.substring(0, Math.min(4, details.gitHash.length()))) : ""
|
|
||||||
def preMarker = (details.commitDistance > 0 || !details.isCleanTag) ? ("-beta." + details.commitDistance) : ""
|
|
||||||
if(preMarker.length() > 0) {
|
|
||||||
// bump to next patch release
|
|
||||||
def versionParts = baseVersion.tokenize(".")
|
|
||||||
baseVersion = "${versionParts[0]}.${versionParts[1]}.${versionParts[2].toInteger() + 1}"
|
|
||||||
}
|
|
||||||
def versionString = "${baseVersion}${preMarker}+mc${minecraft_version}${commitHashMarker}${dirtyMarker}"
|
|
||||||
version = versionString
|
|
||||||
archivesBaseName = rootProject.archives_base_name + '-' + project.name
|
|
||||||
|
|
||||||
sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
exclusiveContent {
|
|
||||||
forRepository {
|
|
||||||
maven {
|
|
||||||
url "https://modmaven.dev"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
filter {
|
|
||||||
includeGroup "appeng"
|
|
||||||
includeGroup "vazkii.patchouli"
|
|
||||||
includeGroup "mezz.jei"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exclusiveContent {
|
|
||||||
forRepository {
|
|
||||||
maven {
|
|
||||||
url "https://cursemaven.com"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
filter {
|
|
||||||
includeGroup "curse.maven"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exclusiveContent {
|
|
||||||
forRepository {
|
|
||||||
maven {
|
|
||||||
name = 'ParchmentMC'
|
|
||||||
url = 'https://maven.parchmentmc.org'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
filter {
|
|
||||||
includeGroup "org.parchmentmc.data"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exclusiveContent {
|
|
||||||
forRepository {
|
|
||||||
maven {
|
|
||||||
url = 'https://maven.architectury.dev'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
filter {
|
|
||||||
includeGroup "me.shedaniel"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exclusiveContent {
|
|
||||||
forRepository {
|
|
||||||
maven {
|
|
||||||
url = 'https://maven.saps.dev/minecraft'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
filter {
|
|
||||||
includeGroup "dev.latvian.mods"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exclusiveContent {
|
|
||||||
forRepository {
|
|
||||||
maven {
|
|
||||||
name = "Fuzs Mod Resources"
|
|
||||||
url = "https://raw.githubusercontent.com/Fuzss/modresources/main/maven/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
filter {
|
|
||||||
includeGroup "fuzs"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exclusiveContent {
|
|
||||||
forRepository {
|
|
||||||
maven {
|
|
||||||
name = "Fabric maven"
|
|
||||||
url = "https://maven.fabricmc.net/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
filter {
|
|
||||||
includeGroup "net.fabricmc"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exclusiveContent {
|
|
||||||
forRepository {
|
|
||||||
maven {
|
|
||||||
name = "Mod Menu"
|
|
||||||
url = "https://maven.terraformersmc.com/releases/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
filter {
|
|
||||||
includeGroup "com.terraformersmc"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exclusiveContent {
|
|
||||||
forRepository {
|
|
||||||
maven {
|
|
||||||
url "https://maven.tterrag.com"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
filter {
|
|
||||||
includeGroup "team.chisel.ctm"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
plugins {
|
|
||||||
id 'modernfix.common-conventions'
|
|
||||||
id 'dev.architectury.loom'
|
|
||||||
}
|
|
||||||
|
|
||||||
loom {
|
|
||||||
silentMojangMappingsLicense()
|
|
||||||
accessWidenerPath = file("${rootDir}/common/src/main/resources/modernfix.accesswidener")
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
|
|
||||||
mappings loom.layered() {
|
|
||||||
officialMojangMappings()
|
|
||||||
if(rootProject.hasProperty("parchment_version")) {
|
|
||||||
parchment("org.parchmentmc.data:parchment-${minecraft_version}:${parchment_version}@zip")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
implementation project(":annotations")
|
|
||||||
annotationProcessor project(path: ":annotation-processor", configuration: 'shadow')
|
|
||||||
}
|
|
||||||
|
|
||||||
project.sourceSets {
|
|
||||||
main.resources.srcDirs += [layout.buildDirectory.dir("generated/sources/annotationProcessor/java/main/resources")]
|
|
||||||
}
|
|
||||||
// hack to shut up gradle about the hack to include generated resources
|
|
||||||
tasks {
|
|
||||||
processResources {
|
|
||||||
dependsOn compileJava
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.withType(JavaCompile) {
|
|
||||||
options.fork = true
|
|
||||||
options.forkOptions.jvmArgs << '--enable-preview'
|
|
||||||
configure(options) {
|
|
||||||
if (!name.toLowerCase().contains('test')) {
|
|
||||||
options.compilerArgs << "-ArootProject.name=${rootProject.name}" << "-Aproject.name=${project.name}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,69 +0,0 @@
|
||||||
plugins {
|
|
||||||
id 'com.matthewprenger.cursegradle'
|
|
||||||
id 'com.modrinth.minotaur'
|
|
||||||
}
|
|
||||||
|
|
||||||
loom {
|
|
||||||
mods {
|
|
||||||
main { // to match the default mod generated for Forge
|
|
||||||
sourceSet project.sourceSets.main
|
|
||||||
sourceSet project(':common').sourceSets.main
|
|
||||||
}
|
|
||||||
}
|
|
||||||
runs {
|
|
||||||
client {
|
|
||||||
vmArgs "-Xmx1G"
|
|
||||||
vmArgs "-Xms1G"
|
|
||||||
property("mixin.debug.export", "true")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def copyJarNameConsistent = tasks.register('copyJarNameConsistent', Copy) {
|
|
||||||
from remapJar // shortcut for createJar.outputs.files
|
|
||||||
into project.file("build/libs")
|
|
||||||
rename { name -> "modernfix-" + project.name + "-latest.jar" }
|
|
||||||
}
|
|
||||||
|
|
||||||
def copyJarToBin = tasks.register('copyJarToBin', Copy) {
|
|
||||||
from remapJar // shortcut for createJar.outputs.files
|
|
||||||
into rootProject.file("bin")
|
|
||||||
mustRunAfter "copyJarNameConsistent"
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.build.dependsOn(copyJarToBin, copyJarNameConsistent)
|
|
||||||
|
|
||||||
def isBeta = project.version.toString().contains("beta")
|
|
||||||
|
|
||||||
curseforge {
|
|
||||||
if (System.getenv("CURSEFORGE_TOKEN") != null) {
|
|
||||||
apiKey = System.getenv("CURSEFORGE_TOKEN")
|
|
||||||
project {
|
|
||||||
id = "790626"
|
|
||||||
changelog = file("${rootDir}/CHANGELOG.md")
|
|
||||||
changelogType = "markdown"
|
|
||||||
releaseType = isBeta ? "beta" : "release"
|
|
||||||
addGameVersion project.name.capitalize()
|
|
||||||
gameVersionStrings.addAll(supported_minecraft_versions.tokenize(","))
|
|
||||||
mainArtifact remapJar
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
modrinth {
|
|
||||||
token = System.getenv("MODRINTH_TOKEN")
|
|
||||||
projectId = "modernfix" // This can be the project ID or the slug. Either will work!
|
|
||||||
versionType = isBeta ? "beta" : "release" // This is the default -- can also be `beta` or `alpha`
|
|
||||||
uploadFile = remapJar
|
|
||||||
gameVersions = supported_minecraft_versions.tokenize(",")
|
|
||||||
loaders = [project.name]
|
|
||||||
changelog.set(provider { file("${rootDir}/CHANGELOG.md").getText('UTF-8') })
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.curseforge.dependsOn(rootProject.generateChangelog)
|
|
||||||
tasks.modrinth.dependsOn(rootProject.generateChangelog)
|
|
||||||
|
|
||||||
tasks.register('publishToModSites') {
|
|
||||||
publishToModSites.dependsOn(tasks.modrinth)
|
|
||||||
publishToModSites.dependsOn(tasks.curseforge)
|
|
||||||
}
|
|
||||||
61
buildSrc/src/main/kotlin/GitVersionSource.kt
Normal file
61
buildSrc/src/main/kotlin/GitVersionSource.kt
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
import org.gradle.api.file.DirectoryProperty
|
||||||
|
import org.gradle.api.provider.Property
|
||||||
|
import org.gradle.api.provider.ValueSource
|
||||||
|
import org.gradle.api.provider.ValueSourceParameters
|
||||||
|
import org.gradle.process.ExecOperations
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
import java.io.File
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
abstract class GitVersionSource : ValueSource<String, GitVersionSource.Parameters> {
|
||||||
|
|
||||||
|
interface Parameters : ValueSourceParameters {
|
||||||
|
val minecraftVersion: Property<String>
|
||||||
|
val projectDir: DirectoryProperty
|
||||||
|
}
|
||||||
|
|
||||||
|
@get:Inject
|
||||||
|
abstract val execOperations: ExecOperations
|
||||||
|
|
||||||
|
override fun obtain(): String {
|
||||||
|
val minecraftVersion = parameters.minecraftVersion.get()
|
||||||
|
val workDir = parameters.projectDir.get().asFile
|
||||||
|
|
||||||
|
val releaseLine = workDir.resolve("release_line.txt").readText().trim()
|
||||||
|
|
||||||
|
val patch = try {
|
||||||
|
// Find the most recent first-parent commit that touched release_line.txt
|
||||||
|
val lineStartCommit = git(workDir,
|
||||||
|
"log", "--first-parent",
|
||||||
|
"-n", "1",
|
||||||
|
"--format=%H",
|
||||||
|
"--",
|
||||||
|
"release_line.txt"
|
||||||
|
).trim()
|
||||||
|
|
||||||
|
if (lineStartCommit.isEmpty()) {
|
||||||
|
// count all first-parent commits as a safe fallback
|
||||||
|
git(workDir, "rev-list", "--count", "--first-parent", "HEAD")
|
||||||
|
.trim().toIntOrNull() ?: 0
|
||||||
|
} else {
|
||||||
|
git(workDir, "rev-list", "--count", "--first-parent", "$lineStartCommit..HEAD")
|
||||||
|
.trim().toIntOrNull() ?: 0
|
||||||
|
}
|
||||||
|
} catch (_: Exception) {
|
||||||
|
// Git is unavailable or this is not a git repository
|
||||||
|
999
|
||||||
|
}
|
||||||
|
|
||||||
|
return "$releaseLine.$patch+mc$minecraftVersion"
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun git(workDir: File, vararg args: String): String {
|
||||||
|
val output = ByteArrayOutputStream()
|
||||||
|
execOperations.exec {
|
||||||
|
commandLine("git", *args)
|
||||||
|
standardOutput = output
|
||||||
|
workingDir(workDir)
|
||||||
|
}
|
||||||
|
return output.toString(Charsets.UTF_8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
plugins {
|
|
||||||
id "modernfix.mod-common-conventions"
|
|
||||||
}
|
|
||||||
|
|
||||||
architectury {
|
|
||||||
common(rootProject.enabled_platforms.split(","))
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
// We depend on fabric loader here to use the fabric @Environment annotations and get the mixin dependencies
|
|
||||||
// Do NOT use other classes from fabric loader
|
|
||||||
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
|
|
||||||
implementation(annotationProcessor("io.github.llamalad7:mixinextras-common:${rootProject.mixinextras_version}"))
|
|
||||||
|
|
||||||
modCompileOnly("dev.latvian.mods:kubejs:${kubejs_version}") {
|
|
||||||
transitive = false
|
|
||||||
}
|
|
||||||
// Remove the next line if you don't want to depend on the API
|
|
||||||
// modApi "me.shedaniel:architectury:${rootProject.architectury_version}"
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't need remapped common jar
|
|
||||||
tasks.named('remapJar') { enabled = false }
|
|
||||||
|
|
||||||
publishing {
|
|
||||||
publications {
|
|
||||||
mavenCommon(MavenPublication) {
|
|
||||||
artifactId = rootProject.archives_base_name
|
|
||||||
from components.java
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing.
|
|
||||||
repositories {
|
|
||||||
// Add repositories to publish to here.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
package org.embeddedt.modernfix;
|
|
||||||
|
|
||||||
import com.google.common.cache.CacheLoader;
|
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
|
||||||
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
public class FileWalker extends CacheLoader<Pair<Path, Integer>, List<Path>> {
|
|
||||||
public static final FileWalker INSTANCE = new FileWalker();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Path> load(Pair<Path, Integer> key) throws Exception {
|
|
||||||
try(Stream<Path> stream = Files.walk(key.getLeft(), key.getRight())) {
|
|
||||||
return stream.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,205 +0,0 @@
|
||||||
package org.embeddedt.modernfix;
|
|
||||||
|
|
||||||
import com.mojang.datafixers.util.Pair;
|
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
|
||||||
import net.minecraft.network.syncher.SynchedEntityData;
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
import net.minecraft.world.entity.Entity;
|
|
||||||
import org.embeddedt.modernfix.api.constants.IntegrationConstants;
|
|
||||||
import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration;
|
|
||||||
import org.embeddedt.modernfix.core.ModernFixMixinPlugin;
|
|
||||||
import org.embeddedt.modernfix.packet.EntityIDSyncPacket;
|
|
||||||
import org.embeddedt.modernfix.platform.ModernFixPlatformHooks;
|
|
||||||
import org.embeddedt.modernfix.util.ClassInfoManager;
|
|
||||||
import org.embeddedt.modernfix.world.IntegratedWatchdog;
|
|
||||||
|
|
||||||
import java.lang.management.ManagementFactory;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
|
||||||
|
|
||||||
public class ModernFixClient {
|
|
||||||
public static ModernFixClient INSTANCE;
|
|
||||||
public static long worldLoadStartTime = -1;
|
|
||||||
private static int numRenderTicks;
|
|
||||||
|
|
||||||
public static float gameStartTimeSeconds = -1;
|
|
||||||
|
|
||||||
public static boolean recipesUpdated, tagsUpdated = false;
|
|
||||||
|
|
||||||
public String brandingString = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The list of loaded client integrations.
|
|
||||||
*/
|
|
||||||
public static List<ModernFixClientIntegration> CLIENT_INTEGRATIONS = new CopyOnWriteArrayList<>();
|
|
||||||
|
|
||||||
public ModernFixClient() {
|
|
||||||
INSTANCE = this;
|
|
||||||
// clear reserve as it's not needed
|
|
||||||
Minecraft.reserve = new byte[0];
|
|
||||||
if(ModernFixMixinPlugin.instance.isOptionEnabled("feature.branding.F3Screen")) {
|
|
||||||
brandingString = ModernFix.NAME + " " + ModernFixPlatformHooks.INSTANCE.getVersionString();
|
|
||||||
}
|
|
||||||
for(String className : ModernFixPlatformHooks.INSTANCE.getCustomModOptions().get(IntegrationConstants.CLIENT_INTEGRATION_CLASS)) {
|
|
||||||
try {
|
|
||||||
CLIENT_INTEGRATIONS.add((ModernFixClientIntegration)Class.forName(className).getDeclaredConstructor().newInstance());
|
|
||||||
} catch(ReflectiveOperationException | ClassCastException e) {
|
|
||||||
ModernFix.LOGGER.error("Could not instantiate integration {}", className, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ModernFixMixinPlugin.instance.isOptionEnabled("perf.dynamic_resources.FireIntegrationHook")) {
|
|
||||||
for(ModernFixClientIntegration integration : ModernFixClient.CLIENT_INTEGRATIONS) {
|
|
||||||
integration.onDynamicResourcesStatusChange(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void resetWorldLoadStateMachine() {
|
|
||||||
numRenderTicks = 0;
|
|
||||||
worldLoadStartTime = -1;
|
|
||||||
recipesUpdated = false;
|
|
||||||
tagsUpdated = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onGameLaunchFinish() {
|
|
||||||
if(gameStartTimeSeconds >= 0)
|
|
||||||
return;
|
|
||||||
gameStartTimeSeconds = ManagementFactory.getRuntimeMXBean().getUptime() / 1000f;
|
|
||||||
if(ModernFixMixinPlugin.instance.isOptionEnabled("feature.measure_time.GameLoad"))
|
|
||||||
ModernFix.LOGGER.warn("Game took " + gameStartTimeSeconds + " seconds to start");
|
|
||||||
ModernFixPlatformHooks.INSTANCE.onLaunchComplete();
|
|
||||||
ClassInfoManager.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onRecipesUpdated() {
|
|
||||||
recipesUpdated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onTagsUpdated() {
|
|
||||||
tagsUpdated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onRenderTickEnd() {
|
|
||||||
if(recipesUpdated
|
|
||||||
&& tagsUpdated
|
|
||||||
&& worldLoadStartTime != -1
|
|
||||||
&& Minecraft.getInstance().player != null
|
|
||||||
&& numRenderTicks++ >= 10) {
|
|
||||||
float timeSpentLoading = ((float)(System.nanoTime() - worldLoadStartTime) / 1000000000f);
|
|
||||||
if(ModernFixMixinPlugin.instance.isOptionEnabled("feature.measure_time.WorldLoad")) {
|
|
||||||
ModernFix.LOGGER.warn("Time from main menu to in-game was " + timeSpentLoading + " seconds");
|
|
||||||
ModernFix.LOGGER.warn("Total time to load game and open world was " + (timeSpentLoading + gameStartTimeSeconds) + " seconds");
|
|
||||||
}
|
|
||||||
resetWorldLoadStateMachine();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the IDs match and remap them if not.
|
|
||||||
* @return true if ID remap was needed
|
|
||||||
*/
|
|
||||||
private static boolean compareAndSwitchIds(Class<? extends Entity> eClass, String fieldName, EntityDataAccessor<?> accessor, int newId) {
|
|
||||||
if(accessor.id != newId) {
|
|
||||||
ModernFix.LOGGER.warn("Corrected ID mismatch on {} field {}. Client had {} but server wants {}.",
|
|
||||||
eClass,
|
|
||||||
fieldName,
|
|
||||||
accessor.id,
|
|
||||||
newId);
|
|
||||||
accessor.id = newId;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
ModernFix.LOGGER.debug("{} {} ID fine: {}", eClass, fieldName, newId);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Horrendous hack to allow tracking every synced entity data manager.
|
|
||||||
*
|
|
||||||
* This is to ensure we can perform ID fixup on already constructed managers.
|
|
||||||
*/
|
|
||||||
public static final Set<SynchedEntityData> allEntityDatas = Collections.newSetFromMap(new WeakHashMap<>());
|
|
||||||
|
|
||||||
private static final Field entriesArrayField;
|
|
||||||
static {
|
|
||||||
Field field;
|
|
||||||
try {
|
|
||||||
field = SynchedEntityData.class.getDeclaredField("entriesArray");
|
|
||||||
field.setAccessible(true);
|
|
||||||
} catch(ReflectiveOperationException e) {
|
|
||||||
field = null;
|
|
||||||
}
|
|
||||||
entriesArrayField = field;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extremely hacky method to detect and correct mismatched entity data parameter IDs on the client and server.
|
|
||||||
*
|
|
||||||
* The technique is far from ideal, but it should detect reliably and also not break already constructed entities.
|
|
||||||
*/
|
|
||||||
public static void handleEntityIDSync(EntityIDSyncPacket packet) {
|
|
||||||
Map<Class<? extends Entity>, List<Pair<String, Integer>>> info = packet.getFieldInfo();
|
|
||||||
boolean fixNeeded = false;
|
|
||||||
for(Map.Entry<Class<? extends Entity>, List<Pair<String, Integer>>> entry : info.entrySet()) {
|
|
||||||
Class<? extends Entity> eClass = entry.getKey();
|
|
||||||
for(Pair<String, Integer> field : entry.getValue()) {
|
|
||||||
String fieldName = field.getFirst();
|
|
||||||
int newId = field.getSecond();
|
|
||||||
try {
|
|
||||||
Field f = eClass.getDeclaredField(fieldName);
|
|
||||||
f.setAccessible(true);
|
|
||||||
EntityDataAccessor<?> accessor = (EntityDataAccessor<?>)f.get(null);
|
|
||||||
if(compareAndSwitchIds(eClass, fieldName, accessor, newId))
|
|
||||||
fixNeeded = true;
|
|
||||||
} catch(NoSuchFieldException e) {
|
|
||||||
ModernFix.LOGGER.warn("Couldn't find field on {}: {}", eClass, fieldName);
|
|
||||||
} catch(ReflectiveOperationException e) {
|
|
||||||
throw new RuntimeException("Unexpected exception", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Now the ID mappings on synced entity data instances are probably all wrong. Fix that. */
|
|
||||||
List<SynchedEntityData> dataEntries;
|
|
||||||
synchronized (allEntityDatas) {
|
|
||||||
if(fixNeeded) {
|
|
||||||
dataEntries = new ArrayList<>(allEntityDatas);
|
|
||||||
for(SynchedEntityData manager : dataEntries) {
|
|
||||||
Int2ObjectOpenHashMap<SynchedEntityData.DataItem<?>> fixedMap = new Int2ObjectOpenHashMap<>();
|
|
||||||
List<SynchedEntityData.DataItem<?>> items = new ArrayList<>(manager.itemsById.values());
|
|
||||||
for(SynchedEntityData.DataItem<?> item : items) {
|
|
||||||
fixedMap.put(item.getAccessor().id, item);
|
|
||||||
}
|
|
||||||
manager.lock.writeLock().lock();
|
|
||||||
try {
|
|
||||||
manager.itemsById.replaceAll((id, parameter) -> fixedMap.get((int)id));
|
|
||||||
if(entriesArrayField != null) {
|
|
||||||
try {
|
|
||||||
SynchedEntityData.DataItem<?>[] dataArray = new SynchedEntityData.DataItem[items.size()];
|
|
||||||
for(int i = 0; i < dataArray.length; i++) {
|
|
||||||
dataArray[i] = fixedMap.get(i);
|
|
||||||
}
|
|
||||||
entriesArrayField.set(manager, dataArray);
|
|
||||||
} catch(ReflectiveOperationException e) {
|
|
||||||
ModernFix.LOGGER.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
manager.lock.writeLock().unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
allEntityDatas.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onServerStarted(MinecraftServer server) {
|
|
||||||
if(!ModernFixMixinPlugin.instance.isOptionEnabled("feature.integrated_server_watchdog.IntegratedWatchdog"))
|
|
||||||
return;
|
|
||||||
IntegratedWatchdog watchdog = new IntegratedWatchdog(server);
|
|
||||||
watchdog.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
package org.embeddedt.modernfix.chunk;
|
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.server.level.ServerLevel;
|
|
||||||
import net.minecraft.world.level.BlockGetter;
|
|
||||||
import net.minecraft.world.level.block.Blocks;
|
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
|
||||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
|
||||||
import net.minecraft.world.level.material.FluidState;
|
|
||||||
import net.minecraft.world.level.material.Fluids;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
public class SafeBlockGetter implements BlockGetter {
|
|
||||||
private final ServerLevel wrapped;
|
|
||||||
private final Thread mainThread;
|
|
||||||
|
|
||||||
public SafeBlockGetter(ServerLevel wrapped) {
|
|
||||||
this.wrapped = wrapped;
|
|
||||||
this.mainThread = Thread.currentThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean shouldUse() {
|
|
||||||
return Thread.currentThread() != this.mainThread;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private BlockGetter getChunkSafe(BlockPos pos) {
|
|
||||||
// can safely call getChunkForLighting off-thread
|
|
||||||
BlockGetter access = this.wrapped.getChunkSource().getChunkForLighting(pos.getX() >> 4, pos.getZ() >> 4);
|
|
||||||
if(!(access instanceof ChunkAccess))
|
|
||||||
return null;
|
|
||||||
ChunkAccess chunk = (ChunkAccess)access;
|
|
||||||
if(!chunk.getStatus().isOrAfter(ChunkStatus.FULL))
|
|
||||||
return null;
|
|
||||||
return chunk;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getMaxBuildHeight() {
|
|
||||||
return this.wrapped.getMaxBuildHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getMaxLightLevel() {
|
|
||||||
return this.wrapped.getMaxLightLevel();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public BlockEntity getBlockEntity(BlockPos pos) {
|
|
||||||
BlockGetter g = getChunkSafe(pos);
|
|
||||||
return g == null ? null : g.getBlockEntity(pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BlockState getBlockState(BlockPos pos) {
|
|
||||||
BlockGetter g = getChunkSafe(pos);
|
|
||||||
return g == null ? Blocks.AIR.defaultBlockState() : g.getBlockState(pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FluidState getFluidState(BlockPos pos) {
|
|
||||||
BlockGetter g = getChunkSafe(pos);
|
|
||||||
return g == null ? Fluids.EMPTY.defaultFluidState() : g.getFluidState(pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
package org.embeddedt.modernfix.command;
|
|
||||||
|
|
||||||
import com.mojang.brigadier.CommandDispatcher;
|
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
|
||||||
import net.minecraft.network.chat.TextComponent;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.server.level.ServerLevel;
|
|
||||||
import net.minecraft.server.packs.resources.Resource;
|
|
||||||
import net.minecraft.server.packs.resources.ResourceManager;
|
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
|
||||||
import org.embeddedt.modernfix.structure.CachingStructureManager;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import static net.minecraft.commands.Commands.*;
|
|
||||||
|
|
||||||
public class ModernFixCommands {
|
|
||||||
public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
|
|
||||||
dispatcher.register(literal("modernfix")
|
|
||||||
.then(literal("upgradeStructures")
|
|
||||||
.requires(source -> source.hasPermission(3))
|
|
||||||
.executes(context -> {
|
|
||||||
ServerLevel level = context.getSource().getLevel();
|
|
||||||
if(level == null) {
|
|
||||||
context.getSource().sendFailure(new TextComponent("Couldn't find server level"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ResourceManager manager = level.getServer().resources.getResourceManager();
|
|
||||||
Collection<ResourceLocation> structures = manager.listResources("structures", p -> p.endsWith(".nbt"));
|
|
||||||
int upgradedNum = 0;
|
|
||||||
Pattern pathPattern = Pattern.compile("^structures/(.*)\\.nbt$");
|
|
||||||
for(ResourceLocation found : structures) {
|
|
||||||
upgradedNum++;
|
|
||||||
Matcher matcher = pathPattern.matcher(found.getPath());
|
|
||||||
if(!matcher.matches())
|
|
||||||
continue;
|
|
||||||
ResourceLocation structureLocation = new ResourceLocation(found.getNamespace(), matcher.group(1));
|
|
||||||
try(Resource resource = manager.getResource(found)) {
|
|
||||||
CachingStructureManager.readStructureTag(structureLocation, level.getServer().getFixerUpper(), resource.getInputStream());
|
|
||||||
context.getSource().sendSuccess(new TextComponent("checked " + structureLocation + " (" + upgradedNum + "/" + structures.size() + ")"), false);
|
|
||||||
} catch(Throwable e) {
|
|
||||||
ModernFix.LOGGER.error("Couldn't upgrade structure " + found, e);
|
|
||||||
context.getSource().sendFailure(new TextComponent("error reading " + structureLocation + " (" + upgradedNum + "/" + structures.size() + ")"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
context.getSource().sendSuccess(new TextComponent("All structures upgraded"), false);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.bugfix.chunk_deadlock;
|
|
||||||
|
|
||||||
import net.minecraft.world.level.BlockGetter;
|
|
||||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
|
||||||
import org.embeddedt.modernfix.chunk.SafeBlockGetter;
|
|
||||||
import org.embeddedt.modernfix.duck.ISafeBlockGetter;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
|
||||||
|
|
||||||
@Mixin(value = BlockBehaviour.BlockStateBase.class, priority = 100)
|
|
||||||
public class BlockStateBaseMixin {
|
|
||||||
@ModifyVariable(method = "getOffset", at = @At("HEAD"), argsOnly = true, index = 1)
|
|
||||||
private BlockGetter useSafeGetter(BlockGetter g) {
|
|
||||||
if(g instanceof ISafeBlockGetter) {
|
|
||||||
SafeBlockGetter replacement = ((ISafeBlockGetter) g).mfix$getSafeBlockGetter();
|
|
||||||
if(replacement.shouldUse())
|
|
||||||
return replacement;
|
|
||||||
}
|
|
||||||
return g;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.bugfix.chunk_deadlock;
|
|
||||||
|
|
||||||
import net.minecraft.server.level.ServerLevel;
|
|
||||||
import org.embeddedt.modernfix.chunk.SafeBlockGetter;
|
|
||||||
import org.embeddedt.modernfix.duck.ISafeBlockGetter;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
|
||||||
|
|
||||||
@Mixin(ServerLevel.class)
|
|
||||||
public class ServerLevelMixin implements ISafeBlockGetter {
|
|
||||||
@Unique
|
|
||||||
private final SafeBlockGetter mfix$safeBlockGetter = new SafeBlockGetter((ServerLevel)(Object)this);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SafeBlockGetter mfix$getSafeBlockGetter() {
|
|
||||||
return mfix$safeBlockGetter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.bugfix.concurrency;
|
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.util.thread.BlockableEventLoop;
|
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
|
|
||||||
import java.util.function.BooleanSupplier;
|
|
||||||
|
|
||||||
@Mixin(Minecraft.class)
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public abstract class MinecraftMixin<R extends Runnable> extends BlockableEventLoop<R> {
|
|
||||||
|
|
||||||
protected MinecraftMixin(String p_i50403_1_) {
|
|
||||||
super(p_i50403_1_);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void managedBlock(BooleanSupplier pIsDone) {
|
|
||||||
if(!this.isSameThread()) {
|
|
||||||
ModernFix.LOGGER.warn("A mod is calling Minecraft.managedBlock from the wrong thread. This is most likely related to one of our parallelizations.");
|
|
||||||
ModernFix.LOGGER.warn("ModernFix will work around this, however ideally the issue should be patched in the other mod.");
|
|
||||||
ModernFix.LOGGER.warn("Stacktrace", new IllegalThreadStateException());
|
|
||||||
while(!pIsDone.getAsBoolean()) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(100);
|
|
||||||
} catch(InterruptedException e) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
super.managedBlock(pIsDone);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.bugfix.concurrency;
|
|
||||||
|
|
||||||
import net.minecraft.client.renderer.RenderType;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
@Mixin(targets = { "net/minecraft/client/renderer/RenderType$CompositeRenderType$EqualsStrategy"})
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public class RenderTypeEqualsStrategyMixin {
|
|
||||||
@Redirect(method = "equals(Lnet/minecraft/client/renderer/RenderType$CompositeRenderType;Lnet/minecraft/client/renderer/RenderType$CompositeRenderType;)Z", at = @At(value = "INVOKE", target = "Ljava/util/Objects;equals(Ljava/lang/Object;Ljava/lang/Object;)Z", ordinal = 0))
|
|
||||||
private boolean alsoCheckName(Object a, Object b, RenderType.CompositeRenderType type1, RenderType.CompositeRenderType type2) {
|
|
||||||
boolean supposedlyEqual = Objects.equals(a, b);
|
|
||||||
return supposedlyEqual && Objects.equals(type1.name, type2.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.bugfix.concurrency;
|
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet;
|
|
||||||
import net.minecraft.client.renderer.RenderType;
|
|
||||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Overwrite;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
|
|
||||||
@Mixin(RenderType.CompositeRenderType.class)
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public class RenderTypeMixin {
|
|
||||||
@Shadow @Final private static ObjectOpenCustomHashSet<RenderType.CompositeRenderType> INSTANCES;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author embeddedt
|
|
||||||
* @reason synchronize, can be accessed by multiple mods during modloading
|
|
||||||
*/
|
|
||||||
@Overwrite
|
|
||||||
private static RenderType.CompositeRenderType memoize(String name, VertexFormat format, int drawMode, int bufferSize, boolean useDelegate, boolean needsSorting, RenderType.CompositeState renderState) {
|
|
||||||
synchronized (INSTANCES){
|
|
||||||
return INSTANCES.addOrGet(new RenderType.CompositeRenderType(name, format, drawMode, bufferSize, useDelegate, needsSorting, renderState));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.bugfix.concurrency;
|
|
||||||
|
|
||||||
import net.minecraft.tags.StaticTagHelper;
|
|
||||||
import net.minecraft.tags.TagCollection;
|
|
||||||
import net.minecraft.tags.TagContainer;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Mutable;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
@Mixin(StaticTagHelper.class)
|
|
||||||
public class StaticTagHelperMixin<T> {
|
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
@Shadow @Mutable
|
|
||||||
@Final private List wrappers;
|
|
||||||
|
|
||||||
@Inject(method = "<init>", at = @At("RETURN"))
|
|
||||||
private void useCOWArrayList(Function<TagContainer, TagCollection<T>> function, CallbackInfo ci) {
|
|
||||||
this.wrappers = new CopyOnWriteArrayList<>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.bugfix.item_cache_flag;
|
|
||||||
|
|
||||||
import net.minecraft.world.item.Item;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
|
||||||
import org.objectweb.asm.Opcodes;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Overwrite;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove emptyCacheFlag from ItemStack, as Mojang did in 1.20 due to <a href="https://bugs.mojang.com/browse/MC-258939">MC-258939</a>.
|
|
||||||
*/
|
|
||||||
@Mixin(ItemStack.class)
|
|
||||||
public class ItemStackMixin {
|
|
||||||
@Shadow @Final @Deprecated private Item item;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author embeddedt, Mojang
|
|
||||||
* @reason avoid getItem()
|
|
||||||
*/
|
|
||||||
@Redirect(method = "isEmpty", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;getItem()Lnet/minecraft/world/item/Item;"))
|
|
||||||
private Item getItemDirect(ItemStack stack) {
|
|
||||||
return this.item;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Redirect(method = "*", at = @At(value = "FIELD", opcode = Opcodes.GETFIELD, target = "Lnet/minecraft/world/item/ItemStack;emptyCacheFlag:Z"))
|
|
||||||
private boolean checkEmptyDirect(ItemStack stack) {
|
|
||||||
return stack.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author embeddedt, Mojang
|
|
||||||
* @reason flag is no longer used
|
|
||||||
*/
|
|
||||||
@Overwrite
|
|
||||||
private void updateEmptyCacheFlag() {}
|
|
||||||
}
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.bugfix.mc218112;
|
|
||||||
|
|
||||||
import net.minecraft.network.syncher.SynchedEntityData;
|
|
||||||
import net.minecraft.world.entity.Entity;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Overwrite;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.locks.ReadWriteLock;
|
|
||||||
|
|
||||||
@Mixin(SynchedEntityData.class)
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public abstract class SynchedEntityDataMixin_Client {
|
|
||||||
@Shadow @Final private ReadWriteLock lock;
|
|
||||||
|
|
||||||
@Shadow private boolean isDirty;
|
|
||||||
|
|
||||||
@Shadow protected abstract <T> void assignValue(SynchedEntityData.DataItem<T> target, SynchedEntityData.DataItem<?> source);
|
|
||||||
|
|
||||||
@Shadow @Final private Entity entity;
|
|
||||||
|
|
||||||
@Shadow @Final private Map<Integer, SynchedEntityData.DataItem<?>> itemsById;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author embeddedt
|
|
||||||
* @reason always unlock
|
|
||||||
*/
|
|
||||||
@Overwrite
|
|
||||||
public void assignValues(List<SynchedEntityData.DataItem<?>> entries) {
|
|
||||||
this.lock.writeLock().lock();
|
|
||||||
try {
|
|
||||||
for(SynchedEntityData.DataItem<?> dataentry : entries) {
|
|
||||||
SynchedEntityData.DataItem<?> dataentry1 = this.itemsById.get(dataentry.getAccessor().getId());
|
|
||||||
if (dataentry1 != null) {
|
|
||||||
this.assignValue(dataentry1, dataentry);
|
|
||||||
this.entity.onSyncedDataUpdated(dataentry.getAccessor());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
this.lock.writeLock().unlock();
|
|
||||||
}
|
|
||||||
this.isDirty = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.bugfix.packet_leak;
|
|
||||||
|
|
||||||
import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
|
||||||
import net.minecraft.network.protocol.game.ClientboundCustomPayloadPacket;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
@Mixin(ClientboundCustomPayloadPacket.class)
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public class SCustomPayloadPlayPacketMixin {
|
|
||||||
@Shadow private FriendlyByteBuf data;
|
|
||||||
|
|
||||||
private boolean needsRelease;
|
|
||||||
|
|
||||||
@Inject(method = "<init>(Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/network/FriendlyByteBuf;)V", at = @At("RETURN"))
|
|
||||||
private void markNotOwned(ResourceLocation pIdentifier, FriendlyByteBuf pData, CallbackInfo ci) {
|
|
||||||
this.needsRelease = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "read", at = @At("RETURN"))
|
|
||||||
private void markOwned(FriendlyByteBuf p_148837_1_, CallbackInfo ci) {
|
|
||||||
this.needsRelease = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Redirect(method = "handle(Lnet/minecraft/network/protocol/game/ClientGamePacketListener;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/protocol/game/ClientGamePacketListener;handleCustomPayload(Lnet/minecraft/network/protocol/game/ClientboundCustomPayloadPacket;)V"))
|
|
||||||
private void handleAndFree(ClientGamePacketListener instance, ClientboundCustomPayloadPacket sCustomPayloadPlayPacket) {
|
|
||||||
/* in 1.16, this method creates a copy inside it, but does not handle freeing correctly. fixing that breaks mods though */
|
|
||||||
instance.handleCustomPayload(sCustomPayloadPlayPacket);
|
|
||||||
if(this.needsRelease)
|
|
||||||
this.data.release(); /* free our own copy of the data if needed */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,61 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.bugfix.paper_chunk_patches;
|
|
||||||
|
|
||||||
import com.mojang.datafixers.util.Either;
|
|
||||||
import net.minecraft.server.level.ChunkHolder;
|
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
|
||||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
|
||||||
import org.embeddedt.modernfix.duck.IPaperChunkHolder;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
|
|
||||||
@Mixin(ChunkHolder.class)
|
|
||||||
public abstract class ChunkHolderMixin implements IPaperChunkHolder {
|
|
||||||
|
|
||||||
@Shadow public abstract CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> getFutureIfPresentUnchecked(ChunkStatus arg);
|
|
||||||
|
|
||||||
@Shadow @Final private static List<ChunkStatus> CHUNK_STATUSES;
|
|
||||||
|
|
||||||
public ChunkStatus mfix$getChunkHolderStatus() {
|
|
||||||
for (ChunkStatus curr = ChunkStatus.FULL, next = curr.getParent(); curr != next; curr = next, next = next.getParent()) {
|
|
||||||
CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> future = this.getFutureIfPresentUnchecked(curr);
|
|
||||||
Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure> either = future.getNow(null);
|
|
||||||
if (either == null || !either.left().isPresent()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
return curr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ChunkAccess mfix$getAvailableChunkNow() {
|
|
||||||
// TODO can we just getStatusFuture(EMPTY)?
|
|
||||||
for (ChunkStatus curr = ChunkStatus.FULL, next = curr.getParent(); curr != next; curr = next, next = next.getParent()) {
|
|
||||||
CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> future = this.getFutureIfPresentUnchecked(curr);
|
|
||||||
Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure> either = future.getNow(null);
|
|
||||||
if (either == null || !either.left().isPresent()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
return either.left().get();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ChunkStatus mfix$getNextStatus(ChunkStatus status) {
|
|
||||||
if (status == ChunkStatus.FULL) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
return CHUNK_STATUSES.get(status.getIndex() + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean mfix$canAdvanceStatus() {
|
|
||||||
ChunkStatus status = mfix$getChunkHolderStatus();
|
|
||||||
ChunkAccess chunk = mfix$getAvailableChunkNow();
|
|
||||||
return chunk != null && (status == null || chunk.getStatus().isOrAfter(mfix$getNextStatus(status)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.bugfix.paper_chunk_patches;
|
|
||||||
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
import net.minecraft.server.level.ChunkHolder;
|
|
||||||
import net.minecraft.server.level.ChunkMap;
|
|
||||||
import net.minecraft.server.level.ServerLevel;
|
|
||||||
import net.minecraft.util.thread.BlockableEventLoop;
|
|
||||||
import org.embeddedt.modernfix.duck.IPaperChunkHolder;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
|
|
||||||
@Mixin(ChunkMap.class)
|
|
||||||
public class ChunkMapMixin {
|
|
||||||
@Shadow @Final private BlockableEventLoop<Runnable> mainThreadExecutor;
|
|
||||||
|
|
||||||
@Shadow @Final private ServerLevel level;
|
|
||||||
private Executor mainInvokingExecutor;
|
|
||||||
|
|
||||||
@Inject(method = "<init>", at = @At("RETURN"))
|
|
||||||
private void setup(CallbackInfo ci) {
|
|
||||||
MinecraftServer server = this.level.getServer();
|
|
||||||
this.mainInvokingExecutor = (runnable) -> {
|
|
||||||
if(server.isSameThread())
|
|
||||||
runnable.run();
|
|
||||||
else
|
|
||||||
this.mainThreadExecutor.execute(runnable);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* https://github.com/PaperMC/Paper/blob/ver/1.17.1/patches/server/0752-Fix-chunks-refusing-to-unload-at-low-TPS.patch */
|
|
||||||
@ModifyArg(method = "unpackTicks", at = @At(value = "INVOKE", target = "Ljava/util/concurrent/CompletableFuture;thenApplyAsync(Ljava/util/function/Function;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;"), index = 1)
|
|
||||||
private Executor useMainThreadExecutor(Executor executor) {
|
|
||||||
return this.mainThreadExecutor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* https://github.com/PaperMC/Paper/blob/master/patches/removed/1.19.2-legacy-chunksystem/0482-Improve-Chunk-Status-Transition-Speed.patch */
|
|
||||||
@ModifyArg(method = "getEntityTickingRangeFuture", at = @At(value = "INVOKE", target = "Ljava/util/concurrent/CompletableFuture;thenApplyAsync(Ljava/util/function/Function;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;"), index = 1)
|
|
||||||
private Executor useMainInvokingExecutor(Executor executor) {
|
|
||||||
return this.mainInvokingExecutor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
|
||||||
@Redirect(method = "scheduleChunkGeneration", at = @At(value = "INVOKE", target = "Ljava/util/concurrent/CompletableFuture;thenComposeAsync(Ljava/util/function/Function;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;"))
|
|
||||||
private CompletableFuture skipWorkerIfPossible(CompletableFuture inputFuture, Function function, Executor executor, ChunkHolder holder) {
|
|
||||||
Executor targetExecutor = (runnable) -> {
|
|
||||||
if(((IPaperChunkHolder)holder).mfix$canAdvanceStatus()) {
|
|
||||||
this.mainInvokingExecutor.execute(runnable);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
executor.execute(runnable);
|
|
||||||
};
|
|
||||||
return inputFuture.thenComposeAsync(function, targetExecutor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.core;
|
|
||||||
|
|
||||||
import net.minecraft.Util;
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
import org.embeddedt.modernfix.duck.ITimeTrackingServer;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
@Mixin(MinecraftServer.class)
|
|
||||||
public class MinecraftServerMixin implements ITimeTrackingServer {
|
|
||||||
private long mfix$lastTickStartTime = -1L;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long mfix$getLastTickStartTime() {
|
|
||||||
return mfix$lastTickStartTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "runServer", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;tickServer(Ljava/util/function/BooleanSupplier;)V"))
|
|
||||||
private void trackTickTime(CallbackInfo ci) {
|
|
||||||
mfix$lastTickStartTime = Util.getMillis();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.core;
|
|
||||||
|
|
||||||
import net.minecraft.network.syncher.SynchedEntityData;
|
|
||||||
import net.minecraft.world.entity.Entity;
|
|
||||||
import org.embeddedt.modernfix.ModernFixClient;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
@Mixin(SynchedEntityData.class)
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public class SynchedEntityDataMixin {
|
|
||||||
/**
|
|
||||||
* Store this in our set of all entity data objects.
|
|
||||||
*
|
|
||||||
* Not an ideal solution, but it should guarantee compatibility with mods.
|
|
||||||
*/
|
|
||||||
@Inject(method = "<init>", at = @At("RETURN"))
|
|
||||||
private void storeInSet(Entity arg, CallbackInfo ci) {
|
|
||||||
synchronized (ModernFixClient.allEntityDatas) {
|
|
||||||
ModernFixClient.allEntityDatas.add((SynchedEntityData)(Object)this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.devenv;
|
|
||||||
|
|
||||||
import com.mojang.authlib.minecraft.OfflineSocialInteractions;
|
|
||||||
import com.mojang.authlib.minecraft.SocialInteractionsService;
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|
||||||
|
|
||||||
@Mixin(Minecraft.class)
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public class MinecraftMixin {
|
|
||||||
@Inject(method = "createSocialInteractions", at = @At("HEAD"), cancellable = true)
|
|
||||||
private void noSocialInteraction(CallbackInfoReturnable<SocialInteractionsService> cir) {
|
|
||||||
cir.setReturnValue(new OfflineSocialInteractions());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.devenv;
|
|
||||||
|
|
||||||
import com.mojang.text2speech.Narrator;
|
|
||||||
import com.mojang.text2speech.NarratorDummy;
|
|
||||||
import net.minecraft.client.gui.chat.NarratorChatListener;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
|
||||||
|
|
||||||
@Mixin(NarratorChatListener.class)
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public class NarratorMixin {
|
|
||||||
@Redirect(method = "<init>", at = @At(value = "INVOKE", target = "Lcom/mojang/text2speech/Narrator;getNarrator()Lcom/mojang/text2speech/Narrator;", remap = false))
|
|
||||||
private Narrator useDummyNarrator() {
|
|
||||||
return new NarratorDummy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.feature.direct_stack_trace;
|
|
||||||
|
|
||||||
import net.minecraft.CrashReport;
|
|
||||||
import net.minecraft.CrashReportCategory;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|
||||||
|
|
||||||
@Mixin(CrashReport.class)
|
|
||||||
public class CrashReportMixin {
|
|
||||||
@Shadow @Final private Throwable exception;
|
|
||||||
|
|
||||||
@Inject(method = "addCategory(Ljava/lang/String;I)Lnet/minecraft/CrashReportCategory;", at = @At(value = "INVOKE", target = "Ljava/io/PrintStream;println(Ljava/lang/String;)V"))
|
|
||||||
private void dumpStacktrace(String s, int i, CallbackInfoReturnable<CrashReportCategory> cir) {
|
|
||||||
new Exception("ModernFix crash stacktrace").printStackTrace();
|
|
||||||
if(this.exception != null)
|
|
||||||
this.exception.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.feature.measure_time;
|
|
||||||
|
|
||||||
import com.mojang.datafixers.util.Function4;
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.client.gui.screens.Overlay;
|
|
||||||
import net.minecraft.server.packs.resources.ResourceManager;
|
|
||||||
import net.minecraft.world.level.DataPackConfig;
|
|
||||||
import net.minecraft.core.RegistryAccess;
|
|
||||||
import net.minecraft.world.level.storage.WorldData;
|
|
||||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
|
||||||
import org.embeddedt.modernfix.ModernFixClient;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|
||||||
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
@Mixin(Minecraft.class)
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public class MinecraftMixin {
|
|
||||||
@Shadow @Nullable public Overlay overlay;
|
|
||||||
private long datapackReloadStartTime;
|
|
||||||
|
|
||||||
@Inject(method = "makeServerStem", at = @At(value = "HEAD"))
|
|
||||||
private void recordReloadStart(RegistryAccess.RegistryHolder p_238189_1_, Function<LevelStorageSource.LevelStorageAccess, DataPackConfig> p_238189_2_, Function4<LevelStorageSource.LevelStorageAccess, RegistryAccess.RegistryHolder, ResourceManager, DataPackConfig, WorldData> p_238189_3_, boolean p_238189_4_, LevelStorageSource.LevelStorageAccess p_238189_5_, CallbackInfoReturnable<Minecraft.ServerStem> cir) {
|
|
||||||
datapackReloadStartTime = System.nanoTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "makeServerStem", at = @At(value = "RETURN"))
|
|
||||||
private void recordReloadEnd(RegistryAccess.RegistryHolder p_238189_1_, Function<LevelStorageSource.LevelStorageAccess, DataPackConfig> p_238189_2_, Function4<LevelStorageSource.LevelStorageAccess, RegistryAccess.RegistryHolder, ResourceManager, DataPackConfig, WorldData> p_238189_3_, boolean p_238189_4_, LevelStorageSource.LevelStorageAccess p_238189_5_, CallbackInfoReturnable<Minecraft.ServerStem> cir) {
|
|
||||||
float timeSpentReloading = ((float)(System.nanoTime() - datapackReloadStartTime) / 1000000000f);
|
|
||||||
ModernFix.LOGGER.warn("Datapack reload took " + timeSpentReloading + " seconds.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "tick", at = @At("HEAD"))
|
|
||||||
private void onClientTick(CallbackInfo ci) {
|
|
||||||
if(this.overlay == null && ModernFixClient.INSTANCE != null) {
|
|
||||||
ModernFixClient.INSTANCE.onGameLaunchFinish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.feature.measure_time;
|
|
||||||
|
|
||||||
import net.minecraft.server.packs.resources.PreparableReloadListener;
|
|
||||||
import net.minecraft.server.packs.resources.ProfiledReloadInstance;
|
|
||||||
import org.embeddedt.modernfix.util.NamedPreparableResourceListener;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Mixin(ProfiledReloadInstance.class)
|
|
||||||
public class ProfiledReloadInstanceMixin {
|
|
||||||
@ModifyVariable(method = "<init>", at = @At("HEAD"), argsOnly = true, ordinal = 0)
|
|
||||||
private static List<PreparableReloadListener> getWrappedListeners(List<PreparableReloadListener> listeners) {
|
|
||||||
List<PreparableReloadListener> newList = new ArrayList<>(listeners.size());
|
|
||||||
for(PreparableReloadListener listener : listeners) {
|
|
||||||
newList.add(new NamedPreparableResourceListener(listener));
|
|
||||||
}
|
|
||||||
return newList;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.feature.measure_time;
|
|
||||||
|
|
||||||
import net.minecraft.server.packs.resources.SimpleReloadableResourceManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
|
||||||
|
|
||||||
@Mixin(SimpleReloadableResourceManager.class)
|
|
||||||
public class SimpleReloadableResourceManagerMixin {
|
|
||||||
// TODO maybe expose as a mixin config
|
|
||||||
private static final boolean ENABLE_DEBUG_RELOADER = Boolean.getBoolean("modernfix.debugReloader");
|
|
||||||
/**
|
|
||||||
* @author embeddedt
|
|
||||||
* @reason add ability to use this feature in modpacks
|
|
||||||
*/
|
|
||||||
@Redirect(method = "createReload", at = @At(value = "INVOKE", target = "Lorg/apache/logging/log4j/Logger;isDebugEnabled()Z", remap = false))
|
|
||||||
private boolean enableDebugReloader(Logger logger) {
|
|
||||||
return logger.isDebugEnabled() || ENABLE_DEBUG_RELOADER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.feature.stalled_chunk_load_detection;
|
|
||||||
|
|
||||||
import com.mojang.datafixers.util.Either;
|
|
||||||
import net.minecraft.server.level.ChunkHolder;
|
|
||||||
import net.minecraft.server.level.ServerChunkCache;
|
|
||||||
import net.minecraft.server.level.ServerLevel;
|
|
||||||
import net.minecraft.world.level.ChunkPos;
|
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
|
||||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
|
||||||
import net.minecraft.world.level.chunk.EmptyLevelChunk;
|
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|
||||||
import java.util.concurrent.*;
|
|
||||||
|
|
||||||
@Mixin(value = ServerChunkCache.class, priority = 1100)
|
|
||||||
public abstract class ServerChunkCacheMixin {
|
|
||||||
@Shadow @Final private Thread mainThread;
|
|
||||||
@Shadow @Final public ServerLevel level;
|
|
||||||
|
|
||||||
@Shadow protected abstract CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> getChunkFutureMainThread(int k, int l, ChunkStatus arg, boolean bl);
|
|
||||||
|
|
||||||
@Shadow @Final private ServerChunkCache.MainThreadExecutor mainThreadProcessor;
|
|
||||||
private final boolean debugDeadServerAccess = Boolean.getBoolean("modernfix.debugBadChunkloading");
|
|
||||||
|
|
||||||
@Inject(method = "getChunk", at = @At("HEAD"), cancellable = true)
|
|
||||||
private void bailIfServerDead(int chunkX, int chunkZ, ChunkStatus requiredStatus, boolean load, CallbackInfoReturnable<ChunkAccess> cir) {
|
|
||||||
if(!this.level.getServer().isRunning() && !this.mainThread.isAlive()) {
|
|
||||||
ModernFix.LOGGER.fatal("A mod is accessing chunks from a stopped server (this will also cause memory leaks)");
|
|
||||||
if(debugDeadServerAccess) {
|
|
||||||
new Exception().printStackTrace();
|
|
||||||
}
|
|
||||||
cir.setReturnValue(new EmptyLevelChunk(this.level, new ChunkPos(chunkX, chunkZ)));
|
|
||||||
} else if(Thread.currentThread() != this.mainThread) {
|
|
||||||
CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> future = CompletableFuture.supplyAsync(() -> this.getChunkFutureMainThread(chunkX, chunkZ, requiredStatus, false), this.mainThreadProcessor).join();
|
|
||||||
if(!future.isDone()) {
|
|
||||||
// Wait at least 500 milliseconds before printing anything
|
|
||||||
Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure> resultingChunk = null;
|
|
||||||
try {
|
|
||||||
resultingChunk = future.get(500, TimeUnit.MILLISECONDS);
|
|
||||||
} catch(InterruptedException | ExecutionException | TimeoutException ignored) {
|
|
||||||
}
|
|
||||||
if(resultingChunk != null && resultingChunk.left().isPresent()) {
|
|
||||||
cir.setReturnValue(resultingChunk.left().get());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(debugDeadServerAccess)
|
|
||||||
ModernFix.LOGGER.warn("Async loading of a chunk was requested, this might not be desirable", new Exception());
|
|
||||||
try {
|
|
||||||
resultingChunk = future.get(10, TimeUnit.SECONDS);
|
|
||||||
if(resultingChunk.left().isPresent()) {
|
|
||||||
cir.setReturnValue(resultingChunk.left().get());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} catch(InterruptedException | ExecutionException | TimeoutException e) {
|
|
||||||
ModernFix.LOGGER.error("Async chunk load took way too long, this needs to be reported to the appropriate mod.", e);
|
|
||||||
}
|
|
||||||
//cir.setReturnValue(new EmptyLevelChunk(this.level, new ChunkPos(chunkX, chunkZ)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.biome_zoomer;
|
|
||||||
|
|
||||||
import net.minecraft.world.level.biome.Biome;
|
|
||||||
import net.minecraft.world.level.biome.BiomeManager;
|
|
||||||
import net.minecraft.world.level.biome.FuzzyOffsetBiomeZoomer;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Overwrite;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
|
|
||||||
@Mixin(FuzzyOffsetBiomeZoomer.class)
|
|
||||||
public abstract class FuzzyOffsetBiomeZoomerMixin {
|
|
||||||
@Shadow protected static double getFiddledDistance(long seed, int x, int y, int z, double scaleX, double scaleY, double scaleZ) {
|
|
||||||
throw new AssertionError();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author embeddedt
|
|
||||||
* @reason use the modern logic that doesn't allocate an array of 8 doubles every time
|
|
||||||
*/
|
|
||||||
@Overwrite
|
|
||||||
public Biome getBiome(long seed, int xIn, int yIn, int zIn, BiomeManager.NoiseBiomeSource biomeReader) {
|
|
||||||
int i = xIn - 2;
|
|
||||||
int j = yIn - 2;
|
|
||||||
int k = zIn - 2;
|
|
||||||
int l = i >> 2;
|
|
||||||
int i1 = j >> 2;
|
|
||||||
int j1 = k >> 2;
|
|
||||||
double d0 = (double)(i & 3) / 4.0D;
|
|
||||||
double d1 = (double)(j & 3) / 4.0D;
|
|
||||||
double d2 = (double)(k & 3) / 4.0D;
|
|
||||||
int k1 = 0;
|
|
||||||
double d3 = Double.POSITIVE_INFINITY;
|
|
||||||
|
|
||||||
for(int l1 = 0; l1 < 8; ++l1) {
|
|
||||||
boolean flag = (l1 & 4) == 0;
|
|
||||||
boolean flag1 = (l1 & 2) == 0;
|
|
||||||
boolean flag2 = (l1 & 1) == 0;
|
|
||||||
int i2 = flag ? l : l + 1;
|
|
||||||
int j2 = flag1 ? i1 : i1 + 1;
|
|
||||||
int k2 = flag2 ? j1 : j1 + 1;
|
|
||||||
double d4 = flag ? d0 : d0 - 1.0D;
|
|
||||||
double d5 = flag1 ? d1 : d1 - 1.0D;
|
|
||||||
double d6 = flag2 ? d2 : d2 - 1.0D;
|
|
||||||
double d7 = getFiddledDistance(seed, i2, j2, k2, d4, d5, d6);
|
|
||||||
if (d3 > d7) {
|
|
||||||
k1 = l1;
|
|
||||||
d3 = d7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int l2 = (k1 & 4) == 0 ? l : l + 1;
|
|
||||||
int i3 = (k1 & 2) == 0 ? i1 : i1 + 1;
|
|
||||||
int j3 = (k1 & 1) == 0 ? j1 : j1 + 1;
|
|
||||||
return biomeReader.getNoiseBiome(l2, i3, j3);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.boost_worker_count;
|
|
||||||
|
|
||||||
import net.minecraft.Util;
|
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Constant;
|
|
||||||
import org.spongepowered.asm.mixin.injection.ModifyConstant;
|
|
||||||
|
|
||||||
@Mixin(Util.class)
|
|
||||||
public class UtilMixin {
|
|
||||||
@ModifyConstant(method = "makeExecutor", constant = @Constant(intValue = 7))
|
|
||||||
private static int useHigherThreadCount(int old) {
|
|
||||||
String requestedMax = System.getProperty("max.bg.threads");
|
|
||||||
if(requestedMax != null) {
|
|
||||||
try {
|
|
||||||
int newMax = Integer.parseInt(requestedMax);
|
|
||||||
if(newMax >= 1 && newMax <= 255)
|
|
||||||
return newMax;
|
|
||||||
} catch(NumberFormatException e) {
|
|
||||||
ModernFix.LOGGER.error("max.bg.threads is not a number");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 255;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,110 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.cache_model_materials;
|
|
||||||
|
|
||||||
import com.mojang.datafixers.util.Either;
|
|
||||||
import net.minecraft.client.renderer.block.model.BlockModel;
|
|
||||||
import net.minecraft.client.resources.model.Material;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.embeddedt.modernfix.duck.ICachedMaterialsModel;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Mutable;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
@Mixin(BlockModel.class)
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public class BlockModelMixin {
|
|
||||||
@Shadow @Final @Mutable public Map<String, Either<Material, String>> textureMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author embeddedt
|
|
||||||
* @reason detect changes to the texture map, and clear the material cache as needed
|
|
||||||
*/
|
|
||||||
@Inject(method = "<init>", at = @At("RETURN"))
|
|
||||||
private void useTrackingTextureMap(CallbackInfo ci) {
|
|
||||||
Map<String, Either<Material, String>> backingMap = this.textureMap;
|
|
||||||
ICachedMaterialsModel cacheHolder = (ICachedMaterialsModel)this;
|
|
||||||
this.textureMap = new Map<String, Either<Material, String>>() {
|
|
||||||
@Override
|
|
||||||
public int size() {
|
|
||||||
return backingMap.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEmpty() {
|
|
||||||
return backingMap.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean containsKey(Object o) {
|
|
||||||
return backingMap.containsKey(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean containsValue(Object o) {
|
|
||||||
return backingMap.containsValue(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Either<Material, String> get(Object o) {
|
|
||||||
return backingMap.get(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public Either<Material, String> put(String s, Either<Material, String> materialStringEither) {
|
|
||||||
Either<Material, String> old = backingMap.put(s, materialStringEither);
|
|
||||||
cacheHolder.clearMaterialsCache();
|
|
||||||
return old;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Either<Material, String> remove(Object o) {
|
|
||||||
Either<Material, String> e = backingMap.remove(o);
|
|
||||||
cacheHolder.clearMaterialsCache();
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void putAll(@NotNull Map<? extends String, ? extends Either<Material, String>> map) {
|
|
||||||
backingMap.putAll(map);
|
|
||||||
cacheHolder.clearMaterialsCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
backingMap.clear();
|
|
||||||
cacheHolder.clearMaterialsCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public Set<String> keySet() {
|
|
||||||
cacheHolder.clearMaterialsCache();
|
|
||||||
return backingMap.keySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public Collection<Either<Material, String>> values() {
|
|
||||||
cacheHolder.clearMaterialsCache();
|
|
||||||
return backingMap.values();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public Set<Entry<String, Either<Material, String>>> entrySet() {
|
|
||||||
cacheHolder.clearMaterialsCache();
|
|
||||||
return backingMap.entrySet();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.cache_model_materials;
|
|
||||||
|
|
||||||
import net.minecraft.client.renderer.block.model.multipart.MultiPart;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
@Mixin(MultiPart.class)
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public class MultipartMixin {
|
|
||||||
private Collection<ResourceLocation> dependencyCache = null;
|
|
||||||
@Inject(method = "getDependencies", at = @At("HEAD"), cancellable = true)
|
|
||||||
private void useDependencyCache(CallbackInfoReturnable<Collection<ResourceLocation>> cir) {
|
|
||||||
if(dependencyCache != null)
|
|
||||||
cir.setReturnValue(dependencyCache);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "getDependencies", at = @At("RETURN"))
|
|
||||||
private void storeDependencyCache(CallbackInfoReturnable<Collection<ResourceLocation>> cir) {
|
|
||||||
if(dependencyCache == null)
|
|
||||||
dependencyCache = cir.getReturnValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.cache_model_materials;
|
|
||||||
|
|
||||||
import com.mojang.datafixers.util.Pair;
|
|
||||||
import net.minecraft.client.renderer.block.model.BlockModel;
|
|
||||||
import net.minecraft.client.resources.model.UnbakedModel;
|
|
||||||
import net.minecraft.client.resources.model.Material;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.embeddedt.modernfix.duck.ICachedMaterialsModel;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
/* only cache BlockModel to prevent issues with CTM on Fabric */
|
|
||||||
@Mixin(value = {BlockModel.class})
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public class VanillaModelMixin implements ICachedMaterialsModel {
|
|
||||||
private Collection<Material> materialsCache = null;
|
|
||||||
|
|
||||||
@Inject(method = "getMaterials", at = @At("HEAD"), cancellable = true)
|
|
||||||
private void useCachedMaterials(Function<ResourceLocation, UnbakedModel> pModelGetter, Set<Pair<String, String>> pMissingTextureErrors, CallbackInfoReturnable<Collection<Material>> cir) {
|
|
||||||
if(materialsCache != null) {
|
|
||||||
cir.setReturnValue(materialsCache);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "getMaterials", at = @At("RETURN"))
|
|
||||||
private void storeCachedMaterials(Function<ResourceLocation, UnbakedModel> pModelGetter, Set<Pair<String, String>> pMissingTextureErrors, CallbackInfoReturnable<Collection<Material>> cir) {
|
|
||||||
if(materialsCache == null)
|
|
||||||
materialsCache = Collections.unmodifiableCollection(cir.getReturnValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearMaterialsCache() {
|
|
||||||
materialsCache = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.cache_strongholds;
|
|
||||||
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
import net.minecraft.server.level.ServerLevel;
|
|
||||||
import net.minecraft.world.level.ChunkPos;
|
|
||||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
|
||||||
import org.embeddedt.modernfix.duck.IServerLevel;
|
|
||||||
import org.embeddedt.modernfix.platform.ModernFixPlatformHooks;
|
|
||||||
import org.embeddedt.modernfix.world.StrongholdLocationCache;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Mixin(ChunkGenerator.class)
|
|
||||||
public class ChunkGeneratorMixin {
|
|
||||||
@Shadow @Final private List<ChunkPos> strongholdPositions;
|
|
||||||
|
|
||||||
@Inject(method = "generateStrongholds", at = @At(value = "INVOKE", target = "Lcom/google/common/collect/Lists;newArrayList()Ljava/util/ArrayList;", ordinal = 0, remap = false), cancellable = true)
|
|
||||||
private void useCachedDataIfAvailable(CallbackInfo ci) {
|
|
||||||
ServerLevel level = searchLevel();
|
|
||||||
if(level == null) {
|
|
||||||
ModernFix.LOGGER.error("Can't find server level for " + this);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
StrongholdLocationCache cache = ((IServerLevel)level).mfix$getStrongholdCache();
|
|
||||||
List<ChunkPos> positions = cache.getChunkPosList();
|
|
||||||
if(positions.isEmpty())
|
|
||||||
return;
|
|
||||||
ModernFix.LOGGER.debug("Loaded stronghold cache for dimension {} with {} positions", level.dimension().location(), positions.size());
|
|
||||||
this.strongholdPositions.addAll(positions);
|
|
||||||
ci.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
private ServerLevel searchLevel() {
|
|
||||||
MinecraftServer server = ModernFixPlatformHooks.INSTANCE.getCurrentServer();
|
|
||||||
if(server != null) {
|
|
||||||
ServerLevel ourLevel = null;
|
|
||||||
for (ServerLevel level : server.getAllLevels()) {
|
|
||||||
if (level.getChunkSource().getGenerator() == ((ChunkGenerator) (Object) this)) {
|
|
||||||
ourLevel = level;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ourLevel;
|
|
||||||
} else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "generateStrongholds", at = @At("TAIL"))
|
|
||||||
private void saveCachedData(CallbackInfo ci) {
|
|
||||||
if(this.strongholdPositions.size() > 0) {
|
|
||||||
ServerLevel level = searchLevel();
|
|
||||||
if(level != null) {
|
|
||||||
StrongholdLocationCache cache = ((IServerLevel)level).mfix$getStrongholdCache();
|
|
||||||
cache.setChunkPosList(this.strongholdPositions);
|
|
||||||
ModernFix.LOGGER.debug("Saved stronghold cache for dimension {}", level.dimension().location());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.cache_strongholds;
|
|
||||||
|
|
||||||
import net.minecraft.resources.ResourceKey;
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
import net.minecraft.server.level.ServerLevel;
|
|
||||||
import net.minecraft.server.level.progress.ChunkProgressListener;
|
|
||||||
import net.minecraft.util.profiling.ProfilerFiller;
|
|
||||||
import net.minecraft.world.level.CustomSpawner;
|
|
||||||
import net.minecraft.world.level.Level;
|
|
||||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
|
||||||
import net.minecraft.world.level.dimension.DimensionType;
|
|
||||||
import net.minecraft.world.level.storage.DimensionDataStorage;
|
|
||||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
|
||||||
import net.minecraft.world.level.storage.ServerLevelData;
|
|
||||||
import net.minecraft.world.level.storage.WritableLevelData;
|
|
||||||
import org.embeddedt.modernfix.duck.IServerLevel;
|
|
||||||
import org.embeddedt.modernfix.world.StrongholdLocationCache;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
@Mixin(ServerLevel.class)
|
|
||||||
public abstract class ServerLevelMixin extends Level implements IServerLevel {
|
|
||||||
protected ServerLevelMixin(WritableLevelData arg, ResourceKey<Level> arg2, DimensionType arg3, Supplier<ProfilerFiller> supplier, boolean bl, boolean bl2, long l) {
|
|
||||||
super(arg, arg2, arg3, supplier, bl, bl2, l);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Shadow public abstract DimensionDataStorage getDataStorage();
|
|
||||||
|
|
||||||
private StrongholdLocationCache mfix$strongholdCache;
|
|
||||||
|
|
||||||
@Inject(method = "<init>", at = @At("RETURN"))
|
|
||||||
private void addStrongholdCache(MinecraftServer minecraftServer, Executor executor, LevelStorageSource.LevelStorageAccess arg,
|
|
||||||
ServerLevelData arg2, ResourceKey<Level> arg3, DimensionType arg4, ChunkProgressListener arg5,
|
|
||||||
ChunkGenerator arg6, boolean bl, long l, List<CustomSpawner> list, boolean bl2, CallbackInfo ci) {
|
|
||||||
mfix$strongholdCache = this.getDataStorage().computeIfAbsent(() -> new StrongholdLocationCache((ServerLevel)(Object)this), StrongholdLocationCache.getFileId(this.dimensionType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public StrongholdLocationCache mfix$getStrongholdCache() {
|
|
||||||
return mfix$strongholdCache;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.cache_upgraded_structures;
|
|
||||||
|
|
||||||
import com.mojang.datafixers.DataFixer;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager;
|
|
||||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
|
|
||||||
import org.embeddedt.modernfix.structure.CachingStructureManager;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
|
|
||||||
@Mixin(StructureManager.class)
|
|
||||||
public class StructureManagerMixin {
|
|
||||||
@Shadow @Final private DataFixer fixerUpper;
|
|
||||||
|
|
||||||
@Redirect(method = "loadFromResource", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/levelgen/structure/templatesystem/StructureManager;readStructure(Ljava/io/InputStream;)Lnet/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate;"))
|
|
||||||
private StructureTemplate readViaCache(StructureManager manager, InputStream stream, ResourceLocation arg) throws IOException {
|
|
||||||
return CachingStructureManager.readStructure(arg, this.fixerUpper, stream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,148 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.compress_biome_container;
|
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.objects.Reference2ShortMap;
|
|
||||||
import it.unimi.dsi.fastutil.objects.Reference2ShortOpenHashMap;
|
|
||||||
import net.minecraft.util.BitStorage;
|
|
||||||
import net.minecraft.core.IdMap;
|
|
||||||
import net.minecraft.world.level.ChunkPos;
|
|
||||||
import net.minecraft.util.Mth;
|
|
||||||
import net.minecraft.world.level.biome.Biome;
|
|
||||||
import net.minecraft.world.level.chunk.ChunkBiomeContainer;
|
|
||||||
import net.minecraft.world.level.biome.BiomeSource;
|
|
||||||
import org.spongepowered.asm.mixin.*;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
@Mixin(ChunkBiomeContainer.class)
|
|
||||||
public class MixinBiomeContainer {
|
|
||||||
@Mutable
|
|
||||||
@Shadow
|
|
||||||
@Final
|
|
||||||
private Biome[] biomes;
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
@Final
|
|
||||||
private IdMap<Biome> biomeRegistry;
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
@Final
|
|
||||||
private static int WIDTH_BITS;
|
|
||||||
|
|
||||||
private Biome[] palette;
|
|
||||||
private BitStorage intArray;
|
|
||||||
|
|
||||||
@Inject(method = "<init>(Lnet/minecraft/core/IdMap;[I)V", at = @At("RETURN"), require = 0)
|
|
||||||
private void reinit1(IdMap p_i241970_1_, int[] p_i241970_2_, CallbackInfo ci) {
|
|
||||||
this.createCompact();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "<init>(Lnet/minecraft/core/IdMap;[Lnet/minecraft/world/level/biome/Biome;)V", at = @At("RETURN"))
|
|
||||||
private void reinit2(IdMap p_i241971_1_, Biome[] p_i241971_2_, CallbackInfo ci) {
|
|
||||||
this.createCompact();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "<init>(Lnet/minecraft/core/IdMap;Lnet/minecraft/world/level/ChunkPos;Lnet/minecraft/world/level/biome/BiomeSource;)V", at = @At("RETURN"))
|
|
||||||
private void reinit3(IdMap p_i241968_1_, ChunkPos p_i241968_2_, BiomeSource p_i241968_3_, CallbackInfo ci) {
|
|
||||||
this.createCompact();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "<init>(Lnet/minecraft/core/IdMap;Lnet/minecraft/world/level/ChunkPos;Lnet/minecraft/world/level/biome/BiomeSource;[I)V", at = @At("RETURN"))
|
|
||||||
private void reinit4(IdMap p_i241969_1_, ChunkPos p_i241969_2_, BiomeSource p_i241969_3_, int[] p_i241969_4_, CallbackInfo ci) {
|
|
||||||
this.createCompact();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createCompact() {
|
|
||||||
if (this.intArray != null || this.biomes[0] == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Reference2ShortOpenHashMap<Biome> paletteTable = this.createPalette();
|
|
||||||
Biome[] paletteIndexed = new Biome[paletteTable.size()];
|
|
||||||
|
|
||||||
for (Reference2ShortMap.Entry<Biome> entry : paletteTable.reference2ShortEntrySet()) {
|
|
||||||
paletteIndexed[entry.getShortValue()] = entry.getKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
int packedIntSize = Math.max(2, Mth.ceillog2(paletteTable.size()));
|
|
||||||
BitStorage integerArray = new BitStorage(packedIntSize, ChunkBiomeContainer.BIOMES_SIZE);
|
|
||||||
|
|
||||||
Biome prevBiome = null;
|
|
||||||
short prevId = -1;
|
|
||||||
|
|
||||||
for (int i = 0; i < this.biomes.length; i++) {
|
|
||||||
Biome biome = this.biomes[i];
|
|
||||||
short id;
|
|
||||||
|
|
||||||
if (prevBiome == biome) {
|
|
||||||
id = prevId;
|
|
||||||
} else {
|
|
||||||
id = paletteTable.getShort(biome);
|
|
||||||
|
|
||||||
if (id < 0) {
|
|
||||||
throw new IllegalStateException("Palette is missing entry: " + biome);
|
|
||||||
}
|
|
||||||
|
|
||||||
prevId = id;
|
|
||||||
prevBiome = biome;
|
|
||||||
}
|
|
||||||
|
|
||||||
integerArray.set(i, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.palette = paletteIndexed;
|
|
||||||
this.intArray = integerArray;
|
|
||||||
this.biomes = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Reference2ShortOpenHashMap<Biome> createPalette() {
|
|
||||||
Reference2ShortOpenHashMap<Biome> map = new Reference2ShortOpenHashMap<>();
|
|
||||||
map.defaultReturnValue(Short.MIN_VALUE);
|
|
||||||
|
|
||||||
Biome prevObj = null;
|
|
||||||
short id = 0;
|
|
||||||
|
|
||||||
for (Biome obj : this.biomes) {
|
|
||||||
if (obj == prevObj) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (map.getShort(obj) < 0) {
|
|
||||||
map.put(obj, id++);
|
|
||||||
}
|
|
||||||
|
|
||||||
prevObj = obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author JellySquid
|
|
||||||
* @reason Use paletted lookup
|
|
||||||
*/
|
|
||||||
@Overwrite
|
|
||||||
public int[] writeBiomes() {
|
|
||||||
int size = this.intArray.getSize();
|
|
||||||
int[] array = new int[size];
|
|
||||||
|
|
||||||
for(int i = 0; i < size; ++i) {
|
|
||||||
array[i] = this.biomeRegistry.getId(this.palette[this.intArray.get(i)]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author JellySquid
|
|
||||||
* @reason Use paletted lookup
|
|
||||||
*/
|
|
||||||
@Overwrite
|
|
||||||
public Biome getNoiseBiome(int biomeX, int biomeY, int biomeZ) {
|
|
||||||
int x = biomeX & ChunkBiomeContainer.HORIZONTAL_MASK;
|
|
||||||
int y = Mth.clamp(biomeY, 0, ChunkBiomeContainer.VERTICAL_MASK);
|
|
||||||
int z = biomeZ & ChunkBiomeContainer.HORIZONTAL_MASK;
|
|
||||||
|
|
||||||
return this.palette[this.intArray.get(y << WIDTH_BITS + WIDTH_BITS | z << WIDTH_BITS | x)];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.deduplicate_location;
|
|
||||||
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import org.embeddedt.modernfix.dedup.IdentifierCaches;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Mutable;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
@Mixin(ResourceLocation.class)
|
|
||||||
public class MixinResourceLocation {
|
|
||||||
@Mutable
|
|
||||||
@Shadow
|
|
||||||
@Final
|
|
||||||
protected String namespace;
|
|
||||||
|
|
||||||
@Mutable
|
|
||||||
@Shadow
|
|
||||||
@Final
|
|
||||||
protected String path;
|
|
||||||
|
|
||||||
@Inject(method = "<init>([Ljava/lang/String;)V", at = @At("RETURN"))
|
|
||||||
private void reinit(String[] id, CallbackInfo ci) {
|
|
||||||
this.namespace = IdentifierCaches.NAMESPACES.deduplicate(this.namespace);
|
|
||||||
this.path = IdentifierCaches.PATH.deduplicate(this.path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.dynamic_resources;
|
|
||||||
|
|
||||||
import com.google.gson.JsonDeserializationContext;
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import net.minecraft.client.renderer.block.model.BlockElementFace;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.embeddedt.modernfix.dynamicresources.UVController;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
|
|
||||||
@Mixin(BlockElementFace.Deserializer.class)
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public class BlockElementFaceDeserializerMixin {
|
|
||||||
|
|
||||||
@Redirect(method = "deserialize(Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;Lcom/google/gson/JsonDeserializationContext;)Lnet/minecraft/client/renderer/block/model/BlockElementFace;",
|
|
||||||
at = @At(value = "INVOKE", target = "Lcom/google/gson/JsonDeserializationContext;deserialize(Lcom/google/gson/JsonElement;Ljava/lang/reflect/Type;)Ljava/lang/Object;", ordinal = 0, remap = false))
|
|
||||||
private Object skipUvsForInitialLoad(JsonDeserializationContext context, JsonElement element, Type type) {
|
|
||||||
return UVController.useDummyUv.get() ? UVController.dummyUv : context.deserialize(element, type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.dynamic_resources;
|
|
||||||
|
|
||||||
import net.minecraft.client.resources.model.BakedModel;
|
|
||||||
import net.minecraft.client.resources.model.ModelManager;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@Mixin(ModelManager.class)
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public class ModelManagerMixin {
|
|
||||||
@Shadow private Map<ResourceLocation, BakedModel> bakedRegistry;
|
|
||||||
|
|
||||||
@Inject(method = "<init>", at = @At("RETURN"))
|
|
||||||
private void injectDummyBakedRegistry(CallbackInfo ci) {
|
|
||||||
if(this.bakedRegistry == null) {
|
|
||||||
// Create a dummy baked registry. This prevents NPEs when mods query block models too early
|
|
||||||
this.bakedRegistry = new HashMap<>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.dynamic_sounds;
|
|
||||||
|
|
||||||
import com.google.common.cache.CacheBuilder;
|
|
||||||
import com.google.common.cache.RemovalCause;
|
|
||||||
import com.google.common.cache.RemovalNotification;
|
|
||||||
import com.mojang.blaze3d.audio.SoundBuffer;
|
|
||||||
import net.minecraft.client.sounds.SoundBufferLibrary;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.embeddedt.modernfix.dynamicresources.DynamicSoundHelpers;
|
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Mutable;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@Mixin(SoundBufferLibrary.class)
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public abstract class SoundBufferLibraryMixin {
|
|
||||||
|
|
||||||
private static final boolean debugDynamicSoundLoading = Boolean.getBoolean("modernfix.debugDynamicSoundLoading");
|
|
||||||
|
|
||||||
@Shadow @Final @Mutable
|
|
||||||
private Map<ResourceLocation, CompletableFuture<SoundBuffer>> cache = CacheBuilder.newBuilder()
|
|
||||||
.expireAfterAccess(DynamicSoundHelpers.MAX_SOUND_LIFETIME_SECS, TimeUnit.SECONDS)
|
|
||||||
.concurrencyLevel(1)
|
|
||||||
// Excessive use of type hinting due to it assuming Object as the broadest correct type
|
|
||||||
.<ResourceLocation, CompletableFuture<SoundBuffer>>removalListener(this::onSoundRemoval)
|
|
||||||
.build()
|
|
||||||
.asMap();
|
|
||||||
|
|
||||||
private <K extends ResourceLocation, V extends CompletableFuture<SoundBuffer>> void onSoundRemoval(RemovalNotification<K, V> notification) {
|
|
||||||
if(notification.getCause() == RemovalCause.REPLACED && notification.getValue() == cache.get(notification.getKey()))
|
|
||||||
return;
|
|
||||||
notification.getValue().thenAccept(SoundBuffer::discardAlBuffer);
|
|
||||||
if(!debugDynamicSoundLoading)
|
|
||||||
return;
|
|
||||||
K k = notification.getKey();
|
|
||||||
if(k == null)
|
|
||||||
return;
|
|
||||||
ModernFix.LOGGER.warn("Evicted sound {}", k);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.faster_font_loading;
|
|
||||||
|
|
||||||
import com.mojang.blaze3d.platform.NativeImage;
|
|
||||||
import net.minecraft.client.gui.font.providers.LegacyUnicodeBitmapsProvider;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Objective: avoid recomputing locations many times, as well as loading all the font sheets in the constructor
|
|
||||||
* only to do it again later.
|
|
||||||
*/
|
|
||||||
@Mixin(LegacyUnicodeBitmapsProvider.class)
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public abstract class LegacyUnicodeBitmapsProviderMixin {
|
|
||||||
@Shadow protected abstract ResourceLocation getSheetLocation(int i);
|
|
||||||
|
|
||||||
@Shadow @Final private Map<ResourceLocation, NativeImage> textures;
|
|
||||||
private final ResourceLocation[] glyphLocations = new ResourceLocation[256];
|
|
||||||
|
|
||||||
private ResourceLocation currentCharIdx;
|
|
||||||
|
|
||||||
@Redirect(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/font/providers/LegacyUnicodeBitmapsProvider;getSheetLocation(I)Lnet/minecraft/resources/ResourceLocation;"))
|
|
||||||
private ResourceLocation storeCurrentCharIdx(LegacyUnicodeBitmapsProvider provider, int i) {
|
|
||||||
ResourceLocation location = getSheetLocation(i);
|
|
||||||
currentCharIdx = location;
|
|
||||||
return location;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Redirect(method = "<init>", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/platform/NativeImage;read(Lcom/mojang/blaze3d/platform/NativeImage$Format;Ljava/io/InputStream;)Lcom/mojang/blaze3d/platform/NativeImage;"))
|
|
||||||
private NativeImage storeLoadedFontSheet(NativeImage.Format format, InputStream stream) throws IOException {
|
|
||||||
NativeImage image = NativeImage.read(format, stream);
|
|
||||||
textures.put(currentCharIdx, image);
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Redirect(method = "<init>", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/platform/NativeImage;close()V"))
|
|
||||||
private void skipCloseNativeImage(NativeImage image) {
|
|
||||||
/* we can't close here, as the image has been stored for use later */
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "<init>", at = @At("RETURN"))
|
|
||||||
private void clearLocation(CallbackInfo ci) {
|
|
||||||
currentCharIdx = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "getSheetLocation", at = @At("HEAD"), cancellable = true)
|
|
||||||
private void useCachedLocation(int idx, CallbackInfoReturnable<ResourceLocation> cir) {
|
|
||||||
int cachedIdx = idx / 256;
|
|
||||||
if(cachedIdx >= 0 && cachedIdx < glyphLocations.length && glyphLocations[cachedIdx] != null)
|
|
||||||
cir.setReturnValue(glyphLocations[cachedIdx]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "getSheetLocation", at = @At("RETURN"))
|
|
||||||
private void saveCachedLocation(int idx, CallbackInfoReturnable<ResourceLocation> cir) {
|
|
||||||
int cachedIdx = idx / 256;
|
|
||||||
if(cachedIdx >= 0 && cachedIdx < glyphLocations.length)
|
|
||||||
glyphLocations[cachedIdx] = cir.getReturnValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,123 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.faster_texture_loading;
|
|
||||||
|
|
||||||
import com.mojang.blaze3d.platform.NativeImage;
|
|
||||||
import com.mojang.datafixers.util.Pair;
|
|
||||||
import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite;
|
|
||||||
import net.minecraft.client.renderer.texture.TextureAtlas;
|
|
||||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
|
||||||
import net.minecraft.client.resources.metadata.animation.AnimationMetadataSection;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.server.packs.resources.Resource;
|
|
||||||
import net.minecraft.server.packs.resources.ResourceManager;
|
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.embeddedt.modernfix.platform.ModernFixPlatformHooks;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
|
||||||
|
|
||||||
@Mixin(value = TextureAtlas.class, priority = 600)
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public abstract class TextureAtlasMixin {
|
|
||||||
@Shadow protected abstract ResourceLocation getResourceLocation(ResourceLocation location);
|
|
||||||
|
|
||||||
@Shadow protected abstract Collection<TextureAtlasSprite.Info> getBasicSpriteInfos(ResourceManager resourceManager, Set<ResourceLocation> spriteLocations);
|
|
||||||
|
|
||||||
private Map<ResourceLocation, Pair<Resource, NativeImage>> loadedImages = new ConcurrentHashMap<>();
|
|
||||||
private boolean usingFasterLoad;
|
|
||||||
private Collection<TextureAtlasSprite.Info> storedResults;
|
|
||||||
/**
|
|
||||||
* @author embeddedt
|
|
||||||
* @reason simplify texture loading by loading whole image once, avoid slow PngInfo code
|
|
||||||
*/
|
|
||||||
@Inject(method = "getBasicSpriteInfos", at = @At("HEAD"))
|
|
||||||
private void loadImages(ResourceManager manager, Set<ResourceLocation> imageLocations, CallbackInfoReturnable<Collection<TextureAtlasSprite.Info>> cir) {
|
|
||||||
usingFasterLoad = ModernFixPlatformHooks.INSTANCE.isLoadingNormally();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Redirect(method = "getBasicSpriteInfos", at = @At(value = "INVOKE", target = "Ljava/util/Set;iterator()Ljava/util/Iterator;", ordinal = 0))
|
|
||||||
private Iterator<?> skipIteration(Set<?> instance, ResourceManager manager, Set<ResourceLocation> imageLocations) {
|
|
||||||
// bail if Forge is erroring to avoid AT crashes
|
|
||||||
if(!usingFasterLoad)
|
|
||||||
return instance.iterator();
|
|
||||||
List<CompletableFuture<?>> futures = new ArrayList<>();
|
|
||||||
ConcurrentLinkedQueue<TextureAtlasSprite.Info> results = new ConcurrentLinkedQueue<>();
|
|
||||||
for(ResourceLocation location : imageLocations) {
|
|
||||||
if(MissingTextureAtlasSprite.getLocation().equals(location))
|
|
||||||
continue;
|
|
||||||
futures.add(CompletableFuture.runAsync(() -> {
|
|
||||||
try {
|
|
||||||
ResourceLocation fileLocation = this.getResourceLocation(location);
|
|
||||||
Resource resource = manager.getResource(fileLocation);
|
|
||||||
NativeImage image = NativeImage.read(resource.getInputStream());
|
|
||||||
AnimationMetadataSection animData = resource.getMetadata(AnimationMetadataSection.SERIALIZER);
|
|
||||||
if (animData == null) {
|
|
||||||
animData = AnimationMetadataSection.EMPTY;
|
|
||||||
}
|
|
||||||
Pair<Integer, Integer> dimensions = animData.getFrameSize(image.getWidth(), image.getHeight());
|
|
||||||
loadedImages.put(location, Pair.of(resource, image));
|
|
||||||
results.add(new TextureAtlasSprite.Info(location, dimensions.getFirst(), dimensions.getSecond(), animData));
|
|
||||||
} catch(IOException e) {
|
|
||||||
ModernFix.LOGGER.error("Using missing texture, unable to load {} : {}", location, e);
|
|
||||||
} catch(RuntimeException e) {
|
|
||||||
ModernFix.LOGGER.error("Unable to parse metadata from {} : {}", location, e);
|
|
||||||
}
|
|
||||||
}, ModernFix.resourceReloadExecutor()));
|
|
||||||
}
|
|
||||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
|
|
||||||
storedResults = results;
|
|
||||||
return Collections.emptyIterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "getBasicSpriteInfos", at = @At("RETURN"))
|
|
||||||
private void injectFastSprites(ResourceManager resourceManager, Set<ResourceLocation> spriteLocations, CallbackInfoReturnable<Collection<TextureAtlasSprite.Info>> cir) {
|
|
||||||
if(usingFasterLoad)
|
|
||||||
cir.getReturnValue().addAll(storedResults);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "prepareToStitch", at = @At("HEAD"))
|
|
||||||
private void initMap(CallbackInfoReturnable<TextureAtlas.Preparations> cir) {
|
|
||||||
loadedImages = new ConcurrentHashMap<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "prepareToStitch", at = @At("RETURN"))
|
|
||||||
private void clearLoadedImages(CallbackInfoReturnable<TextureAtlas.Preparations> cir) {
|
|
||||||
loadedImages = Collections.emptyMap();
|
|
||||||
storedResults = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "load(Lnet/minecraft/server/packs/resources/ResourceManager;Lnet/minecraft/client/renderer/texture/TextureAtlasSprite$Info;IIIII)Lnet/minecraft/client/renderer/texture/TextureAtlasSprite;",
|
|
||||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/texture/TextureAtlas;getResourceLocation(Lnet/minecraft/resources/ResourceLocation;)Lnet/minecraft/resources/ResourceLocation;"), cancellable = true)
|
|
||||||
private void loadFromExisting(ResourceManager resourceManager, TextureAtlasSprite.Info spriteInfo, int width, int height, int mipmapLevel, int originX, int originY, CallbackInfoReturnable<TextureAtlasSprite> cir) {
|
|
||||||
if(!usingFasterLoad)
|
|
||||||
return;
|
|
||||||
Pair<Resource, NativeImage> pair = loadedImages.get(spriteInfo.name());
|
|
||||||
if(pair == null) {
|
|
||||||
ModernFix.LOGGER.error("Texture {} was not loaded in early stage", spriteInfo.name());
|
|
||||||
cir.setReturnValue(null);
|
|
||||||
} else {
|
|
||||||
TextureAtlasSprite sprite = null;
|
|
||||||
try {
|
|
||||||
sprite = ModernFixPlatformHooks.INSTANCE.loadTextureAtlasSprite((TextureAtlas)(Object)this, resourceManager, spriteInfo, pair.getFirst(), width, height, originX, originY, mipmapLevel, pair.getSecond());
|
|
||||||
} catch(RuntimeException e) {
|
|
||||||
ModernFix.LOGGER.error("Error loading texture {}: {}", spriteInfo.name(), e);
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
pair.getFirst().close();
|
|
||||||
} catch(IOException ignored) {
|
|
||||||
// not much we can do
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cir.setReturnValue(sprite);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.fix_loop_spin_waiting;
|
|
||||||
|
|
||||||
import net.minecraft.util.thread.BlockableEventLoop;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Overwrite;
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.locks.LockSupport;
|
|
||||||
|
|
||||||
// This should fix https://bugs.mojang.com/browse/MC-183518
|
|
||||||
@Mixin(value = BlockableEventLoop.class, priority = 500)
|
|
||||||
public class BlockableEventLoopMixin {
|
|
||||||
private static final long MFIX$TICK_WAIT_TIME = TimeUnit.MILLISECONDS.toNanos(2);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author embeddedt
|
|
||||||
* @reason yielding the thread is pretty pointless if we're about to park anyway
|
|
||||||
*/
|
|
||||||
@Overwrite
|
|
||||||
protected void waitForTasks() {
|
|
||||||
LockSupport.parkNanos("waiting for tasks", MFIX$TICK_WAIT_TIME);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.mojang_registry_size;
|
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
|
||||||
import net.minecraft.resources.ResourceKey;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@Mixin(ResourceKey.class)
|
|
||||||
public class ResourceKeyMixin<T> {
|
|
||||||
private static final Map<ResourceLocation, Map<ResourceLocation, ResourceKey<?>>> INTERNING_MAP = new Object2ObjectOpenHashMap<>();
|
|
||||||
@Inject(method = "create(Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/resources/ResourceLocation;)Lnet/minecraft/resources/ResourceKey;", at = @At("HEAD"), cancellable = true)
|
|
||||||
private static <T> void createEfficient(ResourceLocation parent, ResourceLocation location, CallbackInfoReturnable<ResourceKey<T>> cir) {
|
|
||||||
synchronized (ResourceKey.class) {
|
|
||||||
Map<ResourceLocation, ResourceKey<?>> keys = INTERNING_MAP.computeIfAbsent(parent, k -> new Object2ObjectOpenHashMap<>());
|
|
||||||
ResourceKey<?> key = keys.get(location);
|
|
||||||
if(key == null) {
|
|
||||||
key = new ResourceKey<>(parent, location);
|
|
||||||
keys.put(location, key);
|
|
||||||
}
|
|
||||||
cir.setReturnValue((ResourceKey<T>)key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.nbt_memory_usage;
|
|
||||||
|
|
||||||
import net.minecraft.nbt.Tag;
|
|
||||||
import org.embeddedt.modernfix.util.CanonizingStringMap;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@Mixin(targets = "net/minecraft/nbt/CompoundTag$1")
|
|
||||||
public class CompoundTag1Mixin {
|
|
||||||
@ModifyVariable(method = "load(Ljava/io/DataInput;ILnet/minecraft/nbt/NbtAccounter;)Lnet/minecraft/nbt/CompoundTag;", at = @At(value = "INVOKE_ASSIGN", target = "Lcom/google/common/collect/Maps;newHashMap()Ljava/util/HashMap;", remap = false))
|
|
||||||
private Map<String, Tag> modifyMap(Map<String, Tag> map) {
|
|
||||||
CanonizingStringMap<Tag> newMap = new CanonizingStringMap<>();
|
|
||||||
if(map != null)
|
|
||||||
newMap.putAll(map);
|
|
||||||
return newMap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.nbt_memory_usage;
|
|
||||||
|
|
||||||
import net.minecraft.nbt.CompoundTag;
|
|
||||||
import net.minecraft.nbt.Tag;
|
|
||||||
import org.embeddedt.modernfix.util.CanonizingStringMap;
|
|
||||||
import org.spongepowered.asm.mixin.*;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@Mixin(CompoundTag.class)
|
|
||||||
public class CompoundTagMixin {
|
|
||||||
@Shadow @Final
|
|
||||||
private Map<String, Tag> tags;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensure that the default backing map is a CanonizingStringMap.
|
|
||||||
*/
|
|
||||||
@ModifyArg(method = "<init>()V", at = @At(value = "INVOKE", target = "Lnet/minecraft/nbt/CompoundTag;<init>(Ljava/util/Map;)V"), index = 0)
|
|
||||||
private static Map<String, Tag> useCanonizingStringMap(Map<String, Tag> incoming) {
|
|
||||||
CanonizingStringMap<Tag> newMap = new CanonizingStringMap<>();
|
|
||||||
if(incoming != null)
|
|
||||||
newMap.putAll(incoming);
|
|
||||||
return newMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author embeddedt
|
|
||||||
* @reason use more efficient method when copying canonizing string map
|
|
||||||
*/
|
|
||||||
@Inject(method = "copy()Lnet/minecraft/nbt/Tag;", at = @At("HEAD"), cancellable = true)
|
|
||||||
public void copyEfficient(CallbackInfoReturnable<Tag> cir) {
|
|
||||||
if(this.tags instanceof CanonizingStringMap) {
|
|
||||||
cir.setReturnValue(new CompoundTag(CanonizingStringMap.deepCopy((CanonizingStringMap<Tag>)this.tags, Tag::copy)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.nuke_empty_chunk_sections;
|
|
||||||
|
|
||||||
import net.minecraft.world.level.ChunkPos;
|
|
||||||
import net.minecraft.world.level.chunk.UpgradeData;
|
|
||||||
import net.minecraft.world.level.TickList;
|
|
||||||
import net.minecraft.world.level.Level;
|
|
||||||
import net.minecraft.world.level.chunk.ChunkBiomeContainer;
|
|
||||||
import net.minecraft.world.level.chunk.LevelChunk;
|
|
||||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
@Mixin(LevelChunk.class)
|
|
||||||
public class MixinChunk {
|
|
||||||
@Shadow @Final private LevelChunkSection[] sections;
|
|
||||||
|
|
||||||
@Inject(method = "<init>(Lnet/minecraft/world/level/Level;Lnet/minecraft/world/level/ChunkPos;Lnet/minecraft/world/level/chunk/ChunkBiomeContainer;Lnet/minecraft/world/level/chunk/UpgradeData;Lnet/minecraft/world/level/TickList;Lnet/minecraft/world/level/TickList;J[Lnet/minecraft/world/level/chunk/LevelChunkSection;Ljava/util/function/Consumer;)V",
|
|
||||||
at = @At("RETURN"))
|
|
||||||
private void reinit(Level world, ChunkPos pos, ChunkBiomeContainer container, UpgradeData data,
|
|
||||||
TickList list1, TickList list2, long inhabited,
|
|
||||||
LevelChunkSection[] oldSections, Consumer consumer, CallbackInfo ci) {
|
|
||||||
/* taken from Hydrogen */
|
|
||||||
for(int i = 0; i < this.sections.length; i++) {
|
|
||||||
if(LevelChunkSection.isEmpty(this.sections[i])) {
|
|
||||||
this.sections[i] = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,61 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.reduce_blockstate_cache_rebuilds;
|
|
||||||
|
|
||||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
|
||||||
import org.embeddedt.modernfix.duck.IBlockState;
|
|
||||||
import org.objectweb.asm.Opcodes;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
|
||||||
|
|
||||||
|
|
||||||
@Mixin(BlockBehaviour.BlockStateBase.class)
|
|
||||||
public abstract class BlockStateBaseMixin implements IBlockState {
|
|
||||||
@Shadow public abstract void initCache();
|
|
||||||
|
|
||||||
@Shadow private BlockBehaviour.BlockStateBase.Cache cache;
|
|
||||||
|
|
||||||
private volatile boolean cacheInvalid = false;
|
|
||||||
private static boolean buildingCache = false;
|
|
||||||
@Override
|
|
||||||
public void clearCache() {
|
|
||||||
cacheInvalid = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isCacheInvalid() {
|
|
||||||
return cacheInvalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void mfix$generateCache() {
|
|
||||||
if(cacheInvalid) {
|
|
||||||
// Ensure that only one block's cache is built at a time
|
|
||||||
synchronized (BlockBehaviour.BlockStateBase.class) {
|
|
||||||
if(cacheInvalid) {
|
|
||||||
// Ensure that if we end up in here recursively, we just use the original cache
|
|
||||||
if(!buildingCache) {
|
|
||||||
buildingCache = true;
|
|
||||||
try {
|
|
||||||
this.initCache();
|
|
||||||
cacheInvalid = false;
|
|
||||||
} finally {
|
|
||||||
buildingCache = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Redirect(method = "*", at = @At(
|
|
||||||
value = "FIELD",
|
|
||||||
opcode = Opcodes.GETFIELD,
|
|
||||||
target = "Lnet/minecraft/world/level/block/state/BlockBehaviour$BlockStateBase;cache:Lnet/minecraft/world/level/block/state/BlockBehaviour$BlockStateBase$Cache;",
|
|
||||||
ordinal = 0
|
|
||||||
))
|
|
||||||
private BlockBehaviour.BlockStateBase.Cache dynamicCacheGen(BlockBehaviour.BlockStateBase base) {
|
|
||||||
mfix$generateCache();
|
|
||||||
return this.cache;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.reduce_blockstate_cache_rebuilds;
|
|
||||||
|
|
||||||
import net.minecraft.world.level.block.Blocks;
|
|
||||||
import org.embeddedt.modernfix.blockstate.BlockStateCacheHandler;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
@Mixin(value = Blocks.class, priority = 1100)
|
|
||||||
public class BlocksMixin {
|
|
||||||
@ModifyArg(method = "rebuildCache", at = @At(value = "INVOKE", target = "Lnet/minecraft/core/IdMapper;forEach(Ljava/util/function/Consumer;)V"), index = 0)
|
|
||||||
private static Consumer getEmptyConsumer(Consumer original) {
|
|
||||||
BlockStateCacheHandler.rebuildParallel(true);
|
|
||||||
return o -> {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.remove_spawn_chunks;
|
|
||||||
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
import net.minecraft.server.level.ServerChunkCache;
|
|
||||||
import net.minecraft.server.level.TicketType;
|
|
||||||
import net.minecraft.world.level.ChunkPos;
|
|
||||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
|
||||||
|
|
||||||
@Mixin(value = MinecraftServer.class, priority = 1100)
|
|
||||||
public class MinecraftServerMixin {
|
|
||||||
@Redirect(method = "prepareLevels", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerChunkCache;addRegionTicket(Lnet/minecraft/server/level/TicketType;Lnet/minecraft/world/level/ChunkPos;ILjava/lang/Object;)V"))
|
|
||||||
private void addSpawnChunkTicket(ServerChunkCache cache, TicketType<?> type, ChunkPos pos, int distance, Object o) {
|
|
||||||
// load first chunk
|
|
||||||
cache.getChunk(pos.x, pos.z, ChunkStatus.FULL, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Redirect(method = "prepareLevels", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerChunkCache;getTickingGenerated()I"), require = 0)
|
|
||||||
private int getGenerated(ServerChunkCache cache) {
|
|
||||||
return 441;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.remove_spawn_chunks;
|
|
||||||
|
|
||||||
import net.minecraft.server.level.DistanceManager;
|
|
||||||
import net.minecraft.server.level.ServerChunkCache;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
|
||||||
|
|
||||||
@Mixin(ServerChunkCache.class)
|
|
||||||
public interface ServerChunkCacheAccessor {
|
|
||||||
@Accessor("distanceManager")
|
|
||||||
DistanceManager getDistanceManager();
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.resourcepacks;
|
|
||||||
|
|
||||||
import net.minecraft.server.packs.resources.SimpleReloadableResourceManager;
|
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
|
||||||
import org.embeddedt.modernfix.resources.PackResourcesCacheEngine;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|
||||||
|
|
||||||
@Mixin(SimpleReloadableResourceManager.class)
|
|
||||||
public class ReloadableResourceManagerMixin {
|
|
||||||
@Inject(method = "createReload", at = @At("HEAD"))
|
|
||||||
private void invalidateResourceCaches(CallbackInfoReturnable<?> cir) {
|
|
||||||
ModernFix.LOGGER.info("Invalidating pack caches");
|
|
||||||
PackResourcesCacheEngine.invalidate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,83 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.reuse_datapacks;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.commands.Commands;
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
import net.minecraft.server.ServerResources;
|
|
||||||
import net.minecraft.server.packs.PackResources;
|
|
||||||
import net.minecraft.server.packs.repository.Pack;
|
|
||||||
import net.minecraft.server.packs.repository.PackRepository;
|
|
||||||
import net.minecraft.world.level.DataPackConfig;
|
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.embeddedt.modernfix.duck.reuse_datapacks.ICachingResourceClient;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
|
|
||||||
@Mixin(Minecraft.class)
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public abstract class MinecraftMixin implements ICachingResourceClient {
|
|
||||||
@Shadow public abstract boolean isLocalServer();
|
|
||||||
|
|
||||||
private ServerResources cachedResources;
|
|
||||||
private List<String> cachedDataPackConfig;
|
|
||||||
|
|
||||||
private List<String> loadingDataPackConfig;
|
|
||||||
|
|
||||||
@Redirect(method = "makeServerStem", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;configurePackRepository(Lnet/minecraft/server/packs/repository/PackRepository;Lnet/minecraft/world/level/DataPackConfig;Z)Lnet/minecraft/world/level/DataPackConfig;"))
|
|
||||||
private DataPackConfig saveLoadingConfig(PackRepository repo, DataPackConfig inCodec, boolean vanillaOnly) {
|
|
||||||
DataPackConfig config = MinecraftServer.configurePackRepository(repo, inCodec, vanillaOnly);
|
|
||||||
loadingDataPackConfig = repo.getSelectedPacks().stream().map(Pack::getId).collect(ImmutableList.toImmutableList());
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Redirect(method = "makeServerStem", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/ServerResources;loadResources(Ljava/util/List;Lnet/minecraft/commands/Commands$CommandSelection;ILjava/util/concurrent/Executor;Ljava/util/concurrent/Executor;)Ljava/util/concurrent/CompletableFuture;"))
|
|
||||||
private CompletableFuture<ServerResources> useCachedResources(List<PackResources> list, Commands.CommandSelection arg, int i, Executor executor, Executor executor2) {
|
|
||||||
if(cachedResources != null) {
|
|
||||||
if(cachedResources.getResourceManager().getNamespaces().size() > 0) {
|
|
||||||
if (cachedDataPackConfig.equals(loadingDataPackConfig)) {
|
|
||||||
ModernFix.LOGGER.warn("Reusing loaded server resources from previous world");
|
|
||||||
return CompletableFuture.completedFuture(cachedResources);
|
|
||||||
} else {
|
|
||||||
ModernFix.LOGGER.warn("Discarding cached server resources, datapack configs have changed");
|
|
||||||
ModernFix.LOGGER.warn("Old: {}", "[" + String.join(", ", cachedDataPackConfig) + "]");
|
|
||||||
ModernFix.LOGGER.warn("New: {}", "[" + String.join(", ", loadingDataPackConfig) + "]");
|
|
||||||
cachedResources.close();
|
|
||||||
cachedResources = null;
|
|
||||||
cachedDataPackConfig = null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ModernFix.LOGGER.error("Cached server resources were closed somehow, that shouldn't happen");
|
|
||||||
cachedResources = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ServerResources.loadResources(list, arg, i, executor, executor2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setCachedResources(ServerResources r) {
|
|
||||||
cachedResources = r;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setCachedDataPackConfig(Collection<String> c) {
|
|
||||||
cachedDataPackConfig = ImmutableList.copyOf(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "setLevel", at = @At("HEAD"))
|
|
||||||
private void clearResourcesIfNotLocal(CallbackInfo ci) {
|
|
||||||
if(!this.isLocalServer())
|
|
||||||
cachedResources = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.reuse_datapacks;
|
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
import net.minecraft.server.ServerResources;
|
|
||||||
import net.minecraft.server.packs.repository.Pack;
|
|
||||||
import net.minecraft.server.packs.repository.PackRepository;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.embeddedt.modernfix.duck.reuse_datapacks.ICachingResourceClient;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
|
||||||
|
|
||||||
@Mixin(MinecraftServer.class)
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public class MinecraftServerMixin {
|
|
||||||
|
|
||||||
@Shadow @Final private PackRepository packRepository;
|
|
||||||
|
|
||||||
@Redirect(method = "stopServer", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/ServerResources;close()V"))
|
|
||||||
private void saveResources(ServerResources resources) {
|
|
||||||
ICachingResourceClient client = ((ICachingResourceClient) Minecraft.getInstance());
|
|
||||||
client.setCachedDataPackConfig(this.packRepository.getSelectedPacks().stream().map(Pack::getId).collect(ImmutableList.toImmutableList()));
|
|
||||||
client.setCachedResources(resources);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.perf.thread_priorities;
|
|
||||||
|
|
||||||
import com.mojang.authlib.GameProfileRepository;
|
|
||||||
import com.mojang.authlib.minecraft.MinecraftSessionService;
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.server.ServerResources;
|
|
||||||
import net.minecraft.server.packs.repository.PackRepository;
|
|
||||||
import net.minecraft.client.server.IntegratedServer;
|
|
||||||
import net.minecraft.server.players.GameProfileCache;
|
|
||||||
import net.minecraft.core.RegistryAccess;
|
|
||||||
import net.minecraft.server.level.progress.ChunkProgressListenerFactory;
|
|
||||||
import net.minecraft.world.level.storage.WorldData;
|
|
||||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
@Mixin(IntegratedServer.class)
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public class IntegratedServerMixin {
|
|
||||||
@Inject(method = "<init>", at = @At("RETURN"))
|
|
||||||
private void adjustServerPriority(Thread pServerThread, Minecraft pMinecraft, RegistryAccess.RegistryHolder pRegistryHolder, LevelStorageSource.LevelStorageAccess pStorageSource, PackRepository pPackRepository, ServerResources pResources, WorldData pWorldData, MinecraftSessionService pSessionService, GameProfileRepository pProfileRepository, GameProfileCache pProfileCache, ChunkProgressListenerFactory pProgressListenerfactory, CallbackInfo ci) {
|
|
||||||
int pri = 4; //ModernFixConfig.INTEGRATED_SERVER_PRIORITY.get();
|
|
||||||
pServerThread.setPriority(pri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
package org.embeddedt.modernfix.common.mixin.safety;
|
|
||||||
|
|
||||||
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
|
|
||||||
import net.minecraft.client.renderer.entity.layers.RenderLayer;
|
|
||||||
import org.embeddedt.modernfix.annotation.ClientOnlyMixin;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Mutable;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Mixin(LivingEntityRenderer.class)
|
|
||||||
@ClientOnlyMixin
|
|
||||||
public class LivingEntityRendererMixin {
|
|
||||||
@Shadow @Final @Mutable
|
|
||||||
protected List<RenderLayer<?, ?>> layers;
|
|
||||||
|
|
||||||
@Inject(method = "<init>", at = @At("RETURN"))
|
|
||||||
private void synchronizeLayerList(CallbackInfo ci) {
|
|
||||||
/* allows buggy mods to call addLayer concurrently, order is not deterministic but can't fix that */
|
|
||||||
this.layers = Collections.synchronizedList(layers);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
package org.embeddedt.modernfix.dedup;
|
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.Hash;
|
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public class DeduplicationCache<T> {
|
|
||||||
private final ObjectOpenCustomHashSet<T> pool;
|
|
||||||
|
|
||||||
private int attemptedInsertions = 0;
|
|
||||||
private int deduplicated = 0;
|
|
||||||
|
|
||||||
public DeduplicationCache(Hash.Strategy<T> strategy) {
|
|
||||||
this.pool = new ObjectOpenCustomHashSet<>(strategy);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DeduplicationCache() {
|
|
||||||
this.pool = new ObjectOpenCustomHashSet<>(new Hash.Strategy<T>() {
|
|
||||||
@Override
|
|
||||||
public int hashCode(T o) {
|
|
||||||
return Objects.hashCode(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(T a, T b) {
|
|
||||||
return Objects.equals(a, b);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized T deduplicate(T item) {
|
|
||||||
this.attemptedInsertions++;
|
|
||||||
|
|
||||||
T result = this.pool.addOrGet(item);
|
|
||||||
|
|
||||||
if (result != item) {
|
|
||||||
this.deduplicated++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void clearCache() {
|
|
||||||
this.attemptedInsertions = 0;
|
|
||||||
this.deduplicated = 0;
|
|
||||||
|
|
||||||
this.pool.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public synchronized String toString() {
|
|
||||||
return String.format("DeduplicationCache ( %d/%d de-duplicated, %d pooled )",
|
|
||||||
this.deduplicated, this.attemptedInsertions, this.pool.size());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
package org.embeddedt.modernfix.dedup;
|
|
||||||
|
|
||||||
|
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
|
||||||
|
|
||||||
public class IdentifierCaches {
|
|
||||||
public static final DeduplicationCache<String> NAMESPACES = new DeduplicationCache<>();
|
|
||||||
public static final DeduplicationCache<String> PATH = new DeduplicationCache<>();
|
|
||||||
public static final DeduplicationCache<String> PROPERTY = new DeduplicationCache<>();
|
|
||||||
|
|
||||||
public static void printDebug() {
|
|
||||||
ModernFix.LOGGER.info("[[[ Identifier de-duplication statistics ]]]");
|
|
||||||
ModernFix.LOGGER.info("Namespace cache: {}", NAMESPACES);
|
|
||||||
ModernFix.LOGGER.info("Path cache: {}", PATH);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
package org.embeddedt.modernfix.dfu;
|
|
||||||
|
|
||||||
import com.google.common.cache.Cache;
|
|
||||||
import com.google.common.cache.CacheBuilder;
|
|
||||||
import com.mojang.datafixers.RewriteResult;
|
|
||||||
import com.mojang.datafixers.TypeRewriteRule;
|
|
||||||
import com.mojang.datafixers.functions.PointFreeRule;
|
|
||||||
import com.mojang.datafixers.types.Type;
|
|
||||||
import com.mojang.datafixers.util.Pair;
|
|
||||||
import org.apache.commons.lang3.tuple.Triple;
|
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
|
||||||
import sun.misc.Unsafe;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.function.IntFunction;
|
|
||||||
|
|
||||||
public class DFUBlaster {
|
|
||||||
private static final Cache<Pair<IntFunction<RewriteResult<?, ?>>, Integer>, RewriteResult<?, ?>> hmapApplyCache = CacheBuilder.newBuilder()
|
|
||||||
.expireAfterAccess(3, TimeUnit.MINUTES)
|
|
||||||
.build();
|
|
||||||
private static final Cache<Triple<Type<?>, TypeRewriteRule, PointFreeRule>, Optional<? extends RewriteResult<?, ?>>> rewriteCache = CacheBuilder.newBuilder()
|
|
||||||
.expireAfterAccess(3, TimeUnit.MINUTES)
|
|
||||||
.build();
|
|
||||||
public static void blastMaps() {
|
|
||||||
try {
|
|
||||||
Class<?> FOLD_CLASS = Class.forName("com.mojang.datafixers.functions.Fold");
|
|
||||||
Field hmapField = FOLD_CLASS.getDeclaredField("HMAP_APPLY_CACHE");
|
|
||||||
hmapField.setAccessible(true);
|
|
||||||
final Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
|
|
||||||
theUnsafe.setAccessible(true);
|
|
||||||
Unsafe unsafe = (Unsafe)theUnsafe.get(null);
|
|
||||||
Object base = unsafe.staticFieldBase(hmapField);
|
|
||||||
long offset = unsafe.staticFieldOffset(hmapField);
|
|
||||||
unsafe.putObject(base, offset, hmapApplyCache.asMap());
|
|
||||||
Field rewriteCacheField = Type.class.getDeclaredField("REWRITE_CACHE");
|
|
||||||
rewriteCacheField.setAccessible(true);
|
|
||||||
base = unsafe.staticFieldBase(rewriteCacheField);
|
|
||||||
offset = unsafe.staticFieldOffset(rewriteCacheField);
|
|
||||||
unsafe.putObject(base, offset, rewriteCache.asMap());
|
|
||||||
new CleanerThread().start();
|
|
||||||
} catch(Throwable e) {
|
|
||||||
ModernFix.LOGGER.error("Could not replace DFU map", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class CleanerThread extends Thread {
|
|
||||||
CleanerThread() {
|
|
||||||
this.setName("DFU cleaning thread");
|
|
||||||
this.setPriority(1);
|
|
||||||
this.setDaemon(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
while(true) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(15000);
|
|
||||||
} catch(InterruptedException e){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
rewriteCache.cleanUp();
|
|
||||||
hmapApplyCache.cleanUp();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
package org.embeddedt.modernfix.duck;
|
|
||||||
|
|
||||||
import dev.latvian.kubejs.item.ItemStackJS;
|
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public interface ICachedIngredientJS {
|
|
||||||
/**
|
|
||||||
* Returns a cached list of item stacks for the given ingredient. The user must not attempt to modify any contents
|
|
||||||
* of these stacks.
|
|
||||||
* @return cached set of stacks
|
|
||||||
*/
|
|
||||||
Set<ItemStackJS> getCachedStacks();
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
package org.embeddedt.modernfix.duck;
|
|
||||||
|
|
||||||
public interface ICachedMaterialsModel {
|
|
||||||
public void clearMaterialsCache();
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
package org.embeddedt.modernfix.duck;
|
|
||||||
|
|
||||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
|
||||||
|
|
||||||
public interface ILevelSave {
|
|
||||||
public void runWorldPersistenceHooks(LevelStorageSource format);
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
package org.embeddedt.modernfix.duck;
|
|
||||||
|
|
||||||
public interface IPaperChunkHolder {
|
|
||||||
boolean mfix$canAdvanceStatus();
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
package org.embeddedt.modernfix.duck;
|
|
||||||
|
|
||||||
import org.embeddedt.modernfix.chunk.SafeBlockGetter;
|
|
||||||
|
|
||||||
public interface ISafeBlockGetter {
|
|
||||||
SafeBlockGetter mfix$getSafeBlockGetter();
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
package org.embeddedt.modernfix.duck;
|
|
||||||
|
|
||||||
import org.embeddedt.modernfix.world.StrongholdLocationCache;
|
|
||||||
|
|
||||||
public interface IServerLevel {
|
|
||||||
StrongholdLocationCache mfix$getStrongholdCache();
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
package org.embeddedt.modernfix.duck.reuse_datapacks;
|
|
||||||
|
|
||||||
import net.minecraft.server.ServerResources;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
public interface ICachingResourceClient {
|
|
||||||
void setCachedResources(ServerResources r);
|
|
||||||
void setCachedDataPackConfig(Collection<String> c);
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
package org.embeddedt.modernfix.dynamicresources;
|
|
||||||
|
|
||||||
public class DynamicSoundHelpers {
|
|
||||||
/**
|
|
||||||
* The duration until a sound is eligible for eviction if unused.
|
|
||||||
*/
|
|
||||||
public static final int MAX_SOUND_LIFETIME_SECS = 300;
|
|
||||||
}
|
|
||||||
|
|
@ -1,411 +0,0 @@
|
||||||
package org.embeddedt.modernfix.dynamicresources;
|
|
||||||
|
|
||||||
import com.google.common.base.Splitter;
|
|
||||||
import com.google.common.base.Stopwatch;
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.google.common.collect.Sets;
|
|
||||||
import com.google.gson.*;
|
|
||||||
import com.google.gson.stream.JsonReader;
|
|
||||||
import com.mojang.datafixers.util.Pair;
|
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
|
||||||
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
|
|
||||||
import it.unimi.dsi.fastutil.objects.ReferenceSet;
|
|
||||||
import net.minecraft.client.renderer.block.model.BlockModel;
|
|
||||||
import net.minecraft.client.resources.model.*;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.server.packs.PackResources;
|
|
||||||
import net.minecraft.server.packs.PackType;
|
|
||||||
import net.minecraft.server.packs.resources.FallbackResourceManager;
|
|
||||||
import net.minecraft.server.packs.resources.Resource;
|
|
||||||
import net.minecraft.server.packs.resources.ResourceManager;
|
|
||||||
import net.minecraft.server.packs.resources.SimpleReloadableResourceManager;
|
|
||||||
import net.minecraft.world.level.block.Block;
|
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
|
||||||
import net.minecraft.world.level.block.state.StateDefinition;
|
|
||||||
import net.minecraft.world.level.block.state.properties.Property;
|
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
|
||||||
import org.embeddedt.modernfix.api.entrypoint.ModernFixClientIntegration;
|
|
||||||
import org.embeddedt.modernfix.platform.ModernFixPlatformHooks;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
|
||||||
import java.util.function.BiFunction;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import static net.minecraft.client.resources.model.ModelBakery.BLOCK_ENTITY_MARKER;
|
|
||||||
import static net.minecraft.client.resources.model.ModelBakery.GENERATION_MARKER;
|
|
||||||
|
|
||||||
public class ModelBakeryHelpers {
|
|
||||||
/**
|
|
||||||
* The maximum number of baked models kept in memory at once.
|
|
||||||
*/
|
|
||||||
public static final int MAX_BAKED_MODEL_COUNT = 10000;
|
|
||||||
/**
|
|
||||||
* The maximum number of unbaked models kept in memory at once.
|
|
||||||
*/
|
|
||||||
public static final int MAX_UNBAKED_MODEL_COUNT = 10000;
|
|
||||||
/**
|
|
||||||
* The time in seconds after which a model becomes eligible for eviction if not used.
|
|
||||||
*/
|
|
||||||
public static final int MAX_MODEL_LIFETIME_SECS = 300;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* These folders will have all textures stitched onto the atlas when dynamic resources is enabled.
|
|
||||||
*/
|
|
||||||
public static String[] getExtraTextureFolders() {
|
|
||||||
return new String[] {
|
|
||||||
"attachment",
|
|
||||||
"bettergrass",
|
|
||||||
"block",
|
|
||||||
"blocks",
|
|
||||||
"cape",
|
|
||||||
"entity/bed",
|
|
||||||
"entity/chest",
|
|
||||||
"item",
|
|
||||||
"items",
|
|
||||||
"model",
|
|
||||||
"models",
|
|
||||||
"part",
|
|
||||||
"pipe",
|
|
||||||
"ropebridge",
|
|
||||||
"runes",
|
|
||||||
"solid_block",
|
|
||||||
"spell_effect",
|
|
||||||
"spell_projectile"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static JsonElement parseStream(InputStream stream) {
|
|
||||||
JsonParser parser = new JsonParser();
|
|
||||||
JsonReader jsonReader = new JsonReader(new InputStreamReader(stream, StandardCharsets.UTF_8));
|
|
||||||
jsonReader.setLenient(true);
|
|
||||||
return parser.parse(jsonReader);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void gatherAdditionalViaManualScan(List<PackResources> untrustedPacks, Set<ResourceLocation> knownLocations,
|
|
||||||
Collection<ResourceLocation> uncertainLocations, String filePrefix) {
|
|
||||||
if(untrustedPacks.size() > 0) {
|
|
||||||
/* Now make a fallback resource manager and use it on the remaining packs to see if they actually contain these files */
|
|
||||||
FallbackResourceManager frm = new FallbackResourceManager(PackType.CLIENT_RESOURCES, "dummy");
|
|
||||||
for (int i = untrustedPacks.size() - 1; i >= 0; i--) {
|
|
||||||
frm.add(untrustedPacks.get(i));
|
|
||||||
}
|
|
||||||
for (ResourceLocation blockstate : uncertainLocations) {
|
|
||||||
if (knownLocations.contains(blockstate))
|
|
||||||
continue; // don't check ones we know exist
|
|
||||||
ResourceLocation fileLocation = new ResourceLocation(blockstate.getNamespace(), filePrefix + blockstate.getPath() + ".json");
|
|
||||||
try (Resource resource = frm.getResource(fileLocation)) {
|
|
||||||
knownLocations.add(blockstate);
|
|
||||||
} catch (IOException | RuntimeException ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final int ERROR_THRESHOLD = 200;
|
|
||||||
|
|
||||||
private static void logOrSuppressError(Object2IntOpenHashMap<String> suppressionMap, String type, ResourceLocation location, Throwable e) {
|
|
||||||
int numErrors;
|
|
||||||
synchronized (suppressionMap) {
|
|
||||||
numErrors = suppressionMap.computeInt(location.getNamespace(), (k, oldVal) -> (oldVal == null ? 1 : oldVal + 1));
|
|
||||||
}
|
|
||||||
if(numErrors <= ERROR_THRESHOLD)
|
|
||||||
ModernFix.LOGGER.error("Error reading {} {}: {}", type, location, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Some mods (cough, EBE) inject their custom resource pack into the namespaced resource managers, but not into the
|
|
||||||
* main list contained inside the parent resource manager, so we need to scan each of the namespaced managers as
|
|
||||||
* well.
|
|
||||||
*/
|
|
||||||
private static void checkFallbacks(SimpleReloadableResourceManager manager, List<PackResources> resourcePackList) {
|
|
||||||
ReferenceSet<PackResources> knownPacks = new ReferenceOpenHashSet<>(resourcePackList);
|
|
||||||
Map<String, FallbackResourceManager> namespacedMap = manager.namespacedPacks;
|
|
||||||
namespacedMap.values().stream().flatMap(FallbackResourceManager::listPacks).forEach(pack -> {
|
|
||||||
if(knownPacks.add(pack)) {
|
|
||||||
/* the pack was not previously known, add to our list */
|
|
||||||
ModernFix.LOGGER.debug("Injecting unlisted pack '{}': {}", pack.getName(), pack.getClass().getName());
|
|
||||||
resourcePackList.add(pack);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void gatherModelMaterials(ResourceManager manager, Predicate<PackResources> isTrustedPack,
|
|
||||||
Set<Material> materialSet, Set<ResourceLocation> blockStateFiles,
|
|
||||||
Set<ResourceLocation> modelFiles, UnbakedModel missingModel,
|
|
||||||
Function<JsonElement, BlockModel> modelDeserializer,
|
|
||||||
Function<ResourceLocation, UnbakedModel> bakeryModelGetter) {
|
|
||||||
if(!ModernFixPlatformHooks.INSTANCE.isLoadingNormally())
|
|
||||||
return;
|
|
||||||
Stopwatch stopwatch = Stopwatch.createStarted();
|
|
||||||
final Object2IntOpenHashMap<String> blockstateErrors = new Object2IntOpenHashMap<>();
|
|
||||||
/*
|
|
||||||
* First, gather all vanilla packs, and use listResources on them. This will allow us to (hopefully) avoid
|
|
||||||
* scanning most packs a lot.
|
|
||||||
*/
|
|
||||||
List<PackResources> allPackResources = new ArrayList<>(manager.listPacks().collect(Collectors.toList()));
|
|
||||||
if(manager instanceof SimpleReloadableResourceManager) {
|
|
||||||
checkFallbacks((SimpleReloadableResourceManager)manager, allPackResources);
|
|
||||||
}
|
|
||||||
Collections.reverse(allPackResources);
|
|
||||||
ObjectOpenHashSet<ResourceLocation> allAvailableModels = new ObjectOpenHashSet<>(), allAvailableStates = new ObjectOpenHashSet<>();
|
|
||||||
/* try to fix CME in some runtime packs by forcing generation */
|
|
||||||
for(PackResources pack : allPackResources) {
|
|
||||||
try(InputStream stream = pack.getResource(PackType.CLIENT_RESOURCES, new ResourceLocation("modernfix", "dummy.json"))) {
|
|
||||||
} catch(Exception ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
allPackResources.removeIf(pack -> {
|
|
||||||
for(String namespace : pack.getNamespaces(PackType.CLIENT_RESOURCES)) {
|
|
||||||
Collection<ResourceLocation> allBlockstates = pack.getResources(PackType.CLIENT_RESOURCES, namespace, "blockstates", Integer.MAX_VALUE, p -> p.endsWith(".json"));
|
|
||||||
for(ResourceLocation blockstate : allBlockstates) {
|
|
||||||
allAvailableStates.add(new ResourceLocation(blockstate.getNamespace(), blockstate.getPath().replaceFirst("blockstates/", "").replace(".json", "")));
|
|
||||||
}
|
|
||||||
Collection<ResourceLocation> allModels = pack.getResources(PackType.CLIENT_RESOURCES, namespace, "models", Integer.MAX_VALUE, p -> p.endsWith(".json"));
|
|
||||||
for(ResourceLocation blockstate : allModels) {
|
|
||||||
allAvailableModels.add(new ResourceLocation(blockstate.getNamespace(), blockstate.getPath().replaceFirst("models/", "").replace(".json", "")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!isTrustedPack.test(pack)) {
|
|
||||||
ModernFix.LOGGER.debug("Pack with class {} needs manual scan", pack.getClass().getName());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
gatherAdditionalViaManualScan(allPackResources, allAvailableStates, blockStateFiles, "blockstates/");
|
|
||||||
// We now have a list of all blockstates known to exist. Delete anything that we don't have
|
|
||||||
blockStateFiles.retainAll(allAvailableStates);
|
|
||||||
allAvailableStates.clear();
|
|
||||||
allAvailableStates.trim();
|
|
||||||
|
|
||||||
ConcurrentLinkedQueue<Pair<ResourceLocation, JsonElement>> blockStateLoadedFiles = new ConcurrentLinkedQueue<>();
|
|
||||||
List<CompletableFuture<Void>> blockStateData = new ArrayList<>();
|
|
||||||
for(ResourceLocation blockstate : blockStateFiles) {
|
|
||||||
ResourceLocation fileLocation = new ResourceLocation(blockstate.getNamespace(), "blockstates/" + blockstate.getPath() + ".json");
|
|
||||||
List<Resource> resources;
|
|
||||||
try {
|
|
||||||
resources = manager.getResources(fileLocation);
|
|
||||||
if(resources.isEmpty())
|
|
||||||
continue;
|
|
||||||
} catch(IOException e) {
|
|
||||||
logOrSuppressError(blockstateErrors, "blockstate", blockstate, e);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
blockStateData.add(CompletableFuture.runAsync(() -> {
|
|
||||||
try {
|
|
||||||
for(Resource resource : resources) {
|
|
||||||
try {
|
|
||||||
blockStateLoadedFiles.add(Pair.of(blockstate, parseStream(resource.getInputStream())));
|
|
||||||
} catch(JsonParseException e) {
|
|
||||||
logOrSuppressError(blockstateErrors, "blockstate", blockstate, e);
|
|
||||||
} finally {
|
|
||||||
resource.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch(IOException e) {
|
|
||||||
logOrSuppressError(blockstateErrors, "blockstate", blockstate, e);
|
|
||||||
}
|
|
||||||
}, ModernFix.resourceReloadExecutor()));
|
|
||||||
}
|
|
||||||
blockStateFiles = null;
|
|
||||||
CompletableFuture.allOf(blockStateData.toArray(new CompletableFuture[0])).join();
|
|
||||||
for(Pair<ResourceLocation, JsonElement> pair : blockStateLoadedFiles) {
|
|
||||||
if(pair.getSecond() != null) {
|
|
||||||
try {
|
|
||||||
JsonObject obj = pair.getSecond().getAsJsonObject();
|
|
||||||
if(obj.has("variants")) {
|
|
||||||
JsonObject eachVariant = obj.getAsJsonObject("variants");
|
|
||||||
for(Map.Entry<String, JsonElement> entry : eachVariant.entrySet()) {
|
|
||||||
JsonElement variantData = entry.getValue();
|
|
||||||
List<JsonObject> variantModels;
|
|
||||||
if(variantData.isJsonArray()) {
|
|
||||||
variantModels = new ArrayList<>();
|
|
||||||
for(JsonElement model : variantData.getAsJsonArray()) {
|
|
||||||
variantModels.add(model.getAsJsonObject());
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
variantModels = Collections.singletonList(variantData.getAsJsonObject());
|
|
||||||
for(JsonObject variant : variantModels) {
|
|
||||||
modelFiles.add(new ResourceLocation(variant.get("model").getAsString()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
JsonArray multipartData = obj.get("multipart").getAsJsonArray();
|
|
||||||
for(JsonElement element : multipartData) {
|
|
||||||
JsonObject self = element.getAsJsonObject();
|
|
||||||
JsonElement apply = self.get("apply");
|
|
||||||
List<JsonObject> applyObjects;
|
|
||||||
if(apply.isJsonArray()) {
|
|
||||||
applyObjects = new ArrayList<>();
|
|
||||||
for(JsonElement e : apply.getAsJsonArray()) {
|
|
||||||
applyObjects.add(e.getAsJsonObject());
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
applyObjects = Collections.singletonList(apply.getAsJsonObject());
|
|
||||||
for(JsonObject applyEntry : applyObjects) {
|
|
||||||
modelFiles.add(new ResourceLocation(applyEntry.get("model").getAsString()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
} catch(RuntimeException e) {
|
|
||||||
logOrSuppressError(blockstateErrors, "blockstate", pair.getFirst(), e);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
blockstateErrors.object2IntEntrySet().forEach(entry -> {
|
|
||||||
if(entry.getIntValue() > ERROR_THRESHOLD) {
|
|
||||||
ModernFix.LOGGER.error("Suppressed additional {} blockstate errors for domain {}", entry.getIntValue(), entry.getKey());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
blockstateErrors.clear();
|
|
||||||
blockStateData = null;
|
|
||||||
blockStateLoadedFiles.clear();
|
|
||||||
|
|
||||||
modelFiles.addAll(allAvailableModels);
|
|
||||||
/* figure out which models we should actually load */
|
|
||||||
gatherAdditionalViaManualScan(allPackResources, allAvailableModels, modelFiles, "models/");
|
|
||||||
modelFiles.retainAll(allAvailableModels);
|
|
||||||
allAvailableModels.clear();
|
|
||||||
allAvailableModels.trim();
|
|
||||||
|
|
||||||
Map<ResourceLocation, BlockModel> basicModels = new HashMap<>();
|
|
||||||
basicModels.put(ModelBakery.MISSING_MODEL_LOCATION, (BlockModel)missingModel);
|
|
||||||
basicModels.put(new ResourceLocation("builtin/generated"), GENERATION_MARKER);
|
|
||||||
basicModels.put(new ResourceLocation("builtin/entity"), BLOCK_ENTITY_MARKER);
|
|
||||||
Set<Pair<String, String>> errorSet = Sets.newLinkedHashSet();
|
|
||||||
while(modelFiles.size() > 0) {
|
|
||||||
List<CompletableFuture<Pair<ResourceLocation, JsonElement>>> modelBytes = new ArrayList<>();
|
|
||||||
for(ResourceLocation model : modelFiles) {
|
|
||||||
if(basicModels.containsKey(model))
|
|
||||||
continue;
|
|
||||||
ResourceLocation fileLocation = new ResourceLocation(model.getNamespace(), "models/" + model.getPath() + ".json");
|
|
||||||
modelBytes.add(CompletableFuture.supplyAsync(() -> {
|
|
||||||
try(Resource resource = manager.getResource(fileLocation)) {
|
|
||||||
return Pair.of(model, parseStream(resource.getInputStream()));
|
|
||||||
} catch(IOException | JsonParseException e) {
|
|
||||||
logOrSuppressError(blockstateErrors, "model", fileLocation, e);
|
|
||||||
return Pair.of(fileLocation, null);
|
|
||||||
}
|
|
||||||
}, ModernFix.resourceReloadExecutor()));
|
|
||||||
}
|
|
||||||
modelFiles.clear();
|
|
||||||
CompletableFuture.allOf(modelBytes.toArray(new CompletableFuture[0])).join();
|
|
||||||
UVController.useDummyUv.set(Boolean.TRUE);
|
|
||||||
for(CompletableFuture<Pair<ResourceLocation, JsonElement>> future : modelBytes) {
|
|
||||||
Pair<ResourceLocation, JsonElement> pair = future.join();
|
|
||||||
try {
|
|
||||||
if(pair.getSecond() != null) {
|
|
||||||
|
|
||||||
BlockModel model = modelDeserializer.apply(pair.getSecond());
|
|
||||||
model.name = pair.getFirst().toString();
|
|
||||||
modelFiles.addAll(model.getDependencies());
|
|
||||||
basicModels.put(pair.getFirst(), model);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} catch(Throwable e) {
|
|
||||||
logOrSuppressError(blockstateErrors, "model", pair.getFirst(), e);
|
|
||||||
}
|
|
||||||
basicModels.put(pair.getFirst(), (BlockModel)missingModel);
|
|
||||||
}
|
|
||||||
UVController.useDummyUv.set(Boolean.FALSE);
|
|
||||||
}
|
|
||||||
blockstateErrors.object2IntEntrySet().forEach(entry -> {
|
|
||||||
if(entry.getIntValue() > ERROR_THRESHOLD) {
|
|
||||||
ModernFix.LOGGER.error("Suppressed additional {} model errors for domain {}", entry.getIntValue(), entry.getKey());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
blockstateErrors.clear();
|
|
||||||
modelFiles = null;
|
|
||||||
Function<ResourceLocation, UnbakedModel> modelGetter = loc -> {
|
|
||||||
UnbakedModel m = basicModels.get(loc);
|
|
||||||
/* fallback to vanilla loader if missing */
|
|
||||||
return m != null ? m : bakeryModelGetter.apply(loc);
|
|
||||||
};
|
|
||||||
for(BlockModel model : basicModels.values()) {
|
|
||||||
try {
|
|
||||||
materialSet.addAll(model.getMaterials(modelGetter, errorSet));
|
|
||||||
} catch(Throwable e) {
|
|
||||||
ModernFix.LOGGER.error("Model {} threw error while getting materials", model.name, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//errorSet.stream().filter(pair -> !pair.getSecond().equals(MISSING_MODEL_LOCATION_STRING)).forEach(pair -> LOGGER.warn("Unable to resolve texture reference: {} in {}", pair.getFirst(), pair.getSecond()));
|
|
||||||
stopwatch.stop();
|
|
||||||
ModernFix.LOGGER.info("Resolving model textures took " + stopwatch);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static <T extends Comparable<T>, V extends T> BlockState setPropertyGeneric(BlockState state, Property<T> prop, Object o) {
|
|
||||||
return state.setValue(prop, (V)o);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static <T extends Comparable<T>> T getValueHelper(Property<T> property, String value) {
|
|
||||||
return property.getValue(value).orElse(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Splitter COMMA_SPLITTER = Splitter.on(',');
|
|
||||||
private static final Splitter EQUAL_SPLITTER = Splitter.on('=').limit(2);
|
|
||||||
|
|
||||||
public static ImmutableList<BlockState> getBlockStatesForMRL(StateDefinition<Block, BlockState> stateDefinition, ModelResourceLocation location) {
|
|
||||||
if(Objects.equals(location.getVariant(), "inventory"))
|
|
||||||
return ImmutableList.of();
|
|
||||||
Set<Property<?>> fixedProperties = new HashSet<>();
|
|
||||||
BlockState fixedState = stateDefinition.any();
|
|
||||||
for(String s : COMMA_SPLITTER.split(location.getVariant())) {
|
|
||||||
Iterator<String> iterator = EQUAL_SPLITTER.split(s).iterator();
|
|
||||||
if (iterator.hasNext()) {
|
|
||||||
String s1 = iterator.next();
|
|
||||||
Property<?> property = stateDefinition.getProperty(s1);
|
|
||||||
if (property != null && iterator.hasNext()) {
|
|
||||||
String s2 = iterator.next();
|
|
||||||
Object value = getValueHelper(property, s2);
|
|
||||||
if (value == null) {
|
|
||||||
throw new RuntimeException("Unknown value: '" + s2 + "' for blockstate property: '" + s1 + "' " + property.getPossibleValues());
|
|
||||||
}
|
|
||||||
fixedState = setPropertyGeneric(fixedState, property, value);
|
|
||||||
fixedProperties.add(property);
|
|
||||||
} else if (!s1.isEmpty()) {
|
|
||||||
throw new RuntimeException("Unknown blockstate property: '" + s1 + "'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// check if there is only one possible state
|
|
||||||
if(fixedProperties.size() == stateDefinition.getProperties().size()) {
|
|
||||||
return ImmutableList.of(fixedState);
|
|
||||||
}
|
|
||||||
// generate all possible blockstates from the remaining properties
|
|
||||||
ArrayList<Property<?>> anyProperties = new ArrayList<>(stateDefinition.getProperties());
|
|
||||||
anyProperties.removeAll(fixedProperties);
|
|
||||||
ArrayList<BlockState> finalList = new ArrayList<>();
|
|
||||||
finalList.add(fixedState);
|
|
||||||
for(Property<?> property : anyProperties) {
|
|
||||||
ArrayList<BlockState> newPermutations = new ArrayList<>();
|
|
||||||
for(BlockState state : finalList) {
|
|
||||||
for(Comparable<?> value : property.getPossibleValues()) {
|
|
||||||
newPermutations.add(setPropertyGeneric(state, property, value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finalList = newPermutations;
|
|
||||||
}
|
|
||||||
return ImmutableList.copyOf(finalList);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ModernFixClientIntegration bakedModelWrapper(BiFunction<ResourceLocation, Pair<UnbakedModel, BakedModel>, BakedModel> consumer) {
|
|
||||||
return new ModernFixClientIntegration() {
|
|
||||||
@Override
|
|
||||||
public BakedModel onBakedModelLoad(ResourceLocation location, UnbakedModel baseModel, BakedModel originalModel, ModelState state, ModelBakery bakery) {
|
|
||||||
return consumer.apply(location, Pair.of(baseModel, originalModel));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
package org.embeddedt.modernfix.dynamicresources;
|
|
||||||
|
|
||||||
import net.minecraft.client.renderer.block.model.BlockFaceUV;
|
|
||||||
|
|
||||||
public class UVController {
|
|
||||||
public static final ThreadLocal<Boolean> useDummyUv = ThreadLocal.withInitial(() -> Boolean.FALSE);
|
|
||||||
public static final BlockFaceUV dummyUv = new BlockFaceUV(new float[4], 0);
|
|
||||||
}
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
package org.embeddedt.modernfix.entity;
|
|
||||||
|
|
||||||
import com.mojang.datafixers.util.Pair;
|
|
||||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
|
||||||
import net.minecraft.network.syncher.SynchedEntityData;
|
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
|
||||||
import net.minecraft.world.entity.Entity;
|
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
|
||||||
import org.embeddedt.modernfix.packet.EntityIDSyncPacket;
|
|
||||||
import org.embeddedt.modernfix.platform.ModernFixPlatformHooks;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class EntityDataIDSyncHandler {
|
|
||||||
private static Map<Class<? extends Entity>, List<Pair<String, Integer>>> fieldsToSyncMap;
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static void onDatapackSyncEvent(ServerPlayer targetPlayer) {
|
|
||||||
if(targetPlayer != null) {
|
|
||||||
/* Compute the current set of serializer IDs in use and send them */
|
|
||||||
if(fieldsToSyncMap == null) {
|
|
||||||
fieldsToSyncMap = new HashMap<>();
|
|
||||||
Map<Class<? extends Entity>, Integer> entityPoolMap = SynchedEntityData.ENTITY_ID_POOL;
|
|
||||||
List<Field> fieldsToSync = new ArrayList<>();
|
|
||||||
for(Class<? extends Entity> eClass : entityPoolMap.keySet()) {
|
|
||||||
fieldsToSync.clear();
|
|
||||||
try {
|
|
||||||
Field[] classFields = eClass.getDeclaredFields();
|
|
||||||
for(Field field : classFields) {
|
|
||||||
if(!Modifier.isStatic(field.getModifiers()))
|
|
||||||
continue;
|
|
||||||
field.setAccessible(true);
|
|
||||||
Object o = field.get(null);
|
|
||||||
if(o != null && EntityDataAccessor.class.isAssignableFrom(o.getClass())) {
|
|
||||||
fieldsToSync.add(field);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(Field field : fieldsToSync) {
|
|
||||||
int id = ((EntityDataAccessor<?>)field.get(null)).id;
|
|
||||||
fieldsToSyncMap.computeIfAbsent(eClass, k -> new ArrayList<>()).add(Pair.of(field.getName(), id));
|
|
||||||
}
|
|
||||||
} catch(Throwable e) {
|
|
||||||
ModernFix.LOGGER.error("Skipping entity ID sync for {}: {}", eClass.getName(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EntityIDSyncPacket packet = new EntityIDSyncPacket(fieldsToSyncMap);
|
|
||||||
ModernFix.LOGGER.debug("Sending ID correction packet to client with " + fieldsToSyncMap.size() + " classes");
|
|
||||||
ModernFixPlatformHooks.INSTANCE.sendPacket(targetPlayer, packet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
package org.embeddedt.modernfix.jei.async;
|
|
||||||
|
|
||||||
public interface IAsyncJeiStarter {
|
|
||||||
static void checkForLoadInterruption() {
|
|
||||||
if(((JEIReloadThread)Thread.currentThread()).isStopRequested())
|
|
||||||
throw new JEILoadingInterruptedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
package org.embeddedt.modernfix.jei.async;
|
|
||||||
|
|
||||||
public class JEILoadingInterruptedException extends Error {
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
package org.embeddedt.modernfix.jei.async;
|
|
||||||
|
|
||||||
public class JEIReloadThread extends Thread {
|
|
||||||
private volatile boolean stopRequested;
|
|
||||||
|
|
||||||
public JEIReloadThread(Runnable runnable, String s) {
|
|
||||||
super(runnable, s);
|
|
||||||
this.stopRequested = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void requestStop() {
|
|
||||||
stopRequested = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isStopRequested() {
|
|
||||||
return stopRequested;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
package org.embeddedt.modernfix.packet;
|
|
||||||
|
|
||||||
import com.mojang.datafixers.util.Pair;
|
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
|
||||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
|
||||||
import net.minecraft.world.entity.Entity;
|
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class EntityIDSyncPacket {
|
|
||||||
private Map<Class<? extends Entity>, List<Pair<String, Integer>>> map;
|
|
||||||
|
|
||||||
public EntityIDSyncPacket(Map<Class<? extends Entity>, List<Pair<String, Integer>>> map) {
|
|
||||||
this.map = map;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<Class<? extends Entity>, List<Pair<String, Integer>>> getFieldInfo() {
|
|
||||||
return this.map;
|
|
||||||
}
|
|
||||||
|
|
||||||
public EntityIDSyncPacket() {
|
|
||||||
this.map = new HashMap<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void serialize(FriendlyByteBuf buf) {
|
|
||||||
buf.writeVarInt(map.keySet().size());
|
|
||||||
for(Map.Entry<Class<? extends Entity>, List<Pair<String, Integer>>> entry : map.entrySet()) {
|
|
||||||
buf.writeUtf(entry.getKey().getName());
|
|
||||||
buf.writeVarInt(entry.getValue().size());
|
|
||||||
for(Pair<String, Integer> field : entry.getValue()) {
|
|
||||||
buf.writeUtf(field.getFirst());
|
|
||||||
buf.writeVarInt(field.getSecond());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static EntityIDSyncPacket deserialize(FriendlyByteBuf buf) {
|
|
||||||
EntityIDSyncPacket self = new EntityIDSyncPacket();
|
|
||||||
int numEntityClasses = buf.readVarInt();
|
|
||||||
for(int i = 0; i < numEntityClasses; i++) {
|
|
||||||
String clzName = buf.readUtf();
|
|
||||||
try {
|
|
||||||
Class<?> clz;
|
|
||||||
try {
|
|
||||||
clz = Class.forName(clzName);
|
|
||||||
} catch(ClassNotFoundException e) {
|
|
||||||
ModernFix.LOGGER.warn("Entity class not found: {}", clzName);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(!Entity.class.isAssignableFrom(clz)) {
|
|
||||||
ModernFix.LOGGER.error("Not an entity: " + clzName);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
int numFields = buf.readVarInt();
|
|
||||||
for(int j = 0; j < numFields; j++) {
|
|
||||||
String fieldName = buf.readUtf();
|
|
||||||
int id = buf.readVarInt();
|
|
||||||
Field f = clz.getDeclaredField(fieldName);
|
|
||||||
if(!Modifier.isStatic(f.getModifiers()))
|
|
||||||
continue;
|
|
||||||
f.setAccessible(true);
|
|
||||||
if(!EntityDataAccessor.class.isAssignableFrom(f.get(null).getClass())) {
|
|
||||||
ModernFix.LOGGER.error("Not a data accessor field: " + clz + "." + fieldName);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
self.map.computeIfAbsent((Class<? extends Entity>)clz, k -> new ArrayList<>()).add(Pair.of(fieldName, id));
|
|
||||||
}
|
|
||||||
} catch(ReflectiveOperationException e) {
|
|
||||||
ModernFix.LOGGER.error("Error deserializing packet", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,108 +0,0 @@
|
||||||
package org.embeddedt.modernfix.resources;
|
|
||||||
|
|
||||||
import com.google.common.base.Splitter;
|
|
||||||
import com.google.common.collect.Interner;
|
|
||||||
import com.google.common.collect.Interners;
|
|
||||||
import org.embeddedt.modernfix.util.FileUtil;
|
|
||||||
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
public class CachedResourcePath {
|
|
||||||
private final String[] pathComponents;
|
|
||||||
|
|
||||||
public static final Interner<String> PATH_COMPONENT_INTERNER = Interners.newStrongInterner();
|
|
||||||
private static final Splitter SLASH_SPLITTER = Splitter.on('/');
|
|
||||||
public static final String[] NO_PREFIX = new String[0];
|
|
||||||
|
|
||||||
public CachedResourcePath(String[] prefix, Path path) {
|
|
||||||
this(prefix, path, path.getNameCount(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CachedResourcePath(String s) {
|
|
||||||
// normalize so we can guarantee there are no empty sections
|
|
||||||
this(NO_PREFIX, SLASH_SPLITTER.splitToList(FileUtil.normalize(s)), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> CachedResourcePath(String[] prefixElements, Collection<T> collection, boolean intern) {
|
|
||||||
this(prefixElements, collection, collection.size(), intern);
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> CachedResourcePath(String[] prefixElements, Iterable<T> path, int count, boolean intern) {
|
|
||||||
String[] components = new String[prefixElements.length + count];
|
|
||||||
int i = 0;
|
|
||||||
while(i < prefixElements.length) {
|
|
||||||
components[i] = intern ? PATH_COMPONENT_INTERNER.intern(prefixElements[i]) : prefixElements[i];
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
for(Object component : path) {
|
|
||||||
String s = component.toString();
|
|
||||||
if(s.length() == 0)
|
|
||||||
continue;
|
|
||||||
components[i] = intern ? PATH_COMPONENT_INTERNER.intern(s) : s;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
pathComponents = components;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CachedResourcePath(String[] prefixElements, CachedResourcePath other) {
|
|
||||||
String[] components = new String[prefixElements.length + other.pathComponents.length];
|
|
||||||
int i = 0;
|
|
||||||
while(i < prefixElements.length) {
|
|
||||||
components[i] = PATH_COMPONENT_INTERNER.intern(prefixElements[i]);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
System.arraycopy(other.pathComponents, 0, components, i, other.pathComponents.length);
|
|
||||||
pathComponents = components;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DOES NOT INTERN!
|
|
||||||
*/
|
|
||||||
public CachedResourcePath(String[] pathComponents) {
|
|
||||||
for(String s : pathComponents) {
|
|
||||||
if(s.length() == 0) {
|
|
||||||
// reconstruct the whole array skipping blanks. inefficient, but should not be the common case
|
|
||||||
pathComponents = Arrays.stream(pathComponents).filter(comp -> comp.length() > 0).toArray(String[]::new);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.pathComponents = pathComponents;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Arrays.hashCode(pathComponents);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
|
||||||
CachedResourcePath that = (CachedResourcePath) o;
|
|
||||||
return Arrays.equals(pathComponents, that.pathComponents);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFileName() {
|
|
||||||
return pathComponents[pathComponents.length - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNameCount() {
|
|
||||||
return pathComponents.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getNameAt(int i) {
|
|
||||||
return pathComponents[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFullPath(int startIndex) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for(int i = startIndex; i < pathComponents.length; i++) {
|
|
||||||
sb.append(pathComponents[i]);
|
|
||||||
if(i != (pathComponents.length - 1))
|
|
||||||
sb.append('/');
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,184 +0,0 @@
|
||||||
package org.embeddedt.modernfix.resources;
|
|
||||||
|
|
||||||
import com.google.common.base.Joiner;
|
|
||||||
import com.google.common.base.Stopwatch;
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
|
||||||
import com.mojang.datafixers.util.Pair;
|
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.server.packs.PackType;
|
|
||||||
import org.embeddedt.modernfix.ModernFix;
|
|
||||||
import org.embeddedt.modernfix.platform.ModernFixPlatformHooks;
|
|
||||||
import org.embeddedt.modernfix.util.PackTypeHelper;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.function.BiFunction;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The core of the resource pack cache system.
|
|
||||||
*
|
|
||||||
* Using a dedicated set and also separate lists is important; testing without this showed a huge performance
|
|
||||||
* drop.
|
|
||||||
*/
|
|
||||||
public class PackResourcesCacheEngine {
|
|
||||||
private static final Joiner SLASH_JOINER = Joiner.on('/');
|
|
||||||
|
|
||||||
private final Map<PackType, Set<String>> namespacesByType;
|
|
||||||
private final Set<CachedResourcePath> containedPaths;
|
|
||||||
private final EnumMap<PackType, Map<String, List<CachedResourcePath>>> resourceListings;
|
|
||||||
private volatile boolean cacheGenerationFlag = false;
|
|
||||||
private List<Runnable> cacheGenerationTasks = new ArrayList<>();
|
|
||||||
private Path debugPath;
|
|
||||||
|
|
||||||
public PackResourcesCacheEngine(Function<PackType, Set<String>> namespacesRetriever, BiFunction<PackType, String, Path> basePathRetriever) {
|
|
||||||
this.namespacesByType = new EnumMap<>(PackType.class);
|
|
||||||
for(PackType type : PackType.values()) {
|
|
||||||
if(!PackTypeHelper.isVanillaPackType(type))
|
|
||||||
continue;
|
|
||||||
this.namespacesByType.put(type, namespacesRetriever.apply(type));
|
|
||||||
}
|
|
||||||
this.containedPaths = new ObjectOpenHashSet<>();
|
|
||||||
this.resourceListings = new EnumMap<>(PackType.class);
|
|
||||||
// used for log message
|
|
||||||
this.debugPath = basePathRetriever.apply(PackType.CLIENT_RESOURCES, "minecraft").toAbsolutePath();
|
|
||||||
for(PackType type : PackType.values()) {
|
|
||||||
Collection<String> namespaces = PackTypeHelper.isVanillaPackType(type) ? this.namespacesByType.get(type) : namespacesRetriever.apply(type);
|
|
||||||
Collection<Pair<String, Path>> namespacedRoots = namespaces.stream().map(s -> Pair.of(s, basePathRetriever.apply(type, s).toAbsolutePath())).collect(Collectors.toList());
|
|
||||||
cacheGenerationTasks.add(() -> {
|
|
||||||
ImmutableMap.Builder<String, List<CachedResourcePath>> packTypedMap = ImmutableMap.builder();
|
|
||||||
for(Pair<String, Path> pair : namespacedRoots) {
|
|
||||||
try {
|
|
||||||
ImmutableList.Builder<CachedResourcePath> namespacedList = ImmutableList.builder();
|
|
||||||
String namespace = pair.getFirst();
|
|
||||||
Path root = pair.getSecond();
|
|
||||||
String[] prefix = new String[] { type.getDirectory(), namespace };
|
|
||||||
try (Stream<Path> stream = Files.walk(root)) {
|
|
||||||
stream
|
|
||||||
.map(path -> root.relativize(path.toAbsolutePath()))
|
|
||||||
.filter(PackResourcesCacheEngine::isValidCachedResourcePath)
|
|
||||||
.forEach(path -> {
|
|
||||||
CachedResourcePath cachedPath = new CachedResourcePath(prefix, path);
|
|
||||||
synchronized (this.containedPaths) {
|
|
||||||
this.containedPaths.add(cachedPath);
|
|
||||||
}
|
|
||||||
if(!cachedPath.getFileName().endsWith(".mcmeta"))
|
|
||||||
namespacedList.add(cachedPath);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
packTypedMap.put(namespace, namespacedList.build());
|
|
||||||
} catch(IOException ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
synchronized (this.resourceListings) {
|
|
||||||
this.resourceListings.put(type, packTypedMap.build());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
cacheGenerationTasks.add(() -> {
|
|
||||||
((ObjectOpenHashSet<CachedResourcePath>)this.containedPaths).trim();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isValidCachedResourcePath(Path path) {
|
|
||||||
if(path.getFileName() == null || path.getNameCount() == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
String str = SLASH_JOINER.join(path);
|
|
||||||
if(str.length() == 0)
|
|
||||||
return false;
|
|
||||||
for(int i = 0; i < str.length(); i++) {
|
|
||||||
if(!ResourceLocation.validPathChar(str.charAt(i))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<String> getNamespaces(PackType type) {
|
|
||||||
if(PackTypeHelper.isVanillaPackType(type))
|
|
||||||
return this.namespacesByType.get(type);
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void doGenerateCache() {
|
|
||||||
Stopwatch watch = Stopwatch.createStarted();
|
|
||||||
for(Runnable r : this.cacheGenerationTasks) {
|
|
||||||
r.run();
|
|
||||||
}
|
|
||||||
watch.stop();
|
|
||||||
ModernFix.LOGGER.debug("Generated cache for {} in {}", debugPath, watch);
|
|
||||||
debugPath = null;
|
|
||||||
cacheGenerationTasks = ImmutableList.of();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void awaitLoad() {
|
|
||||||
if(!this.cacheGenerationFlag) {
|
|
||||||
synchronized (this) {
|
|
||||||
if(!this.cacheGenerationFlag) {
|
|
||||||
this.doGenerateCache();
|
|
||||||
this.cacheGenerationFlag = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasResource(String path) {
|
|
||||||
awaitLoad();
|
|
||||||
return this.containedPaths.contains(new CachedResourcePath(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasResource(String[] paths) {
|
|
||||||
awaitLoad();
|
|
||||||
return this.containedPaths.contains(new CachedResourcePath(paths));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<ResourceLocation> getResources(PackType type, String resourceNamespace, String pathIn, int maxDepth, Predicate<String> filter) {
|
|
||||||
if(!PackTypeHelper.isVanillaPackType(type))
|
|
||||||
throw new IllegalArgumentException("Only vanilla PackTypes are supported");
|
|
||||||
awaitLoad();
|
|
||||||
List<CachedResourcePath> paths = resourceListings.get(type).getOrDefault(resourceNamespace, Collections.emptyList());
|
|
||||||
if(paths.isEmpty())
|
|
||||||
return Collections.emptyList();
|
|
||||||
String testPath = pathIn.endsWith("/") ? pathIn : (pathIn + "/");
|
|
||||||
ArrayList<ResourceLocation> resources = new ArrayList<>();
|
|
||||||
for(CachedResourcePath cachePath : paths) {
|
|
||||||
if((cachePath.getNameCount() - 2) > maxDepth)
|
|
||||||
continue;
|
|
||||||
String fullPath = cachePath.getFullPath(2);
|
|
||||||
if(!fullPath.startsWith(testPath))
|
|
||||||
continue;
|
|
||||||
if(!filter.test(cachePath.getFileName()))
|
|
||||||
continue;
|
|
||||||
ResourceLocation foundResource = new ResourceLocation(resourceNamespace, fullPath);
|
|
||||||
resources.add(foundResource);
|
|
||||||
}
|
|
||||||
return resources;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final WeakHashMap<ICachingResourcePack, Boolean> cachingPacks = new WeakHashMap<>();
|
|
||||||
public static void track(ICachingResourcePack pack) {
|
|
||||||
synchronized (cachingPacks) {
|
|
||||||
cachingPacks.put(pack, Boolean.TRUE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void invalidate() {
|
|
||||||
if(!ModernFixPlatformHooks.INSTANCE.isDevEnv())
|
|
||||||
return;
|
|
||||||
synchronized (cachingPacks) {
|
|
||||||
cachingPacks.keySet().forEach(pack -> {
|
|
||||||
if(pack != null)
|
|
||||||
pack.invalidateCache();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
package org.embeddedt.modernfix.screen;
|
|
||||||
|
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
|
||||||
import net.minecraft.Util;
|
|
||||||
import net.minecraft.client.gui.components.Button;
|
|
||||||
import net.minecraft.client.gui.screens.Screen;
|
|
||||||
import net.minecraft.network.chat.*;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
public class ModernFixConfigScreen extends Screen {
|
|
||||||
private OptionList optionList;
|
|
||||||
private Screen lastScreen;
|
|
||||||
|
|
||||||
public boolean madeChanges = false;
|
|
||||||
private Button doneButton, wikiButton;
|
|
||||||
private double lastScrollAmount = 0;
|
|
||||||
|
|
||||||
public ModernFixConfigScreen(Screen lastScreen) {
|
|
||||||
super(new TranslatableComponent("modernfix.config"));
|
|
||||||
this.lastScreen = lastScreen;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void init() {
|
|
||||||
this.optionList = new OptionList(this, this.minecraft);
|
|
||||||
this.optionList.setScrollAmount(lastScrollAmount);
|
|
||||||
this.children.add(this.optionList);
|
|
||||||
this.wikiButton = new Button(this.width / 2 - 155, this.height - 29, 150, 20, new TranslatableComponent("modernfix.config.wiki"), (arg) -> {
|
|
||||||
Util.getPlatform().openUri("https://github.com/embeddedt/ModernFix/wiki/Summary-of-Patches");
|
|
||||||
});
|
|
||||||
this.doneButton = new Button(this.width / 2 - 155 + 160, this.height - 29, 150, 20, CommonComponents.GUI_DONE, (arg) -> {
|
|
||||||
this.onClose();
|
|
||||||
});
|
|
||||||
this.addButton(this.wikiButton);
|
|
||||||
this.addButton(this.doneButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClose() {
|
|
||||||
this.minecraft.setScreen(lastScreen);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void render(PoseStack poseStack, int mouseX, int mouseY, float partialTicks) {
|
|
||||||
this.renderBackground(poseStack);
|
|
||||||
this.optionList.render(poseStack, mouseX, mouseY, partialTicks);
|
|
||||||
drawCenteredString(poseStack, this.font, this.title, this.width / 2, 8, 16777215);
|
|
||||||
this.doneButton.setMessage(madeChanges ? new TranslatableComponent("modernfix.config.done_restart") : CommonComponents.GUI_DONE);
|
|
||||||
super.render(poseStack, mouseX, mouseY, partialTicks);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void renderComponentHoverEffect(PoseStack matrixStack, @Nullable Style style, int mouseX, int mouseY) {
|
|
||||||
super.renderComponentHoverEffect(matrixStack, style, mouseX, mouseY);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLastScrollAmount(double d) {
|
|
||||||
this.lastScrollAmount = d;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
package org.embeddedt.modernfix.screen;
|
|
||||||
|
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
|
||||||
import net.minecraft.client.gui.Font;
|
|
||||||
import net.minecraft.client.gui.components.Button;
|
|
||||||
import net.minecraft.client.gui.screens.Screen;
|
|
||||||
import net.minecraft.network.chat.CommonComponents;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.network.chat.TextComponent;
|
|
||||||
import net.minecraft.network.chat.TranslatableComponent;
|
|
||||||
import net.minecraft.util.FormattedCharSequence;
|
|
||||||
|
|
||||||
public class ModernFixOptionInfoScreen extends Screen {
|
|
||||||
private final Screen lastScreen;
|
|
||||||
private final Component description;
|
|
||||||
|
|
||||||
public ModernFixOptionInfoScreen(Screen lastScreen, String optionName) {
|
|
||||||
super(new TextComponent(optionName));
|
|
||||||
|
|
||||||
this.lastScreen = lastScreen;
|
|
||||||
this.description = new TranslatableComponent("modernfix.option." + optionName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void init() {
|
|
||||||
super.init();
|
|
||||||
this.addButton(new Button(this.width / 2 - 100, this.height - 29, 200, 20, CommonComponents.GUI_DONE, (button) -> {
|
|
||||||
this.onClose();
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClose() {
|
|
||||||
this.minecraft.setScreen(lastScreen);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void drawMultilineString(PoseStack mStack, Font fr, Component str, int x, int y) {
|
|
||||||
for(FormattedCharSequence s : fr.split(str, this.width - 50)) {
|
|
||||||
fr.drawShadow(mStack, s, (float)x, (float)y, 16777215);
|
|
||||||
y += fr.lineHeight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void render(PoseStack poseStack, int mouseX, int mouseY, float partialTicks) {
|
|
||||||
this.renderBackground(poseStack);
|
|
||||||
drawCenteredString(poseStack, this.font, this.title, this.width / 2, 8, 16777215);
|
|
||||||
this.drawMultilineString(poseStack, this.minecraft.font, description, 10, 50);
|
|
||||||
super.render(poseStack, mouseX, mouseY, partialTicks);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
package org.embeddedt.modernfix.searchtree;
|
|
||||||
|
|
||||||
import net.minecraft.client.searchtree.MutableSearchTree;
|
|
||||||
import net.minecraft.client.searchtree.ReloadableIdSearchTree;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dummy search tree that stores nothing and returns nothing on searches.
|
|
||||||
*/
|
|
||||||
public class DummySearchTree<T> extends ReloadableIdSearchTree<T> implements MutableSearchTree<T> {
|
|
||||||
public DummySearchTree() {
|
|
||||||
super(t -> Stream.empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void add(T pObj) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void refresh() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<T> search(String pSearchText) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user