mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-10-15 14:07:38 +00:00
Compare commits
513 Commits
v1.20.1-1.
...
v1.21.7-1.
Author | SHA1 | Date | |
---|---|---|---|
![]() |
67412a2b72 | ||
![]() |
76869593f0 | ||
![]() |
fbf994e803 | ||
![]() |
8344c0a5c2 | ||
![]() |
a292d33830 | ||
![]() |
341d1c7bc2 | ||
![]() |
846f9dff03 | ||
![]() |
64d10ad45b | ||
![]() |
531eacfac7 | ||
![]() |
1f3da5205c | ||
![]() |
e3fecb013a | ||
![]() |
798ceefafe | ||
![]() |
7c0f79fc3c | ||
![]() |
b35cefc5dd | ||
![]() |
ec3dd328b3 | ||
![]() |
f3f43191ab | ||
![]() |
89dd521930 | ||
![]() |
9272e2efcd | ||
![]() |
69353a4fcf | ||
![]() |
ff363dca5a | ||
![]() |
1c51282426 | ||
![]() |
4a3a1c9275 | ||
![]() |
2557dd0af9 | ||
![]() |
b5c0c6e104 | ||
![]() |
876fd8ddb8 | ||
![]() |
ee3b1343b5 | ||
![]() |
b440b964b7 | ||
![]() |
5dfc401b45 | ||
![]() |
0790a8346a | ||
![]() |
418c9be7ac | ||
![]() |
b491f6b11f | ||
![]() |
acafc06449 | ||
![]() |
598fd98a8b | ||
![]() |
e13e8ff92e | ||
![]() |
0a0c80db41 | ||
![]() |
4344c3072f | ||
![]() |
c20336286b | ||
![]() |
356366ede8 | ||
![]() |
a1df196673 | ||
![]() |
947001104d | ||
![]() |
8711512769 | ||
![]() |
a939ad8b97 | ||
![]() |
fdae94b3c1 | ||
![]() |
9c0ce27ce6 | ||
![]() |
c458360b18 | ||
![]() |
09ad6c1905 | ||
![]() |
0e1e8a72d3 | ||
![]() |
995a6e7379 | ||
![]() |
ffa6eadc26 | ||
![]() |
7c1e8e1951 | ||
![]() |
b805a34c2d | ||
![]() |
b03546a158 | ||
![]() |
582713467f | ||
![]() |
b6f41a0df5 | ||
![]() |
594738a022 | ||
![]() |
27f2ab364c | ||
![]() |
5a43273757 | ||
![]() |
97e28516fb | ||
![]() |
676fb5fb53 | ||
![]() |
08dc08b5a3 | ||
![]() |
8f4d4038f6 | ||
![]() |
63ba3fe274 | ||
![]() |
749b3df227 | ||
![]() |
b97634b717 | ||
![]() |
8ade1c38ac | ||
![]() |
1b8344d0a3 | ||
![]() |
b42bc0a01a | ||
![]() |
70a7478529 | ||
![]() |
0cff73e2fc | ||
![]() |
05163a4911 | ||
![]() |
a892739f8e | ||
![]() |
9277aa33e9 | ||
![]() |
f8785a092f | ||
![]() |
598fc4aefd | ||
![]() |
dd7e8fcefc | ||
![]() |
29c8f96912 | ||
![]() |
b9267ecbfc | ||
![]() |
9d2c2db22b | ||
![]() |
6660966320 | ||
![]() |
3acb231f01 | ||
![]() |
16324e1eac | ||
![]() |
fa33949113 | ||
![]() |
0c04d9de47 | ||
![]() |
32f5c38485 | ||
![]() |
01fe949b3e | ||
![]() |
c03fce275e | ||
![]() |
0998acaa82 | ||
![]() |
12a44fed6f | ||
![]() |
3f8c3b026a | ||
![]() |
0a8d505323 | ||
![]() |
237a0ac3bb | ||
![]() |
b185d088b3 | ||
![]() |
051c70a731 | ||
![]() |
2e2f308ff3 | ||
![]() |
0f123b5efd | ||
![]() |
1278246cf7 | ||
![]() |
88cb03be6b | ||
![]() |
1e25fa9bc3 | ||
![]() |
74f707aaea | ||
![]() |
9bb62b047a | ||
![]() |
4360485880 | ||
![]() |
b69a44a927 | ||
![]() |
7d8f609c49 | ||
![]() |
e7f56c4d25 | ||
![]() |
fa2140d00b | ||
![]() |
03388149b1 | ||
![]() |
f212861370 | ||
![]() |
4f3663ccc9 | ||
![]() |
53425c1e76 | ||
![]() |
55edced9de | ||
![]() |
dc969c5a78 | ||
![]() |
94ad6dab0e | ||
![]() |
938eb38ad5 | ||
![]() |
6739c4c6c0 | ||
![]() |
d6749f8461 | ||
![]() |
d697c47b80 | ||
![]() |
5ba7f99326 | ||
![]() |
4710ee5bcc | ||
![]() |
62c9e5b08f | ||
![]() |
2ca5850060 | ||
![]() |
ed631b05e7 | ||
![]() |
a2b9490d5c | ||
![]() |
8204944b5f | ||
![]() |
ef0af67e96 | ||
![]() |
9a914e75c4 | ||
![]() |
4a532952d4 | ||
![]() |
546577041b | ||
![]() |
f881c0ced0 | ||
![]() |
0b389e04b0 | ||
![]() |
d3a3ab3c21 | ||
![]() |
22e6c06e59 | ||
![]() |
7337b91692 | ||
![]() |
3c46b8acd7 | ||
![]() |
d9fc1c3a80 | ||
![]() |
479aabdd09 | ||
![]() |
ad74893058 | ||
![]() |
2ba6d5815b | ||
![]() |
7e2f490626 | ||
![]() |
4dc649d5e5 | ||
![]() |
5bab415790 | ||
![]() |
f04c699df6 | ||
![]() |
9bbf3f3e1d | ||
![]() |
a3f8e653d4 | ||
![]() |
7c02979c22 | ||
![]() |
fdb65c9368 | ||
![]() |
ea670cc358 | ||
![]() |
b7396f3796 | ||
![]() |
1963e0160f | ||
![]() |
9a06904634 | ||
![]() |
5eb50ecb06 | ||
![]() |
5e24ad17d7 | ||
![]() |
8b1cb09ddf | ||
![]() |
7af2c14327 | ||
![]() |
d1a6b043c2 | ||
![]() |
cddb8fec11 | ||
![]() |
1d7d8006d4 | ||
![]() |
63bdc2537c | ||
![]() |
f776b17150 | ||
![]() |
0056709999 | ||
![]() |
31da2555cb | ||
![]() |
9b19a93ab9 | ||
![]() |
0c8e757314 | ||
![]() |
f39e86bb10 | ||
![]() |
ad52117f0f | ||
![]() |
bdffabc08e | ||
![]() |
87ce41f251 | ||
![]() |
e7c7919cad | ||
![]() |
4f66ac79d3 | ||
![]() |
ba6da3bc6c | ||
![]() |
b742745854 | ||
![]() |
3293639adf | ||
![]() |
064ff31830 | ||
![]() |
5d473725d5 | ||
![]() |
97a2f2dbdd | ||
![]() |
37c4789fa4 | ||
![]() |
0aaeeeee24 | ||
![]() |
2155ec3d63 | ||
![]() |
0da906fc93 | ||
![]() |
9e5e6a1b60 | ||
![]() |
dcc74e15c7 | ||
![]() |
c271ed7c7f | ||
![]() |
d6a246c122 | ||
![]() |
0bef3ee0d8 | ||
![]() |
bb04df7086 | ||
![]() |
a70baf0d74 | ||
![]() |
86e2f92493 | ||
![]() |
e9aceca1de | ||
![]() |
3042950507 | ||
![]() |
63181e73a1 | ||
![]() |
4f3247a0e2 | ||
![]() |
f7a6aac657 | ||
![]() |
782564e6ab | ||
![]() |
6b8ba8b80b | ||
![]() |
52b76d8886 | ||
![]() |
ba36c69583 | ||
![]() |
370e5f92a0 | ||
![]() |
36d05e4774 | ||
![]() |
89d1be17c9 | ||
![]() |
0069591af9 | ||
![]() |
c36c8605bf | ||
![]() |
3c72a00d46 | ||
![]() |
58aefc8df8 | ||
![]() |
97ddfc2794 | ||
![]() |
4f15f4197b | ||
![]() |
6e4ec86586 | ||
![]() |
0d8ac304c7 | ||
![]() |
fdd5f49369 | ||
![]() |
d24984c1d5 | ||
![]() |
8080dcdd9e | ||
![]() |
d7cea55e2a | ||
![]() |
9b2f974a81 | ||
![]() |
43770fa9bd | ||
![]() |
80c7a54ad4 | ||
![]() |
e57b6fede2 | ||
![]() |
34a2fd039f | ||
![]() |
3299d0e72a | ||
![]() |
b89e2615db | ||
![]() |
cdcd82679c | ||
![]() |
cdfa866760 | ||
![]() |
aa8078ddeb | ||
![]() |
7e53c19d74 | ||
![]() |
b7a8432cfb | ||
![]() |
356c8e8aeb | ||
![]() |
ed283155f7 | ||
![]() |
87dfad026e | ||
![]() |
bb97c465d9 | ||
![]() |
8bd4c3370e | ||
![]() |
3eb84ffedd | ||
![]() |
9484315d37 | ||
![]() |
be59f1a875 | ||
![]() |
bfb28b4710 | ||
![]() |
216f0adb3c | ||
![]() |
dad6874638 | ||
![]() |
77af4bc213 | ||
![]() |
5abab982c7 | ||
![]() |
764e1aa332 | ||
![]() |
c47718b09d | ||
![]() |
45cb597ecc | ||
![]() |
08d4f91c8b | ||
![]() |
b9eac4e509 | ||
![]() |
16577783d3 | ||
![]() |
c179da28f0 | ||
![]() |
dc3d8ea198 | ||
![]() |
cbe075b001 | ||
![]() |
ed0b156e05 | ||
![]() |
2765abf971 | ||
![]() |
4dd0735066 | ||
![]() |
38e516d7c7 | ||
![]() |
70a31855ac | ||
![]() |
6c8e64ffcd | ||
![]() |
7285c32d58 | ||
![]() |
99c60ac54b | ||
![]() |
63e40cf3cb | ||
![]() |
1d45935a25 | ||
![]() |
f80373e7a2 | ||
![]() |
63185629b7 | ||
![]() |
4bfb9ac323 | ||
![]() |
5926b6c994 | ||
![]() |
f5ed43584d | ||
![]() |
2c740bb904 | ||
![]() |
d77f5f135f | ||
![]() |
0e4710a956 | ||
![]() |
aca1d43550 | ||
![]() |
f10e401aea | ||
![]() |
7744d2663b | ||
![]() |
4566cb8273 | ||
![]() |
052e7a7ae5 | ||
![]() |
0895200681 | ||
![]() |
1a1623075f | ||
![]() |
54a95e07a4 | ||
![]() |
09d0f563b7 | ||
![]() |
e188f1d3fa | ||
![]() |
efd9a0f315 | ||
![]() |
28f75a0687 | ||
![]() |
819a4f7231 | ||
![]() |
898cb2a95d | ||
![]() |
03a8f83191 | ||
![]() |
aef92c8ebc | ||
![]() |
571ea794a8 | ||
![]() |
4b102f16b3 | ||
![]() |
e81af93043 | ||
![]() |
bb933d0100 | ||
![]() |
25b8a65c5c | ||
![]() |
e4236824d7 | ||
![]() |
cfd11ffa92 | ||
![]() |
ce133a5e66 | ||
![]() |
038fbc1ed1 | ||
![]() |
c582fb521c | ||
![]() |
af21792844 | ||
![]() |
9fbb1070ef | ||
![]() |
1944995c33 | ||
![]() |
ac851a795b | ||
![]() |
334761788a | ||
![]() |
5af3e15dd5 | ||
![]() |
de078e3037 | ||
![]() |
209b1ddbf9 | ||
![]() |
0c9f9a8652 | ||
![]() |
862d92785e | ||
![]() |
d48b85d50c | ||
![]() |
4d619de357 | ||
![]() |
57c289f173 | ||
![]() |
f63f85921f | ||
![]() |
c7e49d1929 | ||
![]() |
eb584aa94d | ||
![]() |
ad70e2ad90 | ||
![]() |
d9b0cc7075 | ||
![]() |
2c0d8263d3 | ||
![]() |
1e214f329e | ||
![]() |
de930c8d09 | ||
![]() |
94c864759d | ||
![]() |
735e7ce09b | ||
![]() |
2226df7224 | ||
![]() |
959bdaeb61 | ||
![]() |
06ac373e83 | ||
![]() |
0aca6a4dc9 | ||
![]() |
bf203bb1f3 | ||
![]() |
6e9799316a | ||
![]() |
cd9840d1c1 | ||
![]() |
b9a002586c | ||
![]() |
a3b07909b0 | ||
![]() |
d7786ee4b9 | ||
![]() |
4e90240922 | ||
![]() |
1a87d1bf45 | ||
![]() |
188806e8b0 | ||
![]() |
01407544c9 | ||
![]() |
bd2fd9d4c8 | ||
![]() |
00e2e2bd2d | ||
![]() |
7c1f40031b | ||
![]() |
929debd382 | ||
![]() |
4980b7355d | ||
![]() |
5c457950d8 | ||
![]() |
925092add3 | ||
![]() |
550296edc5 | ||
![]() |
0771c4891b | ||
![]() |
776fa00b94 | ||
![]() |
03bb279206 | ||
![]() |
fabd77132d | ||
![]() |
95be0a25bf | ||
![]() |
75f3ecce18 | ||
![]() |
688fdc40a6 | ||
![]() |
22bd5309ba | ||
![]() |
ad49325376 | ||
![]() |
825d45eb26 | ||
![]() |
8b2516abb5 | ||
![]() |
bce099ef32 | ||
![]() |
6d14ce625f | ||
![]() |
c8eadf4011 | ||
![]() |
0c1ab780bb | ||
![]() |
0f623c2cca | ||
![]() |
b9ba2534a4 | ||
![]() |
c764981a40 | ||
![]() |
6363164f2b | ||
![]() |
63580b4acb | ||
![]() |
9af1aa1ecf | ||
![]() |
ad0f551204 | ||
![]() |
0d3e00cc41 | ||
![]() |
836d6b939e | ||
![]() |
0e5248e5e6 | ||
![]() |
e154b0db2a | ||
![]() |
ae767eb5be | ||
![]() |
c50d56d9fa | ||
![]() |
777aa34bb0 | ||
![]() |
286f969f94 | ||
![]() |
7b9a156abc | ||
![]() |
0a9e5c78f3 | ||
![]() |
da5885ef35 | ||
![]() |
57c72711bb | ||
![]() |
cbafbca86b | ||
![]() |
c9caffb10f | ||
![]() |
4675583e1c | ||
![]() |
afe16cc593 | ||
![]() |
0abd107348 | ||
![]() |
cef4b4906b | ||
![]() |
04900dc82f | ||
![]() |
9b63cc81b1 | ||
![]() |
9eead7a0ec | ||
![]() |
ad97b2922b | ||
![]() |
52986f8d73 | ||
![]() |
ab00580389 | ||
![]() |
128ac2f109 | ||
![]() |
5d8c46c7e6 | ||
![]() |
1a5dc92bd4 | ||
![]() |
98b2d3f310 | ||
![]() |
e92c2d02f8 | ||
![]() |
f8ef40d378 | ||
![]() |
61f9b1d0c6 | ||
![]() |
ffb62dfa02 | ||
![]() |
6fb291112d | ||
![]() |
7ee821e9c9 | ||
![]() |
b7df91349a | ||
![]() |
cb8e06af2a | ||
![]() |
6478fca7a2 | ||
![]() |
3493159a05 | ||
![]() |
eead67e314 | ||
![]() |
3b8813cf8f | ||
![]() |
a9191a4d4e | ||
![]() |
451a2593ce | ||
![]() |
d38b1da974 | ||
![]() |
6e374579a4 | ||
![]() |
4daa2a2b6a | ||
![]() |
84b6edab82 | ||
![]() |
31aaf46d09 | ||
![]() |
2d11b51c62 | ||
![]() |
240528cce5 | ||
![]() |
83f1f86888 | ||
![]() |
a0f759527d | ||
![]() |
385e4210fa | ||
![]() |
d2896473f2 | ||
![]() |
f14cb2a3d1 | ||
![]() |
8db5c6bc3a | ||
![]() |
9c202bd1c2 | ||
![]() |
fc834cd97f | ||
![]() |
f26e443e81 | ||
![]() |
033378333f | ||
![]() |
ebeaa757a9 | ||
![]() |
57b1a65db3 | ||
![]() |
27c72a4571 | ||
![]() |
f284328656 | ||
![]() |
6b83c63991 | ||
![]() |
b27526bd21 | ||
![]() |
cb25f6c08a | ||
![]() |
d38b1d04e7 | ||
![]() |
9ccee75a99 | ||
![]() |
359c8d6652 | ||
![]() |
1788afacfc | ||
![]() |
f695f22d8a | ||
![]() |
bc03090ca4 | ||
![]() |
a617d0d566 | ||
![]() |
36599b321e | ||
![]() |
1d6e3f4fc0 | ||
![]() |
30dc4cb38c | ||
![]() |
be4512d1c3 | ||
![]() |
e6ee292850 | ||
![]() |
9d36f72bad | ||
![]() |
b5923c4462 | ||
![]() |
4d1e689719 | ||
![]() |
9d4af07568 | ||
![]() |
89294f4a22 | ||
![]() |
133b51b092 | ||
![]() |
272010e945 | ||
![]() |
e0889c613a | ||
![]() |
f115d43d07 | ||
![]() |
8be6b1b772 | ||
![]() |
104d5e70de | ||
![]() |
e3bda2f763 | ||
![]() |
234f69e8e5 | ||
![]() |
ed3a17f9b9 | ||
![]() |
0349c2b1f9 | ||
![]() |
03f9e6bd6d | ||
![]() |
9d8c933a14 | ||
![]() |
78bb3da58c | ||
![]() |
39a5e40c92 | ||
![]() |
763ba51919 | ||
![]() |
cf6ec8c28f | ||
![]() |
95d3b646b2 | ||
![]() |
488f66eead | ||
![]() |
1f7d245876 | ||
![]() |
af12b3a0ea | ||
![]() |
eb3e8ba677 | ||
![]() |
2043939531 | ||
![]() |
84a799d27a | ||
![]() |
fe826f5c9c | ||
![]() |
f8b7422294 | ||
![]() |
b343c01216 | ||
![]() |
76968f2f28 | ||
![]() |
1d365f5a0b | ||
![]() |
7b240cbf7e | ||
![]() |
d272a327c7 | ||
![]() |
0c0556a5bc | ||
![]() |
87345c6b2e | ||
![]() |
784e623776 | ||
![]() |
bcb3e9bd53 | ||
![]() |
c30bffbd0f | ||
![]() |
91c41856c5 | ||
![]() |
18c9723308 | ||
![]() |
aee382ed70 | ||
![]() |
6656da5877 | ||
![]() |
09e521727f | ||
![]() |
cab66a2d6e | ||
![]() |
8eabd4f303 | ||
![]() |
e3ced84885 | ||
![]() |
0929ab577d | ||
![]() |
2228733abc | ||
![]() |
e67c94d1bd | ||
![]() |
ae5a661a47 | ||
![]() |
0ff58cdc3e | ||
![]() |
1747c74770 | ||
![]() |
71669cf49c | ||
![]() |
bd327e37eb | ||
![]() |
bdce9a8170 | ||
![]() |
7e5598d084 | ||
![]() |
440fca6535 | ||
![]() |
6635edd35c | ||
![]() |
93ad40efbb | ||
![]() |
27dc8b5b2c | ||
![]() |
3ebdf7ef5e | ||
![]() |
905d4cb091 | ||
![]() |
e7ab05d064 | ||
![]() |
6ec34b42e5 | ||
![]() |
ab785a0906 | ||
![]() |
4541decd40 | ||
![]() |
747a5a53b4 | ||
![]() |
c0643fadca | ||
![]() |
0a31de43c2 | ||
![]() |
96b6947ef2 | ||
![]() |
e7a1065bfc | ||
![]() |
663eecff0c | ||
![]() |
e6125bcf60 | ||
![]() |
0d6c6e7ae7 | ||
![]() |
ae71eb3cae | ||
![]() |
3188197447 | ||
![]() |
6c8b391dab | ||
![]() |
b1248e4901 |
@@ -18,11 +18,6 @@ ij_any_if_brace_force = if_multiline
|
|||||||
ij_any_for_brace_force = if_multiline
|
ij_any_for_brace_force = if_multiline
|
||||||
ij_any_spaces_within_array_initializer_braces = true
|
ij_any_spaces_within_array_initializer_braces = true
|
||||||
|
|
||||||
ij_kotlin_allow_trailing_comma = true
|
|
||||||
ij_kotlin_allow_trailing_comma_on_call_site = true
|
|
||||||
ij_kotlin_method_parameters_wrap = off
|
|
||||||
ij_kotlin_call_parameters_wrap = off
|
|
||||||
|
|
||||||
[*.md]
|
[*.md]
|
||||||
trim_trailing_whitespace = false
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
@@ -31,3 +26,27 @@ indent_size = 2
|
|||||||
|
|
||||||
[*.yml]
|
[*.yml]
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.{kt,kts}]
|
||||||
|
ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL
|
||||||
|
ij_kotlin_continuation_indent_size = 4
|
||||||
|
ij_kotlin_spaces_around_equality_operators = true
|
||||||
|
|
||||||
|
ij_kotlin_allow_trailing_comma = true
|
||||||
|
ij_kotlin_allow_trailing_comma_on_call_site = true
|
||||||
|
|
||||||
|
# Prefer to handle these manually
|
||||||
|
ij_kotlin_method_parameters_wrap = off
|
||||||
|
ij_kotlin_call_parameters_wrap = off
|
||||||
|
ij_kotlin_extends_list_wrap = off
|
||||||
|
|
||||||
|
ktlint_code_style = intellij_idea
|
||||||
|
ktlint_standard_class-naming = disabled
|
||||||
|
ktlint_standard_class-signature = disabled
|
||||||
|
ktlint_standard_function-naming = disabled
|
||||||
|
ktlint_standard_no-wildcard-imports = disabled
|
||||||
|
|
||||||
|
# FIXME: These two are disable right now as they're over-eager in putting things
|
||||||
|
# on the same line. We should set max_line_length and handle this properly.
|
||||||
|
ktlint_standard_function-signature = disabled
|
||||||
|
ktlint_standard_function-expression-body = disabled
|
||||||
|
19
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
19
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@@ -1,17 +1,17 @@
|
|||||||
name: Bug report
|
name: Bug report
|
||||||
description: Report some misbehaviour in the mod
|
description: Report some misbehaviour in the mod
|
||||||
labels: [ bug ]
|
labels: [ bug ]
|
||||||
|
type: bug
|
||||||
body:
|
body:
|
||||||
- type: dropdown
|
- type: dropdown
|
||||||
id: mc-version
|
id: mc-version
|
||||||
attributes:
|
attributes:
|
||||||
label: Minecraft Version
|
label: Minecraft Version
|
||||||
description: What version of Minecraft are you using?
|
description: |
|
||||||
|
What version of Minecraft are you using? If your version is not listed, please try to reproduce on one of the supported versions.
|
||||||
options:
|
options:
|
||||||
- 1.16.x
|
- 1.20.1
|
||||||
- 1.18.x
|
- 1.21.x
|
||||||
- 1.19.x
|
|
||||||
- 1.20.x
|
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: input
|
- type: input
|
||||||
@@ -28,8 +28,7 @@ body:
|
|||||||
label: Details
|
label: Details
|
||||||
description: |
|
description: |
|
||||||
Description of the bug. Please include the following:
|
Description of the bug. Please include the following:
|
||||||
- Logs: These will be located in the `logs/` directory of your Minecraft
|
- Logs: These will be located in the `logs/` directory of your Minecraft instance. This is always useful, even if it doesn't include errors, so please upload this!
|
||||||
instance. Please upload them as a gist or directly into this editor.
|
- Detailed reproduction steps: sometimes I can spot a bug pretty easily, but often it's much more obscure. The more information I have to help reproduce it, the quicker it'll get fixed.
|
||||||
- Detailed reproduction steps: sometimes I can spot a bug pretty easily,
|
|
||||||
but often it's much more obscure. The more information I have to help
|

|
||||||
reproduce it, the quicker it'll get fixed.
|
|
||||||
|
1
.github/ISSUE_TEMPLATE/feature_request.md
vendored
1
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -2,6 +2,7 @@
|
|||||||
name: Feature request
|
name: Feature request
|
||||||
about: Suggest an idea or improvement
|
about: Suggest an idea or improvement
|
||||||
labels: enhancement
|
labels: enhancement
|
||||||
|
type: feature
|
||||||
---
|
---
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
72
.github/workflows/main-ci.yml
vendored
72
.github/workflows/main-ci.yml
vendored
@@ -9,16 +9,16 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: 📥 Clone repository
|
- name: 📥 Clone repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: 📥 Set up Java
|
- name: 📥 Set up Java
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: 17
|
java-version: 21
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
|
|
||||||
- name: 📥 Setup Gradle
|
- name: 📥 Setup Gradle
|
||||||
uses: gradle/gradle-build-action@v2
|
uses: gradle/actions/setup-gradle@v3
|
||||||
with:
|
with:
|
||||||
cache-read-only: ${{ !startsWith(github.ref, 'refs/heads/mc-') }}
|
cache-read-only: ${{ !startsWith(github.ref, 'refs/heads/mc-') }}
|
||||||
|
|
||||||
@@ -30,8 +30,28 @@ jobs:
|
|||||||
- name: ⚒️ Build
|
- name: ⚒️ Build
|
||||||
run: ./gradlew assemble || ./gradlew assemble
|
run: ./gradlew assemble || ./gradlew assemble
|
||||||
|
|
||||||
|
- name: 📦 Prepare Jars
|
||||||
|
run: |
|
||||||
|
# Find the main jar and append the git hash onto it.
|
||||||
|
mkdir -p jars
|
||||||
|
find projects/forge/build/libs projects/fabric/build/libs -type f -regex '.*[0-9.]+\(-SNAPSHOT\)?\.jar$' -exec bash -c 'cp {} "jars/$(basename {} .jar)-$(git rev-parse HEAD).jar"' \;
|
||||||
|
|
||||||
|
- name: 📤 Upload Jar
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: CC-Tweaked
|
||||||
|
path: ./jars
|
||||||
|
|
||||||
|
- name: Cache pre-commit
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ~/.cache/pre-commit
|
||||||
|
key: pre-commit-3|${{ env.pythonLocation }}|${{ hashFiles('.pre-commit-config.yaml') }}
|
||||||
|
|
||||||
- name: 💡 Lint
|
- name: 💡 Lint
|
||||||
uses: pre-commit/action@v3.0.0
|
run: |
|
||||||
|
pipx install pre-commit
|
||||||
|
pre-commit run --show-diff-on-failure --color=always
|
||||||
|
|
||||||
- name: 🧪 Run tests
|
- name: 🧪 Run tests
|
||||||
run: ./gradlew test validateMixinNames checkChangelog
|
run: ./gradlew test validateMixinNames checkChangelog
|
||||||
@@ -42,30 +62,10 @@ jobs:
|
|||||||
- name: 🧪 Run integration tests
|
- name: 🧪 Run integration tests
|
||||||
run: ./gradlew runGametest
|
run: ./gradlew runGametest
|
||||||
|
|
||||||
- name: 🧪 Run client tests
|
|
||||||
run: ./gradlew runGametestClient # Not checkClient, as no point running rendering tests.
|
|
||||||
# These are a little flaky on GH actions: its useful to run them, but don't break the build.
|
|
||||||
continue-on-error: true
|
|
||||||
|
|
||||||
- name: 🧪 Parse test reports
|
- name: 🧪 Parse test reports
|
||||||
run: ./tools/parse-reports.py
|
run: ./tools/parse-reports.py
|
||||||
if: ${{ failure() }}
|
if: ${{ failure() }}
|
||||||
|
|
||||||
- name: 📦 Prepare Jars
|
|
||||||
run: |
|
|
||||||
# Find the main jar and append the git hash onto it.
|
|
||||||
mkdir -p jars
|
|
||||||
find projects/forge/build/libs projects/fabric/build/libs -type f -regex '.*[0-9.]+\(-SNAPSHOT\)?\.jar$' -exec bash -c 'cp {} "jars/$(basename {} .jar)-$(git rev-parse HEAD).jar"' \;
|
|
||||||
|
|
||||||
- name: 📤 Upload Jar
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: CC-Tweaked
|
|
||||||
path: ./jars
|
|
||||||
|
|
||||||
- name: 📤 Upload coverage
|
|
||||||
uses: codecov/codecov-action@v3
|
|
||||||
|
|
||||||
build-core:
|
build-core:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
@@ -81,24 +81,28 @@ jobs:
|
|||||||
runs-on: ${{ matrix.uses }}
|
runs-on: ${{ matrix.uses }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Clone repository
|
- name: 📥 Clone repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Java
|
- name: 📥 Set up Java
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: 17
|
java-version: 21
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
|
|
||||||
- name: Setup Gradle
|
- name: 📥 Setup Gradle
|
||||||
uses: gradle/gradle-build-action@v2
|
uses: gradle/actions/setup-gradle@v3
|
||||||
with:
|
with:
|
||||||
cache-read-only: ${{ !startsWith(github.ref, 'refs/heads/mc-') }}
|
cache-read-only: ${{ !startsWith(github.ref, 'refs/heads/mc-') }}
|
||||||
|
|
||||||
- name: Run tests
|
- name: ⚒️ Build
|
||||||
|
run: |
|
||||||
|
./gradlew --configure-on-demand :core:assemble
|
||||||
|
|
||||||
|
- name: 🧪 Run tests
|
||||||
run: |
|
run: |
|
||||||
./gradlew --configure-on-demand :core:test
|
./gradlew --configure-on-demand :core:test
|
||||||
|
|
||||||
- name: Parse test reports
|
- name: 🧪 Parse test reports
|
||||||
run: python3 ./tools/parse-reports.py
|
run: python3 ./tools/parse-reports.py
|
||||||
if: ${{ failure() }}
|
if: ${{ failure() }}
|
||||||
|
19
.github/workflows/make-doc.sh
vendored
19
.github/workflows/make-doc.sh
vendored
@@ -1,19 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
set -eu
|
|
||||||
|
|
||||||
DEST="${GITHUB_REF#refs/*/}"
|
|
||||||
echo "Uploading docs to https://tweaked.cc/$DEST"
|
|
||||||
|
|
||||||
# Setup ssh key
|
|
||||||
mkdir -p "$HOME/.ssh/"
|
|
||||||
echo "$SSH_KEY" > "$HOME/.ssh/key"
|
|
||||||
chmod 600 "$HOME/.ssh/key"
|
|
||||||
|
|
||||||
# And upload
|
|
||||||
rsync -avc -e "ssh -i $HOME/.ssh/key -o StrictHostKeyChecking=no -p $SSH_PORT" \
|
|
||||||
"$GITHUB_WORKSPACE/projects/web/build/site/" \
|
|
||||||
"$SSH_USER@$SSH_HOST:/$DEST"
|
|
||||||
rsync -avc -e "ssh -i $HOME/.ssh/key -o StrictHostKeyChecking=no -p $SSH_PORT" \
|
|
||||||
"$GITHUB_WORKSPACE/projects/common-api/build/docs/javadoc/" \
|
|
||||||
"$SSH_USER@$SSH_HOST:/$DEST/javadoc"
|
|
36
.github/workflows/make-doc.yml
vendored
36
.github/workflows/make-doc.yml
vendored
@@ -3,8 +3,7 @@ name: Build documentation
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- mc-1.19.x
|
- mc-*
|
||||||
- mc-1.20.x
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
make_doc:
|
make_doc:
|
||||||
@@ -12,30 +11,25 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Clone repository
|
- name: 📥 Clone repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Java
|
- name: 📥 Set up Java
|
||||||
uses: actions/setup-java@v1
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: 17
|
java-version: 21
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
|
|
||||||
- name: Setup Gradle
|
- name: 📥 Setup Gradle
|
||||||
uses: gradle/gradle-build-action@v2
|
uses: gradle/actions/setup-gradle@v3
|
||||||
with:
|
with:
|
||||||
cache-read-only: ${{ !startsWith(github.ref, 'refs/heads/mc-') }}
|
cache-read-only: ${{ !startsWith(github.ref, 'refs/heads/mc-') }}
|
||||||
|
|
||||||
- name: Build with Gradle
|
- name: ⚒️ Generate documentation
|
||||||
run: ./gradlew compileJava --no-daemon || ./gradlew compileJava --no-daemon
|
run: ./gradlew docWebsite --no-daemon
|
||||||
|
|
||||||
- name: Generate documentation
|
- name: 📤 Upload Jar
|
||||||
run: ./gradlew docWebsite :common-api:javadoc --no-daemon
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
- name: Upload documentation
|
name: Documentation
|
||||||
run: .github/workflows/make-doc.sh 2> /dev/null
|
path: ./projects/web/build/site/
|
||||||
env:
|
|
||||||
SSH_KEY: ${{ secrets.SSH_KEY }}
|
|
||||||
SSH_USER: ${{ secrets.SSH_USER }}
|
|
||||||
SSH_HOST: ${{ secrets.SSH_HOST }}
|
|
||||||
SSH_PORT: ${{ secrets.SSH_PORT }}
|
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -7,7 +7,9 @@
|
|||||||
/logs
|
/logs
|
||||||
/build
|
/build
|
||||||
/projects/*/logs
|
/projects/*/logs
|
||||||
|
/projects/fabric/fabricloader.log
|
||||||
/projects/*/build
|
/projects/*/build
|
||||||
|
/projects/*/src/test/generated_tests/
|
||||||
/buildSrc/build
|
/buildSrc/build
|
||||||
/out
|
/out
|
||||||
/buildSrc/out
|
/buildSrc/out
|
||||||
@@ -25,6 +27,7 @@
|
|||||||
*.iml
|
*.iml
|
||||||
.idea
|
.idea
|
||||||
.gradle
|
.gradle
|
||||||
|
.kotlin
|
||||||
*.DS_Store
|
*.DS_Store
|
||||||
|
|
||||||
/.classpath
|
/.classpath
|
||||||
|
26
.gitpod.yml
26
.gitpod.yml
@@ -1,26 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
image:
|
|
||||||
file: config/gitpod/Dockerfile
|
|
||||||
|
|
||||||
ports:
|
|
||||||
- port: 25565
|
|
||||||
onOpen: notify
|
|
||||||
|
|
||||||
vscode:
|
|
||||||
extensions:
|
|
||||||
- eamodio.gitlens
|
|
||||||
- github.vscode-pull-request-github
|
|
||||||
- ms-azuretools.vscode-docker
|
|
||||||
- redhat.java
|
|
||||||
- richardwillis.vscode-gradle
|
|
||||||
- vscjava.vscode-java-debug
|
|
||||||
- vscode.github
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- name: Setup pre-commit hool
|
|
||||||
init: pre-commit install --allow-missing-config
|
|
||||||
- name: Install npm packages
|
|
||||||
init: npm ci
|
|
@@ -6,7 +6,7 @@
|
|||||||
# See https://pre-commit.com/hooks.html for more hooks
|
# See https://pre-commit.com/hooks.html for more hooks
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v4.4.0
|
rev: v5.0.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
@@ -27,7 +27,7 @@ repos:
|
|||||||
exclude: "^(.*\\.(bat)|LICENSE)$"
|
exclude: "^(.*\\.(bat)|LICENSE)$"
|
||||||
|
|
||||||
- repo: https://github.com/fsfe/reuse-tool
|
- repo: https://github.com/fsfe/reuse-tool
|
||||||
rev: v2.1.0
|
rev: v5.0.2
|
||||||
hooks:
|
hooks:
|
||||||
- id: reuse
|
- id: reuse
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ repos:
|
|||||||
name: Check Java codestyle
|
name: Check Java codestyle
|
||||||
files: ".*\\.java$"
|
files: ".*\\.java$"
|
||||||
language: system
|
language: system
|
||||||
entry: ./gradlew checkstyleMain checkstyleTest
|
entry: ./gradlew checkstyle
|
||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
require_serial: true
|
require_serial: true
|
||||||
- id: illuaminate
|
- id: illuaminate
|
||||||
@@ -58,6 +58,7 @@ repos:
|
|||||||
exclude: |
|
exclude: |
|
||||||
(?x)^(
|
(?x)^(
|
||||||
projects/[a-z]+/src/generated|
|
projects/[a-z]+/src/generated|
|
||||||
|
projects/[a-z]+/src/examples/generatedResources|
|
||||||
projects/core/src/test/resources/test-rom/data/json-parsing/|
|
projects/core/src/test/resources/test-rom/data/json-parsing/|
|
||||||
.*\.dfpwm
|
.*\.dfpwm
|
||||||
)
|
)
|
||||||
|
87
.reuse/dep5
87
.reuse/dep5
@@ -1,87 +0,0 @@
|
|||||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
|
||||||
Source: https://github.com/cc-tweaked/cc-tweaked
|
|
||||||
Upstream-Name: CC: Tweaked
|
|
||||||
Upstream-Contact: Jonathan Coates <git@squiddev.cc>
|
|
||||||
|
|
||||||
Files:
|
|
||||||
projects/common/src/main/resources/assets/computercraft/sounds.json
|
|
||||||
projects/common/src/main/resources/assets/computercraft/sounds/empty.ogg
|
|
||||||
projects/common/src/testMod/resources/data/cctest/computercraft/turtle_upgrades/*
|
|
||||||
projects/common/src/testMod/resources/data/cctest/structures/*
|
|
||||||
projects/fabric/src/generated/*
|
|
||||||
projects/forge/src/generated/*
|
|
||||||
projects/web/src/export/index.json
|
|
||||||
projects/web/src/export/items/minecraft/*
|
|
||||||
Comment: Generated/data files are CC0.
|
|
||||||
Copyright: The CC: Tweaked Developers
|
|
||||||
License: CC0-1.0
|
|
||||||
|
|
||||||
Files:
|
|
||||||
doc/images/*
|
|
||||||
package.json
|
|
||||||
package-lock.json
|
|
||||||
projects/common/src/client/resources/computercraft-client.mixins.json
|
|
||||||
projects/common/src/main/resources/assets/minecraft/shaders/core/computercraft/monitor_tbo.json
|
|
||||||
projects/common/src/main/resources/computercraft.mixins.json
|
|
||||||
projects/common/src/testMod/resources/computercraft-gametest.mixins.json
|
|
||||||
projects/common/src/testMod/resources/data/computercraft/loot_tables/treasure_disk.json
|
|
||||||
projects/common/src/testMod/resources/pack.mcmeta
|
|
||||||
projects/core/src/main/resources/data/computercraft/lua/rom/modules/command/.ignoreme
|
|
||||||
projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/.ignoreme
|
|
||||||
projects/core/src/main/resources/data/computercraft/lua/rom/modules/turtle/.ignoreme
|
|
||||||
projects/core/src/main/resources/data/computercraft/lua/rom/motd.txt
|
|
||||||
projects/fabric-api/src/main/modJson/fabric.mod.json
|
|
||||||
projects/fabric/src/client/resources/computercraft-client.fabric.mixins.json
|
|
||||||
projects/fabric/src/main/resources/computercraft.fabric.mixins.json
|
|
||||||
projects/fabric/src/main/resources/fabric.mod.json
|
|
||||||
projects/fabric/src/testMod/resources/computercraft-gametest.fabric.mixins.json
|
|
||||||
projects/fabric/src/testMod/resources/fabric.mod.json
|
|
||||||
projects/forge/src/client/resources/computercraft-client.forge.mixins.json
|
|
||||||
projects/web/src/mount/.settings
|
|
||||||
projects/web/src/mount/example.nfp
|
|
||||||
projects/web/src/mount/example.nft
|
|
||||||
projects/web/src/mount/expr_template.lua
|
|
||||||
projects/web/tsconfig.json
|
|
||||||
Comment: Several assets where it's inconvenient to create a .license file.
|
|
||||||
Copyright: The CC: Tweaked Developers
|
|
||||||
License: MPL-2.0
|
|
||||||
|
|
||||||
Files:
|
|
||||||
doc/logo.png
|
|
||||||
doc/logo-darkmode.png
|
|
||||||
projects/common/src/main/resources/assets/computercraft/models/*
|
|
||||||
projects/common/src/main/resources/assets/computercraft/textures/*
|
|
||||||
projects/common/src/main/resources/pack.mcmeta
|
|
||||||
projects/common/src/main/resources/pack.png
|
|
||||||
projects/core/src/main/resources/data/computercraft/lua/rom/autorun/.ignoreme
|
|
||||||
projects/core/src/main/resources/data/computercraft/lua/rom/help/*
|
|
||||||
projects/core/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/levels/*
|
|
||||||
projects/web/src/export/items/computercraft/*
|
|
||||||
Comment: Bulk-license original assets as CCPL.
|
|
||||||
Copyright: 2011 Daniel Ratcliffe
|
|
||||||
License: LicenseRef-CCPL
|
|
||||||
|
|
||||||
Files:
|
|
||||||
projects/common/src/main/resources/assets/computercraft/lang/*
|
|
||||||
Comment: Community-contributed license files
|
|
||||||
Copyright: 2017 The CC: Tweaked Developers
|
|
||||||
License: LicenseRef-CCPL
|
|
||||||
|
|
||||||
Files:
|
|
||||||
.github/*
|
|
||||||
Comment:
|
|
||||||
GitHub build scripts are CC0. While we could add a header to each file,
|
|
||||||
it's unclear if it will break actions or issue templates in some way.
|
|
||||||
Copyright: Jonathan Coates <git@squiddev.cc>
|
|
||||||
License: CC0-1.0
|
|
||||||
|
|
||||||
Files:
|
|
||||||
gradle/wrapper/*
|
|
||||||
gradlew
|
|
||||||
gradlew.bat
|
|
||||||
Copyright: Gradle Inc
|
|
||||||
License: Apache-2.0
|
|
||||||
|
|
||||||
Files: projects/core/src/test/resources/test-rom/data/json-parsing/*
|
|
||||||
Copyright: 2016 Nicolas Seriot
|
|
||||||
License: MIT
|
|
@@ -22,16 +22,15 @@ If you have a bug, suggestion, or other feedback, the best thing to do is [file
|
|||||||
use the issue templates - they provide a useful hint on what information to provide.
|
use the issue templates - they provide a useful hint on what information to provide.
|
||||||
|
|
||||||
## Translations
|
## Translations
|
||||||
Translations are managed through [Weblate], an online interface for managing language strings. This is synced
|
Translations are managed through [CrowdIn], an online interface for managing language strings.
|
||||||
automatically with GitHub, so please don't submit PRs adding/changing translations!
|
|
||||||
|
|
||||||
## Setting up a development environment
|
## Setting up a development environment
|
||||||
In order to develop CC: Tweaked, you'll need to download the source code and then run it.
|
In order to develop CC: Tweaked, you'll need to download the source code and then run it.
|
||||||
|
|
||||||
- Make sure you've got the following software installed:
|
- Make sure you've got the following software installed:
|
||||||
- Java Development Kit (JDK) installed. This can be downloaded from [Adoptium].
|
- Java Development Kit 21 (JDK). This can be downloaded from [Adoptium].
|
||||||
- [Git](https://git-scm.com/).
|
- [Git](https://git-scm.com/).
|
||||||
- If you want to work on documentation, [NodeJS][node].
|
- [NodeJS 20 or later][node].
|
||||||
|
|
||||||
- Download CC: Tweaked's source code:
|
- Download CC: Tweaked's source code:
|
||||||
```
|
```
|
||||||
@@ -49,9 +48,12 @@ If you want to run CC:T in a normal Minecraft instance, run `./gradlew assemble`
|
|||||||
`projects/forge/build/libs` (for Forge) or `projects/fabric/build/libs` (for Fabric).
|
`projects/forge/build/libs` (for Forge) or `projects/fabric/build/libs` (for Fabric).
|
||||||
|
|
||||||
## Developing CC: Tweaked
|
## Developing CC: Tweaked
|
||||||
Before making any major changes to CC: Tweaked, I'd recommend you have a read of the [the architecture
|
Before making any major changes to CC: Tweaked, I'd recommend starting opening an issue or starting a discussion on
|
||||||
document][architecture] first. While it's not a comprehensive document, it gives a good hint of where you should start
|
GitHub first. It's often helpful to discuss features before spending time developing them!
|
||||||
looking to make your changes. As always, if you're not sure, [do ask the community][community]!
|
|
||||||
|
Once you're ready to start programming, have a read of the [the architecture document][architecture] first. While it's
|
||||||
|
not a comprehensive document, it gives a good hint of where you should start looking to make your changes. As always, if
|
||||||
|
you're not sure, [do ask the community][community]!
|
||||||
|
|
||||||
### Testing
|
### Testing
|
||||||
When making larger changes, it may be useful to write a test to make sure your code works as expected.
|
When making larger changes, it may be useful to write a test to make sure your code works as expected.
|
||||||
@@ -86,8 +88,8 @@ You'll first need to [set up a development environment as above](#setting-up-a-d
|
|||||||
|
|
||||||
Once this is set up, you can now run `./gradlew docWebsite`. This generates documentation from our Lua and Java code,
|
Once this is set up, you can now run `./gradlew docWebsite`. This generates documentation from our Lua and Java code,
|
||||||
writing the resulting HTML into `./projects/web/build/site`, which can then be opened in a browser. When iterating on
|
writing the resulting HTML into `./projects/web/build/site`, which can then be opened in a browser. When iterating on
|
||||||
documentation, you can instead run `./gradlew docWebsite -t`, which will rebuild documentation every time you change a
|
documentation, you can instead run `./gradlew :web:assemble -x :web:compileTeaVM -t`, which will rebuild documentation
|
||||||
file.
|
every time you change a file.
|
||||||
|
|
||||||
Documentation is built using [illuaminate] which, while not currently documented (somewhat ironic), is largely the same
|
Documentation is built using [illuaminate] which, while not currently documented (somewhat ironic), is largely the same
|
||||||
as [ldoc][ldoc]. Documentation comments are written in Markdown, though note that we do not support many GitHub-specific
|
as [ldoc][ldoc]. Documentation comments are written in Markdown, though note that we do not support many GitHub-specific
|
||||||
@@ -100,12 +102,11 @@ about how you can build on that until you've covered everything!
|
|||||||
[new-issue]: https://github.com/cc-tweaked/CC-Tweaked/issues/new/choose "Create a new issue"
|
[new-issue]: https://github.com/cc-tweaked/CC-Tweaked/issues/new/choose "Create a new issue"
|
||||||
[community]: README.md#community "Get in touch with the community."
|
[community]: README.md#community "Get in touch with the community."
|
||||||
[Adoptium]: https://adoptium.net/temurin/releases?version=17 "Download OpenJDK 17"
|
[Adoptium]: https://adoptium.net/temurin/releases?version=17 "Download OpenJDK 17"
|
||||||
[checkstyle]: https://checkstyle.org/
|
|
||||||
[illuaminate]: https://github.com/SquidDev/illuaminate/ "Illuaminate on GitHub"
|
[illuaminate]: https://github.com/SquidDev/illuaminate/ "Illuaminate on GitHub"
|
||||||
[weblate]: https://i18n.tweaked.cc/projects/cc-tweaked/minecraft/ "CC: Tweaked weblate instance"
|
|
||||||
[docs]: https://tweaked.cc/ "CC: Tweaked documentation"
|
[docs]: https://tweaked.cc/ "CC: Tweaked documentation"
|
||||||
[ldoc]: http://stevedonovan.github.io/ldoc/ "ldoc, a Lua documentation generator."
|
[ldoc]: http://stevedonovan.github.io/ldoc/ "ldoc, a Lua documentation generator."
|
||||||
[mc-test]: https://www.youtube.com/watch?v=vXaWOJTCYNg
|
[mc-test]: https://www.youtube.com/watch?v=vXaWOJTCYNg
|
||||||
[busted]: https://github.com/Olivine-Labs/busted "busted: Elegant Lua unit testing."
|
[busted]: https://github.com/Olivine-Labs/busted "busted: Elegant Lua unit testing."
|
||||||
[node]: https://nodejs.org/en/ "Node.js"
|
[node]: https://nodejs.org/en/ "Node.js"
|
||||||
[architecture]: projects/ARCHITECTURE.md
|
[architecture]: projects/ARCHITECTURE.md
|
||||||
|
[Crowdin]: https://crowdin.com/project/cc-tweaked/
|
||||||
|
38
README.md
38
README.md
@@ -11,14 +11,13 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
</picture>
|
</picture>
|
||||||
|
|
||||||
[](https://github.com/cc-tweaked/CC-Tweaked/actions "Current build status")
|
[](https://github.com/cc-tweaked/CC-Tweaked/actions "Current build status")
|
||||||
[][CurseForge]
|
|
||||||
[][Modrinth]
|
[][Modrinth]
|
||||||
|
|
||||||
CC: Tweaked is a mod for Minecraft which adds programmable computers, turtles and more to the game. A fork of the
|
CC: Tweaked is a mod for Minecraft which adds programmable computers, turtles and more to the game. A fork of the
|
||||||
much-beloved [ComputerCraft], it continues its legacy with improved performance and stability, along with a wealth of
|
much-beloved [ComputerCraft], it continues its legacy with improved performance and stability, along with a wealth of
|
||||||
new features.
|
new features.
|
||||||
|
|
||||||
CC: Tweaked can be installed from [CurseForge] or [Modrinth]. It runs on both [Minecraft Forge] and [Fabric].
|
CC: Tweaked can be installed from [Modrinth]. It runs on both [Minecraft Forge] and [Fabric].
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
Any contribution is welcome, be that using the mod, reporting bugs or contributing code. If you want to get started
|
Any contribution is welcome, be that using the mod, reporting bugs or contributing code. If you want to get started
|
||||||
@@ -26,8 +25,9 @@ developing the mod, [check out the instructions here](CONTRIBUTING.md#developing
|
|||||||
|
|
||||||
## Community
|
## Community
|
||||||
If you need help getting started with CC: Tweaked, want to show off your latest project, or just want to chat about
|
If you need help getting started with CC: Tweaked, want to show off your latest project, or just want to chat about
|
||||||
ComputerCraft, do check out our [forum] and [GitHub discussions page][GitHub discussions]! There's also a fairly
|
ComputerCraft, do check out our [GitHub discussions page][GitHub discussions]! There's also a fairly populated,
|
||||||
populated, albeit quiet [IRC channel][irc], if that's more your cup of tea.
|
albeit quiet IRC channel on [EsperNet], if that's more your cup of tea. You can join `#computercraft` through your
|
||||||
|
desktop client, or online using [KiwiIRC].
|
||||||
|
|
||||||
We also host fairly comprehensive documentation at [tweaked.cc](https://tweaked.cc/ "The CC: Tweaked website").
|
We also host fairly comprehensive documentation at [tweaked.cc](https://tweaked.cc/ "The CC: Tweaked website").
|
||||||
|
|
||||||
@@ -39,10 +39,9 @@ on is present.
|
|||||||
```groovy
|
```groovy
|
||||||
repositories {
|
repositories {
|
||||||
maven {
|
maven {
|
||||||
url "https://squiddev.cc/maven/"
|
url "https://maven.squiddev.cc"
|
||||||
content {
|
content {
|
||||||
includeGroup("cc.tweaked")
|
includeGroup("cc.tweaked")
|
||||||
includeModule("org.squiddev", "Cobalt")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -52,9 +51,8 @@ dependencies {
|
|||||||
compileOnly("cc.tweaked:cc-tweaked-$mcVersion-common-api:$cctVersion")
|
compileOnly("cc.tweaked:cc-tweaked-$mcVersion-common-api:$cctVersion")
|
||||||
|
|
||||||
// Forge Gradle
|
// Forge Gradle
|
||||||
compileOnly("cc.tweaked:cc-tweaked-$mcVersion-core-api:$cctVersion")
|
compileOnly("cc.tweaked:cc-tweaked-$mcVersion-forge-api:$cctVersion")
|
||||||
compileOnly(fg.deobf("cc.tweaked:cc-tweaked-$mcVersion-forge-api:$cctVersion"))
|
runtimeOnly("cc.tweaked:cc-tweaked-$mcVersion-forge:$cctVersion")
|
||||||
runtimeOnly(fg.deobf("cc.tweaked:cc-tweaked-$mcVersion-forge:$cctVersion"))
|
|
||||||
|
|
||||||
// Fabric Loom
|
// Fabric Loom
|
||||||
modCompileOnly("cc.tweaked:cc-tweaked-$mcVersion-fabric-api:$cctVersion")
|
modCompileOnly("cc.tweaked:cc-tweaked-$mcVersion-fabric-api:$cctVersion")
|
||||||
@@ -62,31 +60,17 @@ dependencies {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
When using ForgeGradle, you may also need to add the following:
|
|
||||||
|
|
||||||
```groovy
|
|
||||||
minecraft {
|
|
||||||
runs {
|
|
||||||
configureEach {
|
|
||||||
property 'mixin.env.remapRefMap', 'true'
|
|
||||||
property 'mixin.env.refMapRemappingFile', "${buildDir}/createSrgToMcp/output.srg"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
You should also be careful to only use classes within the `dan200.computercraft.api` package. Non-API classes are
|
You should also be careful to only use classes within the `dan200.computercraft.api` package. Non-API classes are
|
||||||
subject to change at any point. If you depend on functionality outside the API, file an issue, and we can look into
|
subject to change at any point. If you depend on functionality outside the API (or need to mixin to CC:T), please file
|
||||||
exposing more features.
|
an issue to let me know!
|
||||||
|
|
||||||
We bundle the API sources with the jar, so documentation should be easily viewable within your editor. Alternatively,
|
We bundle the API sources with the jar, so documentation should be easily viewable within your editor. Alternatively,
|
||||||
the generated documentation [can be browsed online](https://tweaked.cc/javadoc/).
|
the generated documentation [can be browsed online](https://tweaked.cc/javadoc/).
|
||||||
|
|
||||||
[computercraft]: https://github.com/dan200/ComputerCraft "ComputerCraft on GitHub"
|
[computercraft]: https://github.com/dan200/ComputerCraft "ComputerCraft on GitHub"
|
||||||
[curseforge]: https://minecraft.curseforge.com/projects/cc-tweaked "Download CC: Tweaked from CurseForge"
|
|
||||||
[modrinth]: https://modrinth.com/mod/gu7yAYhd "Download CC: Tweaked from Modrinth"
|
[modrinth]: https://modrinth.com/mod/gu7yAYhd "Download CC: Tweaked from Modrinth"
|
||||||
[Minecraft Forge]: https://files.minecraftforge.net/ "Download Minecraft Forge."
|
[Minecraft Forge]: https://files.minecraftforge.net/ "Download Minecraft Forge."
|
||||||
[Fabric]: https://fabricmc.net/use/installer/ "Download Fabric."
|
[Fabric]: https://fabricmc.net/use/installer/ "Download Fabric."
|
||||||
[forum]: https://forums.computercraft.cc/
|
|
||||||
[GitHub Discussions]: https://github.com/cc-tweaked/CC-Tweaked/discussions
|
[GitHub Discussions]: https://github.com/cc-tweaked/CC-Tweaked/discussions
|
||||||
[IRC]: https://webchat.esper.net/?channels=computercraft "#computercraft on EsperNet"
|
[EsperNet]: https://www.esper.net/
|
||||||
|
[KiwiIRC]: https://kiwiirc.com/nextclient/#irc://irc.esper.net:+6697/#computercraft "#computercraft on EsperNet"
|
||||||
|
100
REUSE.toml
Normal file
100
REUSE.toml
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2017 The CC: Tweaked Developers
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
version = 1
|
||||||
|
SPDX-PackageName = "CC: Tweaked"
|
||||||
|
SPDX-PackageSupplier = "Jonathan Coates <git@squiddev.cc>"
|
||||||
|
SPDX-PackageDownloadLocation = "https://github.com/cc-tweaked/cc-tweaked"
|
||||||
|
|
||||||
|
[[annotations]]
|
||||||
|
SPDX-FileCopyrightText = "The CC: Tweaked Developers"
|
||||||
|
SPDX-License-Identifier = "CC0-1.0"
|
||||||
|
path = [
|
||||||
|
# Generated/data files are CC0.
|
||||||
|
"gradle/gradle-daemon-jvm.properties",
|
||||||
|
"projects/common/src/main/resources/assets/computercraft/sounds.json",
|
||||||
|
"projects/common/src/main/resources/assets/computercraft/sounds/empty.ogg",
|
||||||
|
"projects/common/src/testMod/resources/data/cctest/computercraft/turtle_upgrade/**",
|
||||||
|
"projects/common/src/testMod/resources/data/cctest/structures/**",
|
||||||
|
"projects/*/src/generated/**",
|
||||||
|
"projects/web/src/htmlTransform/export/index.json",
|
||||||
|
"projects/web/src/htmlTransform/export/items/minecraft/**",
|
||||||
|
# GitHub build scripts are CC0. While we could add a header to each file,
|
||||||
|
# it's unclear if it will break actions or issue templates in some way.
|
||||||
|
".github/**",
|
||||||
|
# Example mod is CC0.
|
||||||
|
"projects/*/src/examples/**"
|
||||||
|
]
|
||||||
|
|
||||||
|
[[annotations]]
|
||||||
|
# Several assets where it's inconvenient to create a .license file.
|
||||||
|
SPDX-FileCopyrightText = "The CC: Tweaked Developers"
|
||||||
|
SPDX-License-Identifier = "MPL-2.0"
|
||||||
|
path = [
|
||||||
|
"doc/images/**",
|
||||||
|
"package.json",
|
||||||
|
"package-lock.json",
|
||||||
|
"projects/*/src/*/resources/*.mixins.json",
|
||||||
|
"projects/fabric/src/*/resources/fabric.mod.json",
|
||||||
|
"projects/common/src/main/resources/assets/minecraft/shaders/core/computercraft/monitor_tbo.json",
|
||||||
|
"projects/common/src/testMod/resources/data/computercraft/loot_tables/treasure_disk.json",
|
||||||
|
"projects/common/src/testMod/resources/pack.mcmeta",
|
||||||
|
"projects/core/src/main/resources/data/computercraft/lua/rom/modules/command/.ignoreme",
|
||||||
|
"projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/.ignoreme",
|
||||||
|
"projects/core/src/main/resources/data/computercraft/lua/rom/modules/turtle/.ignoreme",
|
||||||
|
"projects/core/src/main/resources/data/computercraft/lua/rom/motd.txt",
|
||||||
|
"projects/web/src/frontend/mount/.settings",
|
||||||
|
"projects/web/src/frontend/mount/example.nfp",
|
||||||
|
"projects/web/src/frontend/mount/example.nft",
|
||||||
|
"projects/web/src/frontend/mount/expr_template.lua",
|
||||||
|
"projects/web/tsconfig.json",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[annotations]]
|
||||||
|
# Bulk-license original assets as CCPL.
|
||||||
|
SPDX-FileCopyrightText = "2011 Daniel Ratcliffe"
|
||||||
|
SPDX-License-Identifier = "LicenseRef-CCPL"
|
||||||
|
path = [
|
||||||
|
"doc/logo.png",
|
||||||
|
"doc/logo-darkmode.png",
|
||||||
|
"projects/common/src/main/resources/assets/computercraft/models/**",
|
||||||
|
"projects/common/src/main/resources/assets/computercraft/textures/**",
|
||||||
|
"projects/common/src/main/resources/pack.mcmeta",
|
||||||
|
"projects/common/src/main/resources/pack.png",
|
||||||
|
"projects/core/src/main/resources/assets/computercraft/textures/gui/term_font.png",
|
||||||
|
"projects/core/src/main/resources/data/computercraft/lua/rom/autorun/.ignoreme",
|
||||||
|
"projects/core/src/main/resources/data/computercraft/lua/rom/help/**",
|
||||||
|
"projects/core/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/levels/**",
|
||||||
|
"projects/web/src/htmlTransform/export/items/computercraft/**",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[annotations]]
|
||||||
|
# Community-contributed language files
|
||||||
|
SPDX-FileCopyrightText = "2017 The CC: Tweaked Developers"
|
||||||
|
SPDX-License-Identifier = "LicenseRef-CCPL"
|
||||||
|
path = [
|
||||||
|
"projects/common/src/main/resources/assets/computercraft/lang/cs_cz.json",
|
||||||
|
"projects/common/src/main/resources/assets/computercraft/lang/ko_kr.json",
|
||||||
|
"projects/common/src/main/resources/assets/computercraft/lang/pl_pl.json",
|
||||||
|
"projects/common/src/main/resources/assets/computercraft/lang/pt_br.json",
|
||||||
|
"projects/common/src/main/resources/assets/computercraft/lang/ru_ru.json",
|
||||||
|
"projects/common/src/main/resources/assets/computercraft/lang/uk_ua.json",
|
||||||
|
"projects/common/src/main/resources/assets/computercraft/lang/zh_cn.json",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[annotations]]
|
||||||
|
# Community-contributed language files
|
||||||
|
SPDX-FileCopyrightText = "2017 The CC: Tweaked Developers"
|
||||||
|
SPDX-License-Identifier = "MPL-2.0"
|
||||||
|
path = "projects/common/src/main/resources/assets/computercraft/lang/**"
|
||||||
|
|
||||||
|
[[annotations]]
|
||||||
|
path = ["gradle/wrapper/**"]
|
||||||
|
SPDX-FileCopyrightText = "Gradle Inc"
|
||||||
|
SPDX-License-Identifier = "Apache-2.0"
|
||||||
|
|
||||||
|
[[annotations]]
|
||||||
|
path = "projects/core/src/test/resources/test-rom/data/json-parsing/**"
|
||||||
|
SPDX-FileCopyrightText = "2016 Nicolas Seriot"
|
||||||
|
SPDX-License-Identifier = "MIT"
|
@@ -2,13 +2,18 @@
|
|||||||
//
|
//
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
import org.jetbrains.gradle.ext.compiler
|
import cc.tweaked.gradle.JUnitExt
|
||||||
import org.jetbrains.gradle.ext.settings
|
import net.fabricmc.loom.api.LoomGradleExtensionAPI
|
||||||
|
import net.fabricmc.loom.util.gradle.SourceSetHelper
|
||||||
|
import org.jetbrains.gradle.ext.*
|
||||||
|
import org.jetbrains.gradle.ext.Application
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
publishing
|
publishing
|
||||||
alias(libs.plugins.taskTree)
|
alias(libs.plugins.taskTree)
|
||||||
alias(libs.plugins.githubRelease)
|
alias(libs.plugins.githubRelease)
|
||||||
|
alias(libs.plugins.gradleVersions)
|
||||||
|
alias(libs.plugins.versionCatalogUpdate)
|
||||||
id("org.jetbrains.gradle.plugin.idea-ext")
|
id("org.jetbrains.gradle.plugin.idea-ext")
|
||||||
id("cc-tweaked")
|
id("cc-tweaked")
|
||||||
}
|
}
|
||||||
@@ -19,25 +24,80 @@ val mcVersion: String by extra
|
|||||||
|
|
||||||
githubRelease {
|
githubRelease {
|
||||||
token(findProperty("githubApiKey") as String? ?: "")
|
token(findProperty("githubApiKey") as String? ?: "")
|
||||||
owner.set("cc-tweaked")
|
owner = "cc-tweaked"
|
||||||
repo.set("CC-Tweaked")
|
repo = "CC-Tweaked"
|
||||||
targetCommitish.set(cct.gitBranch)
|
targetCommitish = cct.gitBranch
|
||||||
|
|
||||||
tagName.set("v$mcVersion-$modVersion")
|
tagName = "v$mcVersion-$modVersion"
|
||||||
releaseName.set("[$mcVersion] $modVersion")
|
releaseName = "[$mcVersion] $modVersion"
|
||||||
body.set(
|
body = provider {
|
||||||
provider {
|
"## " + project(":core").file("src/main/resources/data/computercraft/lua/rom/help/whatsnew.md")
|
||||||
"## " + project(":core").file("src/main/resources/data/computercraft/lua/rom/help/whatsnew.md")
|
.readLines()
|
||||||
.readLines()
|
.takeWhile { it != "Type \"help changelog\" to see the full version history." }
|
||||||
.takeWhile { it != "Type \"help changelog\" to see the full version history." }
|
.joinToString("\n").trim()
|
||||||
.joinToString("\n").trim()
|
}
|
||||||
},
|
prerelease = isUnstable
|
||||||
)
|
|
||||||
prerelease.set(isUnstable)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.publish { dependsOn(tasks.githubRelease) }
|
tasks.publish { dependsOn(tasks.githubRelease) }
|
||||||
|
|
||||||
|
idea.project.settings.runConfigurations {
|
||||||
|
register<JUnitExt>("Core Tests") {
|
||||||
|
vmParameters = "-ea"
|
||||||
|
moduleName = "${idea.project.name}.core.test"
|
||||||
|
packageName = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
register<JUnitExt>("CraftOS Tests") {
|
||||||
|
vmParameters = "-ea"
|
||||||
|
moduleName = "${idea.project.name}.core.test"
|
||||||
|
className = "dan200.computercraft.core.ComputerTestDelegate"
|
||||||
|
}
|
||||||
|
|
||||||
|
register<JUnitExt>("CraftOS Tests (Fast)") {
|
||||||
|
vmParameters = "-ea -Dcc.skip_keywords=slow"
|
||||||
|
moduleName = "${idea.project.name}.core.test"
|
||||||
|
className = "dan200.computercraft.core.ComputerTestDelegate"
|
||||||
|
}
|
||||||
|
|
||||||
|
register<JUnitExt>("Common Tests") {
|
||||||
|
vmParameters = "-ea"
|
||||||
|
moduleName = "${idea.project.name}.common.test"
|
||||||
|
packageName = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
register<JUnitExt>("Fabric Tests") {
|
||||||
|
val fabricProject = evaluationDependsOn(":fabric")
|
||||||
|
val classPathGroup = fabricProject.extensions.getByType<LoomGradleExtensionAPI>().mods
|
||||||
|
.joinToString(File.pathSeparator + File.pathSeparator) { modSettings ->
|
||||||
|
SourceSetHelper.getClasspath(modSettings, project).joinToString(File.pathSeparator) { it.absolutePath }
|
||||||
|
}
|
||||||
|
|
||||||
|
vmParameters = "-ea -Dfabric.classPathGroups=$classPathGroup"
|
||||||
|
moduleName = "${idea.project.name}.fabric.test"
|
||||||
|
packageName = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
register<JUnitExt>("Forge Tests") {
|
||||||
|
vmParameters = "-ea"
|
||||||
|
moduleName = "${idea.project.name}.forge.test"
|
||||||
|
packageName = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
register<Application>("Standalone") {
|
||||||
|
moduleName = "${idea.project.name}.standalone.main"
|
||||||
|
mainClass = "cc.tweaked.standalone.Main"
|
||||||
|
programParameters = "--resources=projects/core/src/main/resources --term=80x30 --allow-local-domains"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build with the IntelliJ, rather than through Gradle. This may require setting the "Compiler Output" option in
|
||||||
|
// "Project Structure".
|
||||||
|
idea.project.settings.delegateActions {
|
||||||
|
delegateBuildRunToGradle = false
|
||||||
|
testRunner = ActionDelegationConfig.TestRunner.PLATFORM
|
||||||
|
}
|
||||||
|
|
||||||
idea.project.settings.compiler.javac {
|
idea.project.settings.compiler.javac {
|
||||||
// We want ErrorProne to be present when compiling via IntelliJ, as it offers some helpful warnings
|
// We want ErrorProne to be present when compiling via IntelliJ, as it offers some helpful warnings
|
||||||
// and errors. Loop through our source sets and find the appropriate flags.
|
// and errors. Loop through our source sets and find the appropriate flags.
|
||||||
@@ -54,3 +114,9 @@ idea.project.settings.compiler.javac {
|
|||||||
}
|
}
|
||||||
.toMap()
|
.toMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
versionCatalogUpdate {
|
||||||
|
sortByKey = false
|
||||||
|
pin { versions.addAll("fastutil", "guava", "netty", "slf4j") }
|
||||||
|
keep { keepUnusedLibraries = true }
|
||||||
|
}
|
||||||
|
@@ -5,6 +5,8 @@
|
|||||||
plugins {
|
plugins {
|
||||||
`java-gradle-plugin`
|
`java-gradle-plugin`
|
||||||
`kotlin-dsl`
|
`kotlin-dsl`
|
||||||
|
alias(libs.plugins.gradleVersions)
|
||||||
|
alias(libs.plugins.versionCatalogUpdate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Duplicated in settings.gradle.kts
|
// Duplicated in settings.gradle.kts
|
||||||
@@ -12,25 +14,10 @@ repositories {
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
gradlePluginPortal()
|
gradlePluginPortal()
|
||||||
|
|
||||||
maven("https://maven.minecraftforge.net") {
|
maven("https://maven.neoforged.net") {
|
||||||
name = "Forge"
|
name = "NeoForge"
|
||||||
content {
|
content {
|
||||||
includeGroup("net.minecraftforge")
|
includeGroup("net.neoforged")
|
||||||
includeGroup("net.minecraftforge.gradle")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
maven("https://maven.parchmentmc.org") {
|
|
||||||
name = "Librarian"
|
|
||||||
content {
|
|
||||||
includeGroupByRegex("^org\\.parchmentmc.*")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
maven("https://repo.spongepowered.org/repository/maven-public/") {
|
|
||||||
name = "Sponge"
|
|
||||||
content {
|
|
||||||
includeGroup("org.spongepowered")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,6 +27,13 @@ repositories {
|
|||||||
includeGroup("net.fabricmc")
|
includeGroup("net.fabricmc")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
maven("https://maven.squiddev.cc") {
|
||||||
|
name = "SquidDev"
|
||||||
|
content {
|
||||||
|
includeGroup("cc.tweaked.vanilla-extract")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@@ -47,13 +41,11 @@ dependencies {
|
|||||||
implementation(libs.kotlin.plugin)
|
implementation(libs.kotlin.plugin)
|
||||||
implementation(libs.spotless)
|
implementation(libs.spotless)
|
||||||
|
|
||||||
implementation(libs.curseForgeGradle)
|
|
||||||
implementation(libs.fabric.loom)
|
implementation(libs.fabric.loom)
|
||||||
implementation(libs.forgeGradle)
|
implementation(libs.ideaExt)
|
||||||
implementation(libs.librarian)
|
|
||||||
implementation(libs.minotaur)
|
implementation(libs.minotaur)
|
||||||
implementation(libs.vineflower)
|
implementation(libs.modDevGradle)
|
||||||
implementation(libs.vanillaGradle)
|
implementation(libs.vanillaExtract)
|
||||||
}
|
}
|
||||||
|
|
||||||
gradlePlugin {
|
gradlePlugin {
|
||||||
@@ -74,3 +66,9 @@ gradlePlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
versionCatalogUpdate {
|
||||||
|
sortByKey = false
|
||||||
|
keep { keepUnusedLibraries = true }
|
||||||
|
catalogFile = file("../gradle/libs.versions.toml")
|
||||||
|
}
|
||||||
|
@@ -4,15 +4,11 @@
|
|||||||
|
|
||||||
/** Default configuration for Fabric projects. */
|
/** Default configuration for Fabric projects. */
|
||||||
|
|
||||||
import cc.tweaked.gradle.CCTweakedExtension
|
import cc.tweaked.gradle.*
|
||||||
import cc.tweaked.gradle.CCTweakedPlugin
|
|
||||||
import cc.tweaked.gradle.IdeaRunConfigurations
|
|
||||||
import cc.tweaked.gradle.MinecraftConfigurations
|
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
`java-library`
|
`java-library`
|
||||||
id("fabric-loom")
|
id("fabric-loom")
|
||||||
id("io.github.juuxel.loom-vineflower")
|
|
||||||
id("cc-tweaked.java-convention")
|
id("cc-tweaked.java-convention")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +27,7 @@ repositories {
|
|||||||
|
|
||||||
loom {
|
loom {
|
||||||
splitEnvironmentSourceSets()
|
splitEnvironmentSourceSets()
|
||||||
splitModDependencies.set(true)
|
splitModDependencies = true
|
||||||
}
|
}
|
||||||
|
|
||||||
MinecraftConfigurations.setup(project)
|
MinecraftConfigurations.setup(project)
|
||||||
@@ -68,3 +64,9 @@ dependencies {
|
|||||||
tasks.ideaSyncTask {
|
tasks.ideaSyncTask {
|
||||||
doLast { IdeaRunConfigurations(project).patch() }
|
doLast { IdeaRunConfigurations(project).patch() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.named("checkDependencyConsistency", DependencyCheck::class.java) {
|
||||||
|
val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
|
||||||
|
// Minecraft depends on asm, but Fabric forces it to a more recent version
|
||||||
|
override(libs.findLibrary("asm").get(), "9.8")
|
||||||
|
}
|
||||||
|
@@ -6,25 +6,25 @@
|
|||||||
|
|
||||||
import cc.tweaked.gradle.CCTweakedExtension
|
import cc.tweaked.gradle.CCTweakedExtension
|
||||||
import cc.tweaked.gradle.CCTweakedPlugin
|
import cc.tweaked.gradle.CCTweakedPlugin
|
||||||
import cc.tweaked.gradle.IdeaRunConfigurations
|
|
||||||
import cc.tweaked.gradle.MinecraftConfigurations
|
import cc.tweaked.gradle.MinecraftConfigurations
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("net.minecraftforge.gradle")
|
|
||||||
// We must apply java-convention after Forge, as we need the fg extension to be present.
|
|
||||||
id("cc-tweaked.java-convention")
|
id("cc-tweaked.java-convention")
|
||||||
id("org.parchmentmc.librarian.forgegradle")
|
id("net.neoforged.moddev")
|
||||||
}
|
}
|
||||||
|
|
||||||
plugins.apply(CCTweakedPlugin::class.java)
|
plugins.apply(CCTweakedPlugin::class.java)
|
||||||
|
|
||||||
val mcVersion: String by extra
|
val mcVersion: String by extra
|
||||||
|
|
||||||
minecraft {
|
neoForge {
|
||||||
val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
|
val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
|
||||||
mappings("parchment", "${libs.findVersion("parchmentMc").get()}-${libs.findVersion("parchment").get()}-$mcVersion")
|
version = libs.findVersion("neoForge").get().toString()
|
||||||
|
|
||||||
accessTransformer(project(":forge").file("src/main/resources/META-INF/accesstransformer.cfg"))
|
parchment {
|
||||||
|
minecraftVersion = libs.findVersion("parchmentMc").get().toString()
|
||||||
|
mappingsVersion = libs.findVersion("parchment").get().toString()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MinecraftConfigurations.setup(project)
|
MinecraftConfigurations.setup(project)
|
||||||
@@ -32,13 +32,3 @@ MinecraftConfigurations.setup(project)
|
|||||||
extensions.configure(CCTweakedExtension::class.java) {
|
extensions.configure(CCTweakedExtension::class.java) {
|
||||||
linters(minecraft = true, loader = "forge")
|
linters(minecraft = true, loader = "forge")
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
|
||||||
val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
|
|
||||||
"minecraft"("net.minecraftforge:forge:$mcVersion-${libs.findVersion("forge").get()}")
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.configureEach {
|
|
||||||
// genIntellijRuns isn't registered until much later, so we need this silly hijinks.
|
|
||||||
if (name == "genIntellijRuns") doLast { IdeaRunConfigurations(project).patch() }
|
|
||||||
}
|
|
||||||
|
@@ -29,7 +29,7 @@ base.archivesName.convention("cc-tweaked-$mcVersion-${project.name}")
|
|||||||
|
|
||||||
java {
|
java {
|
||||||
toolchain {
|
toolchain {
|
||||||
languageVersion.set(CCTweakedPlugin.JAVA_VERSION)
|
languageVersion = CCTweakedPlugin.JAVA_VERSION
|
||||||
}
|
}
|
||||||
|
|
||||||
withSourcesJar()
|
withSourcesJar()
|
||||||
@@ -38,36 +38,25 @@ java {
|
|||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
|
||||||
val mainMaven = maven("https://squiddev.cc/maven") {
|
val mainMaven = maven("https://maven.squiddev.cc/mirror") {
|
||||||
name = "SquidDev"
|
name = "SquidDev"
|
||||||
content {
|
|
||||||
// Until https://github.com/SpongePowered/Mixin/pull/593 is merged
|
|
||||||
includeModule("org.spongepowered", "mixin")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exclusiveContent {
|
exclusiveContent {
|
||||||
forRepositories(mainMaven)
|
forRepositories(mainMaven)
|
||||||
|
|
||||||
// Include the ForgeGradle repository if present. This requires that ForgeGradle is already present, which we
|
|
||||||
// enforce in our Forge overlay.
|
|
||||||
val fg =
|
|
||||||
project.extensions.findByType(net.minecraftforge.gradle.userdev.DependencyManagementExtension::class.java)
|
|
||||||
if (fg != null) forRepositories(fg.repository)
|
|
||||||
|
|
||||||
filter {
|
filter {
|
||||||
includeGroup("cc.tweaked")
|
includeGroup("cc.tweaked")
|
||||||
includeModule("org.squiddev", "Cobalt")
|
|
||||||
// Things we mirror
|
// Things we mirror
|
||||||
includeGroup("commoble.morered")
|
includeGroup("com.simibubi.create")
|
||||||
|
includeGroup("net.commoble.morered")
|
||||||
includeGroup("dev.architectury")
|
includeGroup("dev.architectury")
|
||||||
includeGroup("dev.emi")
|
includeGroup("dev.emi")
|
||||||
includeGroup("maven.modrinth")
|
includeGroup("maven.modrinth")
|
||||||
includeGroup("me.shedaniel.cloth")
|
includeGroup("me.shedaniel.cloth")
|
||||||
includeGroup("me.shedaniel")
|
includeGroup("me.shedaniel")
|
||||||
includeGroup("mezz.jei")
|
includeGroup("mezz.jei")
|
||||||
|
includeGroup("org.teavm")
|
||||||
includeModule("com.terraformersmc", "modmenu")
|
includeModule("com.terraformersmc", "modmenu")
|
||||||
includeModule("me.lucko", "fabric-permissions-api")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,6 +65,12 @@ dependencies {
|
|||||||
val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
|
val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
|
||||||
checkstyle(libs.findLibrary("checkstyle").get())
|
checkstyle(libs.findLibrary("checkstyle").get())
|
||||||
|
|
||||||
|
constraints {
|
||||||
|
checkstyle("org.codehaus.plexus:plexus-container-default:2.1.1") {
|
||||||
|
because("2.1.0 depends on deprecated Google collections module")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
errorprone(libs.findLibrary("errorProne-core").get())
|
errorprone(libs.findLibrary("errorProne-core").get())
|
||||||
errorprone(libs.findLibrary("nullAway").get())
|
errorprone(libs.findLibrary("nullAway").get())
|
||||||
}
|
}
|
||||||
@@ -83,27 +78,40 @@ dependencies {
|
|||||||
// Configure default JavaCompile tasks with our arguments.
|
// Configure default JavaCompile tasks with our arguments.
|
||||||
sourceSets.all {
|
sourceSets.all {
|
||||||
tasks.named(compileJavaTaskName, JavaCompile::class.java) {
|
tasks.named(compileJavaTaskName, JavaCompile::class.java) {
|
||||||
// Processing just gives us "No processor claimed any of these annotations", so skip that!
|
|
||||||
options.compilerArgs.addAll(listOf("-Xlint", "-Xlint:-processing"))
|
options.compilerArgs.addAll(
|
||||||
|
listOf(
|
||||||
|
"-Xlint",
|
||||||
|
// Processing just gives us "No processor claimed any of these annotations", so skip that!
|
||||||
|
"-Xlint:-processing",
|
||||||
|
// We violate this pattern too often for it to be a helpful warning. Something to improve one day!
|
||||||
|
"-Xlint:-this-escape",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
options.errorprone {
|
options.errorprone {
|
||||||
check("InvalidBlockTag", CheckSeverity.OFF) // Broken by @cc.xyz
|
check("InvalidBlockTag", CheckSeverity.OFF) // Broken by @cc.xyz
|
||||||
check("InvalidParam", CheckSeverity.OFF) // Broken by records.
|
|
||||||
check("InlineMeSuggester", CheckSeverity.OFF) // Minecraft uses @Deprecated liberally
|
check("InlineMeSuggester", CheckSeverity.OFF) // Minecraft uses @Deprecated liberally
|
||||||
// Too many false positives right now. Maybe we need an indirection for it later on.
|
// Too many false positives right now. Maybe we need an indirection for it later on.
|
||||||
|
check("AssignmentExpression", CheckSeverity.OFF) // I'm a bad person.
|
||||||
check("ReferenceEquality", CheckSeverity.OFF)
|
check("ReferenceEquality", CheckSeverity.OFF)
|
||||||
check("UnusedVariable", CheckSeverity.OFF) // Too many false positives with records.
|
check("EnumOrdinal", CheckSeverity.OFF) // For now. We could replace most of these with EnumMap.
|
||||||
check("OperatorPrecedence", CheckSeverity.OFF) // For now.
|
check("OperatorPrecedence", CheckSeverity.OFF) // For now.
|
||||||
check("AlreadyChecked", CheckSeverity.OFF) // Seems to be broken?
|
|
||||||
check("NonOverridingEquals", CheckSeverity.OFF) // Peripheral.equals makes this hard to avoid
|
check("NonOverridingEquals", CheckSeverity.OFF) // Peripheral.equals makes this hard to avoid
|
||||||
check("FutureReturnValueIgnored", CheckSeverity.OFF) // Too many false positives with Netty
|
check("FutureReturnValueIgnored", CheckSeverity.OFF) // Too many false positives with Netty
|
||||||
|
check("InvalidInlineTag", CheckSeverity.OFF) // Triggered by @snippet. Can be removed on Java 21.
|
||||||
|
|
||||||
check("NullAway", CheckSeverity.ERROR)
|
check("NullAway", CheckSeverity.ERROR)
|
||||||
option("NullAway:AnnotatedPackages", listOf("dan200.computercraft", "net.fabricmc.fabric.api").joinToString(","))
|
option(
|
||||||
|
"NullAway:AnnotatedPackages",
|
||||||
|
listOf("dan200.computercraft", "cc.tweaked", "net.fabricmc.fabric.api").joinToString(","),
|
||||||
|
)
|
||||||
option("NullAway:ExcludedFieldAnnotations", listOf("org.spongepowered.asm.mixin.Shadow").joinToString(","))
|
option("NullAway:ExcludedFieldAnnotations", listOf("org.spongepowered.asm.mixin.Shadow").joinToString(","))
|
||||||
option("NullAway:CastToNonNullMethod", "dan200.computercraft.core.util.Nullability.assertNonNull")
|
option("NullAway:CastToNonNullMethod", "dan200.computercraft.core.util.Nullability.assertNonNull")
|
||||||
option("NullAway:CheckOptionalEmptiness")
|
option("NullAway:CheckOptionalEmptiness")
|
||||||
option("NullAway:AcknowledgeRestrictiveAnnotations")
|
option("NullAway:AcknowledgeRestrictiveAnnotations")
|
||||||
|
|
||||||
|
excludedPaths = ".*/jmh_generated/.*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,7 +122,6 @@ tasks.compileTestJava {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
tasks.withType(JavaCompile::class.java).configureEach {
|
tasks.withType(JavaCompile::class.java).configureEach {
|
||||||
options.encoding = "UTF-8"
|
options.encoding = "UTF-8"
|
||||||
}
|
}
|
||||||
@@ -127,8 +134,8 @@ tasks.processResources {
|
|||||||
tasks.withType(AbstractArchiveTask::class.java).configureEach {
|
tasks.withType(AbstractArchiveTask::class.java).configureEach {
|
||||||
isPreserveFileTimestamps = false
|
isPreserveFileTimestamps = false
|
||||||
isReproducibleFileOrder = true
|
isReproducibleFileOrder = true
|
||||||
dirMode = Integer.valueOf("755", 8)
|
filePermissions {}
|
||||||
fileMode = Integer.valueOf("664", 8)
|
dirPermissions {}
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.jar {
|
tasks.jar {
|
||||||
@@ -148,7 +155,7 @@ tasks.javadoc {
|
|||||||
options {
|
options {
|
||||||
val stdOptions = this as StandardJavadocDocletOptions
|
val stdOptions = this as StandardJavadocDocletOptions
|
||||||
stdOptions.addBooleanOption("Xdoclint:all,-missing", true)
|
stdOptions.addBooleanOption("Xdoclint:all,-missing", true)
|
||||||
stdOptions.links("https://docs.oracle.com/en/java/javase/17/docs/api/")
|
stdOptions.links("https://docs.oracle.com/en/java/javase/21/docs/api/")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,8 +169,8 @@ tasks.test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType(JacocoReport::class.java).configureEach {
|
tasks.withType(JacocoReport::class.java).configureEach {
|
||||||
reports.xml.required.set(true)
|
reports.xml.required = true
|
||||||
reports.html.required.set(true)
|
reports.html.required = true
|
||||||
}
|
}
|
||||||
|
|
||||||
project.plugins.withType(CCTweakedPlugin::class.java) {
|
project.plugins.withType(CCTweakedPlugin::class.java) {
|
||||||
@@ -174,6 +181,12 @@ project.plugins.withType(CCTweakedPlugin::class.java) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.register("checkstyle") {
|
||||||
|
description = "Run Checkstyle on all sources"
|
||||||
|
group = LifecycleBasePlugin.VERIFICATION_GROUP
|
||||||
|
dependsOn(tasks.withType(Checkstyle::class.java))
|
||||||
|
}
|
||||||
|
|
||||||
spotless {
|
spotless {
|
||||||
encoding = StandardCharsets.UTF_8
|
encoding = StandardCharsets.UTF_8
|
||||||
lineEndings = LineEnding.UNIX
|
lineEndings = LineEnding.UNIX
|
||||||
@@ -181,29 +194,23 @@ spotless {
|
|||||||
fun FormatExtension.defaults() {
|
fun FormatExtension.defaults() {
|
||||||
endWithNewline()
|
endWithNewline()
|
||||||
trimTrailingWhitespace()
|
trimTrailingWhitespace()
|
||||||
indentWithSpaces(4)
|
leadingTabsToSpaces(4)
|
||||||
}
|
}
|
||||||
|
|
||||||
java {
|
java {
|
||||||
defaults()
|
defaults()
|
||||||
|
importOrder("", "javax|java", "\\#")
|
||||||
removeUnusedImports()
|
removeUnusedImports()
|
||||||
}
|
}
|
||||||
|
|
||||||
val ktlintConfig = mapOf(
|
|
||||||
"ktlint_standard_no-wildcard-imports" to "disabled",
|
|
||||||
"ktlint_standard_class-naming" to "disabled",
|
|
||||||
"ij_kotlin_allow_trailing_comma" to "true",
|
|
||||||
"ij_kotlin_allow_trailing_comma_on_call_site" to "true",
|
|
||||||
)
|
|
||||||
|
|
||||||
kotlinGradle {
|
kotlinGradle {
|
||||||
defaults()
|
defaults()
|
||||||
ktlint().editorConfigOverride(ktlintConfig)
|
ktlint()
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
defaults()
|
defaults()
|
||||||
ktlint().editorConfigOverride(ktlintConfig)
|
ktlint()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,6 +219,5 @@ idea.module {
|
|||||||
|
|
||||||
// Force Gradle to write to inherit the output directory from the parent, instead of writing to out/xxx/classes.
|
// Force Gradle to write to inherit the output directory from the parent, instead of writing to out/xxx/classes.
|
||||||
// This is required for Loom, and we patch Forge's run configurations to work there.
|
// This is required for Loom, and we patch Forge's run configurations to work there.
|
||||||
// TODO: Submit a patch to Forge to support ProjectRootManager.
|
|
||||||
inheritOutputDirs = true
|
inheritOutputDirs = true
|
||||||
}
|
}
|
||||||
|
@@ -1,25 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
import cc.tweaked.gradle.CCTweakedPlugin
|
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
|
||||||
|
|
||||||
plugins {
|
|
||||||
kotlin("jvm")
|
|
||||||
}
|
|
||||||
|
|
||||||
kotlin {
|
|
||||||
jvmToolchain {
|
|
||||||
languageVersion.set(CCTweakedPlugin.JAVA_VERSION)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.withType(KotlinCompile::class.java).configureEach {
|
|
||||||
// So technically we shouldn't need to do this as the toolchain sets it above. However, the option only appears
|
|
||||||
// to be set when the task executes, so doesn't get picked up by IDEs.
|
|
||||||
kotlinOptions.jvmTarget = when {
|
|
||||||
CCTweakedPlugin.JAVA_VERSION.asInt() > 8 -> CCTweakedPlugin.JAVA_VERSION.toString()
|
|
||||||
else -> "1.${CCTweakedPlugin.JAVA_VERSION.asInt()}"
|
|
||||||
}
|
|
||||||
}
|
|
@@ -2,11 +2,9 @@
|
|||||||
//
|
//
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
import net.darkhax.curseforgegradle.TaskPublishCurseForge
|
|
||||||
import cc.tweaked.gradle.setProvider
|
import cc.tweaked.gradle.setProvider
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("net.darkhax.curseforgegradle")
|
|
||||||
id("com.modrinth.minotaur")
|
id("com.modrinth.minotaur")
|
||||||
id("cc-tweaked.publishing")
|
id("cc-tweaked.publishing")
|
||||||
}
|
}
|
||||||
@@ -25,34 +23,17 @@ val isUnstable = project.properties["isUnstable"] == "true"
|
|||||||
val modVersion: String by extra
|
val modVersion: String by extra
|
||||||
val mcVersion: String by extra
|
val mcVersion: String by extra
|
||||||
|
|
||||||
val publishCurseForge by tasks.registering(TaskPublishCurseForge::class) {
|
|
||||||
group = PublishingPlugin.PUBLISH_TASK_GROUP
|
|
||||||
description = "Upload artifacts to CurseForge"
|
|
||||||
|
|
||||||
apiToken = findProperty("curseForgeApiKey") ?: ""
|
|
||||||
enabled = apiToken != ""
|
|
||||||
|
|
||||||
val mainFile = upload("282001", modPublishing.output.get().archiveFile)
|
|
||||||
mainFile.changelog =
|
|
||||||
"Release notes can be found on the [GitHub repository](https://github.com/cc-tweaked/CC-Tweaked/releases/tag/v$mcVersion-$modVersion)."
|
|
||||||
mainFile.changelogType = "markdown"
|
|
||||||
mainFile.releaseType = if (isUnstable) "alpha" else "release"
|
|
||||||
mainFile.gameVersions.add(mcVersion)
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.publish { dependsOn(publishCurseForge) }
|
|
||||||
|
|
||||||
modrinth {
|
modrinth {
|
||||||
token.set(findProperty("modrinthApiKey") as String? ?: "")
|
token = findProperty("modrinthApiKey") as String? ?: ""
|
||||||
projectId.set("gu7yAYhd")
|
projectId = "gu7yAYhd"
|
||||||
versionNumber.set(modVersion)
|
versionNumber = modVersion
|
||||||
versionName.set(modVersion)
|
versionName = modVersion
|
||||||
versionType.set(if (isUnstable) "alpha" else "release")
|
versionType = if (isUnstable) "alpha" else "release"
|
||||||
uploadFile.setProvider(modPublishing.output)
|
uploadFile.setProvider(modPublishing.output)
|
||||||
gameVersions.add(mcVersion)
|
gameVersions.add(mcVersion)
|
||||||
changelog.set("Release notes can be found on the [GitHub repository](https://github.com/cc-tweaked/CC-Tweaked/releases/tag/v$mcVersion-$modVersion).")
|
changelog = "Release notes can be found on the [GitHub repository](https://github.com/cc-tweaked/CC-Tweaked/releases/tag/v$mcVersion-$modVersion)."
|
||||||
|
|
||||||
syncBodyFrom.set(provider { rootProject.file("doc/mod-page.md").readText() })
|
syncBodyFrom = provider { rootProject.file("doc/mod-page.md").readText() }
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.publish { dependsOn(tasks.modrinth) }
|
tasks.publish { dependsOn(tasks.modrinth) }
|
||||||
|
@@ -2,44 +2,34 @@
|
|||||||
//
|
//
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
import cc.tweaked.gradle.clientClasses
|
|
||||||
import cc.tweaked.gradle.commonClasses
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up the configurations for writing game tests.
|
* Sets up the configurations for writing game tests.
|
||||||
*
|
*
|
||||||
* See notes in [cc.tweaked.gradle.MinecraftConfigurations] for the general design behind these cursed ideas.
|
* See notes in [cc.tweaked.gradle.MinecraftConfigurations] for the general design behind these cursed ideas.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import cc.tweaked.gradle.MinecraftConfigurations
|
||||||
|
import cc.tweaked.gradle.clientClasses
|
||||||
|
import cc.tweaked.gradle.commonClasses
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("cc-tweaked.kotlin-convention")
|
kotlin("jvm")
|
||||||
id("cc-tweaked.java-convention")
|
id("cc-tweaked.java-convention")
|
||||||
}
|
}
|
||||||
|
|
||||||
val main = sourceSets["main"]
|
val main = sourceSets["main"]
|
||||||
val client = sourceSets["client"]
|
val client = sourceSets["client"]
|
||||||
|
|
||||||
// Both testMod and testFixtures inherit from the main and client classpath, just so we have access to Minecraft classes.
|
MinecraftConfigurations.createDerivedConfiguration(project, MinecraftConfigurations.DATAGEN)
|
||||||
val testMod by sourceSets.creating {
|
MinecraftConfigurations.createDerivedConfiguration(project, MinecraftConfigurations.EXAMPLES)
|
||||||
compileClasspath += main.compileClasspath + client.compileClasspath
|
MinecraftConfigurations.createDerivedConfiguration(project, MinecraftConfigurations.TEST_MOD)
|
||||||
runtimeClasspath += main.runtimeClasspath + client.runtimeClasspath
|
|
||||||
}
|
|
||||||
|
|
||||||
configurations {
|
// Set up generated resources
|
||||||
named(testMod.compileClasspathConfigurationName) {
|
sourceSets.main { resources.srcDir("src/generated/resources") }
|
||||||
shouldResolveConsistentlyWith(compileClasspath.get())
|
sourceSets.named("examples") { resources.srcDir("src/examples/generatedResources") }
|
||||||
}
|
|
||||||
|
|
||||||
named(testMod.runtimeClasspathConfigurationName) {
|
// Make sure our examples compile.
|
||||||
shouldResolveConsistentlyWith(runtimeClasspath.get())
|
tasks.check { dependsOn(tasks.named("compileExamplesJava")) }
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Like the main test configurations, we're safe to depend on source set outputs.
|
|
||||||
dependencies {
|
|
||||||
add(testMod.implementationConfigurationName, main.output)
|
|
||||||
add(testMod.implementationConfigurationName, client.output)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Similar to java-test-fixtures, but tries to avoid putting the obfuscated jar on the classpath.
|
// Similar to java-test-fixtures, but tries to avoid putting the obfuscated jar on the classpath.
|
||||||
|
|
@@ -12,25 +12,26 @@ publishing {
|
|||||||
register<MavenPublication>("maven") {
|
register<MavenPublication>("maven") {
|
||||||
artifactId = base.archivesName.get()
|
artifactId = base.archivesName.get()
|
||||||
from(components["java"])
|
from(components["java"])
|
||||||
|
suppressAllPomMetadataWarnings()
|
||||||
|
|
||||||
pom {
|
pom {
|
||||||
name.set("CC: Tweaked")
|
name = "CC: Tweaked"
|
||||||
description.set("CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles and more to Minecraft.")
|
description = "CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles and more to Minecraft."
|
||||||
url.set("https://github.com/cc-tweaked/CC-Tweaked")
|
url = "https://github.com/cc-tweaked/CC-Tweaked"
|
||||||
|
|
||||||
scm {
|
scm {
|
||||||
url.set("https://github.com/cc-tweaked/CC-Tweaked.git")
|
url = "https://github.com/cc-tweaked/CC-Tweaked.git"
|
||||||
}
|
}
|
||||||
|
|
||||||
issueManagement {
|
issueManagement {
|
||||||
system.set("github")
|
system = "github"
|
||||||
url.set("https://github.com/cc-tweaked/CC-Tweaked/issues")
|
url = "https://github.com/cc-tweaked/CC-Tweaked/issues"
|
||||||
}
|
}
|
||||||
|
|
||||||
licenses {
|
licenses {
|
||||||
license {
|
license {
|
||||||
name.set("ComputerCraft Public License, Version 1.0")
|
name = "ComputerCraft Public License, Version 1.0"
|
||||||
url.set("https://github.com/cc-tweaked/CC-Tweaked/blob/HEAD/LICENSE")
|
url = "https://github.com/cc-tweaked/CC-Tweaked/blob/HEAD/LICENSE"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -38,7 +39,7 @@ publishing {
|
|||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
maven("https://squiddev.cc/maven") {
|
maven("https://maven.squiddev.cc") {
|
||||||
name = "SquidDev"
|
name = "SquidDev"
|
||||||
|
|
||||||
credentials(PasswordCredentials::class)
|
credentials(PasswordCredentials::class)
|
||||||
|
@@ -10,25 +10,31 @@ import cc.tweaked.gradle.MinecraftConfigurations
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("cc-tweaked.java-convention")
|
id("cc-tweaked.java-convention")
|
||||||
id("org.spongepowered.gradle.vanilla")
|
id("cc.tweaked.vanilla-extract")
|
||||||
}
|
}
|
||||||
|
|
||||||
plugins.apply(CCTweakedPlugin::class.java)
|
plugins.apply(CCTweakedPlugin::class.java)
|
||||||
|
|
||||||
val mcVersion: String by extra
|
val mcVersion: String by extra
|
||||||
|
|
||||||
|
val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
|
||||||
|
|
||||||
minecraft {
|
minecraft {
|
||||||
version(mcVersion)
|
version(mcVersion)
|
||||||
|
|
||||||
|
mappings {
|
||||||
|
parchment(libs.findVersion("parchmentMc").get().toString(), libs.findVersion("parchment").get().toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
unpick(libs.findLibrary("yarn").get())
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
|
|
||||||
|
|
||||||
// Depend on error prone annotations to silence a lot of compile warnings.
|
// Depend on error prone annotations to silence a lot of compile warnings.
|
||||||
compileOnlyApi(libs.findLibrary("errorProne.annotations").get())
|
compileOnly(libs.findLibrary("errorProne.annotations").get())
|
||||||
}
|
}
|
||||||
|
|
||||||
MinecraftConfigurations.setup(project)
|
MinecraftConfigurations.setupBasic(project)
|
||||||
|
|
||||||
extensions.configure(CCTweakedExtension::class.java) {
|
extensions.configure(CCTweakedExtension::class.java) {
|
||||||
linters(minecraft = true, loader = null)
|
linters(minecraft = true, loader = null)
|
||||||
|
@@ -10,21 +10,16 @@ import org.gradle.api.GradleException
|
|||||||
import org.gradle.api.NamedDomainObjectProvider
|
import org.gradle.api.NamedDomainObjectProvider
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.gradle.api.Task
|
import org.gradle.api.Task
|
||||||
import org.gradle.api.attributes.TestSuiteType
|
|
||||||
import org.gradle.api.file.FileSystemOperations
|
|
||||||
import org.gradle.api.plugins.JavaPluginExtension
|
import org.gradle.api.plugins.JavaPluginExtension
|
||||||
import org.gradle.api.provider.Provider
|
import org.gradle.api.provider.Provider
|
||||||
import org.gradle.api.provider.SetProperty
|
import org.gradle.api.provider.SetProperty
|
||||||
import org.gradle.api.reporting.ReportingExtension
|
|
||||||
import org.gradle.api.tasks.SourceSet
|
import org.gradle.api.tasks.SourceSet
|
||||||
import org.gradle.api.tasks.bundling.Jar
|
import org.gradle.api.tasks.bundling.Jar
|
||||||
import org.gradle.api.tasks.compile.JavaCompile
|
import org.gradle.api.tasks.compile.JavaCompile
|
||||||
import org.gradle.api.tasks.javadoc.Javadoc
|
import org.gradle.api.tasks.javadoc.Javadoc
|
||||||
import org.gradle.configurationcache.extensions.capitalized
|
|
||||||
import org.gradle.language.base.plugins.LifecycleBasePlugin
|
import org.gradle.language.base.plugins.LifecycleBasePlugin
|
||||||
import org.gradle.language.jvm.tasks.ProcessResources
|
import org.gradle.language.jvm.tasks.ProcessResources
|
||||||
import org.gradle.process.JavaForkOptions
|
import org.gradle.process.JavaForkOptions
|
||||||
import org.gradle.testing.jacoco.plugins.JacocoCoverageReport
|
|
||||||
import org.gradle.testing.jacoco.plugins.JacocoPluginExtension
|
import org.gradle.testing.jacoco.plugins.JacocoPluginExtension
|
||||||
import org.gradle.testing.jacoco.plugins.JacocoTaskExtension
|
import org.gradle.testing.jacoco.plugins.JacocoTaskExtension
|
||||||
import org.gradle.testing.jacoco.tasks.JacocoReport
|
import org.gradle.testing.jacoco.tasks.JacocoReport
|
||||||
@@ -33,40 +28,31 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import java.net.URL
|
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
abstract class CCTweakedExtension(
|
abstract class CCTweakedExtension(private val project: Project) {
|
||||||
private val project: Project,
|
|
||||||
private val fs: FileSystemOperations,
|
|
||||||
) {
|
|
||||||
/** Get the hash of the latest git commit. */
|
/** Get the hash of the latest git commit. */
|
||||||
val gitHash: Provider<String> = gitProvider(project, "<no git hash>") {
|
val gitHash: Provider<String> =
|
||||||
ProcessHelpers.captureOut("git", "-C", project.rootProject.projectDir.absolutePath, "rev-parse", "HEAD").trim()
|
gitProvider("<no git commit>", listOf("rev-parse", "HEAD")) { it.trim() }
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the current git branch. */
|
/** Get the current git branch. */
|
||||||
val gitBranch: Provider<String> = gitProvider(project, "<no git branch>") {
|
val gitBranch: Provider<String> =
|
||||||
ProcessHelpers.captureOut("git", "-C", project.rootProject.projectDir.absolutePath, "rev-parse", "--abbrev-ref", "HEAD")
|
gitProvider("<no git branch>", listOf("rev-parse", "--abbrev-ref", "HEAD")) { it.trim() }
|
||||||
.trim()
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a list of all contributors to the project. */
|
/** Get a list of all contributors to the project. */
|
||||||
val gitContributors: Provider<List<String>> = gitProvider(project, listOf()) {
|
val gitContributors: Provider<List<String>> =
|
||||||
ProcessHelpers.captureLines(
|
gitProvider(listOf(), listOf("shortlog", "-ns", "--group=author", "--group=trailer:co-authored-by", "HEAD")) { input ->
|
||||||
"git", "-C", project.rootProject.projectDir.absolutePath, "shortlog", "-ns",
|
input.lineSequence()
|
||||||
"--group=author", "--group=trailer:co-authored-by", "HEAD",
|
.filter { it.isNotEmpty() }
|
||||||
)
|
.map {
|
||||||
.asSequence()
|
val matcher = COMMIT_COUNTS.matcher(it)
|
||||||
.map {
|
matcher.find()
|
||||||
val matcher = COMMIT_COUNTS.matcher(it)
|
matcher.group(1)
|
||||||
matcher.find()
|
}
|
||||||
matcher.group(1)
|
.filter { !IGNORED_USERS.contains(it) }
|
||||||
}
|
.toList()
|
||||||
.filter { !IGNORED_USERS.contains(it) }
|
.sortedWith(String.CASE_INSENSITIVE_ORDER)
|
||||||
.toList()
|
}
|
||||||
.sortedWith(String.CASE_INSENSITIVE_ORDER)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* References to other sources
|
* References to other sources
|
||||||
@@ -103,14 +89,13 @@ abstract class CCTweakedExtension(
|
|||||||
val otherJava = otherProject.extensions.getByType(JavaPluginExtension::class.java)
|
val otherJava = otherProject.extensions.getByType(JavaPluginExtension::class.java)
|
||||||
val main = otherJava.sourceSets.getByName("main")
|
val main = otherJava.sourceSets.getByName("main")
|
||||||
val client = otherJava.sourceSets.getByName("client")
|
val client = otherJava.sourceSets.getByName("client")
|
||||||
val testMod = otherJava.sourceSets.findByName("testMod")
|
|
||||||
val testFixtures = otherJava.sourceSets.findByName("testFixtures")
|
|
||||||
|
|
||||||
// Pull in sources from the other project.
|
// Pull in sources from the other project.
|
||||||
extendSourceSet(otherProject, main)
|
extendSourceSet(otherProject, main)
|
||||||
extendSourceSet(otherProject, client)
|
extendSourceSet(otherProject, client)
|
||||||
if (testMod != null) extendSourceSet(otherProject, testMod)
|
for (sourceSet in listOf(MinecraftConfigurations.DATAGEN, MinecraftConfigurations.EXAMPLES, MinecraftConfigurations.TEST_MOD, "testFixtures")) {
|
||||||
if (testFixtures != null) extendSourceSet(otherProject, testFixtures)
|
otherJava.sourceSets.findByName(sourceSet)?.let { extendSourceSet(otherProject, it) }
|
||||||
|
}
|
||||||
|
|
||||||
// The extra source-processing tasks should include these files too.
|
// The extra source-processing tasks should include these files too.
|
||||||
project.tasks.named(main.javadocTaskName, Javadoc::class.java) { source(main.allJava, client.allJava) }
|
project.tasks.named(main.javadocTaskName, Javadoc::class.java) { source(main.allJava, client.allJava) }
|
||||||
@@ -173,23 +158,19 @@ abstract class CCTweakedExtension(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun <T> jacoco(task: NamedDomainObjectProvider<T>) where T : Task, T : JavaForkOptions {
|
fun <T> jacoco(task: NamedDomainObjectProvider<T>) where T : Task, T : JavaForkOptions {
|
||||||
val classDump = project.buildDir.resolve("jacocoClassDump/${task.name}")
|
val reportTaskName = "jacoco${task.name.capitalise()}Report"
|
||||||
val reportTaskName = "jacoco${task.name.capitalized()}Report"
|
|
||||||
|
|
||||||
val jacoco = project.extensions.getByType(JacocoPluginExtension::class.java)
|
val jacoco = project.extensions.getByType(JacocoPluginExtension::class.java)
|
||||||
task.configure {
|
task.configure {
|
||||||
finalizedBy(reportTaskName)
|
finalizedBy(reportTaskName)
|
||||||
|
|
||||||
doFirst("Clean class dump directory") { fs.delete { delete(classDump) } }
|
|
||||||
|
|
||||||
jacoco.applyTo(this)
|
jacoco.applyTo(this)
|
||||||
|
|
||||||
extensions.configure(JacocoTaskExtension::class.java) {
|
extensions.configure(JacocoTaskExtension::class.java) {
|
||||||
includes = listOf("dan200.computercraft.*")
|
includes = listOf("dan200.computercraft.*")
|
||||||
classDumpDir = classDump
|
excludes = listOf(
|
||||||
|
"dan200.computercraft.mixin.*", // Exclude mixins, as they're not executed at runtime.
|
||||||
// Older versions of modlauncher don't include a protection domain (and thus no code
|
"dan200.computercraft.shared.Capabilities$*", // Exclude capability tokens, as Forge rewrites them.
|
||||||
// source). Jacoco skips such classes by default, so we need to explicitly include them.
|
)
|
||||||
isIncludeNoLocationClasses = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,15 +179,11 @@ abstract class CCTweakedExtension(
|
|||||||
description = "Generates code coverage report for the ${task.name} task."
|
description = "Generates code coverage report for the ${task.name} task."
|
||||||
|
|
||||||
executionData(task.get())
|
executionData(task.get())
|
||||||
classDirectories.from(classDump)
|
|
||||||
|
|
||||||
// Don't want to use sourceSets(...) here as we have a custom class directory.
|
// Don't want to use sourceSets(...) here as we don't use all class directories.
|
||||||
for (ref in sourceSets.get()) sourceDirectories.from(ref.allSource.sourceDirectories)
|
for (ref in this@CCTweakedExtension.sourceDirectories.get()) {
|
||||||
}
|
sourceDirectories.from(ref.sourceSet.allSource.sourceDirectories)
|
||||||
|
if (ref.classes) classDirectories.from(ref.sourceSet.output)
|
||||||
project.extensions.configure(ReportingExtension::class.java) {
|
|
||||||
reports.register("${task.name}CodeCoverageReport", JacocoCoverageReport::class.java) {
|
|
||||||
testType.set(TestSuiteType.INTEGRATION_TEST)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -218,12 +195,12 @@ abstract class CCTweakedExtension(
|
|||||||
* where possible.
|
* where possible.
|
||||||
*/
|
*/
|
||||||
fun downloadFile(label: String, url: String): File {
|
fun downloadFile(label: String, url: String): File {
|
||||||
val url = URL(url)
|
val uri = URI(url)
|
||||||
val path = File(url.path)
|
val path = File(uri.path)
|
||||||
|
|
||||||
project.repositories.ivy {
|
project.repositories.ivy {
|
||||||
name = label
|
name = label
|
||||||
setUrl(URI(url.protocol, url.userInfo, url.host, url.port, path.parent, null, null))
|
setUrl(URI(uri.scheme, uri.userInfo, uri.host, uri.port, path.parent, null, null))
|
||||||
patternLayout {
|
patternLayout {
|
||||||
artifact("[artifact].[ext]")
|
artifact("[artifact].[ext]")
|
||||||
}
|
}
|
||||||
@@ -246,26 +223,31 @@ abstract class CCTweakedExtension(
|
|||||||
).resolve().single()
|
).resolve().single()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun <T> gitProvider(default: T, command: List<String>, process: (String) -> T): Provider<T> {
|
||||||
|
val baseResult = project.providers.exec {
|
||||||
|
commandLine = listOf("git", "-C", project.rootDir.absolutePath) + command
|
||||||
|
}
|
||||||
|
|
||||||
|
return project.provider {
|
||||||
|
val res = try {
|
||||||
|
baseResult.standardOutput.asText.get()
|
||||||
|
} catch (e: IOException) {
|
||||||
|
project.logger.error("Cannot read Git repository: ${e.message}", e)
|
||||||
|
return@provider default
|
||||||
|
} catch (e: GradleException) {
|
||||||
|
project.logger.error("Cannot read Git repository: ${e.message}", e)
|
||||||
|
return@provider default
|
||||||
|
}
|
||||||
|
process(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val COMMIT_COUNTS = Pattern.compile("""^\s*[0-9]+\s+(.*)$""")
|
private val COMMIT_COUNTS = Pattern.compile("""^\s*[0-9]+\s+(.*)$""")
|
||||||
private val IGNORED_USERS = setOf(
|
private val IGNORED_USERS = setOf(
|
||||||
"GitHub", "Daniel Ratcliffe", "Weblate",
|
"GitHub", "Daniel Ratcliffe", "NotSquidDev", "Weblate",
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun <T> gitProvider(project: Project, default: T, supplier: () -> T): Provider<T> {
|
|
||||||
return project.provider {
|
|
||||||
try {
|
|
||||||
supplier()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
project.logger.error("Cannot read Git repository: ${e.message}")
|
|
||||||
default
|
|
||||||
} catch (e: GradleException) {
|
|
||||||
project.logger.error("Cannot read Git repository: ${e.message}")
|
|
||||||
default
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val isIdeSync: Boolean
|
private val isIdeSync: Boolean
|
||||||
get() = java.lang.Boolean.parseBoolean(System.getProperty("idea.sync.active", "false"))
|
get() = java.lang.Boolean.parseBoolean(System.getProperty("idea.sync.active", "false"))
|
||||||
}
|
}
|
||||||
|
@@ -9,6 +9,10 @@ import org.gradle.api.Project
|
|||||||
import org.gradle.api.plugins.JavaPlugin
|
import org.gradle.api.plugins.JavaPlugin
|
||||||
import org.gradle.api.plugins.JavaPluginExtension
|
import org.gradle.api.plugins.JavaPluginExtension
|
||||||
import org.gradle.jvm.toolchain.JavaLanguageVersion
|
import org.gradle.jvm.toolchain.JavaLanguageVersion
|
||||||
|
import org.gradle.plugins.ide.idea.model.IdeaModel
|
||||||
|
import org.jetbrains.gradle.ext.IdeaExtPlugin
|
||||||
|
import org.jetbrains.gradle.ext.runConfigurations
|
||||||
|
import org.jetbrains.gradle.ext.settings
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures projects to match a shared configuration.
|
* Configures projects to match a shared configuration.
|
||||||
@@ -21,9 +25,23 @@ class CCTweakedPlugin : Plugin<Project> {
|
|||||||
val sourceSets = project.extensions.getByType(JavaPluginExtension::class.java).sourceSets
|
val sourceSets = project.extensions.getByType(JavaPluginExtension::class.java).sourceSets
|
||||||
cct.sourceDirectories.add(SourceSetReference.internal(sourceSets.getByName("main")))
|
cct.sourceDirectories.add(SourceSetReference.internal(sourceSets.getByName("main")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
project.plugins.withType(IdeaExtPlugin::class.java) { extendIdea(project) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extend the [IdeaExtPlugin] plugin's `runConfiguration` container to also support [JUnitExt].
|
||||||
|
*/
|
||||||
|
private fun extendIdea(project: Project) {
|
||||||
|
val ideaModel = project.extensions.findByName("idea") as IdeaModel? ?: return
|
||||||
|
val ideaProject = ideaModel.project ?: return
|
||||||
|
|
||||||
|
ideaProject.settings.runConfigurations {
|
||||||
|
registerFactory(JUnitExt::class.java) { name -> project.objects.newInstance(JUnitExt::class.java, name) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val JAVA_VERSION = JavaLanguageVersion.of(17)
|
val JAVA_VERSION = JavaLanguageVersion.of(21)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,98 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package cc.tweaked.gradle
|
||||||
|
|
||||||
|
import org.gradle.api.DefaultTask
|
||||||
|
import org.gradle.api.GradleException
|
||||||
|
import org.gradle.api.artifacts.Configuration
|
||||||
|
import org.gradle.api.artifacts.MinimalExternalModuleDependency
|
||||||
|
import org.gradle.api.artifacts.component.ModuleComponentIdentifier
|
||||||
|
import org.gradle.api.artifacts.component.ModuleComponentSelector
|
||||||
|
import org.gradle.api.artifacts.component.ProjectComponentIdentifier
|
||||||
|
import org.gradle.api.artifacts.result.DependencyResult
|
||||||
|
import org.gradle.api.artifacts.result.ResolvedDependencyResult
|
||||||
|
import org.gradle.api.provider.ListProperty
|
||||||
|
import org.gradle.api.provider.MapProperty
|
||||||
|
import org.gradle.api.provider.Provider
|
||||||
|
import org.gradle.api.tasks.Input
|
||||||
|
import org.gradle.api.tasks.TaskAction
|
||||||
|
import org.gradle.language.base.plugins.LifecycleBasePlugin
|
||||||
|
|
||||||
|
abstract class DependencyCheck : DefaultTask() {
|
||||||
|
@get:Input
|
||||||
|
protected abstract val dependencies: ListProperty<DependencyResult>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A mapping of module coordinates (`group:module`) to versions, overriding the requested version.
|
||||||
|
*/
|
||||||
|
@get:Input
|
||||||
|
protected abstract val overrides: MapProperty<String, String>
|
||||||
|
|
||||||
|
init {
|
||||||
|
description = "Check :core's dependencies are consistent with Minecraft's."
|
||||||
|
group = LifecycleBasePlugin.VERIFICATION_GROUP
|
||||||
|
|
||||||
|
dependencies.finalizeValueOnRead()
|
||||||
|
overrides.finalizeValueOnRead()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override a module with a different version.
|
||||||
|
*/
|
||||||
|
fun override(module: Provider<MinimalExternalModuleDependency>, version: String) {
|
||||||
|
overrides.putAll(project.provider { mutableMapOf(module.get().module.toString() to version) })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a configuration to check.
|
||||||
|
*/
|
||||||
|
fun configuration(configuration: Provider<Configuration>) {
|
||||||
|
// We can't store the Configuration in the cache, so store the resolved dependencies instead.
|
||||||
|
dependencies.addAll(configuration.map { it.incoming.resolutionResult.allDependencies })
|
||||||
|
}
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
fun run() {
|
||||||
|
var ok = true
|
||||||
|
for (configuration in dependencies.get()) {
|
||||||
|
if (!check(configuration)) ok = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
throw GradleException("Mismatched versions in Minecraft dependencies. gradle/libs.versions.toml may need updating.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun check(dependency: DependencyResult): Boolean {
|
||||||
|
if (dependency !is ResolvedDependencyResult) {
|
||||||
|
logger.warn("Found unexpected dependency result {}", dependency)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip dependencies on non-modules.
|
||||||
|
val requested = dependency.requested
|
||||||
|
if (requested !is ModuleComponentSelector) return true
|
||||||
|
|
||||||
|
// If this dependency is specified within some project (so is non-transitive), or is pulled in via Minecraft,
|
||||||
|
// then check for consistency.
|
||||||
|
// It would be nice to be smarter about transitive dependencies, but avoiding false positives is hard.
|
||||||
|
val from = dependency.from.id
|
||||||
|
if (
|
||||||
|
from is ProjectComponentIdentifier ||
|
||||||
|
from is ModuleComponentIdentifier && (from.group == "net.minecraft" || from.group == "io.netty")
|
||||||
|
) {
|
||||||
|
// If the version is different between the requested and selected version, report an error.
|
||||||
|
val selected = dependency.selected.moduleVersion!!.version
|
||||||
|
val requestedVersion = overrides.get()["${requested.group}:${requested.module}"] ?: requested.version
|
||||||
|
if (requestedVersion != selected) {
|
||||||
|
logger.error("Requested dependency {} (via {}) but got version {}", requested, from, selected)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
@@ -4,12 +4,11 @@
|
|||||||
|
|
||||||
package cc.tweaked.gradle
|
package cc.tweaked.gradle
|
||||||
|
|
||||||
import org.gradle.api.provider.Property
|
import org.gradle.api.file.DirectoryProperty
|
||||||
import org.gradle.api.tasks.AbstractExecTask
|
import org.gradle.api.tasks.AbstractExecTask
|
||||||
import org.gradle.api.tasks.OutputDirectory
|
import org.gradle.api.tasks.OutputDirectory
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
abstract class ExecToDir : AbstractExecTask<ExecToDir>(ExecToDir::class.java) {
|
abstract class ExecToDir : AbstractExecTask<ExecToDir>(ExecToDir::class.java) {
|
||||||
@get:OutputDirectory
|
@get:OutputDirectory
|
||||||
abstract val output: Property<File>
|
abstract val output: DirectoryProperty
|
||||||
}
|
}
|
||||||
|
@@ -5,9 +5,11 @@
|
|||||||
package cc.tweaked.gradle
|
package cc.tweaked.gradle
|
||||||
|
|
||||||
import org.gradle.api.artifacts.dsl.DependencyHandler
|
import org.gradle.api.artifacts.dsl.DependencyHandler
|
||||||
|
import org.gradle.api.file.FileSystemLocation
|
||||||
import org.gradle.api.provider.Property
|
import org.gradle.api.provider.Property
|
||||||
import org.gradle.api.provider.Provider
|
import org.gradle.api.provider.Provider
|
||||||
import org.gradle.api.tasks.JavaExec
|
import org.gradle.api.tasks.JavaExec
|
||||||
|
import org.gradle.kotlin.dsl.getByName
|
||||||
import org.gradle.process.BaseExecSpec
|
import org.gradle.process.BaseExecSpec
|
||||||
import org.gradle.process.JavaExecSpec
|
import org.gradle.process.JavaExecSpec
|
||||||
import org.gradle.process.ProcessForkOptions
|
import org.gradle.process.ProcessForkOptions
|
||||||
@@ -45,6 +47,21 @@ fun JavaExec.copyToFull(spec: JavaExec) {
|
|||||||
copyToExec(spec)
|
copyToExec(spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base this [JavaExec] task on an existing task.
|
||||||
|
*/
|
||||||
|
fun JavaExec.copyFromTask(task: JavaExec) {
|
||||||
|
for (dep in task.dependsOn) dependsOn(dep)
|
||||||
|
task.copyToFull(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base this [JavaExec] task on an existing task.
|
||||||
|
*/
|
||||||
|
fun JavaExec.copyFromTask(task: String) {
|
||||||
|
copyFromTask(project.tasks.getByName<JavaExec>(task))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy additional [BaseExecSpec] options which aren't handled by [ProcessForkOptions.copyTo].
|
* Copy additional [BaseExecSpec] options which aren't handled by [ProcessForkOptions.copyTo].
|
||||||
*/
|
*/
|
||||||
@@ -124,3 +141,45 @@ class CloseScope : AutoCloseable {
|
|||||||
|
|
||||||
/** Proxy method to avoid overload ambiguity. */
|
/** Proxy method to avoid overload ambiguity. */
|
||||||
fun <T> Property<T>.setProvider(provider: Provider<out T>) = set(provider)
|
fun <T> Property<T>.setProvider(provider: Provider<out T>) = set(provider)
|
||||||
|
|
||||||
|
/** Short-cut method to get the absolute path of a [FileSystemLocation] provider. */
|
||||||
|
fun Provider<out FileSystemLocation>.getAbsolutePath(): String = get().asFile.absolutePath
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the version immediately after the provided version.
|
||||||
|
*
|
||||||
|
* For example, given "1.2.3", this will return "1.2.4".
|
||||||
|
*/
|
||||||
|
fun getNextVersion(version: String): String {
|
||||||
|
// Split a version like x.y.z-SNAPSHOT into x.y.z and -SNAPSHOT
|
||||||
|
val dashIndex = version.indexOf('-')
|
||||||
|
val mainVersion = if (dashIndex < 0) version else version.substring(0, dashIndex)
|
||||||
|
|
||||||
|
// Find the last component in x.y.z and increment it.
|
||||||
|
val lastIndex = mainVersion.lastIndexOf('.')
|
||||||
|
if (lastIndex < 0) throw IllegalArgumentException("Cannot parse version format \"$version\"")
|
||||||
|
val lastVersion = try {
|
||||||
|
mainVersion.substring(lastIndex + 1).toInt()
|
||||||
|
} catch (e: NumberFormatException) {
|
||||||
|
throw IllegalArgumentException("Cannot parse version format \"$version\"", e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then append all components together.
|
||||||
|
val out = StringBuilder()
|
||||||
|
out.append(version, 0, lastIndex + 1)
|
||||||
|
out.append(lastVersion + 1)
|
||||||
|
if (dashIndex >= 0) out.append(version, dashIndex, version.length)
|
||||||
|
return out.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Capitalise the first letter of the string.
|
||||||
|
*
|
||||||
|
* This is a replacement for the now deprecated [String.capitalize].
|
||||||
|
*/
|
||||||
|
fun String.capitalise(): String {
|
||||||
|
if (isEmpty()) return this
|
||||||
|
val first = this[0]
|
||||||
|
val firstTitle = first.titlecaseChar()
|
||||||
|
return if (first == firstTitle) this else firstTitle + substring(1)
|
||||||
|
}
|
||||||
|
@@ -1,26 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package cc.tweaked.gradle
|
|
||||||
|
|
||||||
import net.minecraftforge.gradle.common.util.RunConfig
|
|
||||||
import net.minecraftforge.gradle.common.util.runs.setRunConfigInternal
|
|
||||||
import org.gradle.api.plugins.JavaPluginExtension
|
|
||||||
import org.gradle.api.tasks.JavaExec
|
|
||||||
import org.gradle.jvm.toolchain.JavaToolchainService
|
|
||||||
import java.nio.file.Files
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set [JavaExec] task to run a given [RunConfig].
|
|
||||||
*/
|
|
||||||
fun JavaExec.setRunConfig(config: RunConfig) {
|
|
||||||
dependsOn("prepareRuns")
|
|
||||||
setRunConfigInternal(project, this, config)
|
|
||||||
doFirst("Create working directory") { Files.createDirectories(workingDir.toPath()) }
|
|
||||||
|
|
||||||
javaLauncher.set(
|
|
||||||
project.extensions.getByType(JavaToolchainService::class.java)
|
|
||||||
.launcherFor(project.extensions.getByType(JavaPluginExtension::class.java).toolchain),
|
|
||||||
)
|
|
||||||
}
|
|
23
buildSrc/src/main/kotlin/cc/tweaked/gradle/IdeaExt.kt
Normal file
23
buildSrc/src/main/kotlin/cc/tweaked/gradle/IdeaExt.kt
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package cc.tweaked.gradle
|
||||||
|
|
||||||
|
import org.jetbrains.gradle.ext.JUnit
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A version of [JUnit] with a functional [className].
|
||||||
|
*
|
||||||
|
* See [#92](https://github.com/JetBrains/gradle-idea-ext-plugin/issues/92).
|
||||||
|
*/
|
||||||
|
open class JUnitExt @Inject constructor(nameParam: String) : JUnit(nameParam) {
|
||||||
|
override fun toMap(): MutableMap<String, *> {
|
||||||
|
val map = HashMap(super.toMap())
|
||||||
|
// Should be "class" instead of "className".
|
||||||
|
// See https://github.com/JetBrains/intellij-community/blob/9ba394021dc73a3926f13d6d6cdf434f9ee7046d/plugins/junit/src/com/intellij/execution/junit/JUnitRunConfigurationImporter.kt#L39
|
||||||
|
map["class"] = className
|
||||||
|
return map
|
||||||
|
}
|
||||||
|
}
|
@@ -25,7 +25,6 @@ import javax.xml.xpath.XPathFactory
|
|||||||
* Would be good to PR some (or all) of these changes upstream at some point.
|
* Would be good to PR some (or all) of these changes upstream at some point.
|
||||||
*
|
*
|
||||||
* @see net.fabricmc.loom.configuration.ide.idea.IdeaSyncTask
|
* @see net.fabricmc.loom.configuration.ide.idea.IdeaSyncTask
|
||||||
* @see net.minecraftforge.gradle.common.util.runs.IntellijRunGenerator
|
|
||||||
*/
|
*/
|
||||||
internal class IdeaRunConfigurations(project: Project) {
|
internal class IdeaRunConfigurations(project: Project) {
|
||||||
private val rootProject = project.rootProject
|
private val rootProject = project.rootProject
|
||||||
@@ -35,22 +34,6 @@ internal class IdeaRunConfigurations(project: Project) {
|
|||||||
private val writer = TransformerFactory.newInstance().newTransformer()
|
private val writer = TransformerFactory.newInstance().newTransformer()
|
||||||
|
|
||||||
private val ideaDir = rootProject.file(".idea/")
|
private val ideaDir = rootProject.file(".idea/")
|
||||||
private val buildDir: Lazy<String?> = lazy {
|
|
||||||
val ideaMisc = ideaDir.resolve("misc.xml")
|
|
||||||
|
|
||||||
try {
|
|
||||||
val doc = Files.newBufferedReader(ideaMisc.toPath()).use {
|
|
||||||
documentBuilder.parse(InputSource(it))
|
|
||||||
}
|
|
||||||
val node =
|
|
||||||
xpath.evaluate("//component[@name=\"ProjectRootManager\"]/output", doc, XPathConstants.NODE) as Node
|
|
||||||
val attr = node.attributes.getNamedItem("url") as Attr
|
|
||||||
attr.value.removePrefix("file://")
|
|
||||||
} catch (e: Exception) {
|
|
||||||
LOGGER.error("Failed to find root directory", e)
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun patch() = synchronized(LOCK) {
|
fun patch() = synchronized(LOCK) {
|
||||||
val runConfigDir = ideaDir.resolve("runConfigurations")
|
val runConfigDir = ideaDir.resolve("runConfigurations")
|
||||||
@@ -58,10 +41,9 @@ internal class IdeaRunConfigurations(project: Project) {
|
|||||||
|
|
||||||
Files.list(runConfigDir.toPath()).use {
|
Files.list(runConfigDir.toPath()).use {
|
||||||
for (configuration in it) {
|
for (configuration in it) {
|
||||||
val filename = configuration.fileName.toString();
|
val filename = configuration.fileName.toString()
|
||||||
when {
|
when {
|
||||||
filename.endsWith("_fabric.xml") -> patchFabric(configuration)
|
filename.endsWith("_fabric.xml") -> patchFabric(configuration)
|
||||||
filename.startsWith("forge_") && filename.endsWith(".xml") -> patchForge(configuration)
|
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -72,65 +54,6 @@ internal class IdeaRunConfigurations(project: Project) {
|
|||||||
setXml("//configuration", "folderName") { "Fabric" }
|
setXml("//configuration", "folderName") { "Fabric" }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun patchForge(path: Path) = withXml(path) {
|
|
||||||
val configId = path.fileName.toString().removePrefix("forge_").removeSuffix(".xml")
|
|
||||||
val sourceSet = forgeConfigs[configId]
|
|
||||||
if (sourceSet == null) {
|
|
||||||
LOGGER.error("[{}] Cannot map run configuration to a known source set", path)
|
|
||||||
return@withXml
|
|
||||||
}
|
|
||||||
|
|
||||||
setXml("//configuration", "folderName") { "Forge" }
|
|
||||||
setXml("//configuration/module", "name") { "${rootProject.name}.forge.$sourceSet" }
|
|
||||||
|
|
||||||
if (buildDir.value == null) return@withXml
|
|
||||||
setXml("//configuration/envs/env[@name=\"MOD_CLASSES\"]", "value") { classpath ->
|
|
||||||
val classes = classpath!!.split(':')
|
|
||||||
val newClasses = mutableListOf<String>()
|
|
||||||
fun appendUnique(x: String) {
|
|
||||||
if (!newClasses.contains(x)) newClasses.add(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
for (entry in classes) {
|
|
||||||
if (!entry.contains("/out/")) {
|
|
||||||
appendUnique(entry)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
val match = CLASSPATH_ENTRY.matchEntire(entry)
|
|
||||||
if (match != null) {
|
|
||||||
val modId = match.groups["modId"]!!.value
|
|
||||||
val proj = match.groups["proj"]!!.value
|
|
||||||
var component = match.groups["component"]!!.value
|
|
||||||
if (component == "production") component = "main"
|
|
||||||
|
|
||||||
appendUnique(forgeModEntry(modId, proj, component))
|
|
||||||
} else {
|
|
||||||
LOGGER.warn("[{}] Unknown classpath entry {}", path, entry)
|
|
||||||
appendUnique(entry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure common code is on the classpath
|
|
||||||
for (proj in listOf("common", "common-api")) {
|
|
||||||
for (component in listOf("main", "client")) {
|
|
||||||
appendUnique(forgeModEntry("computercraft", proj, component))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newClasses.any { it.startsWith("cctest%%") }) {
|
|
||||||
appendUnique(forgeModEntry("cctest", "core", "testFixtures"))
|
|
||||||
appendUnique(forgeModEntry("cctest", "common", "testFixtures"))
|
|
||||||
appendUnique(forgeModEntry("cctest", "common", "testMod"))
|
|
||||||
}
|
|
||||||
|
|
||||||
newClasses.joinToString(":")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun forgeModEntry(mod: String, project: String, component: String) =
|
|
||||||
"$mod%%${buildDir.value}/production/${rootProject.name}.$project.$component"
|
|
||||||
|
|
||||||
private fun LocatedDocument.setXml(xpath: String, attribute: String, value: (String?) -> String) {
|
private fun LocatedDocument.setXml(xpath: String, attribute: String, value: (String?) -> String) {
|
||||||
val node = this@IdeaRunConfigurations.xpath.evaluate(xpath, document, XPathConstants.NODE) as Node?
|
val node = this@IdeaRunConfigurations.xpath.evaluate(xpath, document, XPathConstants.NODE) as Node?
|
||||||
if (node == null) {
|
if (node == null) {
|
||||||
@@ -159,16 +82,5 @@ internal class IdeaRunConfigurations(project: Project) {
|
|||||||
companion object {
|
companion object {
|
||||||
private val LOGGER = Logging.getLogger(IdeaRunConfigurations::class.java)
|
private val LOGGER = Logging.getLogger(IdeaRunConfigurations::class.java)
|
||||||
private val LOCK = Any()
|
private val LOCK = Any()
|
||||||
|
|
||||||
private val CLASSPATH_ENTRY =
|
|
||||||
Regex("(?<modId>[a-z]+)%%\\\$PROJECT_DIR\\\$/projects/(?<proj>[a-z-]+)/out/(?<component>\\w+)/(?<type>[a-z]+)\$")
|
|
||||||
|
|
||||||
private val forgeConfigs = mapOf(
|
|
||||||
"runClient" to "client",
|
|
||||||
"runData" to "main",
|
|
||||||
"runGameTestServer" to "testMod",
|
|
||||||
"runServer" to "main",
|
|
||||||
"runTestClient" to "testMod",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,66 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package cc.tweaked.gradle
|
|
||||||
|
|
||||||
import org.gradle.api.artifacts.Dependency
|
|
||||||
import org.gradle.api.artifacts.MinimalExternalModuleDependency
|
|
||||||
import org.gradle.api.publish.maven.MavenPublication
|
|
||||||
import org.gradle.api.specs.Spec
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A dependency in a POM file.
|
|
||||||
*/
|
|
||||||
data class MavenDependency(val groupId: String?, val artifactId: String?, val version: String?, val scope: String?)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A spec specifying which dependencies to include/exclude.
|
|
||||||
*/
|
|
||||||
class MavenDependencySpec {
|
|
||||||
private val excludeSpecs = mutableListOf<Spec<MavenDependency>>()
|
|
||||||
|
|
||||||
fun exclude(spec: Spec<MavenDependency>) {
|
|
||||||
excludeSpecs.add(spec)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun exclude(dep: Dependency) {
|
|
||||||
exclude {
|
|
||||||
(dep.group.isNullOrEmpty() || dep.group == it.groupId) &&
|
|
||||||
(dep.name.isNullOrEmpty() || dep.name == it.artifactId) &&
|
|
||||||
(dep.version.isNullOrEmpty() || dep.version == it.version)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun exclude(dep: MinimalExternalModuleDependency) {
|
|
||||||
exclude {
|
|
||||||
dep.module.group == it.groupId && dep.module.name == it.artifactId
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isIncluded(dep: MavenDependency) = !excludeSpecs.any { it.isSatisfiedBy(dep) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure dependencies present in this publication's POM file.
|
|
||||||
*
|
|
||||||
* While this approach is very ugly, it's the easiest way to handle it!
|
|
||||||
*/
|
|
||||||
fun MavenPublication.mavenDependencies(action: MavenDependencySpec.() -> Unit) {
|
|
||||||
val spec = MavenDependencySpec()
|
|
||||||
action(spec)
|
|
||||||
|
|
||||||
pom.withXml {
|
|
||||||
val dependencies = XmlUtil.findChild(asNode(), "dependencies") ?: return@withXml
|
|
||||||
dependencies.children().map { it as groovy.util.Node }.forEach {
|
|
||||||
val dep = MavenDependency(
|
|
||||||
groupId = XmlUtil.findChild(it, "groupId")?.text(),
|
|
||||||
artifactId = XmlUtil.findChild(it, "artifactId")?.text(),
|
|
||||||
version = XmlUtil.findChild(it, "version")?.text(),
|
|
||||||
scope = XmlUtil.findChild(it, "scope")?.text(),
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!spec.isIncluded(dep)) it.parent().remove(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
120
buildSrc/src/main/kotlin/cc/tweaked/gradle/MergeTrees.kt
Normal file
120
buildSrc/src/main/kotlin/cc/tweaked/gradle/MergeTrees.kt
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package cc.tweaked.gradle
|
||||||
|
|
||||||
|
import cc.tweaked.vanillaextract.core.util.MoreFiles
|
||||||
|
import org.gradle.api.Action
|
||||||
|
import org.gradle.api.DefaultTask
|
||||||
|
import org.gradle.api.GradleException
|
||||||
|
import org.gradle.api.file.*
|
||||||
|
import org.gradle.api.model.ObjectFactory
|
||||||
|
import org.gradle.api.provider.ListProperty
|
||||||
|
import org.gradle.api.tasks.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge common files across multiple directories into one destination directory.
|
||||||
|
*
|
||||||
|
* This is intended for merging the generated resources from the Forge and Fabric projects. Files common between the two
|
||||||
|
* are written to the global [output] directory, while distinct files are written to the per-source
|
||||||
|
* [MergeTrees.Source.output] directory.
|
||||||
|
*/
|
||||||
|
abstract class MergeTrees : DefaultTask() {
|
||||||
|
/**
|
||||||
|
* A source directory to read from.
|
||||||
|
*/
|
||||||
|
interface Source {
|
||||||
|
/**
|
||||||
|
* The folder contianing all input files.
|
||||||
|
*/
|
||||||
|
@get:InputFiles
|
||||||
|
@get:PathSensitive(PathSensitivity.RELATIVE)
|
||||||
|
val input: ConfigurableFileTree
|
||||||
|
|
||||||
|
fun input(configure: Action<ConfigurableFileTree>) {
|
||||||
|
configure.execute(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The folder to write files unique to this folder to.
|
||||||
|
*/
|
||||||
|
@get:OutputDirectory
|
||||||
|
val output: DirectoryProperty
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of sources.
|
||||||
|
*/
|
||||||
|
@get:Nested
|
||||||
|
abstract val sources: ListProperty<Source>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add and configure a new source.
|
||||||
|
*/
|
||||||
|
fun source(configure: Action<Source>) {
|
||||||
|
val instance = objectFactory.newInstance(Source::class.java)
|
||||||
|
configure.execute(instance)
|
||||||
|
instance.output.disallowChanges()
|
||||||
|
sources.add(instance)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The directory to write common files to.
|
||||||
|
*/
|
||||||
|
@get:OutputDirectory
|
||||||
|
abstract val output: DirectoryProperty
|
||||||
|
|
||||||
|
@get:Inject
|
||||||
|
protected abstract val objectFactory: ObjectFactory
|
||||||
|
|
||||||
|
@get:Inject
|
||||||
|
protected abstract val fsOperations: FileSystemOperations
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
fun run() {
|
||||||
|
val sources = this.sources.get()
|
||||||
|
if (sources.isEmpty()) throw GradleException("Cannot have an empty list of sources")
|
||||||
|
|
||||||
|
val files = mutableMapOf<String, SharedFile>()
|
||||||
|
for (source in sources) {
|
||||||
|
source.input.visit(
|
||||||
|
object : FileVisitor {
|
||||||
|
override fun visitDir(dirDetails: FileVisitDetails) = Unit
|
||||||
|
override fun visitFile(fileDetails: FileVisitDetails) {
|
||||||
|
val path = fileDetails.file.toRelativeString(source.input.dir)
|
||||||
|
val hash = MoreFiles.computeSha1(fileDetails.file.toPath())
|
||||||
|
|
||||||
|
val existing = files[path]
|
||||||
|
if (existing == null) {
|
||||||
|
files[path] = SharedFile(hash, 1)
|
||||||
|
} else if (existing.hash == hash) {
|
||||||
|
existing.found++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val sharedFiles = files.entries.asSequence().filter { (_, v) -> v.found == sources.size }.map { (k, _) -> k }.toList()
|
||||||
|
|
||||||
|
// Copy shared files to the common directory
|
||||||
|
fsOperations.sync {
|
||||||
|
from(sources[0].input)
|
||||||
|
into(output)
|
||||||
|
include(sharedFiles)
|
||||||
|
}
|
||||||
|
|
||||||
|
// And all other files to their per-source directory
|
||||||
|
for (source in sources) {
|
||||||
|
fsOperations.sync {
|
||||||
|
from(source.input)
|
||||||
|
into(source.output)
|
||||||
|
exclude(sharedFiles)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SharedFile(val hash: String, var found: Int)
|
||||||
|
}
|
@@ -4,23 +4,17 @@
|
|||||||
|
|
||||||
package cc.tweaked.gradle
|
package cc.tweaked.gradle
|
||||||
|
|
||||||
|
import cc.tweaked.vanillaextract.configurations.Capabilities
|
||||||
|
import cc.tweaked.vanillaextract.configurations.MinecraftSetup
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.gradle.api.artifacts.Configuration
|
|
||||||
import org.gradle.api.artifacts.ModuleDependency
|
import org.gradle.api.artifacts.ModuleDependency
|
||||||
import org.gradle.api.artifacts.dsl.DependencyHandler
|
import org.gradle.api.artifacts.dsl.DependencyHandler
|
||||||
import org.gradle.api.attributes.Bundling
|
|
||||||
import org.gradle.api.attributes.Category
|
|
||||||
import org.gradle.api.attributes.LibraryElements
|
|
||||||
import org.gradle.api.attributes.Usage
|
|
||||||
import org.gradle.api.attributes.java.TargetJvmVersion
|
|
||||||
import org.gradle.api.capabilities.Capability
|
|
||||||
import org.gradle.api.plugins.BasePlugin
|
import org.gradle.api.plugins.BasePlugin
|
||||||
import org.gradle.api.plugins.JavaPluginExtension
|
import org.gradle.api.plugins.JavaPluginExtension
|
||||||
import org.gradle.api.tasks.SourceSet
|
import org.gradle.api.tasks.SourceSet
|
||||||
import org.gradle.api.tasks.bundling.Jar
|
import org.gradle.api.tasks.bundling.Jar
|
||||||
import org.gradle.api.tasks.javadoc.Javadoc
|
import org.gradle.api.tasks.javadoc.Javadoc
|
||||||
import org.gradle.kotlin.dsl.get
|
import org.gradle.kotlin.dsl.get
|
||||||
import org.gradle.kotlin.dsl.named
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This sets up a separate client-only source set, and extends that and the main/common source set with additional
|
* This sets up a separate client-only source set, and extends that and the main/common source set with additional
|
||||||
@@ -30,7 +24,6 @@ class MinecraftConfigurations private constructor(private val project: Project)
|
|||||||
private val java = project.extensions.getByType(JavaPluginExtension::class.java)
|
private val java = project.extensions.getByType(JavaPluginExtension::class.java)
|
||||||
private val sourceSets = java.sourceSets
|
private val sourceSets = java.sourceSets
|
||||||
private val configurations = project.configurations
|
private val configurations = project.configurations
|
||||||
private val objects = project.objects
|
|
||||||
|
|
||||||
private val main = sourceSets[SourceSet.MAIN_SOURCE_SET_NAME]
|
private val main = sourceSets[SourceSet.MAIN_SOURCE_SET_NAME]
|
||||||
private val test = sourceSets[SourceSet.TEST_SOURCE_SET_NAME]
|
private val test = sourceSets[SourceSet.TEST_SOURCE_SET_NAME]
|
||||||
@@ -43,13 +36,7 @@ class MinecraftConfigurations private constructor(private val project: Project)
|
|||||||
val client = sourceSets.maybeCreate("client")
|
val client = sourceSets.maybeCreate("client")
|
||||||
|
|
||||||
// Ensure the client classpaths behave the same as the main ones.
|
// Ensure the client classpaths behave the same as the main ones.
|
||||||
configurations.named(client.compileClasspathConfigurationName) {
|
consistentWithMain(client)
|
||||||
shouldResolveConsistentlyWith(configurations[main.compileClasspathConfigurationName])
|
|
||||||
}
|
|
||||||
|
|
||||||
configurations.named(client.runtimeClasspathConfigurationName) {
|
|
||||||
shouldResolveConsistentlyWith(configurations[main.runtimeClasspathConfigurationName])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up an API configuration for clients (to ensure it's consistent with the main source set).
|
// Set up an API configuration for clients (to ensure it's consistent with the main source set).
|
||||||
val clientApi = configurations.maybeCreate(client.apiConfigurationName).apply {
|
val clientApi = configurations.maybeCreate(client.apiConfigurationName).apply {
|
||||||
@@ -59,31 +46,13 @@ class MinecraftConfigurations private constructor(private val project: Project)
|
|||||||
}
|
}
|
||||||
configurations.named(client.implementationConfigurationName) { extendsFrom(clientApi) }
|
configurations.named(client.implementationConfigurationName) { extendsFrom(clientApi) }
|
||||||
|
|
||||||
/*
|
|
||||||
Now add outgoing variants for the main and common source sets that we can consume downstream. This is possibly
|
|
||||||
the worst way to do things, but unfortunately the alternatives don't actually work very well:
|
|
||||||
|
|
||||||
- Just using source set outputs: This means dependencies don't propagate, which means when :fabric depends
|
|
||||||
on :fabric-api, we don't inherit the fake :common-api in IDEA.
|
|
||||||
|
|
||||||
- Having separate common/main jars: Nice in principle, but unfortunately Forge needs a separate deobf jar
|
|
||||||
task (as the original jar is obfuscated), and IDEA is not able to map its output back to a source set.
|
|
||||||
|
|
||||||
This works for now, but is incredibly brittle. It's part of the reason we can't use testFixtures inside our
|
|
||||||
MC projects, as that adds a project(self) -> test dependency, which would pull in the jar instead.
|
|
||||||
|
|
||||||
Note we register a fake client jar here. It's not actually needed, but is there to make sure IDEA has
|
|
||||||
a way to tell that client classes are needed at runtime.
|
|
||||||
|
|
||||||
I'm so sorry, deeply aware how cursed this is.
|
|
||||||
*/
|
|
||||||
setupOutgoing(main, "CommonOnly")
|
|
||||||
project.tasks.register(client.jarTaskName, Jar::class.java) {
|
project.tasks.register(client.jarTaskName, Jar::class.java) {
|
||||||
description = "An empty jar standing in for the client classes."
|
description = "An empty jar standing in for the client classes."
|
||||||
group = BasePlugin.BUILD_GROUP
|
group = BasePlugin.BUILD_GROUP
|
||||||
archiveClassifier.set("client")
|
archiveClassifier.set("client")
|
||||||
}
|
}
|
||||||
setupOutgoing(client)
|
|
||||||
|
MinecraftSetup(project).setupOutgoingConfigurations()
|
||||||
|
|
||||||
// Reset the client classpath (Loom configures it slightly differently to this) and add a main -> client
|
// Reset the client classpath (Loom configures it slightly differently to this) and add a main -> client
|
||||||
// dependency. Here we /can/ use source set outputs as we add transitive deps by patching the classpath. Nasty,
|
// dependency. Here we /can/ use source set outputs as we add transitive deps by patching the classpath. Nasty,
|
||||||
@@ -106,88 +75,70 @@ class MinecraftConfigurations private constructor(private val project: Project)
|
|||||||
project.tasks.named("jar", Jar::class.java) { from(client.output) }
|
project.tasks.named("jar", Jar::class.java) { from(client.output) }
|
||||||
project.tasks.named("sourcesJar", Jar::class.java) { from(client.allSource) }
|
project.tasks.named("sourcesJar", Jar::class.java) { from(client.allSource) }
|
||||||
|
|
||||||
|
setupBasic()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun consistentWithMain(sourceSet: SourceSet) {
|
||||||
|
configurations.named(sourceSet.compileClasspathConfigurationName) {
|
||||||
|
shouldResolveConsistentlyWith(configurations[main.compileClasspathConfigurationName])
|
||||||
|
}
|
||||||
|
|
||||||
|
configurations.named(sourceSet.runtimeClasspathConfigurationName) {
|
||||||
|
shouldResolveConsistentlyWith(configurations[main.runtimeClasspathConfigurationName])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupBasic() {
|
||||||
|
val client = sourceSets["client"]
|
||||||
|
|
||||||
project.extensions.configure(CCTweakedExtension::class.java) {
|
project.extensions.configure(CCTweakedExtension::class.java) {
|
||||||
sourceDirectories.add(SourceSetReference.internal(client))
|
sourceDirectories.add(SourceSetReference.internal(client))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun setupOutgoing(sourceSet: SourceSet, suffix: String = "") {
|
// Register a task to check there are no conflicts with the core project.
|
||||||
setupOutgoing("${sourceSet.apiElementsConfigurationName}$suffix", sourceSet, objects.named(Usage.JAVA_API)) {
|
val checkDependencyConsistency =
|
||||||
description = "API elements for ${sourceSet.name}"
|
project.tasks.register("checkDependencyConsistency", DependencyCheck::class.java) {
|
||||||
extendsFrom(configurations[sourceSet.apiConfigurationName])
|
// We need to check both the main and client classpath *configurations*, as the actual configuration
|
||||||
}
|
configuration(configurations.named(main.runtimeClasspathConfigurationName))
|
||||||
|
configuration(configurations.named(client.runtimeClasspathConfigurationName))
|
||||||
setupOutgoing("${sourceSet.runtimeElementsConfigurationName}$suffix", sourceSet, objects.named(Usage.JAVA_RUNTIME)) {
|
}
|
||||||
description = "Runtime elements for ${sourceSet.name}"
|
project.tasks.named("check") { dependsOn(checkDependencyConsistency) }
|
||||||
extendsFrom(configurations[sourceSet.implementationConfigurationName], configurations[sourceSet.runtimeOnlyConfigurationName])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up an outgoing configuration for a specific source set. We set an additional "main" or "client" capability
|
* Create a new configuration that pulls in the main and client classes from the mod.
|
||||||
* (depending on the source set name) which allows downstream projects to consume them separately (see
|
|
||||||
* [DependencyHandler.commonClasses] and [DependencyHandler.clientClasses]).
|
|
||||||
*/
|
*/
|
||||||
private fun setupOutgoing(name: String, sourceSet: SourceSet, usage: Usage, configure: Configuration.() -> Unit) {
|
private fun createDerivedConfiguration(name: String) {
|
||||||
configurations.register(name) {
|
val client = sourceSets["client"]
|
||||||
isVisible = false
|
val sourceSet = sourceSets.create(name)
|
||||||
isCanBeConsumed = true
|
sourceSet.compileClasspath += main.compileClasspath + client.compileClasspath
|
||||||
isCanBeResolved = false
|
sourceSet.runtimeClasspath += main.runtimeClasspath + client.runtimeClasspath
|
||||||
|
consistentWithMain(sourceSet)
|
||||||
configure(this)
|
project.dependencies.add(sourceSet.implementationConfigurationName, main.output)
|
||||||
|
project.dependencies.add(sourceSet.implementationConfigurationName, client.output)
|
||||||
attributes {
|
|
||||||
attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY))
|
|
||||||
attribute(Usage.USAGE_ATTRIBUTE, usage)
|
|
||||||
attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.EXTERNAL))
|
|
||||||
attributeProvider(
|
|
||||||
TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE,
|
|
||||||
java.toolchain.languageVersion.map { it.asInt() },
|
|
||||||
)
|
|
||||||
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.JAR))
|
|
||||||
}
|
|
||||||
|
|
||||||
outgoing {
|
|
||||||
capability(BasicOutgoingCapability(project, sourceSet.name))
|
|
||||||
|
|
||||||
// We have two outgoing variants here: the original jar and the classes.
|
|
||||||
artifact(project.tasks.named(sourceSet.jarTaskName))
|
|
||||||
|
|
||||||
variants.create("classes") {
|
|
||||||
attributes.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.CLASSES))
|
|
||||||
sourceSet.output.classesDirs.forEach { artifact(it) { builtBy(sourceSet.output) } }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
const val DATAGEN = "datagen"
|
||||||
|
const val EXAMPLES = "examples"
|
||||||
|
const val TEST_MOD = "testMod"
|
||||||
|
|
||||||
|
fun setupBasic(project: Project) {
|
||||||
|
MinecraftConfigurations(project).setupBasic()
|
||||||
|
}
|
||||||
|
|
||||||
fun setup(project: Project) {
|
fun setup(project: Project) {
|
||||||
MinecraftConfigurations(project).setup()
|
MinecraftConfigurations(project).setup()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun createDerivedConfiguration(project: Project, name: String) {
|
||||||
|
MinecraftConfigurations(project).createDerivedConfiguration(name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class BasicIncomingCapability(private val module: ModuleDependency, private val name: String) : Capability {
|
fun DependencyHandler.clientClasses(notation: Any): ModuleDependency =
|
||||||
override fun getGroup(): String = module.group!!
|
Capabilities.clientClasses(create(notation) as ModuleDependency)
|
||||||
override fun getName(): String = "${module.name}-$name"
|
|
||||||
override fun getVersion(): String? = null
|
|
||||||
}
|
|
||||||
|
|
||||||
private class BasicOutgoingCapability(private val project: Project, private val name: String) : Capability {
|
fun DependencyHandler.commonClasses(notation: Any): ModuleDependency =
|
||||||
override fun getGroup(): String = project.group.toString()
|
Capabilities.commonClasses(create(notation) as ModuleDependency)
|
||||||
override fun getName(): String = "${project.name}-$name"
|
|
||||||
override fun getVersion(): String = project.version.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun DependencyHandler.clientClasses(notation: Any): ModuleDependency {
|
|
||||||
val dep = create(notation) as ModuleDependency
|
|
||||||
dep.capabilities { requireCapability(BasicIncomingCapability(dep, "client")) }
|
|
||||||
return dep
|
|
||||||
}
|
|
||||||
|
|
||||||
fun DependencyHandler.commonClasses(notation: Any): ModuleDependency {
|
|
||||||
val dep = create(notation) as ModuleDependency
|
|
||||||
dep.capabilities { requireCapability(BasicIncomingCapability(dep, "main")) }
|
|
||||||
return dep
|
|
||||||
}
|
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
package cc.tweaked.gradle
|
package cc.tweaked.gradle
|
||||||
|
|
||||||
import net.minecraftforge.gradle.common.util.RunConfig
|
import net.neoforged.moddevgradle.internal.RunGameTask
|
||||||
import org.gradle.api.GradleException
|
import org.gradle.api.GradleException
|
||||||
import org.gradle.api.file.FileSystemOperations
|
import org.gradle.api.file.FileSystemOperations
|
||||||
import org.gradle.api.invocation.Gradle
|
import org.gradle.api.invocation.Gradle
|
||||||
@@ -19,6 +19,7 @@ import java.nio.file.Files
|
|||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import java.util.function.Supplier
|
import java.util.function.Supplier
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
import kotlin.collections.set
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -58,18 +59,26 @@ abstract class ClientJavaExec : JavaExec() {
|
|||||||
if (!clientDebug) systemProperty("cctest.client", "")
|
if (!clientDebug) systemProperty("cctest.client", "")
|
||||||
if (renderdoc) environment("LD_PRELOAD", "/usr/lib/librenderdoc.so")
|
if (renderdoc) environment("LD_PRELOAD", "/usr/lib/librenderdoc.so")
|
||||||
systemProperty("cctest.gametest-report", testResults.get().asFile.absoluteFile)
|
systemProperty("cctest.gametest-report", testResults.get().asFile.absoluteFile)
|
||||||
workingDir(project.buildDir.resolve("gametest").resolve(name))
|
workingDir(project.layout.buildDirectory.dir("gametest/$name"))
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
setTestProperties()
|
setTestProperties()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun copyFromForge(path: String) = copyFromForge(project.tasks.getByName(path, RunGameTask::class))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set this task to run a given [RunConfig].
|
* Set this task to run a given [RunGameTask].
|
||||||
*/
|
*/
|
||||||
fun setRunConfig(config: RunConfig) {
|
fun copyFromForge(task: RunGameTask) {
|
||||||
(this as JavaExec).setRunConfig(config)
|
copyFrom(task)
|
||||||
|
|
||||||
|
// Eagerly evaluate the behaviour of RunGameTask.exec
|
||||||
|
environment.putAll(task.environmentProperty.get())
|
||||||
|
classpath(task.classpathProvider)
|
||||||
|
workingDir = task.gameDirectory.get().asFile
|
||||||
|
|
||||||
setTestProperties() // setRunConfig may clobber some properties, ensure everything is set.
|
setTestProperties() // setRunConfig may clobber some properties, ensure everything is set.
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,6 +126,23 @@ abstract class ClientJavaExec : JavaExec() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure Iris to use Complementary Shaders.
|
||||||
|
*/
|
||||||
|
fun withComplementaryShaders() {
|
||||||
|
val cct = project.extensions.getByType(CCTweakedExtension::class.java)
|
||||||
|
|
||||||
|
withFileFrom(workingDir.resolve("shaderpacks/ComplementaryShaders_v4.6.zip")) {
|
||||||
|
cct.downloadFile("Complementary Shaders", "https://edge.forgecdn.net/files/3951/170/ComplementaryShaders_v4.6.zip")
|
||||||
|
}
|
||||||
|
withFileContents(workingDir.resolve("config/iris.properties")) {
|
||||||
|
"""
|
||||||
|
enableShaders=true
|
||||||
|
shaderPack=ComplementaryShaders_v4.6.zip
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TaskAction
|
@TaskAction
|
||||||
override fun exec() {
|
override fun exec() {
|
||||||
Files.createDirectories(workingDir.toPath())
|
Files.createDirectories(workingDir.toPath())
|
||||||
|
@@ -11,7 +11,9 @@ import org.gradle.api.file.Directory
|
|||||||
import org.gradle.api.file.DirectoryProperty
|
import org.gradle.api.file.DirectoryProperty
|
||||||
import org.gradle.api.provider.Provider
|
import org.gradle.api.provider.Provider
|
||||||
import org.gradle.api.tasks.*
|
import org.gradle.api.tasks.*
|
||||||
|
import org.gradle.process.ExecOperations
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
class NodePlugin : Plugin<Project> {
|
class NodePlugin : Plugin<Project> {
|
||||||
override fun apply(project: Project) {
|
override fun apply(project: Project) {
|
||||||
@@ -43,10 +45,13 @@ abstract class NpmInstall : DefaultTask() {
|
|||||||
@get:OutputDirectory
|
@get:OutputDirectory
|
||||||
val nodeModules: Provider<Directory> = projectRoot.dir("node_modules")
|
val nodeModules: Provider<Directory> = projectRoot.dir("node_modules")
|
||||||
|
|
||||||
|
@get:Inject
|
||||||
|
protected abstract val execOperations: ExecOperations
|
||||||
|
|
||||||
@TaskAction
|
@TaskAction
|
||||||
fun install() {
|
fun install() {
|
||||||
project.exec {
|
execOperations.exec {
|
||||||
commandLine("npm", "ci")
|
commandLine(ProcessHelpers.getExecutable("npm"), "ci")
|
||||||
workingDir = projectRoot.get().asFile
|
workingDir = projectRoot.get().asFile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -59,6 +64,6 @@ abstract class NpmInstall : DefaultTask() {
|
|||||||
abstract class NpxExecToDir : ExecToDir() {
|
abstract class NpxExecToDir : ExecToDir() {
|
||||||
init {
|
init {
|
||||||
dependsOn(NpmInstall.TASK_NAME)
|
dependsOn(NpmInstall.TASK_NAME)
|
||||||
executable = "npx"
|
executable = ProcessHelpers.getExecutable("npx")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,48 +4,36 @@
|
|||||||
|
|
||||||
package cc.tweaked.gradle
|
package cc.tweaked.gradle
|
||||||
|
|
||||||
import org.codehaus.groovy.runtime.ProcessGroovyMethods
|
|
||||||
import org.gradle.api.GradleException
|
import org.gradle.api.GradleException
|
||||||
import java.io.BufferedReader
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.InputStreamReader
|
|
||||||
|
|
||||||
internal object ProcessHelpers {
|
internal object ProcessHelpers {
|
||||||
fun startProcess(vararg command: String): Process {
|
|
||||||
// Something randomly passes in "GIT_DIR=" as an environment variable which clobbers everything else. Don't
|
|
||||||
// inherit the environment array!
|
|
||||||
return ProcessBuilder()
|
|
||||||
.command(*command)
|
|
||||||
.redirectError(ProcessBuilder.Redirect.INHERIT)
|
|
||||||
.also { it.environment().clear() }
|
|
||||||
.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun captureOut(vararg command: String): String {
|
|
||||||
val process = startProcess(*command)
|
|
||||||
process.outputStream.close()
|
|
||||||
|
|
||||||
val result = ProcessGroovyMethods.getText(process)
|
|
||||||
process.waitForOrThrow("Failed to run command")
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
fun captureLines(vararg command: String): List<String> {
|
|
||||||
val process = startProcess(*command)
|
|
||||||
process.outputStream.close()
|
|
||||||
|
|
||||||
val out = BufferedReader(InputStreamReader(process.inputStream)).use { reader ->
|
|
||||||
reader.lines().filter { it.isNotEmpty() }.toList()
|
|
||||||
}
|
|
||||||
ProcessGroovyMethods.closeStreams(process)
|
|
||||||
process.waitForOrThrow("Failed to run command")
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onPath(name: String): Boolean {
|
fun onPath(name: String): Boolean {
|
||||||
val path = System.getenv("PATH") ?: return false
|
val path = System.getenv("PATH") ?: return false
|
||||||
return path.splitToSequence(File.pathSeparator).any { File(it, name).exists() }
|
return path.splitToSequence(File.pathSeparator).any { File(it, name).exists() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search for an executable on the `PATH` if required.
|
||||||
|
*
|
||||||
|
* [Process]/[ProcessBuilder] does not handle all executable file extensions on Windows (such as `.com). When on
|
||||||
|
* Windows, this function searches `PATH` and `PATHEXT` for an executable matching [name].
|
||||||
|
*/
|
||||||
|
fun getExecutable(name: String): String {
|
||||||
|
if (!System.getProperty("os.name").lowercase().contains("windows")) return name
|
||||||
|
|
||||||
|
val path = (System.getenv("PATH") ?: return name).split(File.pathSeparator)
|
||||||
|
val pathExt = (System.getenv("PATHEXT") ?: return name).split(File.pathSeparator)
|
||||||
|
|
||||||
|
for (pathEntry in path) {
|
||||||
|
for (ext in pathExt) {
|
||||||
|
val resolved = File(pathEntry, name + ext)
|
||||||
|
if (resolved.exists()) return resolved.getAbsolutePath()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return name
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun Process.waitForOrThrow(message: String) {
|
internal fun Process.waitForOrThrow(message: String) {
|
||||||
|
@@ -1,16 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package cc.tweaked.gradle
|
|
||||||
|
|
||||||
import groovy.util.Node
|
|
||||||
import groovy.util.NodeList
|
|
||||||
|
|
||||||
object XmlUtil {
|
|
||||||
fun findChild(node: Node, name: String): Node? = when (val child = node.get(name)) {
|
|
||||||
is Node -> child
|
|
||||||
is NodeList -> child.singleOrNull() as Node?
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,51 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package net.minecraftforge.gradle.common.util.runs
|
|
||||||
|
|
||||||
import net.minecraftforge.gradle.common.util.RunConfig
|
|
||||||
import org.gradle.api.Project
|
|
||||||
import org.gradle.process.CommandLineArgumentProvider
|
|
||||||
import org.gradle.process.JavaExecSpec
|
|
||||||
import java.io.File
|
|
||||||
import java.util.function.Supplier
|
|
||||||
import java.util.stream.Collectors
|
|
||||||
import java.util.stream.Stream
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set up a [JavaExecSpec] to execute a [RunConfig].
|
|
||||||
*
|
|
||||||
* [MinecraftRunTask] sets up all its properties when the task is executed, rather than when configured. As such, it's
|
|
||||||
* not possible to use [cc.tweaked.gradle.copyToFull] like we do for Fabric. Instead, we set up the task manually.
|
|
||||||
*
|
|
||||||
* Unfortunately most of the functionality we need is package-private, and so we have to put our code into the package.
|
|
||||||
*/
|
|
||||||
internal fun setRunConfigInternal(project: Project, spec: JavaExecSpec, config: RunConfig) {
|
|
||||||
spec.workingDir = File(config.workingDirectory)
|
|
||||||
|
|
||||||
spec.mainClass.set(config.main)
|
|
||||||
for (source in config.allSources) spec.classpath(source.runtimeClasspath)
|
|
||||||
|
|
||||||
val originalTask = project.tasks.named(config.taskName, MinecraftRunTask::class.java)
|
|
||||||
|
|
||||||
// Add argument and JVM argument via providers, to be as lazy as possible with fetching artifacts.
|
|
||||||
val lazyTokens = RunConfigGenerator.configureTokensLazy(
|
|
||||||
project, config, RunConfigGenerator.mapModClassesToGradle(project, config),
|
|
||||||
originalTask.get().minecraftArtifacts,
|
|
||||||
originalTask.get().runtimeClasspathArtifacts,
|
|
||||||
)
|
|
||||||
spec.argumentProviders.add(
|
|
||||||
CommandLineArgumentProvider {
|
|
||||||
RunConfigGenerator.getArgsStream(config, lazyTokens, false).toList()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
spec.jvmArgumentProviders.add(
|
|
||||||
CommandLineArgumentProvider {
|
|
||||||
(if (config.isClient) config.jvmArgs + originalTask.get().additionalClientArgs.get() else config.jvmArgs).map { config.replace(lazyTokens, it) } +
|
|
||||||
config.properties.map { (k, v) -> "-D${k}=${config.replace(lazyTokens, v)}" }
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
for ((key, value) in config.environment) spec.environment(key, config.replace(lazyTokens, value))
|
|
||||||
}
|
|
@@ -13,8 +13,21 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<property name="tabWidth" value="4"/>
|
<property name="tabWidth" value="4"/>
|
||||||
<property name="charset" value="UTF-8" />
|
<property name="charset" value="UTF-8" />
|
||||||
|
|
||||||
|
<module name="BeforeExecutionExclusionFileFilter">
|
||||||
|
<property name="fileNamePattern" value="module\-info\.java$"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
<module name="SuppressionFilter">
|
<module name="SuppressionFilter">
|
||||||
<property name="file" value="${config_loc}/suppressions.xml" />
|
<property name="file" value="${config_loc}/suppressions.xml" />
|
||||||
|
</module>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Checkstyle doesn't support @snippet (https://github.com/checkstyle/checkstyle/issues/11455),
|
||||||
|
so suppress warnings nearby
|
||||||
|
-->
|
||||||
|
<module name="SuppressWithNearbyTextFilter">
|
||||||
|
<property name="nearbyTextPattern" value="@snippet" />
|
||||||
|
<property name="lineRange" value="20" />
|
||||||
</module>
|
</module>
|
||||||
|
|
||||||
<module name="BeforeExecutionExclusionFileFilter">
|
<module name="BeforeExecutionExclusionFileFilter">
|
||||||
@@ -88,7 +101,10 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<module name="InvalidJavadocPosition" />
|
<module name="InvalidJavadocPosition" />
|
||||||
<module name="JavadocBlockTagLocation" />
|
<module name="JavadocBlockTagLocation" />
|
||||||
<module name="JavadocMethod"/>
|
<module name="JavadocMethod"/>
|
||||||
<module name="JavadocType"/>
|
<module name="JavadocType">
|
||||||
|
<!-- Seems to complain about @hidden!? -->
|
||||||
|
<property name="allowUnknownTags" value="true" />
|
||||||
|
</module>
|
||||||
<module name="JavadocStyle">
|
<module name="JavadocStyle">
|
||||||
<property name="checkHtml" value="false" />
|
<property name="checkHtml" value="false" />
|
||||||
</module>
|
</module>
|
||||||
@@ -112,17 +128,19 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<module name="LambdaParameterName" />
|
<module name="LambdaParameterName" />
|
||||||
<module name="LocalFinalVariableName" />
|
<module name="LocalFinalVariableName" />
|
||||||
<module name="LocalVariableName" />
|
<module name="LocalVariableName" />
|
||||||
<module name="MemberName" />
|
<module name="MemberName">
|
||||||
|
<property name="format" value="^(computercraft\$|\$)?[a-z][a-zA-Z0-9]*$" />
|
||||||
|
</module>
|
||||||
<module name="MethodName">
|
<module name="MethodName">
|
||||||
<property name="format" value="^(computercraft\$)?[a-z][a-zA-Z0-9]*$" />
|
<property name="format" value="^(computercraft\$)?[a-z][a-zA-Z0-9]*$" />
|
||||||
</module>
|
</module>
|
||||||
<module name="MethodTypeParameterName" />
|
<module name="MethodTypeParameterName" />
|
||||||
<module name="PackageName">
|
<module name="PackageName">
|
||||||
<property name="format" value="^(dan200\.computercraft|cc\.tweaked)(\.[a-z][a-z0-9]*)*" />
|
<property name="format" value="^(dan200\.computercraft|cc\.tweaked|com\.example\.examplemod)(\.[a-z][a-z0-9]*)*" />
|
||||||
</module>
|
</module>
|
||||||
<module name="ParameterName" />
|
<module name="ParameterName" />
|
||||||
<module name="StaticVariableName">
|
<module name="StaticVariableName">
|
||||||
<property name="format" value="^[a-z][a-zA-Z0-9]*|CAPABILITY(_[A-Z_]+)?$" />
|
<property name="format" value="^[a-z][a-zA-Z0-9]*$" />
|
||||||
</module>
|
</module>
|
||||||
<module name="TypeName" />
|
<module name="TypeName" />
|
||||||
|
|
||||||
@@ -137,7 +155,10 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<module name="NoWhitespaceAfter">
|
<module name="NoWhitespaceAfter">
|
||||||
<property name="tokens" value="AT,INC,DEC,UNARY_MINUS,UNARY_PLUS,BNOT,LNOT,DOT,ARRAY_DECLARATOR,INDEX_OP,METHOD_REF" />
|
<property name="tokens" value="AT,INC,DEC,UNARY_MINUS,UNARY_PLUS,BNOT,LNOT,DOT,ARRAY_DECLARATOR,INDEX_OP,METHOD_REF" />
|
||||||
</module>
|
</module>
|
||||||
<module name="NoWhitespaceBefore" />
|
<module name="NoWhitespaceBefore">
|
||||||
|
<!-- Allow whitespace before "..." for @Nullable annotations -->
|
||||||
|
<property name="tokens" value="COMMA,SEMI,POST_INC,POST_DEC,LABELED_STAT" />
|
||||||
|
</module>
|
||||||
<!-- TODO: Decide on an OperatorWrap style. -->
|
<!-- TODO: Decide on an OperatorWrap style. -->
|
||||||
<module name="ParenPad" />
|
<module name="ParenPad" />
|
||||||
<module name="SeparatorWrap">
|
<module name="SeparatorWrap">
|
||||||
|
@@ -16,4 +16,13 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
|
|
||||||
<!-- The commands API is documented in Lua. -->
|
<!-- The commands API is documented in Lua. -->
|
||||||
<suppress checks="SummaryJavadocCheck" files=".*[\\/]CommandAPI.java" />
|
<suppress checks="SummaryJavadocCheck" files=".*[\\/]CommandAPI.java" />
|
||||||
|
|
||||||
|
<!-- Allow putting files in other packages if they look like our TeaVM stubs. -->
|
||||||
|
<suppress checks="PackageName" files=".*[\\/]T[A-Za-z]+.java" />
|
||||||
|
|
||||||
|
<!-- Allow underscores in our test classes. -->
|
||||||
|
<suppress checks="MethodName" files=".*(Contract|Test).java" />
|
||||||
|
|
||||||
|
<!-- Allow underscores in Mixin classes -->
|
||||||
|
<suppress checks="TypeName" files=".*[\\/]mixin[\\/].*.java" />
|
||||||
</suppressions>
|
</suppressions>
|
||||||
|
@@ -1,12 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
FROM gitpod/workspace-base
|
|
||||||
|
|
||||||
USER gitpod
|
|
||||||
|
|
||||||
RUN sudo apt-get -q update \
|
|
||||||
&& sudo apt-get install -yq openjdk-16-jdk python3-pip npm \
|
|
||||||
&& sudo pip3 install pre-commit \
|
|
||||||
&& sudo update-java-alternatives --set java-1.16.0-openjdk-amd64
|
|
28
crowdin.yml
Normal file
28
crowdin.yml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2017 The CC: Tweaked Developers
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
files:
|
||||||
|
- source: projects/common/src/generated/resources/assets/computercraft/lang/en_us.json
|
||||||
|
translation: /projects/common/src/main/resources/assets/computercraft/lang/%locale_with_underscore%.json
|
||||||
|
languages_mapping:
|
||||||
|
locale_with_underscore:
|
||||||
|
cs: cs_cz # Czech
|
||||||
|
da: da_dk # Danish
|
||||||
|
de: de_de # German
|
||||||
|
es-ES: es_es # Spanish
|
||||||
|
fr: fr_fr # French
|
||||||
|
it: it_it # Italian
|
||||||
|
ja: ja_jp # Japanese
|
||||||
|
ko: ko_kr # Korean
|
||||||
|
nb: nb_no # Norwegian Bokmal
|
||||||
|
nl: nl_nl # Dutch
|
||||||
|
pl: pl_pl # Polish
|
||||||
|
pt-BR: pt_br # Portuguese, Brazilian
|
||||||
|
ru: ru_ru # Russian
|
||||||
|
sv-SE: sv_se # Sweedish
|
||||||
|
tok: tok # Toki Pona
|
||||||
|
tr: tr_tr # Turkish
|
||||||
|
uk: uk_ua # Ukraine
|
||||||
|
vi: vi_vn # Vietnamese
|
||||||
|
zh-CN: zh_cn # Chinese Simplified
|
@@ -6,7 +6,7 @@ see: key To listen to any key press.
|
|||||||
<!--
|
<!--
|
||||||
SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
||||||
|
|
||||||
SPDX-License-Identifier: LicenseRef-CCPL
|
SPDX-License-Identifier: MPL-2.0
|
||||||
-->
|
-->
|
||||||
|
|
||||||
The [`char`] event is fired when a character is typed on the keyboard.
|
The [`char`] event is fired when a character is typed on the keyboard.
|
||||||
|
@@ -12,7 +12,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
The [`file_transfer`] event is queued when a user drags-and-drops a file on an open computer.
|
The [`file_transfer`] event is queued when a user drags-and-drops a file on an open computer.
|
||||||
|
|
||||||
This event contains a single argument of type [`TransferredFiles`], which can be used to [get the files to be
|
This event contains a single argument of type [`TransferredFiles`], which can be used to [get the files to be
|
||||||
transferred][`TransferredFiles.getFiles`]. Each file returned is a [binary file handle][`fs.BinaryReadHandle`] with an
|
transferred][`TransferredFiles.getFiles`]. Each file returned is a [binary file handle][`fs.ReadHandle`] with an
|
||||||
additional [getName][`TransferredFile.getName`] method.
|
additional [getName][`TransferredFile.getName`] method.
|
||||||
|
|
||||||
## Return values
|
## Return values
|
||||||
@@ -29,7 +29,7 @@ for _, file in ipairs(files.getFiles()) do
|
|||||||
local size = file.seek("end")
|
local size = file.seek("end")
|
||||||
file.seek("set", 0)
|
file.seek("set", 0)
|
||||||
|
|
||||||
print(file.getName() .. " " .. file.getSize())
|
print(file.getName() .. " " .. size)
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@@ -5,7 +5,7 @@ module: [kind=event] key
|
|||||||
<!--
|
<!--
|
||||||
SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
||||||
|
|
||||||
SPDX-License-Identifier: LicenseRef-CCPL
|
SPDX-License-Identifier: MPL-2.0
|
||||||
-->
|
-->
|
||||||
|
|
||||||
This event is fired when any key is pressed while the terminal is focused.
|
This event is fired when any key is pressed while the terminal is focused.
|
||||||
|
@@ -6,7 +6,7 @@ see: keys For a lookup table of the given keys.
|
|||||||
<!--
|
<!--
|
||||||
SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
||||||
|
|
||||||
SPDX-License-Identifier: LicenseRef-CCPL
|
SPDX-License-Identifier: MPL-2.0
|
||||||
-->
|
-->
|
||||||
|
|
||||||
Fired whenever a key is released (or the terminal is closed while a key was being pressed).
|
Fired whenever a key is released (or the terminal is closed while a key was being pressed).
|
||||||
|
@@ -8,7 +8,7 @@ SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
|||||||
SPDX-License-Identifier: MPL-2.0
|
SPDX-License-Identifier: MPL-2.0
|
||||||
-->
|
-->
|
||||||
|
|
||||||
The [`monitor_resize`] event is fired when an adjacent or networked monitor's size is changed.
|
The [`monitor_resize`] event is fired when an adjacent or networked [monitor's][`monitor`] size is changed.
|
||||||
|
|
||||||
## Return Values
|
## Return Values
|
||||||
1. [`string`]: The event name.
|
1. [`string`]: The event name.
|
||||||
|
@@ -8,7 +8,7 @@ SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
|||||||
SPDX-License-Identifier: MPL-2.0
|
SPDX-License-Identifier: MPL-2.0
|
||||||
-->
|
-->
|
||||||
|
|
||||||
The [`monitor_touch`] event is fired when an adjacent or networked Advanced Monitor is right-clicked.
|
The [`monitor_touch`] event is fired when an adjacent or networked [Advanced Monitor][`monitor`] is right-clicked.
|
||||||
|
|
||||||
## Return Values
|
## Return Values
|
||||||
1. [`string`]: The event name.
|
1. [`string`]: The event name.
|
||||||
|
@@ -5,7 +5,7 @@ module: [kind=event] mouse_click
|
|||||||
<!--
|
<!--
|
||||||
SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
||||||
|
|
||||||
SPDX-License-Identifier: LicenseRef-CCPL
|
SPDX-License-Identifier: MPL-2.0
|
||||||
-->
|
-->
|
||||||
|
|
||||||
This event is fired when the terminal is clicked with a mouse. This event is only fired on advanced computers (including
|
This event is fired when the terminal is clicked with a mouse. This event is only fired on advanced computers (including
|
||||||
|
@@ -6,7 +6,7 @@ see: mouse_click For when a mouse button is initially pressed.
|
|||||||
<!--
|
<!--
|
||||||
SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
||||||
|
|
||||||
SPDX-License-Identifier: LicenseRef-CCPL
|
SPDX-License-Identifier: MPL-2.0
|
||||||
-->
|
-->
|
||||||
|
|
||||||
This event is fired every time the mouse is moved while a mouse button is being held.
|
This event is fired every time the mouse is moved while a mouse button is being held.
|
||||||
|
@@ -5,7 +5,7 @@ module: [kind=event] mouse_scroll
|
|||||||
<!--
|
<!--
|
||||||
SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
||||||
|
|
||||||
SPDX-License-Identifier: LicenseRef-CCPL
|
SPDX-License-Identifier: MPL-2.0
|
||||||
-->
|
-->
|
||||||
|
|
||||||
This event is fired when a mouse wheel is scrolled in the terminal.
|
This event is fired when a mouse wheel is scrolled in the terminal.
|
||||||
|
@@ -5,7 +5,7 @@ module: [kind=event] mouse_up
|
|||||||
<!--
|
<!--
|
||||||
SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
||||||
|
|
||||||
SPDX-License-Identifier: LicenseRef-CCPL
|
SPDX-License-Identifier: MPL-2.0
|
||||||
-->
|
-->
|
||||||
|
|
||||||
This event is fired when a mouse button is released or a held mouse leaves the computer's terminal.
|
This event is fired when a mouse button is released or a held mouse leaves the computer's terminal.
|
||||||
|
@@ -8,7 +8,7 @@ SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
|||||||
SPDX-License-Identifier: MPL-2.0
|
SPDX-License-Identifier: MPL-2.0
|
||||||
-->
|
-->
|
||||||
|
|
||||||
The [`event!redstone`] event is fired whenever any redstone inputs on the computer change.
|
The [`event!redstone`] event is fired whenever any redstone inputs on the computer or [relay][`redstone_relay`] change.
|
||||||
|
|
||||||
## Return values
|
## Return values
|
||||||
1. [`string`]: The event name.
|
1. [`string`]: The event name.
|
||||||
@@ -21,3 +21,7 @@ while true do
|
|||||||
print("A redstone input has changed!")
|
print("A redstone input has changed!")
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## See also
|
||||||
|
- [The `redstone` API on computers][`module!redstone`]
|
||||||
|
- [The `redstone_relay` peripheral][`redstone_relay`]
|
||||||
|
@@ -19,7 +19,7 @@ In order to give the best results, a GPS constellation needs at least four compu
|
|||||||
constellation is redundant, but it does not cause problems.
|
constellation is redundant, but it does not cause problems.
|
||||||
|
|
||||||
## Building a GPS constellation
|
## Building a GPS constellation
|
||||||
<img alt="An example GPS constellation." src="/images/gps-constellation-example.png" class="big-image" />
|
<img alt="An example GPS constellation." src="../images/gps-constellation-example.png" class="big-image" />
|
||||||
|
|
||||||
We are going to build our GPS constellation as shown in the image above. You will need 4 computers and either 4 wireless
|
We are going to build our GPS constellation as shown in the image above. You will need 4 computers and either 4 wireless
|
||||||
modems or 4 ender modems. Try not to mix ender and wireless modems together as you might get some odd behavior when your
|
modems or 4 ender modems. Try not to mix ender and wireless modems together as you might get some odd behavior when your
|
||||||
|
@@ -131,10 +131,10 @@ different.
|
|||||||
First, we require the dfpwm module and call [`cc.audio.dfpwm.make_decoder`] to construct a new decoder. This decoder
|
First, we require the dfpwm module and call [`cc.audio.dfpwm.make_decoder`] to construct a new decoder. This decoder
|
||||||
accepts blocks of DFPWM data and converts it to a list of 8-bit amplitudes, which we can then play with our speaker.
|
accepts blocks of DFPWM data and converts it to a list of 8-bit amplitudes, which we can then play with our speaker.
|
||||||
|
|
||||||
As mentioned above, [`speaker.playAudio`] accepts at most 128×1024 samples in one go. DFPMW uses a single bit for each
|
As mentioned above, [`speaker.playAudio`] accepts at most 128×1024 samples in one go. DFPWM uses a single bit for each
|
||||||
sample, which means we want to process our audio in chunks of 16×1024 bytes (16KiB). In order to do this, we use
|
sample, which means we want to process our audio in chunks of 16×1024 bytes (16KiB). In order to do this, we use
|
||||||
[`io.lines`], which provides a nice way to loop over chunks of a file. You can of course just use [`fs.open`] and
|
[`io.lines`], which provides a nice way to loop over chunks of a file. You can of course just use [`fs.open`] and
|
||||||
[`fs.BinaryReadHandle.read`] if you prefer.
|
[`fs.ReadHandle.read`] if you prefer.
|
||||||
|
|
||||||
## Processing audio
|
## Processing audio
|
||||||
As mentioned near the beginning of this guide, PCM audio is pretty easy to work with as it's just a list of amplitudes.
|
As mentioned near the beginning of this guide, PCM audio is pretty easy to work with as it's just a list of amplitudes.
|
||||||
@@ -191,7 +191,7 @@ end
|
|||||||
|
|
||||||
> [Confused?][!NOTE]
|
> [Confused?][!NOTE]
|
||||||
> Don't worry if you don't understand this example. It's quite advanced, and does use some ideas that this guide doesn't
|
> Don't worry if you don't understand this example. It's quite advanced, and does use some ideas that this guide doesn't
|
||||||
> cover. That said, don't be afraid to ask on [GitHub Discussions] or [IRC] either!
|
> cover. That said, don't be afraid to ask [the community for help][community].
|
||||||
|
|
||||||
It's worth noting that the examples of audio processing we've mentioned here are about manipulating the _amplitude_ of
|
It's worth noting that the examples of audio processing we've mentioned here are about manipulating the _amplitude_ of
|
||||||
the wave. If you wanted to modify the _frequency_ (for instance, shifting the pitch), things get rather more complex.
|
the wave. If you wanted to modify the _frequency_ (for instance, shifting the pitch), things get rather more complex.
|
||||||
@@ -205,5 +205,4 @@ This is, I'm afraid, left as an exercise to the reader.
|
|||||||
[PCM]: https://en.wikipedia.org/wiki/Pulse-code_modulation "Pulse-code Modulation - Wikipedia"
|
[PCM]: https://en.wikipedia.org/wiki/Pulse-code_modulation "Pulse-code Modulation - Wikipedia"
|
||||||
[Ring Buffer]: https://en.wikipedia.org/wiki/Circular_buffer "Circular buffer - Wikipedia"
|
[Ring Buffer]: https://en.wikipedia.org/wiki/Circular_buffer "Circular buffer - Wikipedia"
|
||||||
[Sine Wave]: https://en.wikipedia.org/wiki/Sine_wave "Sine wave - Wikipedia"
|
[Sine Wave]: https://en.wikipedia.org/wiki/Sine_wave "Sine wave - Wikipedia"
|
||||||
[GitHub Discussions]: https://github.com/cc-tweaked/CC-Tweaked/discussions
|
[Community]: /#community
|
||||||
[IRC]: https://webchat.esper.net/?channels=computercraft "#computercraft on EsperNet"
|
|
||||||
|
BIN
doc/images/computercraft-dump.png
Normal file
BIN
doc/images/computercraft-dump.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 254 KiB |
BIN
doc/images/computercraft-track.png
Normal file
BIN
doc/images/computercraft-track.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 304 KiB |
23
doc/index.md
23
doc/index.md
@@ -4,12 +4,19 @@ SPDX-FileCopyrightText: 2020 The CC: Tweaked Developers
|
|||||||
SPDX-License-Identifier: MPL-2.0
|
SPDX-License-Identifier: MPL-2.0
|
||||||
-->
|
-->
|
||||||
|
|
||||||
# 
|
<h1>
|
||||||
|
<picture>
|
||||||
|
<source media="(prefers-color-scheme: dark)" srcset="logo-darkmode.png">
|
||||||
|
<source media="(prefers-color-scheme: light)" srcset="logo.png">
|
||||||
|
<img alt="CC: Tweaked" src="logo.png">
|
||||||
|
</picture>
|
||||||
|
</h1>
|
||||||
|
|
||||||
CC: Tweaked is a mod for Minecraft which adds programmable computers, turtles and more to the game. A fork of the
|
CC: Tweaked is a mod for Minecraft which adds programmable computers, turtles and more to the game. A fork of the
|
||||||
much-beloved [ComputerCraft], it continues its legacy with improved performance and stability, along with a wealth of
|
much-beloved [ComputerCraft], it continues its legacy with improved performance and stability, along with a wealth of
|
||||||
new features.
|
new features.
|
||||||
|
|
||||||
CC: Tweaked can be installed from [CurseForge] or [Modrinth]. It runs on both [Minecraft Forge] and [Fabric].
|
CC: Tweaked can be installed from [Modrinth]. It runs on both [Minecraft Forge] and [Fabric].
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
Controlled using the [Lua programming language][lua], CC: Tweaked's computers provides all the tools you need to start
|
Controlled using the [Lua programming language][lua], CC: Tweaked's computers provides all the tools you need to start
|
||||||
@@ -38,12 +45,16 @@ little daunting getting started. Thankfully, there's several fantastic tutorials
|
|||||||
|
|
||||||
- [Direwolf20's ComputerCraft tutorials](https://www.youtube.com/watch?v=wrUHUhfCY5A "ComputerCraft Tutorial Episode 1 - HELP! and Hello World")
|
- [Direwolf20's ComputerCraft tutorials](https://www.youtube.com/watch?v=wrUHUhfCY5A "ComputerCraft Tutorial Episode 1 - HELP! and Hello World")
|
||||||
- [Sethbling's ComputerCraft series](https://www.youtube.com/watch?v=DSsx4VSe-Uk "Programming Tutorial with Minecraft Turtles -- Ep. 1: Intro to Turtles and If-Then-Else_End")
|
- [Sethbling's ComputerCraft series](https://www.youtube.com/watch?v=DSsx4VSe-Uk "Programming Tutorial with Minecraft Turtles -- Ep. 1: Intro to Turtles and If-Then-Else_End")
|
||||||
- [Lyqyd's Computer Basics 1](http://www.computercraft.info/forums2/index.php?/topic/15033-computer-basics-i/ "Computer Basics I")
|
- [Lyqyd's Computer Basics 1](https://ccf.squiddev.cc/forums2/index.php?/topic/15033-computer-basics-i/ "Computer Basics I")
|
||||||
|
|
||||||
Once you're a little more familiar with the mod, the sidebar and links below provide more detailed documentation on the
|
Once you're a little more familiar with the mod, the sidebar and links below provide more detailed documentation on the
|
||||||
various APIs and peripherals provided by the mod.
|
various APIs and peripherals provided by the mod.
|
||||||
|
|
||||||
If you get stuck, do [ask a question on GitHub][GitHub Discussions] or pop in to the ComputerCraft's [IRC channel][IRC].
|
<h2 id="community">Community</h2>
|
||||||
|
If you need help getting started with CC: Tweaked, want to show off your latest project, or just want to chat about
|
||||||
|
ComputerCraft, do check out our [GitHub discussions page][GitHub discussions]! There's also a fairly populated,
|
||||||
|
albeit quiet IRC channel on [EsperNet], if that's more your cup of tea. You can join `#computercraft` through your
|
||||||
|
desktop client, or online using [KiwiIRC].
|
||||||
|
|
||||||
## Get Involved
|
## Get Involved
|
||||||
CC: Tweaked lives on [GitHub]. If you've got any ideas, feedback or bugs please do [create an issue][bug].
|
CC: Tweaked lives on [GitHub]. If you've got any ideas, feedback or bugs please do [create an issue][bug].
|
||||||
@@ -51,11 +62,11 @@ CC: Tweaked lives on [GitHub]. If you've got any ideas, feedback or bugs please
|
|||||||
[github]: https://github.com/cc-tweaked/CC-Tweaked/ "CC: Tweaked on GitHub"
|
[github]: https://github.com/cc-tweaked/CC-Tweaked/ "CC: Tweaked on GitHub"
|
||||||
[bug]: https://github.com/cc-tweaked/CC-Tweaked/issues/new/choose
|
[bug]: https://github.com/cc-tweaked/CC-Tweaked/issues/new/choose
|
||||||
[computercraft]: https://github.com/dan200/ComputerCraft "ComputerCraft on GitHub"
|
[computercraft]: https://github.com/dan200/ComputerCraft "ComputerCraft on GitHub"
|
||||||
[curseforge]: https://minecraft.curseforge.com/projects/cc-tweaked "Download CC: Tweaked from CurseForge"
|
|
||||||
[modrinth]: https://modrinth.com/mod/gu7yAYhd "Download CC: Tweaked from Modrinth"
|
[modrinth]: https://modrinth.com/mod/gu7yAYhd "Download CC: Tweaked from Modrinth"
|
||||||
[forge]: https://files.minecraftforge.net/ "Download Minecraft Forge."
|
[forge]: https://files.minecraftforge.net/ "Download Minecraft Forge."
|
||||||
[Minecraft Forge]: https://files.minecraftforge.net/ "Download Minecraft Forge."
|
[Minecraft Forge]: https://files.minecraftforge.net/ "Download Minecraft Forge."
|
||||||
[Fabric]: https://fabricmc.net/use/installer/ "Download Fabric."
|
[Fabric]: https://fabricmc.net/use/installer/ "Download Fabric."
|
||||||
[lua]: https://www.lua.org/ "Lua's main website"
|
[lua]: https://www.lua.org/ "Lua's main website"
|
||||||
[GitHub Discussions]: https://github.com/cc-tweaked/CC-Tweaked/discussions
|
[GitHub Discussions]: https://github.com/cc-tweaked/CC-Tweaked/discussions
|
||||||
[IRC]: https://webchat.esper.net/?channels=computercraft "#computercraft on EsperNet"
|
[EsperNet]: https://www.esper.net/
|
||||||
|
[KiwiIRC]: https://kiwiirc.com/nextclient/#irc://irc.esper.net:+6697/#computercraft "#computercraft on EsperNet"
|
||||||
|
@@ -45,12 +45,16 @@ little daunting getting started. Thankfully, there's several fantastic tutorials
|
|||||||
|
|
||||||
- [Direwolf20's ComputerCraft tutorials](https://www.youtube.com/watch?v=wrUHUhfCY5A "ComputerCraft Tutorial Episode 1 - HELP! and Hello World")
|
- [Direwolf20's ComputerCraft tutorials](https://www.youtube.com/watch?v=wrUHUhfCY5A "ComputerCraft Tutorial Episode 1 - HELP! and Hello World")
|
||||||
- [Sethbling's ComputerCraft series](https://www.youtube.com/watch?v=DSsx4VSe-Uk "Programming Tutorial with Minecraft Turtles -- Ep. 1: Intro to Turtles and If-Then-Else_End")
|
- [Sethbling's ComputerCraft series](https://www.youtube.com/watch?v=DSsx4VSe-Uk "Programming Tutorial with Minecraft Turtles -- Ep. 1: Intro to Turtles and If-Then-Else_End")
|
||||||
- [Lyqyd's Computer Basics 1](http://www.computercraft.info/forums2/index.php?/topic/15033-computer-basics-i/ "Computer Basics I")
|
- [Lyqyd's Computer Basics 1](https://ccf.squiddev.cc/forums2/index.php?/topic/15033-computer-basics-i/ "Computer Basics I")
|
||||||
|
|
||||||
Once you're a little more familiar with the mod, the [wiki](https://tweaked.cc/) provides more detailed documentation on the
|
Once you're a little more familiar with the mod, the [wiki](https://tweaked.cc/) provides more detailed documentation on the
|
||||||
various APIs and peripherals provided by the mod.
|
various APIs and peripherals provided by the mod.
|
||||||
|
|
||||||
If you get stuck, do [ask a question on GitHub][GitHub Discussions] or pop in to the ComputerCraft's [IRC channel][IRC].
|
## Community
|
||||||
|
If you need help getting started with CC: Tweaked, want to show off your latest project, or just want to chat about
|
||||||
|
ComputerCraft, do check out our [GitHub discussions page][GitHub discussions]! There's also a fairly populated,
|
||||||
|
albeit quiet IRC channel on [EsperNet], if that's more your cup of tea. You can join `#computercraft` through your
|
||||||
|
desktop client, or online using [KiwiIRC].
|
||||||
|
|
||||||
## Get Involved
|
## Get Involved
|
||||||
CC: Tweaked lives on [GitHub]. If you've got any ideas, feedback or bugs please do [create an issue][bug].
|
CC: Tweaked lives on [GitHub]. If you've got any ideas, feedback or bugs please do [create an issue][bug].
|
||||||
@@ -60,4 +64,5 @@ CC: Tweaked lives on [GitHub]. If you've got any ideas, feedback or bugs please
|
|||||||
[computercraft]: https://github.com/dan200/ComputerCraft "ComputerCraft on GitHub"
|
[computercraft]: https://github.com/dan200/ComputerCraft "ComputerCraft on GitHub"
|
||||||
[lua]: https://www.lua.org/ "Lua's main website"
|
[lua]: https://www.lua.org/ "Lua's main website"
|
||||||
[GitHub Discussions]: https://github.com/cc-tweaked/CC-Tweaked/discussions
|
[GitHub Discussions]: https://github.com/cc-tweaked/CC-Tweaked/discussions
|
||||||
[IRC]: http://webchat.esper.net/?channels=computercraft "#computercraft on EsperNet"
|
[EsperNet]: https://www.esper.net/
|
||||||
|
[KiwiIRC]: https://kiwiirc.com/nextclient/#irc://irc.esper.net:+6697/#computercraft "#computercraft on EsperNet"
|
||||||
|
81
doc/reference/breaking_changes.md
Normal file
81
doc/reference/breaking_changes.md
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
---
|
||||||
|
module: [kind=reference] breaking_changes
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
SPDX-FileCopyrightText: 2019 The CC: Tweaked Developers
|
||||||
|
|
||||||
|
SPDX-License-Identifier: MPL-2.0
|
||||||
|
-->
|
||||||
|
|
||||||
|
# Incompatibilities between versions
|
||||||
|
|
||||||
|
CC: Tweaked tries to remain as compatible between versions as possible, meaning most programs written for older version
|
||||||
|
of the mod should run fine on later versions.
|
||||||
|
|
||||||
|
> [External peripherals][!WARNING]
|
||||||
|
>
|
||||||
|
> While CC: Tweaked is relatively stable across versions, this may not be true for other mods which add their own
|
||||||
|
> peripherals. Older programs which interact with external blocks may not work on newer versions of the game.
|
||||||
|
|
||||||
|
However, some changes to the underlying game, or CC: Tweaked's own internals may break some programs. This page serves
|
||||||
|
as documentation for breaking changes and "gotchas" one should look out for between versions.
|
||||||
|
|
||||||
|
## CC: Tweaked 1.109.0 to 1.109.3 {#cct-1.109}
|
||||||
|
|
||||||
|
- Update to Lua 5.2:
|
||||||
|
- Support for Lua 5.0's pseudo-argument `arg` has been removed. You should always use `...` for varargs.
|
||||||
|
- Environments are no longer baked into the runtime, and instead use the `_ENV` local or upvalue. [`getfenv`]/[`setfenv`]
|
||||||
|
now only work on Lua functions with an `_ENV` upvalue. [`getfenv`] will return the global environment when called
|
||||||
|
with other functions, and [`setfenv`] will have no effect.
|
||||||
|
- [`load`]/[`loadstring`] defaults to using the global environment (`_G`) rather than the current coroutine's
|
||||||
|
environment.
|
||||||
|
- Support for dumping functions ([`string.dump`]) and loading binary chunks has been removed.
|
||||||
|
- [`math.random`] now uses Lua 5.4's random number generator.
|
||||||
|
|
||||||
|
- File handles, HTTP requests and websockets now always use the original bytes rather than encoding/decoding to UTF-8.
|
||||||
|
|
||||||
|
## Minecraft 1.13 {#mc-1.13}
|
||||||
|
- The "key code" for [`key`] and [`key_up`] events has changed, due to Minecraft updating to LWJGL 3. Make sure you're
|
||||||
|
using the constants provided by the [`keys`] API, rather than hard-coding numerical values.
|
||||||
|
|
||||||
|
Related to this change, the numpad enter key now has a different key code to the enter key. You may need to adjust
|
||||||
|
your programs to handle both. (Note, the `keys.numpadEnter` constant was defined in pre-1.13 versions of CC, but the
|
||||||
|
`keys.enter` constant was queued when the key was pressed)
|
||||||
|
|
||||||
|
- Minecraft 1.13 removed the concept of item damage and block metadata (see ["The Flattening"][flattening]). As a
|
||||||
|
result [`turtle.inspect`] no longer provides block metadata, and [`turtle.getItemDetail`] no longer provides damage.
|
||||||
|
|
||||||
|
- Block states (`turtle.inspect().state`) should provide all the same information as block metadata, but in a much
|
||||||
|
more understandable format.
|
||||||
|
|
||||||
|
- Item and block names now represent a unique item type. For instance, wool is split into 16 separate items
|
||||||
|
(`minecraft:white_wool`, etc...) rather than a single `minecraft:wool` with each meta/damage value specifying the
|
||||||
|
colour.
|
||||||
|
|
||||||
|
- Custom ROMs are now provided using data packs rather than resource packs. This should mostly be a matter of renaming
|
||||||
|
the "assets" folder to "data", and placing it in "datapacks", but there are a couple of other gotchas to look out
|
||||||
|
for:
|
||||||
|
|
||||||
|
- Data packs [impose some restrictions on file names][legal_data_pack]. As a result, your programs and directories
|
||||||
|
must all be lower case.
|
||||||
|
- Due to how data packs are read by CC: Tweaked, you may need to use the `/reload` command to see changes to your
|
||||||
|
pack show up on the computer.
|
||||||
|
|
||||||
|
See [the example datapack][datapack-example] for how to get started.
|
||||||
|
|
||||||
|
- Turtles can now be waterlogged and move "through" water sources rather than breaking them.
|
||||||
|
|
||||||
|
## CC: Tweaked 1.88.0 {#cc-1.88}
|
||||||
|
- Unlabelled computers and turtles now keep their ID when broken, meaning that unlabelled computers/items do not stack.
|
||||||
|
|
||||||
|
## ComputerCraft 1.80pr1 {#cc-1.80}
|
||||||
|
- Programs run via [`shell.run`] are now started in their own isolated environment. This means globals set by programs
|
||||||
|
will not be accessible outside of this program.
|
||||||
|
|
||||||
|
- Programs containing `/` are looked up in the current directory and are no longer looked up on the path. For instance,
|
||||||
|
you can no longer type `turtle/excavate` to run `/rom/programs/turtle/excavate.lua`.
|
||||||
|
|
||||||
|
[flattening]: https://minecraft.wiki/w/Java_Edition_1.13/Flattening
|
||||||
|
[legal_data_pack]: https://minecraft.wiki/w/Tutorials/Creating_a_data_pack#Legal_characters
|
||||||
|
[datapack-example]: https://github.com/cc-tweaked/datapack-example "An example datapack for CC: Tweaked"
|
140
doc/reference/command.md
Normal file
140
doc/reference/command.md
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
---
|
||||||
|
module: [kind=reference] computercraft_command
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||||
|
|
||||||
|
SPDX-License-Identifier: MPL-2.0
|
||||||
|
-->
|
||||||
|
|
||||||
|
# The `/computercraft` command
|
||||||
|
CC: Tweaked provides a `/computercraft` command for server owners to manage running computers on a server.
|
||||||
|
|
||||||
|
## Permissions {#permissions}
|
||||||
|
As the `/computercraft` command is mostly intended for debugging and administrative purposes, its sub-commands typically
|
||||||
|
require you to have op (or similar).
|
||||||
|
|
||||||
|
- All players have access to the [`queue`] sub-command.
|
||||||
|
- On a multi-player server, all other commands require op.
|
||||||
|
- On a single-player world, the player can run the [`dump`], [`turn-on`]/[`shutdown`], and [`track`] sub-commands, even
|
||||||
|
when cheats are not enabled. The [`tp`] and [`view`] commands require cheats.
|
||||||
|
|
||||||
|
If a permission mod such as [LuckPerms] is installed[^permission], you can configure access to the individual
|
||||||
|
sub-commands. Each sub-command creates a `computercraft.command.NAME` permission node to control which players can
|
||||||
|
execute it.
|
||||||
|
|
||||||
|
[LuckPerms]: https://github.com/LuckPerms/LuckPerms/ "A permissions plugin for Minecraft servers."
|
||||||
|
[fabric-permission-api]: https://github.com/lucko/fabric-permissions-api "A simple permissions API for Fabric"
|
||||||
|
|
||||||
|
[^permission]: This supports any mod which uses Forge's permission API or [fabric-permission-api].
|
||||||
|
|
||||||
|
## Computer selectors {#computer-selectors}
|
||||||
|
Some commands (such as [`tp`] or [`turn-on`]) target a specific computer, or a list of computers. To specify which
|
||||||
|
computers to operate on, you must use "computer selectors".
|
||||||
|
|
||||||
|
Computer selectors are similar to Minecraft's [entity target selectors], but targeting computers instead. They allow
|
||||||
|
you to select one or more computers, based on a set of predicates.
|
||||||
|
|
||||||
|
The following predicates are supported:
|
||||||
|
- `id=<id>`: Select computer(s) with a specific id.
|
||||||
|
- `instance=<id>`: Select the computer with the given instance id.
|
||||||
|
- `family=<normal|advanced|command>`: Select computers based on their type.
|
||||||
|
- `label=<label>`: Select computers with the given label.
|
||||||
|
- `distance=<distance>`: Select computers within a specific distance of the player executing the command. This uses
|
||||||
|
Minecraft's [float range] syntax.
|
||||||
|
|
||||||
|
`#<id>` may also be used as a shorthand for `@c[id=<id>]`, to select computer(s) with a specific id.
|
||||||
|
|
||||||
|
### Examples:
|
||||||
|
- `/computercraft turn-on #12`: Turn on the computer(s) with an id of 12.
|
||||||
|
- `/computercraft shutdown @c[distance=..100]`: Shut down all computers with 100 blocks of the player.
|
||||||
|
|
||||||
|
[entity target selectors]: https://minecraft.wiki/w/Target_selectors "Target Selectors on the Minecraft wiki"
|
||||||
|
[Float range]: https://minecraft.wiki/w/Argument_types#minecraft:float_range
|
||||||
|
|
||||||
|
## Commands {#commands}
|
||||||
|
### `/computercraft dump` {#dump}
|
||||||
|
`/computercraft dump` prints a table of currently loaded computers, including their id, position, and whether they're
|
||||||
|
running. It can also be run with a single computer argument to dump more detailed information about a computer.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Next to the computer id, there are several buttons to either [teleport][`tp`] to the computer, or [open its terminal
|
||||||
|
][`view`].
|
||||||
|
|
||||||
|
Computers are sorted by distance to the player, so nearby computers will appear earlier.
|
||||||
|
|
||||||
|
### `/computercraft turn-on [computers...]` {#turn-on}
|
||||||
|
Turn on one or more computers or, if no run with no arguments, all loaded computers.
|
||||||
|
|
||||||
|
#### Examples
|
||||||
|
- `/computercraft turn-on #0 #2`: Turn on computers with id 0 and 2.
|
||||||
|
- `/computercraft turn-on @c[family=command]`: Turn on all command computers.
|
||||||
|
|
||||||
|
### `/computercraft shutdown [computers...]` {#shutdown}
|
||||||
|
Shutdown one or more computers or, if no run with no arguments, all loaded computers.
|
||||||
|
|
||||||
|
This is sometimes useful when dealing with lag, as a way to ensure that ComputerCraft is not causing problems.
|
||||||
|
|
||||||
|
#### Examples
|
||||||
|
- `/computercraft shutdown`: Shut down all loaded computers.
|
||||||
|
- `/computercraft shutdown @c[distance=..10]`: Shut down all computers in a block radius.
|
||||||
|
|
||||||
|
### `/computercraft tp [computer]` {#tp}
|
||||||
|
Teleport to the given computer.
|
||||||
|
|
||||||
|
This is normally used from via the [`dump`] command interface rather than being invoked directly.
|
||||||
|
|
||||||
|
### `/computercraft view [computer]` {#view}
|
||||||
|
Open a terminal for the specified computer. This allows remotely viewing computers without having to interact with the
|
||||||
|
block.
|
||||||
|
|
||||||
|
This is normally used from via the [`dump`] command interface rather than being invoked directly.
|
||||||
|
|
||||||
|
### `/computercraft track` {#track}
|
||||||
|
The `/computercraft track` command allows you to enable profiling of computers. When a computer runs code, or interacts
|
||||||
|
with the Minecraft world, we time how long that takes. This timing information may then be queried, and used to find
|
||||||
|
computers which may be causing lag.
|
||||||
|
|
||||||
|
To enable the profiler, run `/computercraft track start`. Computers will then start recording metrics. Once enough data
|
||||||
|
has been gathered, run `/computercraft track stop` to stop profiling and display the recorded data.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
The table by default shows the number of times each computer has run, and how long it ran for (in total, and on
|
||||||
|
average). In the above screenshot, we can see one computer was particularly badly behaved, and ran for 7 seconds. The
|
||||||
|
buttons may be used to [teleport][`tp`] to the computer, or [open its terminal ][`view`], and inspect it further.
|
||||||
|
|
||||||
|
`/computercraft track dump` can be used to display this table at any point (including while profiling is still running).
|
||||||
|
|
||||||
|
Computers also record other information, such as how much server-thread time they consume, or their HTTP bandwidth
|
||||||
|
usage. The `dump` subcommand accepts a list of other fields to display, instead of the default timings.
|
||||||
|
|
||||||
|
#### Examples
|
||||||
|
- `/computercraft track dump server_tasks_count server_tasks`: Print the number of server-thread tasks each computer
|
||||||
|
executed, and how long they took in total.
|
||||||
|
- `/computercraft track dump http_upload http_download`: Print the number of bytes uploaded and downloaded by each
|
||||||
|
computer.
|
||||||
|
|
||||||
|
|
||||||
|
### `/computercraft queue` {#queue}
|
||||||
|
The queue subcommand allows non-operator players to queue a `computer_command` event on *command* computers.
|
||||||
|
|
||||||
|
This has a similar purpose to vanilla's [`/trigger`] command. Command computers may choose to listen to this event, and
|
||||||
|
then perform some action.
|
||||||
|
|
||||||
|
[`/trigger`]: https://minecraft.wiki/w/Commands/trigger "/trigger on the Minecraft wiki"
|
||||||
|
|
||||||
|
|
||||||
|
[`dump`]: #dump "/computercraft dump"
|
||||||
|
[`queue`]: #queue "/computercraft queue"
|
||||||
|
[`shutdown`]: #shutdown "/computercraft shutdown"
|
||||||
|
[`tp`]: #tp "/computercraft tp"
|
||||||
|
[`track`]: #track "/computercraft track"
|
||||||
|
[`turn-on`]: #turn-on "/computercraft turn-on"
|
||||||
|
[`view`]: #view "/computercraft view"
|
||||||
|
[computer selectors]: #computer-selectors "Computer selectors"
|
@@ -9,17 +9,19 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
# Lua 5.2/5.3 features in CC: Tweaked
|
# Lua 5.2/5.3 features in CC: Tweaked
|
||||||
CC: Tweaked is based off of the Cobalt Lua runtime, which uses Lua 5.1. However, Cobalt and CC:T implement additional features from Lua 5.2 and 5.3 (as well as some deprecated 5.0 features) that are not available in base 5.1. This page lists all of the compatibility for these newer versions.
|
CC: Tweaked is based off of the Cobalt Lua runtime, which uses Lua 5.2. However, Cobalt and CC:T implement additional
|
||||||
|
features from Lua 5.2 and 5.3 (as well as some deprecated 5.0 and 5.1 features). This page lists all of the
|
||||||
|
compatibility for these newer versions.
|
||||||
|
|
||||||
## Lua 5.2
|
## Lua 5.2
|
||||||
| Feature | Supported? | Notes |
|
| Feature | Supported? | Notes |
|
||||||
|---------------------------------------------------------------|------------|-------------------------------------------------------------------|
|
|---------------------------------------------------------------|------------|-------------------------------------------------------------------|
|
||||||
| `goto`/labels | ❌ | |
|
| `goto`/labels | ✔ | |
|
||||||
| `_ENV` | 🔶 | The `_ENV` global points to `getfenv()`, but it cannot be set. |
|
| `_ENV` | ✔ | |
|
||||||
| `\z` escape | ✔ | |
|
| `\z` escape | ✔ | |
|
||||||
| `\xNN` escape | ✔ | |
|
| `\xNN` escape | ✔ | |
|
||||||
| Hex literal fractional/exponent parts | ✔ | |
|
| Hex literal fractional/exponent parts | ✔ | |
|
||||||
| Empty statements | ❌ | |
|
| Empty statements | ✔ | |
|
||||||
| `__len` metamethod | ✔ | |
|
| `__len` metamethod | ✔ | |
|
||||||
| `__ipairs` metamethod | ❌ | Deprecated in Lua 5.3. `ipairs` uses `__len`/`__index` instead. |
|
| `__ipairs` metamethod | ❌ | Deprecated in Lua 5.3. `ipairs` uses `__len`/`__index` instead. |
|
||||||
| `__pairs` metamethod | ✔ | |
|
| `__pairs` metamethod | ✔ | |
|
||||||
@@ -27,12 +29,12 @@ CC: Tweaked is based off of the Cobalt Lua runtime, which uses Lua 5.1. However,
|
|||||||
| `collectgarbage` isrunning, generational, incremental options | ❌ | `collectgarbage` does not exist in CC:T. |
|
| `collectgarbage` isrunning, generational, incremental options | ❌ | `collectgarbage` does not exist in CC:T. |
|
||||||
| New `load` syntax | ✔ | |
|
| New `load` syntax | ✔ | |
|
||||||
| `loadfile` mode parameter | ✔ | Supports both 5.1 and 5.2+ syntax. |
|
| `loadfile` mode parameter | ✔ | Supports both 5.1 and 5.2+ syntax. |
|
||||||
| Removed `loadstring` | 🔶 | Only if `disable_lua51_features` is enabled in the configuration. |
|
| Removed `loadstring` | ❌ | |
|
||||||
| Removed `getfenv`, `setfenv` | 🔶 | Only if `disable_lua51_features` is enabled in the configuration. |
|
| Removed `getfenv`, `setfenv` | 🔶 | Only supports closures with an `_ENV` upvalue. |
|
||||||
| `rawlen` function | ✔ | |
|
| `rawlen` function | ✔ | |
|
||||||
| Negative index to `select` | ✔ | |
|
| Negative index to `select` | ✔ | |
|
||||||
| Removed `unpack` | 🔶 | Only if `disable_lua51_features` is enabled in the configuration. |
|
| Removed `unpack` | ❌ | |
|
||||||
| Arguments to `xpcall` | ✔ | |
|
| Arguments to `xpcall` | ✔ | |
|
||||||
| Second return value from `coroutine.running` | ✔ | |
|
| Second return value from `coroutine.running` | ✔ | |
|
||||||
| Removed `module` | ✔ | |
|
| Removed `module` | ✔ | |
|
||||||
| `package.loaders` -> `package.searchers` | ❌ | |
|
| `package.loaders` -> `package.searchers` | ❌ | |
|
||||||
@@ -40,14 +42,14 @@ CC: Tweaked is based off of the Cobalt Lua runtime, which uses Lua 5.1. However,
|
|||||||
| `package.config` | ✔ | |
|
| `package.config` | ✔ | |
|
||||||
| `package.searchpath` | ✔ | |
|
| `package.searchpath` | ✔ | |
|
||||||
| Removed `package.seeall` | ✔ | |
|
| Removed `package.seeall` | ✔ | |
|
||||||
| `string.dump` on functions with upvalues (blanks them out) | ✔ | |
|
| `string.dump` on functions with upvalues (blanks them out) | ❌ | `string.dump` is not supported |
|
||||||
| `string.rep` separator | ✔ | |
|
| `string.rep` separator | ✔ | |
|
||||||
| `%g` match group | ❌ | |
|
| `%g` match group | ❌ | |
|
||||||
| Removal of `%z` match group | ❌ | |
|
| Removal of `%z` match group | ❌ | |
|
||||||
| Removed `table.maxn` | 🔶 | Only if `disable_lua51_features` is enabled in the configuration. |
|
| Removed `table.maxn` | ❌ | |
|
||||||
| `table.pack`/`table.unpack` | ✔ | |
|
| `table.pack`/`table.unpack` | ✔ | |
|
||||||
| `math.log` base argument | ✔ | |
|
| `math.log` base argument | ✔ | |
|
||||||
| Removed `math.log10` | 🔶 | Only if `disable_lua51_features` is enabled in the configuration. |
|
| Removed `math.log10` | ❌ | |
|
||||||
| `*L` mode to `file:read` | ✔ | |
|
| `*L` mode to `file:read` | ✔ | |
|
||||||
| `os.execute` exit type + return value | ❌ | `os.execute` does not exist in CC:T. |
|
| `os.execute` exit type + return value | ❌ | `os.execute` does not exist in CC:T. |
|
||||||
| `os.exit` close argument | ❌ | `os.exit` does not exist in CC:T. |
|
| `os.exit` close argument | ❌ | `os.exit` does not exist in CC:T. |
|
||||||
@@ -61,7 +63,7 @@ CC: Tweaked is based off of the Cobalt Lua runtime, which uses Lua 5.1. However,
|
|||||||
| Tail call hooks | ❌ | |
|
| Tail call hooks | ❌ | |
|
||||||
| `=` prefix for chunks | ✔ | |
|
| `=` prefix for chunks | ✔ | |
|
||||||
| Yield across C boundary | ✔ | |
|
| Yield across C boundary | ✔ | |
|
||||||
| Removal of ambiguity error | ❌ | |
|
| Removal of ambiguity error | ✔ | |
|
||||||
| Identifiers may no longer use locale-dependent letters | ✔ | |
|
| Identifiers may no longer use locale-dependent letters | ✔ | |
|
||||||
| Ephemeron tables | ❌ | |
|
| Ephemeron tables | ❌ | |
|
||||||
| Identical functions may be reused | ❌ | Removed in Lua 5.4 |
|
| Identical functions may be reused | ❌ | Removed in Lua 5.4 |
|
||||||
@@ -79,7 +81,7 @@ CC: Tweaked is based off of the Cobalt Lua runtime, which uses Lua 5.1. However,
|
|||||||
| `string.dump` strip argument | ✔ | |
|
| `string.dump` strip argument | ✔ | |
|
||||||
| `string.pack`/`string.unpack`/`string.packsize` | ✔ | |
|
| `string.pack`/`string.unpack`/`string.packsize` | ✔ | |
|
||||||
| `table.move` | ✔ | |
|
| `table.move` | ✔ | |
|
||||||
| `math.atan2` -> `math.atan` | ❌ | |
|
| `math.atan2` -> `math.atan` | 🔶 | `math.atan` supports its two argument form. |
|
||||||
| Removed `math.frexp`, `math.ldexp`, `math.pow`, `math.cosh`, `math.sinh`, `math.tanh` | ❌ | |
|
| Removed `math.frexp`, `math.ldexp`, `math.pow`, `math.cosh`, `math.sinh`, `math.tanh` | ❌ | |
|
||||||
| `math.maxinteger`/`math.mininteger` | ❌ | |
|
| `math.maxinteger`/`math.mininteger` | ❌ | |
|
||||||
| `math.tointeger` | ❌ | |
|
| `math.tointeger` | ❌ | |
|
||||||
|
@@ -95,10 +95,10 @@ function pullEventRaw(filter) end
|
|||||||
-- nearest multiple of 0.05.
|
-- nearest multiple of 0.05.
|
||||||
function sleep(time) end
|
function sleep(time) end
|
||||||
|
|
||||||
--- Get the current CraftOS version (for example, `CraftOS 1.8`).
|
--- Get the current CraftOS version (for example, `CraftOS 1.9`).
|
||||||
--
|
--
|
||||||
-- This is defined by `bios.lua`. For the current version of CC:Tweaked, this
|
-- This is defined by `bios.lua`. For the current version of CC:Tweaked, this
|
||||||
-- should return `CraftOS 1.8`.
|
-- should return `CraftOS 1.9`.
|
||||||
--
|
--
|
||||||
-- @treturn string The current CraftOS version.
|
-- @treturn string The current CraftOS version.
|
||||||
-- @usage os.version()
|
-- @usage os.version()
|
||||||
|
@@ -2,15 +2,17 @@
|
|||||||
#
|
#
|
||||||
# SPDX-License-Identifier: MPL-2.0
|
# SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
org.gradle.jvmargs=-Xmx3G
|
org.gradle.jvmargs=-Xmx3G -Dfile.encoding=UTF-8
|
||||||
org.gradle.parallel=true
|
org.gradle.parallel=true
|
||||||
|
|
||||||
kotlin.stdlib.default.dependency=false
|
kotlin.stdlib.default.dependency=false
|
||||||
kotlin.jvm.target.validation.mode=error
|
kotlin.jvm.target.validation.mode=error
|
||||||
|
|
||||||
|
neogradle.subsystems.conventions.runs.enabled=false
|
||||||
|
|
||||||
# Mod properties
|
# Mod properties
|
||||||
isUnstable=false
|
isUnstable=true
|
||||||
modVersion=1.108.1
|
modVersion=1.116.0
|
||||||
|
|
||||||
# Minecraft properties: We want to configure this here so we can read it in settings.gradle
|
# Minecraft properties: We want to configure this here so we can read it in settings.gradle
|
||||||
mcVersion=1.20.1
|
mcVersion=1.21.7
|
||||||
|
2
gradle/gradle-daemon-jvm.properties
Normal file
2
gradle/gradle-daemon-jvm.properties
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#This file is generated by updateDaemonJvm
|
||||||
|
toolchainVersion=21
|
@@ -6,161 +6,194 @@
|
|||||||
|
|
||||||
# Minecraft
|
# Minecraft
|
||||||
# MC version is specified in gradle.properties, as we need that in settings.gradle.
|
# MC version is specified in gradle.properties, as we need that in settings.gradle.
|
||||||
# Remember to update corresponding versions in fabric.mod.json/mods.toml
|
# Remember to update corresponding versions in fabric.mod.json/neoforge.mods.toml
|
||||||
fabric-api = "0.86.1+1.20.1"
|
fabric-api = "0.128.0+1.21.7"
|
||||||
fabric-loader = "0.14.21"
|
fabric-loader = "0.16.14"
|
||||||
forge = "47.1.0"
|
neoForge = "21.7.1-beta"
|
||||||
forgeSpi = "6.0.0"
|
neoMergeTool = "2.0.0"
|
||||||
mixin = "0.8.5"
|
mixin = "0.8.5"
|
||||||
parchment = "2023.08.20"
|
parchment = "2025.06.29"
|
||||||
parchmentMc = "1.20.1"
|
parchmentMc = "1.21.6"
|
||||||
|
yarn = "1.21.7+build.1"
|
||||||
|
|
||||||
# Normal dependencies
|
# Core dependencies (these versions are tied to the version Minecraft uses)
|
||||||
asm = "9.5"
|
fastutil = "8.5.15"
|
||||||
|
guava = "33.3.1-jre"
|
||||||
|
netty = "4.1.118.Final"
|
||||||
|
slf4j = "2.0.16"
|
||||||
|
|
||||||
|
# Core dependencies (independent of Minecraft)
|
||||||
|
asm = "9.7.1"
|
||||||
autoService = "1.1.1"
|
autoService = "1.1.1"
|
||||||
checkerFramework = "3.32.0"
|
checkerFramework = "3.42.0"
|
||||||
cobalt = "0.7.3"
|
cobalt = { strictly = "0.9.6" }
|
||||||
cobalt-next = "0.7.4" # Not a real version, used to constrain the version we accept.
|
commonsCli = "1.6.0"
|
||||||
fastutil = "8.5.9"
|
jetbrainsAnnotations = "24.1.0"
|
||||||
guava = "31.1-jre"
|
jspecify = "1.0.0"
|
||||||
jetbrainsAnnotations = "24.0.1"
|
|
||||||
jsr305 = "3.0.2"
|
|
||||||
jzlib = "1.1.3"
|
jzlib = "1.1.3"
|
||||||
kotlin = "1.8.10"
|
kotlin = "2.1.10"
|
||||||
kotlin-coroutines = "1.6.4"
|
kotlin-coroutines = "1.10.1"
|
||||||
netty = "4.1.82.Final"
|
nightConfig = "3.8.1"
|
||||||
nightConfig = "3.6.7"
|
|
||||||
slf4j = "1.7.36"
|
|
||||||
|
|
||||||
# Minecraft mods
|
# Minecraft mods
|
||||||
emi = "1.0.8+1.20.1"
|
emi = "1.1.7+1.21"
|
||||||
fabricPermissions = "0.3.20230723"
|
fabricPermissions = "0.3.3"
|
||||||
iris = "1.6.4+1.20"
|
iris-fabric = "1.8.11+1.21.5-fabric"
|
||||||
jei = "15.2.0.22"
|
iris-forge = "1.8.11+1.21.5-neoforge"
|
||||||
modmenu = "7.1.0"
|
jei = "19.8.2.99"
|
||||||
moreRed = "4.0.0.4"
|
modmenu = "13.0.2"
|
||||||
oculus = "1.2.5"
|
moreRed = "6.0.0.3"
|
||||||
rei = "12.0.626"
|
rei = "18.0.800"
|
||||||
rubidium = "0.6.1"
|
sodium-fabric = "mc1.21.5-0.6.12-fabric"
|
||||||
sodium = "mc1.20-0.4.10"
|
sodium-forge = "mc1.21.5-0.6.12-neoforge"
|
||||||
|
mixinExtra = "0.3.5"
|
||||||
|
create-forge = "6.0.0-6"
|
||||||
|
create-fabric = "0.5.1-f-build.1467+mc1.20.1"
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
byteBuddy = "1.14.7"
|
|
||||||
hamcrest = "2.2"
|
hamcrest = "2.2"
|
||||||
jqwik = "1.7.4"
|
jqwik = "1.8.2"
|
||||||
junit = "5.10.0"
|
junit = "5.11.4"
|
||||||
|
junitPlatform = "1.11.4"
|
||||||
|
jmh = "1.37"
|
||||||
|
|
||||||
# Build tools
|
# Build tools
|
||||||
cctJavadoc = "1.8.0"
|
cctJavadoc = "1.8.5"
|
||||||
checkstyle = "10.12.3"
|
checkstyle = "10.23.1"
|
||||||
curseForgeGradle = "1.0.14"
|
errorProne-core = "2.38.0"
|
||||||
errorProne-core = "2.21.1"
|
errorProne-plugin = "4.1.0"
|
||||||
errorProne-plugin = "3.1.0"
|
fabric-loom = "1.10.4"
|
||||||
fabric-loom = "1.3.7"
|
githubRelease = "2.5.2"
|
||||||
forgeGradle = "6.0.8"
|
gradleVersions = "0.50.0"
|
||||||
githubRelease = "2.4.1"
|
|
||||||
ideaExt = "1.1.7"
|
ideaExt = "1.1.7"
|
||||||
illuaminate = "0.1.0-40-g975cbc3"
|
illuaminate = "0.1.0-83-g1131f68"
|
||||||
librarian = "1.+"
|
lwjgl = "3.3.3"
|
||||||
minotaur = "2.+"
|
minotaur = "2.8.7"
|
||||||
mixinGradle = "0.7.+"
|
modDevGradle = "2.0.95"
|
||||||
nullAway = "0.9.9"
|
nullAway = "0.12.7"
|
||||||
spotless = "6.21.0"
|
shadow = "8.3.1"
|
||||||
|
spotless = "7.0.2"
|
||||||
taskTree = "2.1.1"
|
taskTree = "2.1.1"
|
||||||
vanillaGradle = "0.2.1-SNAPSHOT"
|
teavm = "0.11.0-SQUID.1"
|
||||||
vineflower = "1.11.0"
|
vanillaExtract = "0.2.1"
|
||||||
|
versionCatalogUpdate = "0.8.1"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
# Normal dependencies
|
# Normal dependencies
|
||||||
asm = { module = "org.ow2.asm:asm", version.ref = "asm" }
|
asm = { module = "org.ow2.asm:asm", version.ref = "asm" }
|
||||||
|
asm-commons = { module = "org.ow2.asm:asm-commons", version.ref = "asm" }
|
||||||
autoService = { module = "com.google.auto.service:auto-service", version.ref = "autoService" }
|
autoService = { module = "com.google.auto.service:auto-service", version.ref = "autoService" }
|
||||||
checkerFramework = { module = "org.checkerframework:checker-qual", version.ref = "checkerFramework" }
|
checkerFramework = { module = "org.checkerframework:checker-qual", version.ref = "checkerFramework" }
|
||||||
cobalt = { module = "org.squiddev:Cobalt", version.ref = "cobalt" }
|
cobalt = { module = "cc.tweaked:cobalt", version.ref = "cobalt" }
|
||||||
|
commonsCli = { module = "commons-cli:commons-cli", version.ref = "commonsCli" }
|
||||||
fastutil = { module = "it.unimi.dsi:fastutil", version.ref = "fastutil" }
|
fastutil = { module = "it.unimi.dsi:fastutil", version.ref = "fastutil" }
|
||||||
forgeSpi = { module = "net.minecraftforge:forgespi", version.ref = "forgeSpi" }
|
neoMergeTool = { module = "net.neoforged:mergetool", version.ref = "neoMergeTool" }
|
||||||
guava = { module = "com.google.guava:guava", version.ref = "guava" }
|
guava = { module = "com.google.guava:guava", version.ref = "guava" }
|
||||||
jetbrainsAnnotations = { module = "org.jetbrains:annotations", version.ref = "jetbrainsAnnotations" }
|
jetbrainsAnnotations = { module = "org.jetbrains:annotations", version.ref = "jetbrainsAnnotations" }
|
||||||
jsr305 = { module = "com.google.code.findbugs:jsr305", version.ref = "jsr305" }
|
jspecify = { module = "org.jspecify:jspecify", version.ref = "jspecify" }
|
||||||
jzlib = { module = "com.jcraft:jzlib", version.ref = "jzlib" }
|
jzlib = { module = "com.jcraft:jzlib", version.ref = "jzlib" }
|
||||||
kotlin-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlin-coroutines" }
|
kotlin-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlin-coroutines" }
|
||||||
kotlin-platform = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "kotlin" }
|
kotlin-platform = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "kotlin" }
|
||||||
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
|
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
|
||||||
|
netty-codec = { module = "io.netty:netty-codec", version.ref = "netty" }
|
||||||
netty-http = { module = "io.netty:netty-codec-http", version.ref = "netty" }
|
netty-http = { module = "io.netty:netty-codec-http", version.ref = "netty" }
|
||||||
netty-socks = { module = "io.netty:netty-codec-socks", version.ref = "netty" }
|
|
||||||
netty-proxy = { module = "io.netty:netty-handler-proxy", version.ref = "netty" }
|
netty-proxy = { module = "io.netty:netty-handler-proxy", version.ref = "netty" }
|
||||||
|
netty-socks = { module = "io.netty:netty-codec-socks", version.ref = "netty" }
|
||||||
nightConfig-core = { module = "com.electronwill.night-config:core", version.ref = "nightConfig" }
|
nightConfig-core = { module = "com.electronwill.night-config:core", version.ref = "nightConfig" }
|
||||||
nightConfig-toml = { module = "com.electronwill.night-config:toml", version.ref = "nightConfig" }
|
nightConfig-toml = { module = "com.electronwill.night-config:toml", version.ref = "nightConfig" }
|
||||||
slf4j = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
|
slf4j = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
|
||||||
|
|
||||||
# Minecraft mods
|
# Minecraft mods
|
||||||
|
create-fabric = { module = "com.simibubi.create:create-fabric-1.20.1", version.ref = "create-fabric" }
|
||||||
|
create-forge = { module = "com.simibubi.create:create-1.21.1", version.ref = "create-forge" }
|
||||||
|
emi = { module = "dev.emi:emi-xplat-mojmap", version.ref = "emi" }
|
||||||
fabric-api = { module = "net.fabricmc.fabric-api:fabric-api", version.ref = "fabric-api" }
|
fabric-api = { module = "net.fabricmc.fabric-api:fabric-api", version.ref = "fabric-api" }
|
||||||
|
fabric-junit = { module = "net.fabricmc:fabric-loader-junit", version.ref = "fabric-loader" }
|
||||||
fabric-loader = { module = "net.fabricmc:fabric-loader", version.ref = "fabric-loader" }
|
fabric-loader = { module = "net.fabricmc:fabric-loader", version.ref = "fabric-loader" }
|
||||||
fabricPermissions = { module = "me.lucko:fabric-permissions-api", version.ref = "fabricPermissions" }
|
fabricPermissions = { module = "me.lucko:fabric-permissions-api", version.ref = "fabricPermissions" }
|
||||||
emi = { module = "dev.emi:emi-xplat-mojmap", version.ref = "emi" }
|
iris-fabric = { module = "maven.modrinth:iris", version.ref = "iris-fabric" }
|
||||||
iris = { module = "maven.modrinth:iris", version.ref = "iris" }
|
iris-forge = { module = "maven.modrinth:iris", version.ref = "iris-forge" }
|
||||||
jei-api = { module = "mezz.jei:jei-1.20.1-common-api", version.ref = "jei" }
|
jei-api = { module = "mezz.jei:jei-1.21-common-api", version.ref = "jei" }
|
||||||
jei-fabric = { module = "mezz.jei:jei-1.20.1-fabric", version.ref = "jei" }
|
jei-fabric = { module = "mezz.jei:jei-1.21-fabric", version.ref = "jei" }
|
||||||
jei-forge = { module = "mezz.jei:jei-1.20.1-forge", version.ref = "jei" }
|
jei-forge = { module = "mezz.jei:jei-1.21-neoforge", version.ref = "jei" }
|
||||||
mixin = { module = "org.spongepowered:mixin", version.ref = "mixin" }
|
mixin = { module = "org.spongepowered:mixin", version.ref = "mixin" }
|
||||||
|
mixinExtra = { module = "io.github.llamalad7:mixinextras-common", version.ref = "mixinExtra" }
|
||||||
modmenu = { module = "com.terraformersmc:modmenu", version.ref = "modmenu" }
|
modmenu = { module = "com.terraformersmc:modmenu", version.ref = "modmenu" }
|
||||||
moreRed = { module = "commoble.morered:morered-1.20.1", version.ref = "moreRed" }
|
moreRed = { module = "net.commoble.morered:morered-1.21.1", version.ref = "moreRed" }
|
||||||
oculus = { module = "maven.modrinth:oculus", version.ref = "oculus" }
|
|
||||||
rei-api = { module = "me.shedaniel:RoughlyEnoughItems-api", version.ref = "rei" }
|
rei-api = { module = "me.shedaniel:RoughlyEnoughItems-api", version.ref = "rei" }
|
||||||
rei-builtin = { module = "me.shedaniel:RoughlyEnoughItems-default-plugin", version.ref = "rei" }
|
rei-builtin = { module = "me.shedaniel:RoughlyEnoughItems-default-plugin", version.ref = "rei" }
|
||||||
rei-fabric = { module = "me.shedaniel:RoughlyEnoughItems-fabric", version.ref = "rei" }
|
rei-fabric = { module = "me.shedaniel:RoughlyEnoughItems-fabric", version.ref = "rei" }
|
||||||
rubidium = { module = "maven.modrinth:rubidium", version.ref = "rubidium" }
|
sodium-fabric = { module = "maven.modrinth:sodium", version.ref = "sodium.fabric" }
|
||||||
sodium = { module = "maven.modrinth:sodium", version.ref = "sodium" }
|
sodium-forge = { module = "maven.modrinth:sodium", version.ref = "sodium.forge" }
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
byteBuddyAgent = { module = "net.bytebuddy:byte-buddy-agent", version.ref = "byteBuddy" }
|
|
||||||
byteBuddy = { module = "net.bytebuddy:byte-buddy", version.ref = "byteBuddy" }
|
|
||||||
hamcrest = { module = "org.hamcrest:hamcrest", version.ref = "hamcrest" }
|
hamcrest = { module = "org.hamcrest:hamcrest", version.ref = "hamcrest" }
|
||||||
jqwik-api = { module = "net.jqwik:jqwik-api", version.ref = "jqwik" }
|
jqwik-api = { module = "net.jqwik:jqwik-api", version.ref = "jqwik" }
|
||||||
jqwik-engine = { module = "net.jqwik:jqwik-engine", version.ref = "jqwik" }
|
jqwik-engine = { module = "net.jqwik:jqwik-engine", version.ref = "jqwik" }
|
||||||
junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit" }
|
junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit" }
|
||||||
junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit" }
|
junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit" }
|
||||||
junit-jupiter-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "junit" }
|
junit-jupiter-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "junit" }
|
||||||
|
junit-platform-launcher = { module = "org.junit.platform:junit-platform-launcher", version.ref = "junitPlatform" }
|
||||||
slf4j-simple = { module = "org.slf4j:slf4j-simple", version.ref = "slf4j" }
|
slf4j-simple = { module = "org.slf4j:slf4j-simple", version.ref = "slf4j" }
|
||||||
|
jmh = { module = "org.openjdk.jmh:jmh-core", version.ref = "jmh" }
|
||||||
|
jmh-processor = { module = "org.openjdk.jmh:jmh-generator-annprocess", version.ref = "jmh" }
|
||||||
|
|
||||||
|
# LWJGL
|
||||||
|
lwjgl-bom = { module = "org.lwjgl:lwjgl-bom", version.ref = "lwjgl" }
|
||||||
|
lwjgl-core = { module = "org.lwjgl:lwjgl" }
|
||||||
|
lwjgl-opengl = { module = "org.lwjgl:lwjgl-opengl" }
|
||||||
|
lwjgl-glfw = { module = "org.lwjgl:lwjgl-glfw" }
|
||||||
|
|
||||||
# Build tools
|
# Build tools
|
||||||
cctJavadoc = { module = "cc.tweaked:cct-javadoc", version.ref = "cctJavadoc" }
|
cctJavadoc = { module = "cc.tweaked:cct-javadoc", version.ref = "cctJavadoc" }
|
||||||
checkstyle = { module = "com.puppycrawl.tools:checkstyle", version.ref = "checkstyle" }
|
checkstyle = { module = "com.puppycrawl.tools:checkstyle", version.ref = "checkstyle" }
|
||||||
curseForgeGradle = { module = "net.darkhax.curseforgegradle:CurseForgeGradle", version.ref = "curseForgeGradle" }
|
|
||||||
errorProne-annotations = { module = "com.google.errorprone:error_prone_annotations", version.ref = "errorProne-core" }
|
errorProne-annotations = { module = "com.google.errorprone:error_prone_annotations", version.ref = "errorProne-core" }
|
||||||
errorProne-api = { module = "com.google.errorprone:error_prone_check_api", version.ref = "errorProne-core" }
|
errorProne-api = { module = "com.google.errorprone:error_prone_check_api", version.ref = "errorProne-core" }
|
||||||
errorProne-core = { module = "com.google.errorprone:error_prone_core", version.ref = "errorProne-core" }
|
errorProne-core = { module = "com.google.errorprone:error_prone_core", version.ref = "errorProne-core" }
|
||||||
errorProne-plugin = { module = "net.ltgt.gradle:gradle-errorprone-plugin", version.ref = "errorProne-plugin" }
|
errorProne-plugin = { module = "net.ltgt.gradle:gradle-errorprone-plugin", version.ref = "errorProne-plugin" }
|
||||||
errorProne-testHelpers = { module = "com.google.errorprone:error_prone_test_helpers", version.ref = "errorProne-core" }
|
errorProne-testHelpers = { module = "com.google.errorprone:error_prone_test_helpers", version.ref = "errorProne-core" }
|
||||||
fabric-loom = { module = "net.fabricmc:fabric-loom", version.ref = "fabric-loom" }
|
fabric-loom = { module = "net.fabricmc:fabric-loom", version.ref = "fabric-loom" }
|
||||||
forgeGradle = { module = "net.minecraftforge.gradle:ForgeGradle", version.ref = "forgeGradle" }
|
ideaExt = { module = "gradle.plugin.org.jetbrains.gradle.plugin.idea-ext:gradle-idea-ext", version.ref = "ideaExt" }
|
||||||
kotlin-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
|
kotlin-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
|
||||||
librarian = { module = "org.parchmentmc:librarian", version.ref = "librarian" }
|
|
||||||
minotaur = { module = "com.modrinth.minotaur:Minotaur", version.ref = "minotaur" }
|
minotaur = { module = "com.modrinth.minotaur:Minotaur", version.ref = "minotaur" }
|
||||||
nullAway = { module = "com.uber.nullaway:nullaway", version.ref = "nullAway" }
|
nullAway = { module = "com.uber.nullaway:nullaway", version.ref = "nullAway" }
|
||||||
|
modDevGradle = { module = "net.neoforged:moddev-gradle", version.ref = "modDevGradle" }
|
||||||
spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version.ref = "spotless" }
|
spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version.ref = "spotless" }
|
||||||
vanillaGradle = { module = "org.spongepowered:vanillagradle", version.ref = "vanillaGradle" }
|
teavm-classlib = { module = "org.teavm:teavm-classlib", version.ref = "teavm" }
|
||||||
vineflower = { module = "io.github.juuxel:loom-vineflower", version.ref = "vineflower" }
|
teavm-core = { module = "org.teavm:teavm-core", version.ref = "teavm" }
|
||||||
|
teavm-jso = { module = "org.teavm:teavm-jso", version.ref = "teavm" }
|
||||||
|
teavm-jso-apis = { module = "org.teavm:teavm-jso-apis", version.ref = "teavm" }
|
||||||
|
teavm-jso-impl = { module = "org.teavm:teavm-jso-impl", version.ref = "teavm" }
|
||||||
|
teavm-metaprogramming-api = { module = "org.teavm:teavm-metaprogramming-api", version.ref = "teavm" }
|
||||||
|
teavm-metaprogramming-impl = { module = "org.teavm:teavm-metaprogramming-impl", version.ref = "teavm" }
|
||||||
|
teavm-platform = { module = "org.teavm:teavm-platform", version.ref = "teavm" }
|
||||||
|
teavm-tooling = { module = "org.teavm:teavm-tooling", version.ref = "teavm" }
|
||||||
|
vanillaExtract = { module = "cc.tweaked.vanilla-extract:plugin", version.ref = "vanillaExtract" }
|
||||||
|
yarn = { module = "net.fabricmc:yarn", version.ref = "yarn" }
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
forgeGradle = { id = "net.minecraftforge.gradle", version.ref = "forgeGradle" }
|
|
||||||
githubRelease = { id = "com.github.breadmoirai.github-release", version.ref = "githubRelease" }
|
githubRelease = { id = "com.github.breadmoirai.github-release", version.ref = "githubRelease" }
|
||||||
ideaExt = { id = "org.jetbrains.gradle.plugin.idea-ext", version.ref = "ideaExt" }
|
gradleVersions = { id = "com.github.ben-manes.versions", version.ref = "gradleVersions" }
|
||||||
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
||||||
librarian = { id = "org.parchmentmc.librarian.forgegradle", version.ref = "librarian" }
|
shadow = { id = "com.gradleup.shadow", version.ref = "shadow" }
|
||||||
mixinGradle = { id = "org.spongepowered.mixin", version.ref = "mixinGradle" }
|
|
||||||
taskTree = { id = "com.dorongold.task-tree", version.ref = "taskTree" }
|
taskTree = { id = "com.dorongold.task-tree", version.ref = "taskTree" }
|
||||||
|
versionCatalogUpdate = { id = "nl.littlerobots.version-catalog-update", version.ref = "versionCatalogUpdate" }
|
||||||
|
|
||||||
[bundles]
|
[bundles]
|
||||||
|
annotations = ["checkerFramework", "jetbrainsAnnotations", "jspecify"]
|
||||||
kotlin = ["kotlin-stdlib", "kotlin-coroutines"]
|
kotlin = ["kotlin-stdlib", "kotlin-coroutines"]
|
||||||
|
|
||||||
# Minecraft
|
# Minecraft
|
||||||
externalMods-common = ["jei-api", "nightConfig-core", "nightConfig-toml"]
|
externalMods-common = ["iris-forge", "jei-api", "nightConfig-core", "nightConfig-toml"]
|
||||||
externalMods-forge-compile = ["moreRed", "oculus", "jei-api"]
|
externalMods-forge-compile = ["moreRed", "iris-forge", "jei-api"]
|
||||||
externalMods-forge-runtime = ["jei-forge"]
|
externalMods-forge-runtime = []
|
||||||
externalMods-fabric = ["nightConfig-core", "nightConfig-toml"]
|
externalMods-fabric-compile = ["fabricPermissions", "iris-fabric", "jei-api", "rei-api", "rei-builtin"]
|
||||||
externalMods-fabric-compile = ["fabricPermissions", "iris", "jei-api", "rei-api", "rei-builtin"]
|
externalMods-fabric-runtime = []
|
||||||
externalMods-fabric-runtime = ["jei-fabric", "modmenu"]
|
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
test = ["junit-jupiter-api", "junit-jupiter-params", "hamcrest", "jqwik-api"]
|
test = ["junit-jupiter-api", "junit-jupiter-params", "hamcrest", "jqwik-api"]
|
||||||
testRuntime = ["junit-jupiter-engine", "jqwik-engine"]
|
testRuntime = ["junit-jupiter-engine", "junit-platform-launcher", "jqwik-engine"]
|
||||||
|
|
||||||
|
# Build tools
|
||||||
|
teavm-api = ["teavm-jso", "teavm-jso-apis", "teavm-platform", "teavm-classlib", "teavm-metaprogramming-api"]
|
||||||
|
teavm-tooling = ["teavm-tooling", "teavm-metaprogramming-impl", "teavm-jso-impl"]
|
||||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
3
gradle/wrapper/gradle-wrapper.properties
vendored
3
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,7 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
26
gradlew
vendored
26
gradlew
vendored
@@ -15,6 +15,8 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
@@ -55,7 +57,7 @@
|
|||||||
# Darwin, MinGW, and NonStop.
|
# Darwin, MinGW, and NonStop.
|
||||||
#
|
#
|
||||||
# (3) This script is generated from the Groovy template
|
# (3) This script is generated from the Groovy template
|
||||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
# within the Gradle project.
|
# within the Gradle project.
|
||||||
#
|
#
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
@@ -83,7 +85,8 @@ done
|
|||||||
# This is normally unused
|
# This is normally unused
|
||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
APP_BASE_NAME=${0##*/}
|
APP_BASE_NAME=${0##*/}
|
||||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
|
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD=maximum
|
MAX_FD=maximum
|
||||||
@@ -130,10 +133,13 @@ location of your Java installation."
|
|||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
JAVACMD=java
|
JAVACMD=java
|
||||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
if ! command -v java >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
location of your Java installation."
|
location of your Java installation."
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
# Increase the maximum file descriptors if we can.
|
||||||
@@ -141,7 +147,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
|||||||
case $MAX_FD in #(
|
case $MAX_FD in #(
|
||||||
max*)
|
max*)
|
||||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||||
# shellcheck disable=SC3045
|
# shellcheck disable=SC2039,SC3045
|
||||||
MAX_FD=$( ulimit -H -n ) ||
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
warn "Could not query maximum file descriptor limit"
|
warn "Could not query maximum file descriptor limit"
|
||||||
esac
|
esac
|
||||||
@@ -149,7 +155,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
|||||||
'' | soft) :;; #(
|
'' | soft) :;; #(
|
||||||
*)
|
*)
|
||||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||||
# shellcheck disable=SC3045
|
# shellcheck disable=SC2039,SC3045
|
||||||
ulimit -n "$MAX_FD" ||
|
ulimit -n "$MAX_FD" ||
|
||||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
esac
|
esac
|
||||||
@@ -198,11 +204,11 @@ fi
|
|||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
# Collect all arguments for the java command;
|
# Collect all arguments for the java command:
|
||||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||||
# shell script including quotes and variable substitutions, so put them in
|
# and any embedded shellness will be escaped.
|
||||||
# double quotes to make sure that they get re-expanded; and
|
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||||
# * put everything else in single quotes, so that it's not re-expanded.
|
# treated as '${Hostname}' itself on the command line.
|
||||||
|
|
||||||
set -- \
|
set -- \
|
||||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
22
gradlew.bat
vendored
22
gradlew.bat
vendored
@@ -13,6 +13,8 @@
|
|||||||
@rem See the License for the specific language governing permissions and
|
@rem See the License for the specific language governing permissions and
|
||||||
@rem limitations under the License.
|
@rem limitations under the License.
|
||||||
@rem
|
@rem
|
||||||
|
@rem SPDX-License-Identifier: Apache-2.0
|
||||||
|
@rem
|
||||||
|
|
||||||
@if "%DEBUG%"=="" @echo off
|
@if "%DEBUG%"=="" @echo off
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
@@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
|
|||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if %ERRORLEVEL% equ 0 goto execute
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation.
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
@@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|||||||
|
|
||||||
if exist "%JAVA_EXE%" goto execute
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation.
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
|
@@ -2,15 +2,15 @@
|
|||||||
|
|
||||||
; SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
; SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
||||||
;
|
;
|
||||||
; SPDX-License-Identifier: LicenseRef-CCPL
|
; SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
(sources
|
(sources
|
||||||
/doc/
|
/doc/
|
||||||
/projects/forge/build/docs/luaJavadoc/
|
/projects/common/build/docs/luaJavadoc/
|
||||||
/projects/core/src/main/resources/data/computercraft/lua/bios.lua
|
/projects/core/src/main/resources/data/computercraft/lua/bios.lua
|
||||||
/projects/core/src/main/resources/data/computercraft/lua/rom/
|
/projects/core/src/main/resources/data/computercraft/lua/rom/
|
||||||
/projects/core/src/test/resources/test-rom
|
/projects/core/src/test/resources/test-rom
|
||||||
/projects/web/src/mount)
|
/projects/web/src/frontend/mount)
|
||||||
|
|
||||||
(doc
|
(doc
|
||||||
; Also defined in projects/web/build.gradle.kts
|
; Also defined in projects/web/build.gradle.kts
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
(url https://tweaked.cc/)
|
(url https://tweaked.cc/)
|
||||||
(source-link https://github.com/cc-tweaked/CC-Tweaked/blob/${commit}/${path}#L${line})
|
(source-link https://github.com/cc-tweaked/CC-Tweaked/blob/${commit}/${path}#L${line})
|
||||||
|
|
||||||
(styles /projects/web/src/styles.css)
|
(styles /projects/web/build/rollup/index.css)
|
||||||
(scripts /projects/web/build/rollup/index.js)
|
(scripts /projects/web/build/rollup/index.js)
|
||||||
(head doc/head.html))
|
(head doc/head.html))
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
(library-path
|
(library-path
|
||||||
/doc/stub/
|
/doc/stub/
|
||||||
/projects/forge/build/docs/luaJavadoc/
|
/projects/common/build/docs/luaJavadoc/
|
||||||
|
|
||||||
/projects/core/src/main/resources/data/computercraft/lua/rom/apis/
|
/projects/core/src/main/resources/data/computercraft/lua/rom/apis/
|
||||||
/projects/core/src/main/resources/data/computercraft/lua/rom/apis/command/
|
/projects/core/src/main/resources/data/computercraft/lua/rom/apis/command/
|
||||||
@@ -77,7 +77,6 @@
|
|||||||
(globals
|
(globals
|
||||||
:max
|
:max
|
||||||
_CC_DEFAULT_SETTINGS
|
_CC_DEFAULT_SETTINGS
|
||||||
_CC_DISABLE_LUA51_FEATURES
|
|
||||||
_HOST
|
_HOST
|
||||||
;; Ideally we'd pick these up from bios.lua, but illuaminate currently
|
;; Ideally we'd pick these up from bios.lua, but illuaminate currently
|
||||||
;; isn't smart enough.
|
;; isn't smart enough.
|
||||||
@@ -89,7 +88,7 @@
|
|||||||
(/doc/stub/
|
(/doc/stub/
|
||||||
/projects/core/src/main/resources/data/computercraft/lua/bios.lua
|
/projects/core/src/main/resources/data/computercraft/lua/bios.lua
|
||||||
/projects/core/src/main/resources/data/computercraft/lua/rom/apis/
|
/projects/core/src/main/resources/data/computercraft/lua/rom/apis/
|
||||||
/projects/forge/build/docs/luaJavadoc/)
|
/projects/common/build/docs/luaJavadoc/)
|
||||||
(linters -var:unused-global)
|
(linters -var:unused-global)
|
||||||
(lint (allow-toplevel-global true)))
|
(lint (allow-toplevel-global true)))
|
||||||
|
|
||||||
@@ -106,6 +105,10 @@
|
|||||||
/projects/core/src/main/resources/data/computercraft/lua/rom/apis/turtle/turtle.lua)
|
/projects/core/src/main/resources/data/computercraft/lua/rom/apis/turtle/turtle.lua)
|
||||||
(linters -var:deprecated))
|
(linters -var:deprecated))
|
||||||
|
|
||||||
|
;; Suppress unused variable warnings in the parser.
|
||||||
|
(at /projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/cc/internal/syntax/parser.lua
|
||||||
|
(linters -var:unused))
|
||||||
|
|
||||||
(at /projects/core/src/test/resources/test-rom
|
(at /projects/core/src/test/resources/test-rom
|
||||||
; We should still be able to test deprecated members.
|
; We should still be able to test deprecated members.
|
||||||
(linters -var:deprecated)
|
(linters -var:deprecated)
|
||||||
@@ -115,4 +118,4 @@
|
|||||||
:max sleep write
|
:max sleep write
|
||||||
cct_test describe expect howlci fail it pending stub before_each)))
|
cct_test describe expect howlci fail it pending stub before_each)))
|
||||||
|
|
||||||
(at /projects/web/src/mount/expr_template.lua (lint (globals :max __expr__)))
|
(at /projects/web/src/frontend/mount/expr_template.lua (lint (globals :max __expr__)))
|
||||||
|
5065
package-lock.json
generated
5065
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
26
package.json
26
package.json
@@ -6,24 +6,24 @@
|
|||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@squid-dev/cc-web-term": "^2.0.0",
|
||||||
"preact": "^10.5.5",
|
"preact": "^10.5.5",
|
||||||
|
"setimmediate": "^1.0.5",
|
||||||
"tslib": "^2.0.3"
|
"tslib": "^2.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rollup/plugin-terser": "^0.4.0",
|
"@rollup/plugin-node-resolve": "^16.0.0",
|
||||||
"@rollup/plugin-typescript": "^11.0.0",
|
"@rollup/plugin-typescript": "^12.0.0 && <12.1.3",
|
||||||
"@rollup/plugin-url": "^8.0.1",
|
"@rollup/plugin-url": "^8.0.1",
|
||||||
"@types/glob": "^8.1.0",
|
"@swc/core": "^1.3.92",
|
||||||
"@types/react-dom": "^18.0.5",
|
"@types/node": "^24.0.0",
|
||||||
"glob": "^10.3.4",
|
"lightningcss": "^1.22.0",
|
||||||
"react-dom": "^18.1.0",
|
"preact-render-to-string": "^6.2.1",
|
||||||
"react": "^18.1.0",
|
"rehype": "^13.0.0",
|
||||||
"rehype-highlight": "^6.0.0",
|
"rehype-highlight": "^7.0.0",
|
||||||
"rehype-react": "^7.1.1",
|
"rehype-react": "^8.0.0",
|
||||||
"rehype": "^12.0.0",
|
"rollup": "^4.0.0",
|
||||||
"requirejs": "^2.3.6",
|
"tsx": "^4.7.0",
|
||||||
"rollup": "^3.19.1",
|
|
||||||
"ts-node": "^10.8.0",
|
|
||||||
"typescript": "^5.2.2"
|
"typescript": "^5.2.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -62,6 +62,9 @@ mentioning:
|
|||||||
- `lints`: This defines an [ErrorProne] plugin which adds a couple of compile-time checks to our code. This is what
|
- `lints`: This defines an [ErrorProne] plugin which adds a couple of compile-time checks to our code. This is what
|
||||||
enforces that no client-specific code is used inside the `main` source set (and a couple of other things!).
|
enforces that no client-specific code is used inside the `main` source set (and a couple of other things!).
|
||||||
|
|
||||||
|
- `standalone`: This contains a standalone UI for computers, allowing debugging and development of CraftOS without
|
||||||
|
launching Minecraft.
|
||||||
|
|
||||||
- `web`: This contains the additional tooling for building [the documentation website][tweaked.cc], such as support for
|
- `web`: This contains the additional tooling for building [the documentation website][tweaked.cc], such as support for
|
||||||
rendering recipes
|
rendering recipes
|
||||||
|
|
||||||
|
@@ -8,6 +8,8 @@ plugins {
|
|||||||
id("cc-tweaked.vanilla")
|
id("cc-tweaked.vanilla")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val mcVersion: String by extra
|
||||||
|
|
||||||
java {
|
java {
|
||||||
withJavadocJar()
|
withJavadocJar()
|
||||||
}
|
}
|
||||||
@@ -16,9 +18,70 @@ dependencies {
|
|||||||
api(project(":core-api"))
|
api(project(":core-api"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val javadocOverview by tasks.registering(Copy::class) {
|
||||||
|
from("src/overview.html")
|
||||||
|
into(layout.buildDirectory.dir(name))
|
||||||
|
|
||||||
|
expand(
|
||||||
|
mapOf(
|
||||||
|
"mcVersion" to mcVersion,
|
||||||
|
"modVersion" to version,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
tasks.javadoc {
|
tasks.javadoc {
|
||||||
|
title = "CC: Tweaked $version for Minecraft $mcVersion"
|
||||||
include("dan200/computercraft/api/**/*.java")
|
include("dan200/computercraft/api/**/*.java")
|
||||||
|
|
||||||
|
options {
|
||||||
|
(this as StandardJavadocDocletOptions)
|
||||||
|
|
||||||
|
inputs.files(javadocOverview)
|
||||||
|
overview(javadocOverview.get().destinationDir.resolve("overview.html").absolutePath)
|
||||||
|
|
||||||
|
groups = mapOf(
|
||||||
|
"Common" to listOf(
|
||||||
|
"dan200.computercraft.api",
|
||||||
|
"dan200.computercraft.api.lua",
|
||||||
|
"dan200.computercraft.api.peripheral",
|
||||||
|
),
|
||||||
|
"Upgrades" to listOf(
|
||||||
|
"dan200.computercraft.api.client.turtle",
|
||||||
|
"dan200.computercraft.api.pocket",
|
||||||
|
"dan200.computercraft.api.turtle",
|
||||||
|
"dan200.computercraft.api.upgrades",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
addBooleanOption("-allow-script-in-comments", true)
|
||||||
|
bottom(
|
||||||
|
"""
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/prismjs@v1.29.0/components/prism-core.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/prismjs@v1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
|
||||||
|
<link href=" https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css " rel="stylesheet">
|
||||||
|
""".trimIndent(),
|
||||||
|
)
|
||||||
|
|
||||||
|
val snippetSources = listOf(":common", ":fabric", ":forge").flatMap {
|
||||||
|
project(it).sourceSets["examples"].allSource.sourceDirectories
|
||||||
|
}
|
||||||
|
inputs.files(snippetSources)
|
||||||
|
addPathOption("-snippet-path").value = snippetSources
|
||||||
|
}
|
||||||
|
|
||||||
// Include the core-api in our javadoc export. This is wrong, but it means we can export a single javadoc dump.
|
// Include the core-api in our javadoc export. This is wrong, but it means we can export a single javadoc dump.
|
||||||
source(project(":core-api").sourceSets.main.map { it.allJava })
|
source(project(":core-api").sourceSets.main.map { it.allJava })
|
||||||
|
|
||||||
|
options {
|
||||||
|
this as StandardJavadocDocletOptions
|
||||||
|
addBooleanOption("-allow-script-in-comments", true)
|
||||||
|
bottom(
|
||||||
|
"""
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/prismjs@v1.29.0/components/prism-core.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/prismjs@v1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
|
||||||
|
<link href=" https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css " rel="stylesheet">
|
||||||
|
""".trimIndent(),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,38 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package dan200.computercraft.api.client;
|
|
||||||
|
|
||||||
import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
|
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
|
||||||
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
|
|
||||||
import dan200.computercraft.impl.client.ComputerCraftAPIClientService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The public API for client-only code.
|
|
||||||
*
|
|
||||||
* @see dan200.computercraft.api.ComputerCraftAPI The main API
|
|
||||||
*/
|
|
||||||
public final class ComputerCraftAPIClient {
|
|
||||||
private ComputerCraftAPIClient() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a {@link TurtleUpgradeModeller} for a class of turtle upgrades.
|
|
||||||
* <p>
|
|
||||||
* This may be called at any point after registry creation, though it is recommended to call it within your client
|
|
||||||
* setup step.
|
|
||||||
*
|
|
||||||
* @param serialiser The turtle upgrade serialiser.
|
|
||||||
* @param modeller The upgrade modeller.
|
|
||||||
* @param <T> The type of the turtle upgrade.
|
|
||||||
*/
|
|
||||||
public static <T extends ITurtleUpgrade> void registerTurtleUpgradeModeller(TurtleUpgradeSerialiser<T> serialiser, TurtleUpgradeModeller<T> modeller) {
|
|
||||||
getInstance().registerTurtleUpgradeModeller(serialiser, modeller);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ComputerCraftAPIClientService getInstance() {
|
|
||||||
return ComputerCraftAPIClientService.get();
|
|
||||||
}
|
|
||||||
}
|
|
@@ -0,0 +1,166 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.api.client;
|
||||||
|
|
||||||
|
import com.google.common.base.Suppliers;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import dan200.computercraft.api.client.turtle.TurtleUpgradeModel;
|
||||||
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
import net.minecraft.client.renderer.Sheets;
|
||||||
|
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||||
|
import net.minecraft.client.renderer.item.BlockModelWrapper;
|
||||||
|
import net.minecraft.client.renderer.item.ItemModel;
|
||||||
|
import net.minecraft.client.renderer.item.ItemModelResolver;
|
||||||
|
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
||||||
|
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||||
|
import net.minecraft.client.resources.model.BlockModelRotation;
|
||||||
|
import net.minecraft.client.resources.model.ModelBaker;
|
||||||
|
import net.minecraft.client.resources.model.ResolvedModel;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.util.ARGB;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.item.ItemDisplayContext;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A standalone model.
|
||||||
|
* <p>
|
||||||
|
* This is very similar to vanilla's {@link BlockModelWrapper}, but suitable for use in both {@link ItemModel}s and
|
||||||
|
* block models. This is primarily intended for use with {@link TurtleUpgradeModel}s.
|
||||||
|
*/
|
||||||
|
public final class StandaloneModel {
|
||||||
|
private final List<BakedQuad> quads;
|
||||||
|
private final boolean useBlockLight;
|
||||||
|
private final TextureAtlasSprite particleIcon;
|
||||||
|
private final RenderType renderType;
|
||||||
|
private final Supplier<Vector3f[]> extents;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new {@link StandaloneModel}.
|
||||||
|
*
|
||||||
|
* @param quads The list of quads which form this model.
|
||||||
|
* @param usesBlockLight Whether this uses block lighting. See {@link ItemStackRenderState.LayerRenderState#setUsesBlockLight(boolean)}.
|
||||||
|
* @param particleIcon The sprite for the model's particles. See {@link ItemStackRenderState.LayerRenderState#setParticleIcon(TextureAtlasSprite)}.
|
||||||
|
* @param renderType The render type for this model.
|
||||||
|
*/
|
||||||
|
public StandaloneModel(List<BakedQuad> quads, boolean usesBlockLight, TextureAtlasSprite particleIcon, RenderType renderType) {
|
||||||
|
this.quads = quads;
|
||||||
|
this.useBlockLight = usesBlockLight;
|
||||||
|
this.particleIcon = particleIcon;
|
||||||
|
this.renderType = renderType;
|
||||||
|
this.extents = Suppliers.memoize(() -> BlockModelWrapper.computeExtents(quads));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a model from a {@link ModelBaker} and bake it.
|
||||||
|
*
|
||||||
|
* @param model The model id to load.
|
||||||
|
* @param baker The model baker.
|
||||||
|
* @return The baked {@link StandaloneModel}.
|
||||||
|
*/
|
||||||
|
public static StandaloneModel of(ResourceLocation model, ModelBaker baker) {
|
||||||
|
return of(baker.getModel(model), baker);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bake a {@link ResolvedModel} into a {@link StandaloneModel}.
|
||||||
|
*
|
||||||
|
* @param model The resolved model.
|
||||||
|
* @param baker The model baker.
|
||||||
|
* @return The baked {@link StandaloneModel}.
|
||||||
|
*/
|
||||||
|
public static StandaloneModel of(ResolvedModel model, ModelBaker baker) {
|
||||||
|
return baker.compute(new CacheKey(model));
|
||||||
|
}
|
||||||
|
|
||||||
|
private record CacheKey(ResolvedModel model) implements ModelBaker.SharedOperationKey<StandaloneModel> {
|
||||||
|
@Override
|
||||||
|
public StandaloneModel compute(ModelBaker baker) {
|
||||||
|
return ofUncached(model(), baker);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object other) {
|
||||||
|
return other instanceof CacheKey(var otherModel) && model() == otherModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return System.identityHashCode(model());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static StandaloneModel ofUncached(ResolvedModel model, ModelBaker baker) {
|
||||||
|
var slots = model.getTopTextureSlots();
|
||||||
|
return new StandaloneModel(
|
||||||
|
model.bakeTopGeometry(slots, baker, BlockModelRotation.X0_Y0).getAll(),
|
||||||
|
model.getTopGuiLight().lightLikeBlock(),
|
||||||
|
model.resolveParticleSprite(slots, baker),
|
||||||
|
Sheets.translucentItemSheet()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up an {@link ItemStackRenderState.LayerRenderState} to render this model.
|
||||||
|
*
|
||||||
|
* @param layer The layer to set up.
|
||||||
|
* @see ItemModel#update(ItemStackRenderState, ItemStack, ItemModelResolver, ItemDisplayContext, ClientLevel, LivingEntity, int)
|
||||||
|
*/
|
||||||
|
public void setupItemLayer(ItemStackRenderState.LayerRenderState layer) {
|
||||||
|
layer.setExtents(extents);
|
||||||
|
layer.setRenderType(renderType);
|
||||||
|
layer.setUsesBlockLight(useBlockLight);
|
||||||
|
layer.setParticleIcon(particleIcon);
|
||||||
|
layer.prepareQuadList().addAll(quads);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the model directly.
|
||||||
|
*
|
||||||
|
* @param transform The current pose stack transformations.
|
||||||
|
* @param buffers The buffer source to use for rendering.
|
||||||
|
* @param light The current light texture coordinate.
|
||||||
|
* @param overlay The current overlay texture coordinate.
|
||||||
|
*/
|
||||||
|
public void render(PoseStack transform, MultiBufferSource buffers, int light, int overlay) {
|
||||||
|
render(transform, buffers, light, overlay, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the model directly.
|
||||||
|
*
|
||||||
|
* @param transform The current pose stack transformations.
|
||||||
|
* @param buffers The buffer source to use for rendering.
|
||||||
|
* @param light The current light texture coordinate.
|
||||||
|
* @param overlay The current overlay texture coordinate.
|
||||||
|
* @param tints The tints for this model.
|
||||||
|
*/
|
||||||
|
public void render(PoseStack transform, MultiBufferSource buffers, int light, int overlay, int @Nullable [] tints) {
|
||||||
|
var pose = transform.last();
|
||||||
|
var buffer = buffers.getBuffer(renderType);
|
||||||
|
for (var quad : quads) {
|
||||||
|
float r, g, b, a;
|
||||||
|
var idx = quad.tintIndex();
|
||||||
|
if (tints != null && idx >= 0 && idx < tints.length) {
|
||||||
|
var tint = tints[idx];
|
||||||
|
r = ARGB.red(tint) / 255.0f;
|
||||||
|
g = ARGB.green(tint) / 255.0f;
|
||||||
|
b = ARGB.blue(tint) / 255.0f;
|
||||||
|
a = ARGB.alpha(tint) / 255.0f;
|
||||||
|
} else {
|
||||||
|
r = g = b = a = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.putBulkData(pose, quad, r, g, b, a, light, overlay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,57 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2020 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
|
|
||||||
package dan200.computercraft.api.client;
|
|
||||||
|
|
||||||
import com.mojang.math.Transformation;
|
|
||||||
import dan200.computercraft.impl.client.ClientPlatformHelper;
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.client.resources.model.BakedModel;
|
|
||||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A model to render, combined with a transformation matrix to apply.
|
|
||||||
*/
|
|
||||||
public final class TransformedModel {
|
|
||||||
private final BakedModel model;
|
|
||||||
private final Transformation matrix;
|
|
||||||
|
|
||||||
public TransformedModel(BakedModel model, Transformation matrix) {
|
|
||||||
this.model = Objects.requireNonNull(model);
|
|
||||||
this.matrix = Objects.requireNonNull(matrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TransformedModel(BakedModel model) {
|
|
||||||
this.model = Objects.requireNonNull(model);
|
|
||||||
matrix = Transformation.identity();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TransformedModel of(ModelResourceLocation location) {
|
|
||||||
var modelManager = Minecraft.getInstance().getModelManager();
|
|
||||||
return new TransformedModel(modelManager.getModel(location));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TransformedModel of(ResourceLocation location) {
|
|
||||||
var modelManager = Minecraft.getInstance().getModelManager();
|
|
||||||
return new TransformedModel(ClientPlatformHelper.get().getModel(modelManager, location));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TransformedModel of(ItemStack item, Transformation transform) {
|
|
||||||
var model = Minecraft.getInstance().getItemRenderer().getItemModelShaper().getItemModel(item);
|
|
||||||
return new TransformedModel(model, transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BakedModel getModel() {
|
|
||||||
return model;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Transformation getMatrix() {
|
|
||||||
return matrix;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -0,0 +1,95 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.api.client.turtle;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import com.mojang.serialization.MapCodec;
|
||||||
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||||
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
|
import dan200.computercraft.api.client.StandaloneModel;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
import net.minecraft.client.renderer.block.model.ItemTransform;
|
||||||
|
import net.minecraft.client.renderer.item.BlockModelWrapper;
|
||||||
|
import net.minecraft.client.renderer.item.ItemModelResolver;
|
||||||
|
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
||||||
|
import net.minecraft.client.resources.model.ModelBaker;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link TurtleUpgradeModel} that renders a basic model.
|
||||||
|
* <p>
|
||||||
|
* This is the {@link TurtleUpgradeModel} equivalent of {@link BlockModelWrapper}.
|
||||||
|
*/
|
||||||
|
public final class BasicUpgradeModel implements TurtleUpgradeModel {
|
||||||
|
public static final ResourceLocation ID = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "sided");
|
||||||
|
public static final MapCodec<? extends TurtleUpgradeModel.Unbaked> CODEC = RecordCodecBuilder.<Unbaked>mapCodec(instance -> instance.group(
|
||||||
|
ResourceLocation.CODEC.fieldOf("left").forGetter(Unbaked::left),
|
||||||
|
ResourceLocation.CODEC.fieldOf("right").forGetter(Unbaked::right)
|
||||||
|
).apply(instance, Unbaked::new));
|
||||||
|
|
||||||
|
private final StandaloneModel left;
|
||||||
|
private final StandaloneModel right;
|
||||||
|
|
||||||
|
private BasicUpgradeModel(StandaloneModel left, StandaloneModel right) {
|
||||||
|
this.left = left;
|
||||||
|
this.right = right;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an unbaked {@link BasicUpgradeModel}.
|
||||||
|
*
|
||||||
|
* @param left The model when equipped on the left.
|
||||||
|
* @param right The model when equipped on the right.
|
||||||
|
* @return The unbaked turtle upgrade model.
|
||||||
|
*/
|
||||||
|
public static TurtleUpgradeModel.Unbaked unbaked(ResourceLocation left, ResourceLocation right) {
|
||||||
|
return new Unbaked(left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
private StandaloneModel getModel(TurtleSide side) {
|
||||||
|
return switch (side) {
|
||||||
|
case LEFT -> left;
|
||||||
|
case RIGHT -> right;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderForItem(UpgradeData<ITurtleUpgrade> upgrade, TurtleSide side, ItemStackRenderState renderer, ItemModelResolver resolver, ItemTransform transform, int seed) {
|
||||||
|
renderer.appendModelIdentityElement(this);
|
||||||
|
renderer.appendModelIdentityElement(side);
|
||||||
|
renderer.appendModelIdentityElement(transform);
|
||||||
|
|
||||||
|
var layer = renderer.newLayer();
|
||||||
|
layer.setTransform(transform);
|
||||||
|
getModel(side).setupItemLayer(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderForLevel(UpgradeData<ITurtleUpgrade> upgrade, TurtleSide side, ITurtleAccess turtle, PoseStack transform, MultiBufferSource buffers, int light, int overlay) {
|
||||||
|
getModel(side).render(transform, buffers, light, overlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
private record Unbaked(ResourceLocation left, ResourceLocation right) implements TurtleUpgradeModel.Unbaked {
|
||||||
|
@Override
|
||||||
|
public MapCodec<? extends TurtleUpgradeModel.Unbaked> type() {
|
||||||
|
return CODEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TurtleUpgradeModel bake(ModelBaker baker) {
|
||||||
|
return new BasicUpgradeModel(StandaloneModel.of(left(), baker), StandaloneModel.of(right(), baker));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resolveDependencies(Resolver resolver) {
|
||||||
|
resolver.markDependency(left());
|
||||||
|
resolver.markDependency(right());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,143 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.api.client.turtle;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import com.mojang.math.Axis;
|
||||||
|
import com.mojang.math.Transformation;
|
||||||
|
import com.mojang.serialization.MapCodec;
|
||||||
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
import net.minecraft.client.renderer.block.model.ItemTransform;
|
||||||
|
import net.minecraft.client.renderer.item.ItemModelResolver;
|
||||||
|
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
||||||
|
import net.minecraft.client.renderer.item.TrackingItemStackRenderState;
|
||||||
|
import net.minecraft.client.renderer.special.SpecialModelRenderer;
|
||||||
|
import net.minecraft.client.resources.model.ModelBaker;
|
||||||
|
import net.minecraft.core.component.DataComponentPatch;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.world.item.ItemDisplayContext;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import org.joml.Matrix4f;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A sic {@link TurtleUpgradeModel} that renders the upgrade's {@linkplain ITurtleUpgrade#getUpgradeItem(DataComponentPatch)
|
||||||
|
* upgrade item}.
|
||||||
|
* <p>
|
||||||
|
* This uses appropriate transformations for "flat" items, namely those extending the {@literal minecraft:item/generated}
|
||||||
|
* model type. It will not appear correct for 3D models with additional depth, such as blocks.
|
||||||
|
*/
|
||||||
|
public final class ItemUpgradeModel implements TurtleUpgradeModel {
|
||||||
|
private static final TurtleUpgradeModel.Unbaked UNBAKED = new Unbaked();
|
||||||
|
private static final TurtleUpgradeModel INSTANCE = new ItemUpgradeModel();
|
||||||
|
|
||||||
|
public static final ResourceLocation ID = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "item");
|
||||||
|
public static final MapCodec<TurtleUpgradeModel.Unbaked> CODEC = MapCodec.unit(UNBAKED);
|
||||||
|
|
||||||
|
private static final TransformedRenderer LEFT = computeRenderer(TurtleSide.LEFT);
|
||||||
|
private static final TransformedRenderer RIGHT = computeRenderer(TurtleSide.RIGHT);
|
||||||
|
|
||||||
|
private ItemUpgradeModel() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the unbaked {@link ItemUpgradeModel}.
|
||||||
|
*
|
||||||
|
* @return The unbaked item upgrade model.
|
||||||
|
*/
|
||||||
|
public static TurtleUpgradeModel.Unbaked unbaked() {
|
||||||
|
return UNBAKED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderForItem(UpgradeData<ITurtleUpgrade> upgrade, TurtleSide side, ItemStackRenderState renderer, ItemModelResolver resolver, ItemTransform transform, int seed) {
|
||||||
|
renderer.appendModelIdentityElement(this);
|
||||||
|
|
||||||
|
var childState = new TrackingItemStackRenderState();
|
||||||
|
resolver.updateForTopItem(childState, upgrade.getUpgradeItem(), ItemDisplayContext.NONE, null, null, seed);
|
||||||
|
if (!childState.isEmpty()) {
|
||||||
|
renderer.appendModelIdentityElement(childState.getModelIdentity());
|
||||||
|
renderer.appendModelIdentityElement(transform);
|
||||||
|
|
||||||
|
var layer = renderer.newLayer();
|
||||||
|
layer.setTransform(transform);
|
||||||
|
layer.setupSpecialModel(getRenderer(side), childState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderForLevel(UpgradeData<ITurtleUpgrade> upgrade, TurtleSide side, ITurtleAccess turtle, PoseStack transform, MultiBufferSource buffers, int light, int overlay) {
|
||||||
|
transform.mulPose(getRenderer(side).transform().getMatrix());
|
||||||
|
transform.mulPose(Axis.YP.rotation(Mth.PI));
|
||||||
|
Minecraft.getInstance().getItemRenderer().renderStatic(
|
||||||
|
upgrade.getUpgradeItem(), ItemDisplayContext.FIXED, light, overlay, transform, buffers, turtle.getLevel(), 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class Unbaked implements TurtleUpgradeModel.Unbaked {
|
||||||
|
@Override
|
||||||
|
public MapCodec<? extends TurtleUpgradeModel.Unbaked> type() {
|
||||||
|
return CODEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TurtleUpgradeModel bake(ModelBaker baker) {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resolveDependencies(Resolver resolver) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TransformedRenderer computeRenderer(TurtleSide side) {
|
||||||
|
var pose = new Matrix4f();
|
||||||
|
pose.translate(0.5f, 0.5f, 0.5f);
|
||||||
|
pose.rotate(Axis.YN.rotationDegrees(90f));
|
||||||
|
pose.rotate(Axis.ZP.rotationDegrees(90f));
|
||||||
|
pose.translate(0.0f, 0.0f, side == TurtleSide.RIGHT ? -0.4065f : 0.4065f);
|
||||||
|
return new TransformedRenderer(new Transformation(pose));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TransformedRenderer getRenderer(TurtleSide side) {
|
||||||
|
return switch (side) {
|
||||||
|
case LEFT -> LEFT;
|
||||||
|
case RIGHT -> RIGHT;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private record TransformedRenderer(Transformation transform) implements SpecialModelRenderer<ItemStackRenderState> {
|
||||||
|
@Override
|
||||||
|
public void render(
|
||||||
|
@Nullable ItemStackRenderState state, ItemDisplayContext itemDisplayContext, PoseStack poseStack,
|
||||||
|
MultiBufferSource multiBufferSource, int overlay, int light, boolean bl
|
||||||
|
) {
|
||||||
|
if (state == null) return;
|
||||||
|
poseStack.pushPose();
|
||||||
|
poseStack.mulPose(transform.getMatrix());
|
||||||
|
state.render(poseStack, multiBufferSource, overlay, light);
|
||||||
|
poseStack.popPose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getExtents(Set<Vector3f> set) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable ItemStackRenderState extractArgument(ItemStack itemStack) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,25 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.api.client.turtle;
|
||||||
|
|
||||||
|
import com.mojang.serialization.MapCodec;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A functional interface to register a {@link TurtleUpgradeModel}.
|
||||||
|
* <p>
|
||||||
|
* This interface is largely intended to be used from multi-loader code, to allow sharing registration code between
|
||||||
|
* multiple loaders.
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface RegisterTurtleUpgradeModel {
|
||||||
|
/**
|
||||||
|
* Register a {@link TurtleUpgradeModel}.
|
||||||
|
*
|
||||||
|
* @param id The id used for this type of upgrade model.
|
||||||
|
* @param model The codec used to read/decode an upgrade model.
|
||||||
|
*/
|
||||||
|
void register(ResourceLocation id, MapCodec<? extends TurtleUpgradeModel.Unbaked> model);
|
||||||
|
}
|
@@ -0,0 +1,209 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.api.client.turtle;
|
||||||
|
|
||||||
|
import com.google.common.collect.HashMultiset;
|
||||||
|
import com.google.common.collect.Multiset;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import com.mojang.datafixers.util.Pair;
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
|
import com.mojang.serialization.DataResult;
|
||||||
|
import com.mojang.serialization.MapCodec;
|
||||||
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||||
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||||
|
import net.minecraft.Util;
|
||||||
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
import net.minecraft.client.renderer.block.model.ItemTransform;
|
||||||
|
import net.minecraft.client.renderer.item.ItemModelResolver;
|
||||||
|
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
||||||
|
import net.minecraft.client.renderer.item.SelectItemModel;
|
||||||
|
import net.minecraft.client.resources.model.MissingBlockModel;
|
||||||
|
import net.minecraft.client.resources.model.ModelBaker;
|
||||||
|
import net.minecraft.core.component.DataComponentType;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link TurtleUpgradeModel} which selects between different models based on the value of a component in
|
||||||
|
* {@linkplain UpgradeData#data() the upgrade's data}.
|
||||||
|
* <p>
|
||||||
|
* This is the {@link TurtleUpgradeModel} equivalent of {@link SelectItemModel}.
|
||||||
|
*
|
||||||
|
* @param <T> The type of value to switch on.
|
||||||
|
*/
|
||||||
|
public final class SelectUpgradeModel<T> implements TurtleUpgradeModel {
|
||||||
|
public static final ResourceLocation ID = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "select");
|
||||||
|
public static final MapCodec<? extends TurtleUpgradeModel.Unbaked> CODEC = RecordCodecBuilder.<Unbaked<?>>mapCodec(instance -> instance.group(
|
||||||
|
Cases.CODEC.forGetter(Unbaked::cases),
|
||||||
|
TurtleUpgradeModel.CODEC.optionalFieldOf("fallback").forGetter(Unbaked::fallback)
|
||||||
|
).apply(instance, Unbaked::new));
|
||||||
|
|
||||||
|
private final DataComponentType<T> component;
|
||||||
|
private final Map<T, TurtleUpgradeModel> cases;
|
||||||
|
private final TurtleUpgradeModel fallback;
|
||||||
|
|
||||||
|
private SelectUpgradeModel(DataComponentType<T> component, Map<T, TurtleUpgradeModel> cases, TurtleUpgradeModel fallback) {
|
||||||
|
this.component = component;
|
||||||
|
this.cases = cases;
|
||||||
|
this.fallback = fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TurtleUpgradeModel getModel(UpgradeData<ITurtleUpgrade> upgrade) {
|
||||||
|
var value = upgrade.get(component);
|
||||||
|
if (value == null) return fallback;
|
||||||
|
|
||||||
|
var model = cases.get(value);
|
||||||
|
return model != null ? model : fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderForItem(UpgradeData<ITurtleUpgrade> upgrade, TurtleSide side, ItemStackRenderState renderer, ItemModelResolver resolver, ItemTransform transform, int seed) {
|
||||||
|
getModel(upgrade).renderForItem(upgrade, side, renderer, resolver, transform, seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderForLevel(UpgradeData<ITurtleUpgrade> upgrade, TurtleSide side, ITurtleAccess turtle, PoseStack transform, MultiBufferSource buffers, int light, int overlay) {
|
||||||
|
getModel(upgrade).renderForLevel(upgrade, side, turtle, transform, buffers, light, overlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
private record Unbaked<T>(
|
||||||
|
Cases<T> cases,
|
||||||
|
Optional<TurtleUpgradeModel.Unbaked> fallback
|
||||||
|
) implements TurtleUpgradeModel.Unbaked {
|
||||||
|
private static final TurtleUpgradeModel.Unbaked MISSING = BasicUpgradeModel.unbaked(MissingBlockModel.LOCATION, MissingBlockModel.LOCATION);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MapCodec<? extends TurtleUpgradeModel.Unbaked> type() {
|
||||||
|
return CODEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TurtleUpgradeModel bake(ModelBaker baker) {
|
||||||
|
Map<T, TurtleUpgradeModel> cases = new Object2ObjectOpenHashMap<>();
|
||||||
|
for (var condition : cases().cases()) {
|
||||||
|
var model = condition.getSecond().bake(baker);
|
||||||
|
for (var when : condition.getFirst()) cases.put(when, model);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SelectUpgradeModel<>(cases().component(), cases, fallback().orElse(MISSING).bake(baker));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resolveDependencies(Resolver resolver) {
|
||||||
|
cases().cases().forEach(x -> x.getSecond().resolveDependencies(resolver));
|
||||||
|
fallback().orElse(MISSING).resolveDependencies(resolver);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private record Cases<T>(DataComponentType<T> component, List<Pair<List<T>, TurtleUpgradeModel.Unbaked>> cases) {
|
||||||
|
private static final MapCodec<Cases<?>> CODEC = DataComponentType.CODEC.dispatchMap("property", Cases::component, Util.memoize(Cases::codec));
|
||||||
|
|
||||||
|
private static <T> MapCodec<Cases<T>> codec(DataComponentType<T> component) {
|
||||||
|
return RecordCodecBuilder.mapCodec(instance -> instance.group(
|
||||||
|
MapCodec.unit(component).forGetter(Cases::component),
|
||||||
|
caseCodec(component.codecOrThrow()).listOf().fieldOf("cases").validate(Cases::validate).forGetter(Cases::cases)
|
||||||
|
).apply(instance, Cases<T>::new));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> Codec<Pair<List<T>, TurtleUpgradeModel.Unbaked>> caseCodec(Codec<T> codec) {
|
||||||
|
return RecordCodecBuilder.create(instance -> instance.group(
|
||||||
|
codec.listOf().fieldOf("when").forGetter(Pair::getFirst),
|
||||||
|
TurtleUpgradeModel.CODEC.fieldOf("model").forGetter(Pair::getSecond)
|
||||||
|
).apply(instance, Pair::new));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> DataResult<List<Pair<List<T>, TurtleUpgradeModel.Unbaked>>> validate(List<Pair<List<T>, TurtleUpgradeModel.Unbaked>> cases) {
|
||||||
|
Multiset<T> multiset = HashMultiset.create();
|
||||||
|
for (var condition : cases) multiset.addAll(condition.getFirst());
|
||||||
|
|
||||||
|
if (multiset.isEmpty()) return DataResult.error(() -> "Empty cases");
|
||||||
|
if (multiset.size() != multiset.entrySet().size()) {
|
||||||
|
return DataResult.error(() -> "Duplicate case conditions: " + multiset.entrySet().stream()
|
||||||
|
.filter(x -> x.getCount() > 1)
|
||||||
|
.map(x -> Objects.toString(x.getElement()))
|
||||||
|
.collect(Collectors.joining(", ")));
|
||||||
|
}
|
||||||
|
|
||||||
|
return DataResult.success(cases);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a {@link SelectUpgradeModel} that selects a model based on a component.
|
||||||
|
*
|
||||||
|
* @param component The component to select.
|
||||||
|
* @param <T> The type the component stores.
|
||||||
|
* @return A {@link Builder}.
|
||||||
|
*/
|
||||||
|
public static <T> Builder<T> onComponent(DataComponentType<T> component) {
|
||||||
|
return new Builder<>(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A builder for constructing {@link SelectUpgradeModel}s.
|
||||||
|
*
|
||||||
|
* @param <T> The type of value to switch on.
|
||||||
|
*/
|
||||||
|
public static final class Builder<T> {
|
||||||
|
private final DataComponentType<T> component;
|
||||||
|
private final List<Pair<List<T>, TurtleUpgradeModel.Unbaked>> cases = new ArrayList<>();
|
||||||
|
private TurtleUpgradeModel.@Nullable Unbaked fallback;
|
||||||
|
|
||||||
|
private Builder(DataComponentType<T> component) {
|
||||||
|
this.component = component;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a case to our model.
|
||||||
|
*
|
||||||
|
* @param value The value for this case.
|
||||||
|
* @param model The model to use.
|
||||||
|
* @return {@code this}, for chaining.
|
||||||
|
*/
|
||||||
|
public Builder<T> when(T value, TurtleUpgradeModel.Unbaked model) {
|
||||||
|
return when(List.of(value), model);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a case to our model.
|
||||||
|
*
|
||||||
|
* @param values The value(s) for this case.
|
||||||
|
* @param model The model to use.
|
||||||
|
* @return {@code this}, for chaining.
|
||||||
|
*/
|
||||||
|
public Builder<T> when(List<T> values, TurtleUpgradeModel.Unbaked model) {
|
||||||
|
cases.add(Pair.of(values, model));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a fallback value, when no previous value matches or the component is not present.
|
||||||
|
*
|
||||||
|
* @param model The fallback model.
|
||||||
|
* @return {@code this}, for chaining.
|
||||||
|
*/
|
||||||
|
public Builder<T> fallback(TurtleUpgradeModel.Unbaked model) {
|
||||||
|
this.fallback = model;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert this builder into an unbaked model.
|
||||||
|
*
|
||||||
|
* @return The unbaked {@link SelectUpgradeModel}.
|
||||||
|
*/
|
||||||
|
public TurtleUpgradeModel.Unbaked create() {
|
||||||
|
return new Unbaked<>(new Cases<>(component, cases), Optional.ofNullable(fallback));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,110 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.api.client.turtle;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
|
import com.mojang.serialization.MapCodec;
|
||||||
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
|
import dan200.computercraft.impl.client.ComputerCraftAPIClientService;
|
||||||
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
import net.minecraft.client.renderer.block.model.ItemTransform;
|
||||||
|
import net.minecraft.client.renderer.item.ItemModel;
|
||||||
|
import net.minecraft.client.renderer.item.ItemModelResolver;
|
||||||
|
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
||||||
|
import net.minecraft.client.resources.model.ModelBaker;
|
||||||
|
import net.minecraft.client.resources.model.ResolvableModel;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.item.ItemDisplayContext;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The model for a {@link ITurtleUpgrade}.
|
||||||
|
* <p>
|
||||||
|
* Turtle upgrade models are very similar to vanilla's {@link ItemModel}. Each upgrade's model is defined in JSON, and
|
||||||
|
* loaded from resource packs with other assets.
|
||||||
|
* <p>
|
||||||
|
* In most cases, upgrades can use one of the existing implementations of {@link TurtleUpgradeModel} (e.g.
|
||||||
|
* {@link BasicUpgradeModel} or {@link ItemUpgradeModel}), and do not need to subclass it. However, in the cases where
|
||||||
|
* a custom model is required, one should use
|
||||||
|
* {@code dan200.computercraft.api.client.FabricComputerCraftAPIClient#registerTurtleUpgradeModel} to register a
|
||||||
|
* model on Fabric and {@code dan200.computercraft.api.client.turtle.RegisterTurtleModelEvent} to register one
|
||||||
|
* on Forge.
|
||||||
|
* <p>
|
||||||
|
* See {@link ITurtleUpgrade} for a full example of registering turtle upgrades and their models.
|
||||||
|
*
|
||||||
|
* @see RegisterTurtleUpgradeModel For multi-loader registration support.
|
||||||
|
* @see ItemUpgradeModel A {@code TurtleUpgradeModel} which uses the upgrade's item.
|
||||||
|
* @see BasicUpgradeModel A {@code TurtleUpgradeModel} which renders a simple model.
|
||||||
|
*/
|
||||||
|
public interface TurtleUpgradeModel {
|
||||||
|
/**
|
||||||
|
* The directory from which turtle upgrade models are loaded. This may be used by data generators.
|
||||||
|
*/
|
||||||
|
String SOURCE = ComputerCraftAPI.MOD_ID + "/turtle_upgrade";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The codec used to read/write {@linkplain TurtleUpgradeModel.Unbaked unbaked upgrade models}.
|
||||||
|
*/
|
||||||
|
Codec<TurtleUpgradeModel.Unbaked> CODEC = Codec.lazyInitialized(() -> ComputerCraftAPIClientService.get().getTurtleUpgradeModelCodec());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render this upgrade to an {@link ItemStackRenderState}. This is used for rendering the item form of the upgrade.
|
||||||
|
* <p>
|
||||||
|
* Like with {@link ItemModel}, implementations must be careful to call {@link ItemStackRenderState#appendModelIdentityElement}
|
||||||
|
* where appropriate.
|
||||||
|
*
|
||||||
|
* @param upgrade The upgrade being rendered.
|
||||||
|
* @param side Which side of the turtle (left or right) the upgrade is equipped on.
|
||||||
|
* @param renderer The render state to draw to.
|
||||||
|
* @param resolver The model resolver.
|
||||||
|
* @param transform The root model's transformation.
|
||||||
|
* @param seed The current model seed.
|
||||||
|
* @see ItemModel#update(ItemStackRenderState, ItemStack, ItemModelResolver, ItemDisplayContext, ClientLevel, LivingEntity, int)
|
||||||
|
*/
|
||||||
|
void renderForItem(UpgradeData<ITurtleUpgrade> upgrade, TurtleSide side, ItemStackRenderState renderer, ItemModelResolver resolver, ItemTransform transform, int seed);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render this upgrade to a {@link MultiBufferSource}. This is used for rendering the block-entity form of the
|
||||||
|
* upgrade.
|
||||||
|
*
|
||||||
|
* @param upgrade The upgrade being rendered.
|
||||||
|
* @param side Which side of the turtle (left or right) the upgrade is equipped on.
|
||||||
|
* @param turtle Access to the turtle that the upgrade resides on.
|
||||||
|
* @param transform The current pose stack.
|
||||||
|
* @param buffers The buffers to render to.
|
||||||
|
* @param light The lightmap coordinate.
|
||||||
|
* @param overlay The overlay coordinate.
|
||||||
|
*/
|
||||||
|
void renderForLevel(UpgradeData<ITurtleUpgrade> upgrade, TurtleSide side, ITurtleAccess turtle, PoseStack transform, MultiBufferSource buffers, int light, int overlay);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An unbaked turtle model. Much like other unbaked models (e.g. {@link ItemModel.Unbaked}), this should resolve
|
||||||
|
* any dependencies and returned the fully-resolved model.
|
||||||
|
*/
|
||||||
|
interface Unbaked extends ResolvableModel {
|
||||||
|
/**
|
||||||
|
* The {@link MapCodec} used to read/write this unbaked model.
|
||||||
|
*
|
||||||
|
* @return The codec used to read/write this model.
|
||||||
|
* @see ItemModel.Unbaked#type()
|
||||||
|
*/
|
||||||
|
MapCodec<? extends Unbaked> type();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bake this turtle model.
|
||||||
|
*
|
||||||
|
* @param baker The current model baker
|
||||||
|
* @return The baked upgrade model.
|
||||||
|
* @see ItemModel.Unbaked#bake(ItemModel.BakingContext)
|
||||||
|
*/
|
||||||
|
TurtleUpgradeModel bake(ModelBaker baker);
|
||||||
|
}
|
||||||
|
}
|
@@ -1,120 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package dan200.computercraft.api.client.turtle;
|
|
||||||
|
|
||||||
import dan200.computercraft.api.client.ComputerCraftAPIClient;
|
|
||||||
import dan200.computercraft.api.client.TransformedModel;
|
|
||||||
import dan200.computercraft.api.turtle.ITurtleAccess;
|
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
|
||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
|
||||||
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
|
|
||||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
|
||||||
import net.minecraft.client.resources.model.UnbakedModel;
|
|
||||||
import net.minecraft.nbt.CompoundTag;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides models for a {@link ITurtleUpgrade}.
|
|
||||||
*
|
|
||||||
* @param <T> The type of turtle upgrade this modeller applies to.
|
|
||||||
* @see ComputerCraftAPIClient#registerTurtleUpgradeModeller(TurtleUpgradeSerialiser, TurtleUpgradeModeller) To register a modeller.
|
|
||||||
*/
|
|
||||||
public interface TurtleUpgradeModeller<T extends ITurtleUpgrade> {
|
|
||||||
/**
|
|
||||||
* Obtain the model to be used when rendering a turtle peripheral.
|
|
||||||
* <p>
|
|
||||||
* When the current turtle is {@literal null}, this function should be constant for a given upgrade and side.
|
|
||||||
*
|
|
||||||
* @param upgrade The upgrade that you're getting the model for.
|
|
||||||
* @param turtle Access to the turtle that the upgrade resides on. This will be null when getting item models, unless
|
|
||||||
* {@link #getModel(ITurtleUpgrade, CompoundTag, TurtleSide)} is overriden.
|
|
||||||
* @param side Which side of the turtle (left or right) the upgrade resides on.
|
|
||||||
* @return The model that you wish to be used to render your upgrade.
|
|
||||||
*/
|
|
||||||
TransformedModel getModel(T upgrade, @Nullable ITurtleAccess turtle, TurtleSide side);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain the model to be used when rendering a turtle peripheral.
|
|
||||||
* <p>
|
|
||||||
* This is used when rendering the turtle's item model, and so no {@link ITurtleAccess} is available.
|
|
||||||
*
|
|
||||||
* @param upgrade The upgrade that you're getting the model for.
|
|
||||||
* @param data Upgrade data instance for current turtle side.
|
|
||||||
* @param side Which side of the turtle (left or right) the upgrade resides on.
|
|
||||||
* @return The model that you wish to be used to render your upgrade.
|
|
||||||
*/
|
|
||||||
default TransformedModel getModel(T upgrade, CompoundTag data, TurtleSide side) {
|
|
||||||
return getModel(upgrade, (ITurtleAccess) null, side);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a list of models that this turtle modeller depends on.
|
|
||||||
* <p>
|
|
||||||
* Models included in this list will be loaded and baked alongside item and block models, and so may be referenced
|
|
||||||
* by {@link TransformedModel#of(ResourceLocation)}. You do not need to override this method if you will load models
|
|
||||||
* by other means.
|
|
||||||
*
|
|
||||||
* @return A list of models that this modeller depends on.
|
|
||||||
* @see UnbakedModel#getDependencies()
|
|
||||||
*/
|
|
||||||
default Collection<ResourceLocation> getDependencies() {
|
|
||||||
return List.of();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A basic {@link TurtleUpgradeModeller} which renders using the upgrade's {@linkplain ITurtleUpgrade#getUpgradeItem(CompoundTag)}
|
|
||||||
* upgrade item}.
|
|
||||||
* <p>
|
|
||||||
* This uses appropriate transformations for "flat" items, namely those extending the {@literal minecraft:item/generated}
|
|
||||||
* model type. It will not appear correct for 3D models with additional depth, such as blocks.
|
|
||||||
*
|
|
||||||
* @param <T> The type of the turtle upgrade.
|
|
||||||
* @return The constructed modeller.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
static <T extends ITurtleUpgrade> TurtleUpgradeModeller<T> flatItem() {
|
|
||||||
return (TurtleUpgradeModeller<T>) TurtleUpgradeModellers.UPGRADE_ITEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a {@link TurtleUpgradeModeller} which has a single model for the left and right side.
|
|
||||||
*
|
|
||||||
* @param left The model to use on the left.
|
|
||||||
* @param right The model to use on the right.
|
|
||||||
* @param <T> The type of the turtle upgrade.
|
|
||||||
* @return The constructed modeller.
|
|
||||||
*/
|
|
||||||
static <T extends ITurtleUpgrade> TurtleUpgradeModeller<T> sided(ModelResourceLocation left, ModelResourceLocation right) {
|
|
||||||
// TODO(1.21.0): Remove this.
|
|
||||||
return sided((ResourceLocation) left, right);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a {@link TurtleUpgradeModeller} which has a single model for the left and right side.
|
|
||||||
*
|
|
||||||
* @param left The model to use on the left.
|
|
||||||
* @param right The model to use on the right.
|
|
||||||
* @param <T> The type of the turtle upgrade.
|
|
||||||
* @return The constructed modeller.
|
|
||||||
*/
|
|
||||||
static <T extends ITurtleUpgrade> TurtleUpgradeModeller<T> sided(ResourceLocation left, ResourceLocation right) {
|
|
||||||
return new TurtleUpgradeModeller<>() {
|
|
||||||
@Override
|
|
||||||
public TransformedModel getModel(T upgrade, @Nullable ITurtleAccess turtle, TurtleSide side) {
|
|
||||||
return TransformedModel.of(side == TurtleSide.LEFT ? left : right);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<ResourceLocation> getDependencies() {
|
|
||||||
return List.of(left, right);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,55 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package dan200.computercraft.api.client.turtle;
|
|
||||||
|
|
||||||
import com.mojang.math.Transformation;
|
|
||||||
import dan200.computercraft.api.client.TransformedModel;
|
|
||||||
import dan200.computercraft.api.turtle.ITurtleAccess;
|
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
|
||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
|
||||||
import dan200.computercraft.impl.client.ClientPlatformHelper;
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.nbt.CompoundTag;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
|
||||||
import org.joml.Matrix4f;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
final class TurtleUpgradeModellers {
|
|
||||||
private static final Transformation leftTransform = getMatrixFor(-0.4065f);
|
|
||||||
private static final Transformation rightTransform = getMatrixFor(0.4065f);
|
|
||||||
|
|
||||||
private static Transformation getMatrixFor(float offset) {
|
|
||||||
var matrix = new Matrix4f();
|
|
||||||
matrix.set(new float[]{
|
|
||||||
0.0f, 0.0f, -1.0f, 1.0f + offset,
|
|
||||||
1.0f, 0.0f, 0.0f, 0.0f,
|
|
||||||
0.0f, -1.0f, 0.0f, 1.0f,
|
|
||||||
0.0f, 0.0f, 0.0f, 1.0f,
|
|
||||||
});
|
|
||||||
matrix.transpose();
|
|
||||||
return new Transformation(matrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
static final TurtleUpgradeModeller<ITurtleUpgrade> UPGRADE_ITEM = new UpgradeItemModeller();
|
|
||||||
|
|
||||||
private static final class UpgradeItemModeller implements TurtleUpgradeModeller<ITurtleUpgrade> {
|
|
||||||
@Override
|
|
||||||
public TransformedModel getModel(ITurtleUpgrade upgrade, @Nullable ITurtleAccess turtle, TurtleSide side) {
|
|
||||||
return getModel(turtle == null ? upgrade.getCraftingItem() : upgrade.getUpgradeItem(turtle.getUpgradeNBTData(side)), side);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TransformedModel getModel(ITurtleUpgrade upgrade, CompoundTag data, TurtleSide side) {
|
|
||||||
return getModel(upgrade.getUpgradeItem(data), side);
|
|
||||||
}
|
|
||||||
|
|
||||||
private TransformedModel getModel(ItemStack stack, TurtleSide side) {
|
|
||||||
var model = Minecraft.getInstance().getItemRenderer().getItemModelShaper().getItemModel(stack);
|
|
||||||
if (stack.hasFoil()) model = ClientPlatformHelper.get().createdFoiledModel(model);
|
|
||||||
return new TransformedModel(model, side == TurtleSide.LEFT ? leftTransform : rightTransform);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,55 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package dan200.computercraft.impl.client;
|
|
||||||
|
|
||||||
import dan200.computercraft.impl.Services;
|
|
||||||
import net.minecraft.client.renderer.RenderType;
|
|
||||||
import net.minecraft.client.resources.model.BakedModel;
|
|
||||||
import net.minecraft.client.resources.model.ModelManager;
|
|
||||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
@ApiStatus.Internal
|
|
||||||
public interface ClientPlatformHelper {
|
|
||||||
/**
|
|
||||||
* Equivalent to {@link ModelManager#getModel(ModelResourceLocation)} but for arbitrary {@link ResourceLocation}s.
|
|
||||||
*
|
|
||||||
* @param manager The model manager.
|
|
||||||
* @param location The model location.
|
|
||||||
* @return The baked model.
|
|
||||||
*/
|
|
||||||
BakedModel getModel(ModelManager manager, ResourceLocation location);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrap this model in a version which renders a foil/enchantment glint.
|
|
||||||
*
|
|
||||||
* @param model The model to wrap.
|
|
||||||
* @return The wrapped model.
|
|
||||||
* @see RenderType#glint()
|
|
||||||
*/
|
|
||||||
BakedModel createdFoiledModel(BakedModel model);
|
|
||||||
|
|
||||||
static ClientPlatformHelper get() {
|
|
||||||
var instance = Instance.INSTANCE;
|
|
||||||
return instance == null ? Services.raise(ClientPlatformHelper.class, Instance.ERROR) : instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
final class Instance {
|
|
||||||
static final @Nullable ClientPlatformHelper INSTANCE;
|
|
||||||
static final @Nullable Throwable ERROR;
|
|
||||||
|
|
||||||
static {
|
|
||||||
var helper = Services.tryLoad(ClientPlatformHelper.class);
|
|
||||||
INSTANCE = helper.instance();
|
|
||||||
ERROR = helper.error();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Instance() {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,20 +1,17 @@
|
|||||||
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
|
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
package dan200.computercraft.impl.client;
|
package dan200.computercraft.impl.client;
|
||||||
|
|
||||||
import dan200.computercraft.api.client.ComputerCraftAPIClient;
|
import com.mojang.serialization.Codec;
|
||||||
import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
|
import dan200.computercraft.api.client.turtle.TurtleUpgradeModel;
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
|
||||||
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
|
|
||||||
import dan200.computercraft.impl.Services;
|
import dan200.computercraft.impl.Services;
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Backing interface for {@link ComputerCraftAPIClient}
|
* Bridge between implementation
|
||||||
* <p>
|
* <p>
|
||||||
* Do <strong>NOT</strong> directly reference this class. It exists for internal use by the API.
|
* Do <strong>NOT</strong> directly reference this class. It exists for internal use by the API.
|
||||||
*/
|
*/
|
||||||
@@ -25,7 +22,7 @@ public interface ComputerCraftAPIClientService {
|
|||||||
return instance == null ? Services.raise(ComputerCraftAPIClientService.class, Instance.ERROR) : instance;
|
return instance == null ? Services.raise(ComputerCraftAPIClientService.class, Instance.ERROR) : instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
<T extends ITurtleUpgrade> void registerTurtleUpgradeModeller(TurtleUpgradeSerialiser<T> serialiser, TurtleUpgradeModeller<T> modeller);
|
Codec<TurtleUpgradeModel.Unbaked> getTurtleUpgradeModelCodec();
|
||||||
|
|
||||||
final class Instance {
|
final class Instance {
|
||||||
static final @Nullable ComputerCraftAPIClientService INSTANCE;
|
static final @Nullable ComputerCraftAPIClientService INSTANCE;
|
||||||
|
@@ -4,13 +4,13 @@
|
|||||||
|
|
||||||
package dan200.computercraft.api;
|
package dan200.computercraft.api;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.component.ComputerComponent;
|
||||||
import dan200.computercraft.api.filesystem.Mount;
|
import dan200.computercraft.api.filesystem.Mount;
|
||||||
import dan200.computercraft.api.filesystem.WritableMount;
|
import dan200.computercraft.api.filesystem.WritableMount;
|
||||||
import dan200.computercraft.api.lua.GenericSource;
|
import dan200.computercraft.api.lua.GenericSource;
|
||||||
|
import dan200.computercraft.api.lua.IComputerSystem;
|
||||||
import dan200.computercraft.api.lua.ILuaAPI;
|
import dan200.computercraft.api.lua.ILuaAPI;
|
||||||
import dan200.computercraft.api.lua.ILuaAPIFactory;
|
import dan200.computercraft.api.lua.ILuaAPIFactory;
|
||||||
import dan200.computercraft.api.media.IMedia;
|
|
||||||
import dan200.computercraft.api.media.MediaProvider;
|
|
||||||
import dan200.computercraft.api.network.PacketNetwork;
|
import dan200.computercraft.api.network.PacketNetwork;
|
||||||
import dan200.computercraft.api.network.wired.WiredElement;
|
import dan200.computercraft.api.network.wired.WiredElement;
|
||||||
import dan200.computercraft.api.network.wired.WiredNode;
|
import dan200.computercraft.api.network.wired.WiredNode;
|
||||||
@@ -24,8 +24,7 @@ import net.minecraft.core.Direction;
|
|||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The static entry point to the ComputerCraft API.
|
* The static entry point to the ComputerCraft API.
|
||||||
@@ -141,16 +140,6 @@ public final class ComputerCraftAPI {
|
|||||||
return getInstance().getBundledRedstoneOutput(world, pos, side);
|
return getInstance().getBundledRedstoneOutput(world, pos, side);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers a media provider to provide {@link IMedia} implementations for Items.
|
|
||||||
*
|
|
||||||
* @param provider The media provider to register.
|
|
||||||
* @see MediaProvider
|
|
||||||
*/
|
|
||||||
public static void registerMediaProvider(MediaProvider provider) {
|
|
||||||
getInstance().registerMediaProvider(provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt to get the game-wide wireless network.
|
* Attempt to get the game-wide wireless network.
|
||||||
*
|
*
|
||||||
@@ -165,7 +154,13 @@ public final class ComputerCraftAPI {
|
|||||||
* Register a custom {@link ILuaAPI}, which may be added onto all computers without requiring a peripheral.
|
* Register a custom {@link ILuaAPI}, which may be added onto all computers without requiring a peripheral.
|
||||||
* <p>
|
* <p>
|
||||||
* Before implementing this interface, consider alternative methods of providing methods. It is generally preferred
|
* Before implementing this interface, consider alternative methods of providing methods. It is generally preferred
|
||||||
* to use peripherals to provide functionality to users.
|
* to use peripherals to provide functionality to users. If an API is <em>required</em>, you may want to consider
|
||||||
|
* using {@link ILuaAPI#getModuleName()} to expose this library as a module instead of as a global.
|
||||||
|
* <p>
|
||||||
|
* This may be used with {@link IComputerSystem#getComponent(ComputerComponent)} to only attach APIs to specific
|
||||||
|
* computers. For example, one can add a new API just to turtles with the following code:
|
||||||
|
*
|
||||||
|
* {@snippet class=com.example.examplemod.ExampleAPI region=register}
|
||||||
*
|
*
|
||||||
* @param factory The factory for your API subclass.
|
* @param factory The factory for your API subclass.
|
||||||
* @see ILuaAPIFactory
|
* @see ILuaAPIFactory
|
||||||
|
@@ -6,10 +6,12 @@ package dan200.computercraft.api;
|
|||||||
|
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.tags.ItemTags;
|
||||||
import net.minecraft.tags.TagKey;
|
import net.minecraft.tags.TagKey;
|
||||||
import net.minecraft.world.InteractionHand;
|
import net.minecraft.world.InteractionHand;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.context.UseOnContext;
|
import net.minecraft.world.item.context.UseOnContext;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
@@ -26,6 +28,20 @@ public class ComputerCraftTags {
|
|||||||
public static final TagKey<Item> WIRED_MODEM = make("wired_modem");
|
public static final TagKey<Item> WIRED_MODEM = make("wired_modem");
|
||||||
public static final TagKey<Item> MONITOR = make("monitor");
|
public static final TagKey<Item> MONITOR = make("monitor");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Floppy disks. Both the read/write version, and treasure disks.
|
||||||
|
*
|
||||||
|
* @since 1.116.0
|
||||||
|
*/
|
||||||
|
public static final TagKey<Item> DISKS = make("disks");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All pocket computers.
|
||||||
|
*
|
||||||
|
* @since 1.116.0
|
||||||
|
*/
|
||||||
|
public static final TagKey<Item> POCKET_COMPUTERS = make("pocket_computers");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Items which can be {@linkplain Item#use(Level, Player, InteractionHand) used} when calling
|
* Items which can be {@linkplain Item#use(Level, Player, InteractionHand) used} when calling
|
||||||
* {@code turtle.place()}.
|
* {@code turtle.place()}.
|
||||||
@@ -35,8 +51,16 @@ public class ComputerCraftTags {
|
|||||||
*/
|
*/
|
||||||
public static final TagKey<Item> TURTLE_CAN_PLACE = make("turtle_can_place");
|
public static final TagKey<Item> TURTLE_CAN_PLACE = make("turtle_can_place");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Items which can be dyed.
|
||||||
|
* <p>
|
||||||
|
* This is similar to {@link ItemTags#DYEABLE}, but allows cleaning the item with a sponge, rather than in a
|
||||||
|
* cauldron.
|
||||||
|
*/
|
||||||
|
public static final TagKey<Item> DYEABLE = make("dyeable");
|
||||||
|
|
||||||
private static TagKey<Item> make(String name) {
|
private static TagKey<Item> make(String name) {
|
||||||
return TagKey.create(Registries.ITEM, new ResourceLocation(ComputerCraftAPI.MOD_ID, name));
|
return TagKey.create(Registries.ITEM, ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,6 +70,14 @@ public class ComputerCraftTags {
|
|||||||
public static final TagKey<Block> WIRED_MODEM = make("wired_modem");
|
public static final TagKey<Block> WIRED_MODEM = make("wired_modem");
|
||||||
public static final TagKey<Block> MONITOR = make("monitor");
|
public static final TagKey<Block> MONITOR = make("monitor");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blocks which should be ignored by a {@code peripheral_hub} peripheral.
|
||||||
|
* <p>
|
||||||
|
* This should include blocks which themselves expose a peripheral hub (such as {@linkplain #WIRED_MODEM wired
|
||||||
|
* modems}).
|
||||||
|
*/
|
||||||
|
public static final TagKey<Block> PERIPHERAL_HUB_IGNORE = make("peripheral_hub_ignore");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blocks which can be broken by any turtle tool.
|
* Blocks which can be broken by any turtle tool.
|
||||||
*/
|
*/
|
||||||
@@ -67,13 +99,13 @@ public class ComputerCraftTags {
|
|||||||
public static final TagKey<Block> TURTLE_HOE_BREAKABLE = make("turtle_hoe_harvestable");
|
public static final TagKey<Block> TURTLE_HOE_BREAKABLE = make("turtle_hoe_harvestable");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Block which can be {@linkplain BlockState#use(Level, Player, InteractionHand, BlockHitResult) used} when
|
* Block which can be {@linkplain BlockState#useItemOn(ItemStack, Level, Player, InteractionHand, BlockHitResult) used}
|
||||||
* calling {@code turtle.place()}.
|
* when calling {@code turtle.place()}.
|
||||||
*/
|
*/
|
||||||
public static final TagKey<Block> TURTLE_CAN_USE = make("turtle_can_use");
|
public static final TagKey<Block> TURTLE_CAN_USE = make("turtle_can_use");
|
||||||
|
|
||||||
private static TagKey<Block> make(String name) {
|
private static TagKey<Block> make(String name) {
|
||||||
return TagKey.create(Registries.BLOCK, new ResourceLocation(ComputerCraftAPI.MOD_ID, name));
|
return TagKey.create(Registries.BLOCK, ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,24 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.api.component;
|
||||||
|
|
||||||
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A computer which has permission to perform administrative/op commands, such as the command computer.
|
||||||
|
*/
|
||||||
|
@ApiStatus.NonExtendable
|
||||||
|
public interface AdminComputer {
|
||||||
|
/**
|
||||||
|
* The permission level that this computer can operate at.
|
||||||
|
*
|
||||||
|
* @return The permission level for this computer.
|
||||||
|
* @see CommandSourceStack#hasPermission(int)
|
||||||
|
*/
|
||||||
|
default int permissionLevel() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,48 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.api.component;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.lua.IComputerSystem;
|
||||||
|
import dan200.computercraft.api.lua.ILuaAPIFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A component attached to a computer.
|
||||||
|
* <p>
|
||||||
|
* Components provide a mechanism to attach additional data to a computer, that can then be queried with
|
||||||
|
* {@link IComputerSystem#getComponent(ComputerComponent)}.
|
||||||
|
* <p>
|
||||||
|
* This is largely designed for {@linkplain ILuaAPIFactory custom APIs}, allowing APIs to read additional properties
|
||||||
|
* of the computer, such as its position.
|
||||||
|
*
|
||||||
|
* @param <T> The type of this component.
|
||||||
|
* @see ComputerComponents The built-in components.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("UnusedTypeParameter")
|
||||||
|
public final class ComputerComponent<T> {
|
||||||
|
private final String id;
|
||||||
|
|
||||||
|
private ComputerComponent(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new computer component.
|
||||||
|
* <p>
|
||||||
|
* Mods typically will not need to create their own components.
|
||||||
|
*
|
||||||
|
* @param namespace The namespace of this component. This should be the mod id.
|
||||||
|
* @param id The unique id of this component.
|
||||||
|
* @param <T> The component
|
||||||
|
* @return The newly created component.
|
||||||
|
*/
|
||||||
|
public static <T> ComputerComponent<T> create(String namespace, String id) {
|
||||||
|
return new ComputerComponent<>(namespace + ":" + id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ComputerComponent(" + id + ")";
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,30 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.api.component;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
|
import dan200.computercraft.api.pocket.IPocketAccess;
|
||||||
|
import dan200.computercraft.api.pocket.PocketComputer;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link ComputerComponent}s provided by ComputerCraft.
|
||||||
|
*/
|
||||||
|
public class ComputerComponents {
|
||||||
|
/**
|
||||||
|
* The {@link ITurtleAccess} associated with a turtle.
|
||||||
|
*/
|
||||||
|
public static final ComputerComponent<ITurtleAccess> TURTLE = ComputerComponent.create(ComputerCraftAPI.MOD_ID, "turtle");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link IPocketAccess} associated with a pocket computer.
|
||||||
|
*/
|
||||||
|
public static final ComputerComponent<PocketComputer> POCKET = ComputerComponent.create(ComputerCraftAPI.MOD_ID, "pocket");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component is only present on "command computers", and other computers with admin capabilities.
|
||||||
|
*/
|
||||||
|
public static final ComputerComponent<AdminComputer> ADMIN_COMPUTER = ComputerComponent.create(ComputerCraftAPI.MOD_ID, "admin_computer");
|
||||||
|
}
|
@@ -6,14 +6,14 @@ package dan200.computercraft.api.detail;
|
|||||||
|
|
||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An item detail provider for {@link ItemStack}'s whose {@link Item} has a specific type.
|
* An item detail provider for {@link ItemStack}s whose {@link Item} has a specific type.
|
||||||
*
|
*
|
||||||
* @param <T> The type the stack's item must have.
|
* @param <T> The type the stack's item must have.
|
||||||
*/
|
*/
|
||||||
@@ -22,7 +22,7 @@ public abstract class BasicItemDetailProvider<T> implements DetailProvider<ItemS
|
|||||||
private final @Nullable String namespace;
|
private final @Nullable String namespace;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new item detail provider. Meta will be inserted into a new sub-map named as per {@code namespace}.
|
* Create a new item detail provider. Details will be inserted into a new sub-map named as per {@code namespace}.
|
||||||
*
|
*
|
||||||
* @param itemType The type the stack's item must have.
|
* @param itemType The type the stack's item must have.
|
||||||
* @param namespace The namespace to use for this provider.
|
* @param namespace The namespace to use for this provider.
|
||||||
@@ -34,7 +34,7 @@ public abstract class BasicItemDetailProvider<T> implements DetailProvider<ItemS
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new item detail provider. Meta will be inserted directly into the results.
|
* Create a new item detail provider. Details will be inserted directly into the results.
|
||||||
*
|
*
|
||||||
* @param itemType The type the stack's item must have.
|
* @param itemType The type the stack's item must have.
|
||||||
*/
|
*/
|
||||||
@@ -53,21 +53,18 @@ public abstract class BasicItemDetailProvider<T> implements DetailProvider<ItemS
|
|||||||
* @param stack The item stack to provide details for.
|
* @param stack The item stack to provide details for.
|
||||||
* @param item The item to provide details for.
|
* @param item The item to provide details for.
|
||||||
*/
|
*/
|
||||||
public abstract void provideDetails(
|
public abstract void provideDetails(Map<? super String, Object> data, ItemStack stack, T item);
|
||||||
Map<? super String, Object> data, ItemStack stack, T item
|
|
||||||
);
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void provideDetails(Map<? super String, Object> data, ItemStack stack) {
|
public final void provideDetails(Map<? super String, Object> data, ItemStack stack) {
|
||||||
var item = stack.getItem();
|
var item = stack.getItem();
|
||||||
if (!itemType.isInstance(item)) return;
|
if (!itemType.isInstance(item)) return;
|
||||||
|
|
||||||
// If `namespace` is specified, insert into a new data map instead of the existing one.
|
if (namespace == null) {
|
||||||
Map<? super String, Object> child = namespace == null ? data : new HashMap<>();
|
provideDetails(data, stack, itemType.cast(item));
|
||||||
|
} else {
|
||||||
provideDetails(child, stack, itemType.cast(item));
|
Map<? super String, Object> child = new HashMap<>();
|
||||||
|
provideDetails(child, stack, itemType.cast(item));
|
||||||
if (namespace != null) {
|
|
||||||
data.put(namespace, child);
|
data.put(namespace, child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,8 +8,7 @@ import net.minecraft.core.BlockPos;
|
|||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A reference to a block in the world, used by block detail providers.
|
* A reference to a block in the world, used by block detail providers.
|
||||||
|
@@ -0,0 +1,72 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.api.detail;
|
||||||
|
|
||||||
|
import net.minecraft.core.component.DataComponentHolder;
|
||||||
|
import net.minecraft.core.component.DataComponentType;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An item detail provider for a specific {@linkplain DataComponentType data component} on {@link ItemStack}s or
|
||||||
|
* other {@link DataComponentHolder}.
|
||||||
|
*
|
||||||
|
* @param <T> The type of the component's contents.
|
||||||
|
*/
|
||||||
|
public abstract class ComponentDetailProvider<T> implements DetailProvider<DataComponentHolder> {
|
||||||
|
private final DataComponentType<T> component;
|
||||||
|
private final @Nullable String namespace;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new component detail provider. Details will be inserted into a new sub-map named as per {@code namespace}.
|
||||||
|
*
|
||||||
|
* @param component The data component to provide details for.
|
||||||
|
* @param namespace The namespace to use for this provider.
|
||||||
|
*/
|
||||||
|
public ComponentDetailProvider(@Nullable String namespace, DataComponentType<T> component) {
|
||||||
|
Objects.requireNonNull(component);
|
||||||
|
this.component = component;
|
||||||
|
this.namespace = namespace;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new component detail provider. Details will be inserted directly into the results.
|
||||||
|
*
|
||||||
|
* @param component The data component to provide details for.
|
||||||
|
*/
|
||||||
|
public ComponentDetailProvider(DataComponentType<T> component) {
|
||||||
|
this(null, component);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide additional details for the given data component. This method is called by {@code turtle.getItemDetail()}.
|
||||||
|
* New properties should be added to the given {@link Map}, {@code data}.
|
||||||
|
* <p>
|
||||||
|
* This method is always called on the server thread, so it is safe to interact with the world here, but you should
|
||||||
|
* take care to avoid long blocking operations as this will stall the server and other computers.
|
||||||
|
*
|
||||||
|
* @param data The full details to be returned for this item stack. New properties should be added to this map.
|
||||||
|
* @param component The component to provide details for.
|
||||||
|
*/
|
||||||
|
public abstract void provideComponentDetails(Map<? super String, Object> data, T component);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void provideDetails(Map<? super String, Object> data, DataComponentHolder holder) {
|
||||||
|
var value = holder.get(component);
|
||||||
|
if (value == null) return;
|
||||||
|
|
||||||
|
if (namespace == null) {
|
||||||
|
provideComponentDetails(data, value);
|
||||||
|
} else {
|
||||||
|
Map<? super String, Object> child = new HashMap<>();
|
||||||
|
provideComponentDetails(child, value);
|
||||||
|
data.put(namespace, child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -14,6 +14,7 @@ import java.util.Map;
|
|||||||
*
|
*
|
||||||
* @param <T> The type of object that this provider can provide details for.
|
* @param <T> The type of object that this provider can provide details for.
|
||||||
* @see DetailRegistry
|
* @see DetailRegistry
|
||||||
|
* @see dan200.computercraft.api.detail An overview of the detail system.
|
||||||
*/
|
*/
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface DetailProvider<T> {
|
public interface DetailProvider<T> {
|
||||||
|
@@ -17,6 +17,7 @@ import java.util.Map;
|
|||||||
* also in this package.
|
* also in this package.
|
||||||
*
|
*
|
||||||
* @param <T> The type of object that this registry provides details for.
|
* @param <T> The type of object that this registry provides details for.
|
||||||
|
* @see dan200.computercraft.api.detail An overview of the detail system.
|
||||||
*/
|
*/
|
||||||
@ApiStatus.NonExtendable
|
@ApiStatus.NonExtendable
|
||||||
public interface DetailRegistry<T> {
|
public interface DetailRegistry<T> {
|
||||||
@@ -26,7 +27,7 @@ public interface DetailRegistry<T> {
|
|||||||
* @param provider The detail provider to register.
|
* @param provider The detail provider to register.
|
||||||
* @see DetailProvider
|
* @see DetailProvider
|
||||||
*/
|
*/
|
||||||
void addProvider(DetailProvider<T> provider);
|
void addProvider(DetailProvider<? super T> provider);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute basic details about an object. This is cheaper than computing all details operation, and so is suitable
|
* Compute basic details about an object. This is cheaper than computing all details operation, and so is suitable
|
||||||
|
@@ -17,6 +17,9 @@ public class VanillaDetailRegistries {
|
|||||||
* <p>
|
* <p>
|
||||||
* This instance's {@link DetailRegistry#getBasicDetails(Object)} is thread safe (assuming the stack is immutable)
|
* This instance's {@link DetailRegistry#getBasicDetails(Object)} is thread safe (assuming the stack is immutable)
|
||||||
* and may be called from the computer thread.
|
* and may be called from the computer thread.
|
||||||
|
* <p>
|
||||||
|
* This does not have special handling for {@linkplain ItemStack#isEmpty() empty item stacks}, and so the returned
|
||||||
|
* details will be an empty stack of air. Callers should generally check for empty stacks before calling this.
|
||||||
*/
|
*/
|
||||||
public static final DetailRegistry<ItemStack> ITEM_STACK = ComputerCraftAPIService.get().getItemStackDetailRegistry();
|
public static final DetailRegistry<ItemStack> ITEM_STACK = ComputerCraftAPIService.get().getItemStackDetailRegistry();
|
||||||
|
|
||||||
|
@@ -0,0 +1,48 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The detail system provides a standard way for mods to return descriptions of common game objects, such as blocks or
|
||||||
|
* items, as well as registering additional detail to be included in those descriptions.
|
||||||
|
* <p>
|
||||||
|
* For instance, the built-in {@code turtle.getItemDetail()} method uses
|
||||||
|
* {@linkplain dan200.computercraft.api.detail.VanillaDetailRegistries#ITEM_STACK in order to provide information about}
|
||||||
|
* the selected item:
|
||||||
|
*
|
||||||
|
* <pre class="language language-lua">{@code
|
||||||
|
* local item = turtle.getItemDetail(nil, true)
|
||||||
|
* --[[
|
||||||
|
* item = {
|
||||||
|
* name = "minecraft:wheat",
|
||||||
|
* displayName = "Wheat",
|
||||||
|
* count = 1,
|
||||||
|
* maxCount = 64,
|
||||||
|
* tags = {},
|
||||||
|
* }
|
||||||
|
* ]]
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* <h2>Built-in detail providers</h2>
|
||||||
|
* While you can define your own detail providers (perhaps for types from your own mod), CC comes with several built-in
|
||||||
|
* detail registries for vanilla and mod-loader objects:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link dan200.computercraft.api.detail.VanillaDetailRegistries}, for vanilla objects</li>
|
||||||
|
* <li>{@code dan200.computercraft.api.detail.ForgeDetailRegistries} for Forge-specific objects</li>
|
||||||
|
* <li>{@code dan200.computercraft.api.detail.FabricDetailRegistries} for Fabric-specific objects</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <h2>Example: Returning details from methods</h2>
|
||||||
|
* Here we define a {@code getHeldItem()} method for pocket computers which finds the currently held item of the player
|
||||||
|
* and returns it to the user using {@link dan200.computercraft.api.detail.VanillaDetailRegistries#ITEM_STACK} and
|
||||||
|
* {@link dan200.computercraft.api.detail.DetailRegistry#getDetails(java.lang.Object)}.
|
||||||
|
*
|
||||||
|
* {@snippet class=com.example.examplemod.ExamplePocketPeripheral region=details}
|
||||||
|
*
|
||||||
|
* <h2>Example: Registering custom detail registries</h2>
|
||||||
|
* Here we define a new detail provider for items that includes the nutrition and saturation values in the returned object.
|
||||||
|
*
|
||||||
|
* {@snippet class=com.example.examplemod.ExampleMod region=details}
|
||||||
|
*/
|
||||||
|
package dan200.computercraft.api.detail;
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user