mirror of
https://github.com/GTNewHorizons/Angelica.git
synced 2026-11-15 17:55:08 +00:00
Compare commits
585
Commits
0.0.2
...
2.0.0-alpha12
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36d98fcb22 | ||
|
|
44c5b9617a | ||
|
|
f3f1677db8 | ||
|
|
d396b611ad | ||
|
|
08f4c0f9db | ||
|
|
50b0d22dc2 | ||
|
|
7fed54264e | ||
|
|
be87401be6 | ||
|
|
94254006df | ||
|
|
f79774df65 | ||
|
|
2f2fc22df3 | ||
|
|
26300bbb1b | ||
|
|
88e4d2fd6c | ||
|
|
bb52476d27 | ||
|
|
6d60477b93 | ||
|
|
362724610c | ||
|
|
ea4a3cdf0b | ||
|
|
65959268d0 | ||
|
|
58d820cd7e | ||
|
|
685d68bd9c | ||
|
|
ad63d2d62c | ||
|
|
d2730ccca8 | ||
|
|
e9257b8739 | ||
|
|
3984225faa | ||
|
|
52db6b56d6 | ||
|
|
34bfe513f1 | ||
|
|
42d7ed58aa | ||
|
|
9a4f0f9b99 | ||
|
|
be90a01725 | ||
|
|
e5e8250d44 | ||
|
|
062a03ffc2 | ||
|
|
9f5afaaec3 | ||
|
|
b05f17a477 | ||
|
|
57caf08212 | ||
|
|
085ec79c21 | ||
|
|
38641268ae | ||
|
|
fe8e723638 | ||
|
|
16debfd518 | ||
|
|
8cfc3e1f4a | ||
|
|
2c808fae43 | ||
|
|
1649c3c0c6 | ||
|
|
b84286ba3b | ||
|
|
ee6c79802a | ||
|
|
d3366ad31a | ||
|
|
92b6dcc010 | ||
|
|
89132f3ef9 | ||
|
|
f0d45b0d62 | ||
|
|
173d986a5b | ||
|
|
473a690054 | ||
|
|
2515b3520f | ||
|
|
a32f9ca244 | ||
|
|
941fc88484 | ||
|
|
4106dd3865 | ||
|
|
61f6aa19a8 | ||
|
|
77875f7f91 | ||
|
|
241c32def1 | ||
|
|
a8107f97e8 | ||
|
|
8bec433699 | ||
|
|
2d39fb2397 | ||
|
|
cfd8eb1411 | ||
|
|
59c270a5b9 | ||
|
|
87ac03281c | ||
|
|
36b82fa2ce | ||
|
|
2fc2e2e38d | ||
|
|
33de1de9c4 | ||
|
|
55811b9d7b | ||
|
|
a10d92f52e | ||
|
|
7d2fe12ce9 | ||
|
|
006ded801e | ||
|
|
03afd6939e | ||
|
|
adc5421e00 | ||
|
|
dfe60e4b3e | ||
|
|
72c6cdfa60 | ||
|
|
c5daea86f8 | ||
|
|
f8958ee990 | ||
|
|
073260060b | ||
|
|
771fee124d | ||
|
|
680285bf54 | ||
|
|
df8784536e | ||
|
|
c8991d810c | ||
|
|
e3b02642ac | ||
|
|
2759dd6689 | ||
|
|
996dbaef2c | ||
|
|
72ca675c93 | ||
|
|
e6e230e270 | ||
|
|
43d7282ba5 | ||
|
|
4b2d57a32d | ||
|
|
06bf71126f | ||
|
|
4c0f2f2685 | ||
|
|
78334717e7 | ||
|
|
a77765a2c9 | ||
|
|
1a9fe45ee9 | ||
|
|
21ef5905c8 | ||
|
|
5b67eaa474 | ||
|
|
c9d59c3b90 | ||
|
|
fa7ff74fec | ||
|
|
a34a3ebd39 | ||
|
|
2e7476d287 | ||
|
|
3244071012 | ||
|
|
7035dbde02 | ||
|
|
97ae04c2fa | ||
|
|
e7fa7f62d0 | ||
|
|
ea39712749 | ||
|
|
66dd3eaa94 | ||
|
|
270697cd10 | ||
|
|
2b53a851ef | ||
|
|
34b6efde7b | ||
|
|
86edb721da | ||
|
|
39c5f4bf7b | ||
|
|
5dc54bb1da | ||
|
|
7924769ab1 | ||
|
|
8afe2e2ccf | ||
|
|
e8dd60e088 | ||
|
|
9a621405ba | ||
|
|
45a677030d | ||
|
|
4d531022d2 | ||
|
|
48ba2160ad | ||
|
|
334ec81f9b | ||
|
|
86c726e50b | ||
|
|
e6d778dad3 | ||
|
|
dce5013ffb | ||
|
|
6eef63619c | ||
|
|
a8153fa0f7 | ||
|
|
49c04cf776 | ||
|
|
85b0277a66 | ||
|
|
0525b31262 | ||
|
|
fdb2053c50 | ||
|
|
31abbcce32 | ||
|
|
063b2242e8 | ||
|
|
577f905dc5 | ||
|
|
071d2d4a39 | ||
|
|
891715b113 | ||
|
|
30a35ef25e | ||
|
|
33453b3b8c | ||
|
|
62e699f6d0 | ||
|
|
f107d173b7 | ||
|
|
d0948b36f3 | ||
|
|
ae1211f280 | ||
|
|
3d76cb3073 | ||
|
|
45fb120223 | ||
|
|
d7a196eb5c | ||
|
|
4d53e2af9b | ||
|
|
cb6336a365 | ||
|
|
5095021e0e | ||
|
|
f88ecbf68d | ||
|
|
7da9b9eb1c | ||
|
|
02c394108f | ||
|
|
720aaca1b7 | ||
|
|
1e71b1c4d8 | ||
|
|
df4c423e93 | ||
|
|
78e0074e5a | ||
|
|
0350ea2cb6 | ||
|
|
bed724ba59 | ||
|
|
6fa973dbc8 | ||
|
|
c4ad460f34 | ||
|
|
2a8404c6c2 | ||
|
|
108db9031b | ||
|
|
d6d8a5dad6 | ||
|
|
ad2b73edf9 | ||
|
|
bb5526598e | ||
|
|
611bbf02c8 | ||
|
|
ca16036604 | ||
|
|
f118211257 | ||
|
|
81d03ea552 | ||
|
|
67c8628aeb | ||
|
|
f9b9873637 | ||
|
|
c66bf8658e | ||
|
|
052824017d | ||
|
|
6a5d914a43 | ||
|
|
208373deaa | ||
|
|
f22a3f612b | ||
|
|
9ff1015d19 | ||
|
|
0023fe3da2 | ||
|
|
7e2399714c | ||
|
|
9029182353 | ||
|
|
e6039691b5 | ||
|
|
5db1edba33 | ||
|
|
d450461726 | ||
|
|
95f8afc0f3 | ||
|
|
19635e20ec | ||
|
|
ead4e11376 | ||
|
|
b0ceb5306a | ||
|
|
99a81369f0 | ||
|
|
e2ee822948 | ||
|
|
9fe7e800f6 | ||
|
|
debfcdfda0 | ||
|
|
df662188f4 | ||
|
|
842916405f | ||
|
|
09afe81290 | ||
|
|
292809d8e8 | ||
|
|
47503ce254 | ||
|
|
f738adbdef | ||
|
|
70d15f2383 | ||
|
|
d66b5577f4 | ||
|
|
e293f12fb8 | ||
|
|
b69eca6749 | ||
|
|
03342f08c6 | ||
|
|
b85614f983 | ||
|
|
5afb5d8f5a | ||
|
|
c353c83cf3 | ||
|
|
78072236d2 | ||
|
|
350fdcd7e4 | ||
|
|
3d98e57178 | ||
|
|
55c1786811 | ||
|
|
356d826387 | ||
|
|
c34d8548a5 | ||
|
|
81a000af75 | ||
|
|
711c23c722 | ||
|
|
5aa1d504b0 | ||
|
|
60ab3b7900 | ||
|
|
912e0e83b8 | ||
|
|
104eda0b51 | ||
|
|
7fb8cde66d | ||
|
|
0e4421f2ce | ||
|
|
3cf3d096fd | ||
|
|
ffa1193dd2 | ||
|
|
d180023469 | ||
|
|
762275a6da | ||
|
|
0e66bcf42f | ||
|
|
979ad344a1 | ||
|
|
5f328e9b57 | ||
|
|
2dba62bf20 | ||
|
|
0fd4d457e2 | ||
|
|
b56e803622 | ||
|
|
3ab965ded7 | ||
|
|
538b38898c | ||
|
|
e43cd6f18e | ||
|
|
38285087c9 | ||
|
|
deb6c2b6e5 | ||
|
|
e11985a913 | ||
|
|
4bbf39eb4d | ||
|
|
8c90f79c17 | ||
|
|
e4e657846d | ||
|
|
2dace708b4 | ||
|
|
1df1ec3530 | ||
|
|
d96ac28043 | ||
|
|
72c13cff67 | ||
|
|
f233ba65e3 | ||
|
|
c0d636d4f7 | ||
|
|
bd5cd350c3 | ||
|
|
88936d3713 | ||
|
|
cf5bf2e2e7 | ||
|
|
cfd2388c85 | ||
|
|
fd78f63f12 | ||
|
|
6cf119dfee | ||
|
|
8c5f4d2543 | ||
|
|
9e1fa7b80f | ||
|
|
6c99872459 | ||
|
|
f0809410ee | ||
|
|
98299b69d2 | ||
|
|
fed0aa77c5 | ||
|
|
f7fb3186c8 | ||
|
|
ab243bb936 | ||
|
|
60cce7ea1d | ||
|
|
b837b0571d | ||
|
|
7abc6213f5 | ||
|
|
b46643ae8c | ||
|
|
e3d1fedd48 | ||
|
|
ebcee499eb | ||
|
|
ad26b1ad6f | ||
|
|
73338e3c3e | ||
|
|
2c89244fbe | ||
|
|
991f658819 | ||
|
|
1588c7000d | ||
|
|
260d57e308 | ||
|
|
3a1d1b03b3 | ||
|
|
66563f41c8 | ||
|
|
a52adb9190 | ||
|
|
1c6f9aa131 | ||
|
|
8c584fed05 | ||
|
|
558ea0fe12 | ||
|
|
1315d8971a | ||
|
|
e33f2ff7e3 | ||
|
|
29072ee3f8 | ||
|
|
ff8315270b | ||
|
|
54f276a460 | ||
|
|
feef745722 | ||
|
|
88cb3faf47 | ||
|
|
f477675ee9 | ||
|
|
4294059fbe | ||
|
|
e40c9f2441 | ||
|
|
52e886adcc | ||
|
|
f38fcd1d82 | ||
|
|
fbebbd4049 | ||
|
|
03a0406199 | ||
|
|
1ef691ecc8 | ||
|
|
b242a13fd6 | ||
|
|
2274bfabfd | ||
|
|
7e4292bdba | ||
|
|
f79e112700 | ||
|
|
ba46feb20b | ||
|
|
33804c67da | ||
|
|
3c9353e143 | ||
|
|
77eb3ad46a | ||
|
|
8a56ab8ca1 | ||
|
|
fe065803aa | ||
|
|
f94268c384 | ||
|
|
f7a8b0f3bf | ||
|
|
8893cf2291 | ||
|
|
adc575c5ab | ||
|
|
35a056b73b | ||
|
|
fbbb0ed4f2 | ||
|
|
bc148ba09c | ||
|
|
1db3932af0 | ||
|
|
0fd4611a97 | ||
|
|
27243991b7 | ||
|
|
956eec0366 | ||
|
|
9b06c5a210 | ||
|
|
5511759b6d | ||
|
|
fb5aa81e01 | ||
|
|
6592e13e02 | ||
|
|
31174dc35a | ||
|
|
f0bd9de081 | ||
|
|
75617a5456 | ||
|
|
e158faada0 | ||
|
|
f684bc0a1b | ||
|
|
3d56b1c2fc | ||
|
|
6e60f671b5 | ||
|
|
323d2e726c | ||
|
|
88d5030aa9 | ||
|
|
894b9573db | ||
|
|
d8d8cd93c5 | ||
|
|
986f1bd6a1 | ||
|
|
e85ca85027 | ||
|
|
d96023f36c | ||
|
|
203b552993 | ||
|
|
96e2f42251 | ||
|
|
9a73dc9bfd | ||
|
|
f01cdfda4b | ||
|
|
daa1405ba4 | ||
|
|
846d70f0c0 | ||
|
|
e59e41bfdb | ||
|
|
eb8a826419 | ||
|
|
efe7c16c50 | ||
|
|
c4b4b79f6c | ||
|
|
2e5ce0abdb | ||
|
|
d317b05f5b | ||
|
|
cc51a464f1 | ||
|
|
3e6aa461c6 | ||
|
|
d236689e6a | ||
|
|
d15bbb56ee | ||
|
|
f4355bd4c4 | ||
|
|
5dbd244d72 | ||
|
|
367c82a225 | ||
|
|
852bcbb38b | ||
|
|
464af945b2 | ||
|
|
996b3df9cb | ||
|
|
22d28abce6 | ||
|
|
636b616f64 | ||
|
|
14b7178419 | ||
|
|
22bf48c093 | ||
|
|
4600bca2d0 | ||
|
|
fcb9536d93 | ||
|
|
51a6a72ae5 | ||
|
|
f41f27e706 | ||
|
|
346a305f1d | ||
|
|
da8f700068 | ||
|
|
f2445fabba | ||
|
|
bc3ca5209f | ||
|
|
00517079d2 | ||
|
|
7b8a64ec94 | ||
|
|
794e59b6de | ||
|
|
9710801cb1 | ||
|
|
c5bda3b19c | ||
|
|
f9678a3793 | ||
|
|
091290b218 | ||
|
|
d991b55af7 | ||
|
|
1530a8f6fe | ||
|
|
98156191fe | ||
|
|
956914efa3 | ||
|
|
51c3beea9e | ||
|
|
657ff921de | ||
|
|
c9539faf44 | ||
|
|
2ca4d5338f | ||
|
|
236a513705 | ||
|
|
6d49e82a0c | ||
|
|
2fea614a45 | ||
|
|
85ed121158 | ||
|
|
9316f42808 | ||
|
|
74b66746eb | ||
|
|
5abeb9709e | ||
|
|
5ec50f22d9 | ||
|
|
dfe3a4220b | ||
|
|
1e1e95f249 | ||
|
|
02b0d1b728 | ||
|
|
9c81c96bb3 | ||
|
|
fff5b2cb01 | ||
|
|
77f1e9b5a2 | ||
|
|
3158a33a65 | ||
|
|
f6f840235e | ||
|
|
793f668ef8 | ||
|
|
da01393799 | ||
|
|
3030be32f4 | ||
|
|
dbdeba9865 | ||
|
|
80ff6af14e | ||
|
|
c34290d182 | ||
|
|
6e3235a985 | ||
|
|
419fa9f0c0 | ||
|
|
c996e5e58c | ||
|
|
6d28df74a6 | ||
|
|
ce97ef876d | ||
|
|
8898a6f252 | ||
|
|
37f638ac34 | ||
|
|
f73c698a5a | ||
|
|
029da0e7fa | ||
|
|
e40ee19ac8 | ||
|
|
33832fe547 | ||
|
|
671a776952 | ||
|
|
445b6a3e68 | ||
|
|
ff65370cc5 | ||
|
|
ff290c19e2 | ||
|
|
d1e505308c | ||
|
|
594799103b | ||
|
|
8a65f471a0 | ||
|
|
d52e2b0454 | ||
|
|
9b31bae1c8 | ||
|
|
7cbb905bd7 | ||
|
|
8a50ed036d | ||
|
|
f1394382ab | ||
|
|
74e6c80aad | ||
|
|
da9d6bad56 | ||
|
|
58a6fabf3c | ||
|
|
f8c11967d1 | ||
|
|
6d1c4bf39c | ||
|
|
018a47e400 | ||
|
|
509017551a | ||
|
|
cf454f287c | ||
|
|
0e3e4283af | ||
|
|
8176e1cd1c | ||
|
|
d2cba7c321 | ||
|
|
f791b0dab3 | ||
|
|
5093531811 | ||
|
|
c942df386a | ||
|
|
1d24789362 | ||
|
|
b8b445322c | ||
|
|
38c72b7af0 | ||
|
|
466b0544e3 | ||
|
|
26da0c2b64 | ||
|
|
8c3ac9e310 | ||
|
|
6a7c2520d0 | ||
|
|
a0d782a1a5 | ||
|
|
aebaab8d6f | ||
|
|
05158317e8 | ||
|
|
4d39c90ba6 | ||
|
|
83cf0801ef | ||
|
|
db49a613a0 | ||
|
|
64087f53c5 | ||
|
|
efb039ff38 | ||
|
|
388929cc0c | ||
|
|
6691511e17 | ||
|
|
b956a44857 | ||
|
|
8863826d0e | ||
|
|
65d9bf8f2f | ||
|
|
3ee82e7157 | ||
|
|
3b61bb74a2 | ||
|
|
f378b6e7ba | ||
|
|
aff05e1812 | ||
|
|
806bcf2d6b | ||
|
|
3755e2595f | ||
|
|
0d79f5e193 | ||
|
|
9210cd3283 | ||
|
|
733ffff81f | ||
|
|
32e2efc1e5 | ||
|
|
d9a688f1d8 | ||
|
|
ba66a0602b | ||
|
|
d53a85e013 | ||
|
|
5f6c418315 | ||
|
|
15569aadc7 | ||
|
|
0f97c09fda | ||
|
|
fd43fbd9c9 | ||
|
|
2b4ea9fd96 | ||
|
|
1837dcec72 | ||
|
|
84e1fa284b | ||
|
|
c211d90faf | ||
|
|
537eb06b66 | ||
|
|
93b03847df | ||
|
|
85e44369bb | ||
|
|
fbc1b1b440 | ||
|
|
97152a6ace | ||
|
|
3cde764d33 | ||
|
|
45b20efc45 | ||
|
|
869f843e3e | ||
|
|
ad533bcae9 | ||
|
|
b100652a7d | ||
|
|
d497c301c9 | ||
|
|
17dddb6691 | ||
|
|
818f4d3cca | ||
|
|
9141137606 | ||
|
|
9b6e781a7c | ||
|
|
8229ed9aa0 | ||
|
|
71ea27ee3a | ||
|
|
f760a3e011 | ||
|
|
14c09770eb | ||
|
|
a0646456d3 | ||
|
|
7a783b9d45 | ||
|
|
b0828fb96a | ||
|
|
369893cfa3 | ||
|
|
a96a973d44 | ||
|
|
2c767f2970 | ||
|
|
2839e892e0 | ||
|
|
a16ed9460a | ||
|
|
921545ca1f | ||
|
|
717c918bd4 | ||
|
|
98b707e3e3 | ||
|
|
73c7ca94e1 | ||
|
|
cf3cfd806f | ||
|
|
c58870fdeb | ||
|
|
a8ccc8903a | ||
|
|
adb582cd1e | ||
|
|
364f3a9c00 | ||
|
|
c19c812c10 | ||
|
|
0460f6dbcd | ||
|
|
4fabe45ae7 | ||
|
|
ab54359f03 | ||
|
|
0c9ec5b23a | ||
|
|
20ae68aa62 | ||
|
|
46164ebac7 | ||
|
|
de0a600163 | ||
|
|
956f9e344e | ||
|
|
acc1f58778 | ||
|
|
1a38bd1a00 | ||
|
|
cfc19bb35e | ||
|
|
446c8e74ee | ||
|
|
74cdc561e6 | ||
|
|
67fbcc8ff0 | ||
|
|
d19b8d5302 | ||
|
|
ae0e03bead | ||
|
|
7d7d73a48f | ||
|
|
6dcc4649db | ||
|
|
5db5c7f683 | ||
|
|
21b9b8cb3f | ||
|
|
fc520de642 | ||
|
|
9916075569 | ||
|
|
6624a9adb3 | ||
|
|
c3216007c1 | ||
|
|
92b22b1827 | ||
|
|
f32c14f795 | ||
|
|
ef15577b15 | ||
|
|
ac60c01788 | ||
|
|
9410902937 | ||
|
|
52776530d8 | ||
|
|
9cebb352ad | ||
|
|
d810eaf876 | ||
|
|
1a1ca32721 | ||
|
|
a3d689e806 | ||
|
|
d4e22b6c0c | ||
|
|
7e24f6a395 | ||
|
|
c8e6a6f34f | ||
|
|
f7a79cf02f | ||
|
|
21b0de542c | ||
|
|
7ae4e14a3e | ||
|
|
bfd6c25a03 | ||
|
+4 |
992644c20f | ||
|
|
96036a67eb | ||
|
|
95d3332675 | ||
|
|
62ed17757b | ||
|
|
f69d2bb9f8 | ||
|
|
d4310a6163 | ||
|
|
0a37dc6a9a | ||
|
|
a3fefe413e | ||
|
|
fa8be308de | ||
|
|
2329be3d2d | ||
|
|
d5eadf8e22 | ||
|
|
f559e032bb | ||
|
|
940037bc27 | ||
|
|
c7d721aa5c | ||
|
|
40a987d81a | ||
|
|
6840ff5c64 | ||
|
|
dd6bbccd32 | ||
|
|
bdb473a1ee | ||
|
|
26cf4c7e5a | ||
|
|
746f6b11eb | ||
|
|
6134e7ac6b | ||
|
|
c2c42ffdc9 | ||
|
|
82f2180888 | ||
|
|
63cc799966 | ||
|
|
bf467a3b96 | ||
|
|
992d5e08b9 | ||
|
|
102938304c | ||
|
|
9af8478236 | ||
|
|
3cc367bf0d | ||
|
|
416b967e8a | ||
|
|
5f4739cc78 | ||
|
|
f64f7f366a | ||
|
|
c47661b619 |
No files matched your search
@@ -0,0 +1,2 @@
|
||||
# Ignore spotlessApply reformat
|
||||
f64f7f366af8fc32dddfe9c9acd1259eb7d65787
|
||||
+36
-27
@@ -1,35 +1,44 @@
|
||||
* text eol=lf
|
||||
|
||||
*.jar binary
|
||||
*.[jJ][aA][rR] binary
|
||||
|
||||
*.png binary
|
||||
*.jpg binary
|
||||
*.jpeg binary
|
||||
*.gif binary
|
||||
*.tif binary
|
||||
*.tiff binary
|
||||
*.ico binary
|
||||
*.svg text
|
||||
*.eps binary
|
||||
*.[pP][nN][gG] binary
|
||||
*.[jJ][pP][gG] binary
|
||||
*.[jJ][pP][eE][gG] binary
|
||||
*.[gG][iI][fF] binary
|
||||
*.[tT][iI][fF] binary
|
||||
*.[tT][iI][fF][fF] binary
|
||||
*.[iI][cC][oO] binary
|
||||
*.[sS][vV][gG] text
|
||||
*.[eE][pP][sS] binary
|
||||
*.[xX][cC][fF] binary
|
||||
|
||||
*.kar binary
|
||||
*.m4a binary
|
||||
*.mid binary
|
||||
*.midi binary
|
||||
*.mp3 binary
|
||||
*.ogg binary
|
||||
*.ra binary
|
||||
*.[kK][aA][rR] binary
|
||||
*.[mM]4[aA] binary
|
||||
*.[mM][iI][dD] binary
|
||||
*.[mM][iI][dD][iI] binary
|
||||
*.[mM][pP]3 binary
|
||||
*.[oO][gG][gG] binary
|
||||
*.[rR][aA] binary
|
||||
|
||||
*.7z binary
|
||||
*.gz binary
|
||||
*.tar binary
|
||||
*.tgz binary
|
||||
*.zip binary
|
||||
*.7[zZ] binary
|
||||
*.[gG][zZ] binary
|
||||
*.[tT][aA][rR] binary
|
||||
*.[tT][gG][zZ] binary
|
||||
*.[zZ][iI][pP] binary
|
||||
|
||||
*.patch -text
|
||||
*.[tT][cC][nN] binary
|
||||
*.[sS][oO] binary
|
||||
*.[dD][lL][lL] binary
|
||||
*.[dD][yY][lL][iI][bB] binary
|
||||
*.[pP][sS][dD] binary
|
||||
*.[tT][tT][fF] binary
|
||||
*.[oO][tT][fF] binary
|
||||
|
||||
*.bat text eol=crlf
|
||||
*.cmd text eol=crlf
|
||||
*.ps1 text eol=crlf
|
||||
*.[pP][aA][tT][cC][hH] -text
|
||||
|
||||
*autogenerated binary
|
||||
*.[bB][aA][tT] text eol=crlf
|
||||
*.[cC][mM][dD] text eol=crlf
|
||||
*.[pP][sS]1 text eol=crlf
|
||||
|
||||
*[aA][uU][tT][oO][gG][eE][nN][eE][rR][aA][tT][eE][dD]* binary
|
||||
@@ -0,0 +1,102 @@
|
||||
name: Report Bug
|
||||
description: "Report a bug."
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "A bug/crash report with sufficient information and logs to reproduce and track down."
|
||||
- type: input
|
||||
id: discord
|
||||
attributes:
|
||||
label: Your GTNH Discord Username
|
||||
description: Leave empty if you don't have one, but this will make it harder to contact you if we need additional info.
|
||||
placeholder: "Example: Fake#1234"
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Mod Version
|
||||
description: "What version of the Mod are you using?"
|
||||
placeholder: "Example: 1.0.0-alpha1"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: report
|
||||
attributes:
|
||||
label: Bug Report
|
||||
description: "Relevant information, as well as relevant logs attached such as `logs/fml-client-latest.log."
|
||||
placeholder: "Example: https://mclo.gs/ OR submit the file to github by dragging it to this textbox."
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: java
|
||||
attributes:
|
||||
label: Java Version
|
||||
description: What Java version are you using? It's worth mentioning that if you play on Java9+ you should try update to latest minor release (e.g. prefer Java 17.0.6 over 17.0.2) of that version.
|
||||
options:
|
||||
- Java 8
|
||||
- Java 9
|
||||
- Java 11
|
||||
- Java 17
|
||||
- Java 19
|
||||
- Java 20
|
||||
- Java 21
|
||||
- Java 25
|
||||
- Other (Please Specify)
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: graphics
|
||||
attributes:
|
||||
label: Graphics Card Vendor
|
||||
description: What graphics card vendor are you using?
|
||||
options:
|
||||
- Other (Please Specify)
|
||||
- NVidia
|
||||
- AMD/ATI
|
||||
- Intel iGPU
|
||||
- AMD iGPU
|
||||
- Mesa/Software
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: shaders
|
||||
attributes:
|
||||
label: Shaders
|
||||
description: Do you have a shaderpack enabled?
|
||||
options:
|
||||
- "No"
|
||||
- "Yes: Please put relevant information about shaderpack in the report(what shaderpack, any special settings of note, etc)"
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: mcpf
|
||||
attributes:
|
||||
label: MCPF or other features disabled by default
|
||||
description: Do you have MCPF or any other features that are disabled by default enabled?
|
||||
options:
|
||||
- "No: Go ahead and create an issue"
|
||||
- "Yes: I will not create an issue"
|
||||
- "Yes: I don't read and shouldn't be creating an issue"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: modlist
|
||||
attributes:
|
||||
label: Mod List or GTNH Pack Version
|
||||
description: "List of mods, ideally a minimal reproducible set (can be retrieved from latest.log). If using GTNH please indicate pack version and any changed mods, not the entire modlist."
|
||||
placeholder: "List of mods or GTNH Pack version goes here"
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: final
|
||||
attributes:
|
||||
label: Final Checklist
|
||||
description: Certify that you read things
|
||||
options:
|
||||
- label: "I have searched the issues and haven't found a similar issue."
|
||||
required: true
|
||||
- label: "I have read the known incompatibilities and this is not related to one of those."
|
||||
required: true
|
||||
- label: "I am running an officially released version. (Or, if I've compiled it myself I plan to fix the issue)"
|
||||
required: true
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
name: Feature Request
|
||||
description: "Request a feature."
|
||||
labels: ["enhancement"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "Please use this form to request features. We ask you check if it was already requested though"
|
||||
- type: input
|
||||
id: discord
|
||||
attributes:
|
||||
label: Your GTNH Discord Username
|
||||
description: Leave empty if you don't have one, but this will make it harder to contact you if we need additional info.
|
||||
placeholder: "Example: Wumpus#1234"
|
||||
- type: textarea
|
||||
id: request
|
||||
attributes:
|
||||
label: Feature Request
|
||||
description: "Relevant information, as well as relevant images"
|
||||
placeholder: "Example: https://mclo.gs/ OR submit the file to github by dragging it to this textbox."
|
||||
validations:
|
||||
required: true
|
||||
- type: checkboxes
|
||||
id: final
|
||||
attributes:
|
||||
label: Final Checklist
|
||||
description: Certify that you read things
|
||||
options:
|
||||
- label: "I have searched the issues and haven't found a similar issue."
|
||||
required: true
|
||||
- label: "I have read the known incompatibilities and this is not related to one of those."
|
||||
required: true
|
||||
- label: "This issue is not related to a feature that is disabed by default - MCPF, etc. [They'll be enabled when they're ready for testing]"
|
||||
required: true
|
||||
@@ -0,0 +1 @@
|
||||
blank_issues_enabled: false
|
||||
+8
-1
@@ -1,6 +1,7 @@
|
||||
.gradle
|
||||
.settings
|
||||
/.idea/
|
||||
/.vs/
|
||||
/.vscode/
|
||||
/run/
|
||||
/build/
|
||||
@@ -26,7 +27,13 @@ whitelist.json
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
src/main/resources/mixins.*.json
|
||||
src/main/resources/mixins.*([!.]).json
|
||||
*.bat
|
||||
*.DS_Store
|
||||
!gradlew.bat
|
||||
layout.json
|
||||
addon.local.gradle
|
||||
addon.local.gradle.kts
|
||||
addon.late.local.gradle
|
||||
addon.late.local.gradle.kts
|
||||
local/
|
||||
@@ -1,19 +1,87 @@
|
||||
# Angelica
|
||||
the little angle that supports shaders while saving your fps from a certain death - boubou
|
||||
# Angelica<img src="img/logo-readme.png" align="right">
|
||||
|
||||
Not yet in an usable state
|
||||
<sup>**[CurseForge](https://www.curseforge.com/minecraft/mc-mods/angelica) | [Modrinth](https://modrinth.com/mod/angelica)**</sup>
|
||||
|
||||
Original build instructions obtained via minecraftforums archeology:
|
||||
```
|
||||
Developing environment
|
||||
- Extract forge src to forge folder. Run "gradlew setupDecompWorkspace setupDevWorkspace" until it succeeded, then "gradlew build", then "gradlew eclipse".
|
||||
- Delete everything in src\main folder inside forge folder.
|
||||
- Extract smc-2.3.18-mc1.7.10-src.7z to src\main folder.
|
||||
- Read patch file shadersmod-mcf.patch
|
||||
- Find %userprofile%\.gradle\caches\minecraft\net\minecraftforge\forge\*\forgeSrc-*-sources.jar and extract it somewhere.
|
||||
-- Select files that need to be patched and copy them to src\main with correct folder structure.
|
||||
- Apply patch shadersmod-mcf.patch
|
||||
- In eclipse, add java_dev folder as another source folder.
|
||||
- In eclipse, exclude InitNames in src folder from build path. Use InitNames in java_dev folder instead.
|
||||
- Find %userprofile%\.gradle\caches\modules-2\files-2.1\net.minecraftforge\forge\*\*\forge-*-userdev.jar and extract conf\*.csv and conf\*.srg in it to forge\conf and rename packaged.srg to joined.srg.
|
||||
```
|
||||
* The little Angle [sic] that supports shaders while saving your fps from a certain death -boubou
|
||||
* Is it obtuse, or accute? -Caedis
|
||||
* It's a cute angle -mitchej123
|
||||
* It's the angel that pulls you out of OptiFine's hell -Roadhog360
|
||||
|
||||
## **Beta Quality - Here there be Dragons**
|
||||
* Shaders - Beta
|
||||
* Complementary + Euphoria Patches is the primary compatibility target
|
||||
* Sildurs, Seus, and any other shaders might work
|
||||
|
||||
|
||||
# Required Dependencies
|
||||
* [UniMixins](https://github.com/LegacyModdingMC/UniMixins/releases) >= 0.1.23
|
||||
* [GTNHLib](https://github.com/GTNewHorizons/GTNHLib/releases) >= 0.9.0
|
||||
* NOTE: Some mods are not required, but a specific version is required if present - see: `Permanent Incompatibilities` below.
|
||||
|
||||
# Known (temporary) Incompatibilities
|
||||
* Forge Relocation - Currently non Thread Safe; safe if not in use
|
||||
* ProjectRed Frames - Currently non Thread Safe; safe if not in use
|
||||
|
||||
# Potential Incompatibilities
|
||||
* EndlessIDs - Compat commits have been made, might work, might not - not fully tested
|
||||
|
||||
# Known Incompatibilities
|
||||
* FalseTweaks - Not currently planned (Looking for volunteers) [Might work if you effectively disable most of the mod]
|
||||
* RPLE - Not currently planned (Looking for volunteers)
|
||||
* LiteLoader - Install [LiteloaderLoader](https://github.com/Midnight145/LiteloaderLoader)
|
||||
|
||||
# Permanent Incompatibilities
|
||||
* OptiFine [Disabled, won't fix]
|
||||
* FastCraft [Disabled, won't fix]
|
||||
* BetterFPS [Disabled, won't fix]
|
||||
* OptimizationsAndTweaks [Disabled, won't fix]
|
||||
* [Amazing Trophies 1.2.1 and below](https://github.com/GTNewHorizons/Amazing-Trophies/releases) - Use 1.2.2+
|
||||
* [LWJGL3ify 1.5.4 and below](https://github.com/GTNewHorizons/lwjgl3ify/releases/) - Use the latest version available, 1.5.7+
|
||||
* [ArchaicFix 0.6.2 and below](https://www.curseforge.com/minecraft/mc-mods/archaicfix/files/all?page=1&pageSize=20) - Use 0.7.0 or above
|
||||
* [Hodgepodge 2.4.3 and below](https://github.com/GTNewHorizons/Hodgepodge/releases) - Use 2.4.5 or above
|
||||
* CodeChicken[Core](https://github.com/GTNewHorizons/CodeChickenCore/releases)/[Lib](https://github.com/GTNewHorizons/CodeChickenLib/releases) <1.2.0 - Threading issues, use 1.3.0+
|
||||
* Neodymium - Untested, but unlikely to be compatible. (Chunk Meshing is definitely incompatible, other features might work depending on config)
|
||||
* SmoothFont - Equivalent functionality added
|
||||
|
||||
# Credits
|
||||
* ShadersMod
|
||||
* Original ShadersMods: karyonix, sonic ether, id_miner, daxnitro
|
||||
* eigenraven, Caedis, glowredman, and mitchej123 for the conversion of ASM to Mixin
|
||||
* eigenraven and vlaetansky for getting the original ShadersMod compiling again
|
||||
* ArchaicFix
|
||||
* Includes graphic enhancements from [ArchaicFix](https://github.com/embeddedt/ArchaicFix/tree/4afb943751883b27a1f0aa7c5ba71698bc897e95) by embeddedt under the [LGPL](https://github.com/embeddedt/ArchaicFix/blob/main/LICENSE.md)
|
||||
* NotFine
|
||||
* Includes modified version of [NotFine](https://github.com/jss2a98aj/NotFine/tree/a2652e24b5654f437fb7138f6d1f5e947a7d7125) by jss2a98aj under the LGPL
|
||||
* Iris Shaders
|
||||
* The [Iris](https://github.com/IrisShaders/Iris) Team: coderbot, IMS212, Justsnoopy30, FoundationGames
|
||||
* Asek3 for the Iris Forge port [Oculus](https://github.com/Asek3/Oculus/tree/839ce8eca8cf0c4f6b7a1322b906e5c99125ca69)
|
||||
* Backported code under the LGPL
|
||||
* Sodium
|
||||
* JellySquid & the CaffeineMC team, for making Sodium in the first place
|
||||
* Embeddedt for [Embeddium](https://github.com/embeddedt/embeddium/tree/dc59ca357c25beefd6288f0d1d40b4cd8e670ab8) under the [LGPL 3.0](https://github.com/embeddedt/embeddium/blob/16.x/forge/LICENSE)
|
||||
* Reese's Sodium Options
|
||||
* FlashyReese for [Reese's Sodium Options](https://github.com/FlashyReese/reeses-sodium-options/tree/aa4ea67047cf53e54976e93c6bb1ab5ba16b142b) under the [MIT license](https://github.com/FlashyReese/reeses-sodium-options/blob/aa4ea67047cf53e54976e93c6bb1ab5ba16b142b/LICENSE.txt)
|
||||
* Neodymium
|
||||
* Makamys for [Neodymium](https://github.com/makamys/Neodymium) - Various Tessellator -> Quad functionality taken under the LGPL 3
|
||||
* MCPatcherForge
|
||||
* Original [MCPatcher](https://bitbucket.org/prupe/mcpatcher/src/master/): Paul Rupe
|
||||
* [Forge version](https://github.com/mist475/MCPatcherForge): Mist475 under LGPL 3.0 with default ctm textures for glass and bookshelves by DarkBum under CC-BY-SA
|
||||
* HUDCaching
|
||||
* Created by [Moulberry](https://github.com/Moulberry/MCHUDCaching), backported from [Patcher](https://github.com/Sk1erLLC/Patcher) mod by Alexdoru under the CC-BY-SA-NC 4.0 license
|
||||
* Angelica
|
||||
* mitchej123, Omni, Makamys, Embeddedt, NanoLive, Caedis, Cardinalstar, Alexdoru, Eigenraven, mist475, Clepto, kurrycat for helping get Angelica up and running!
|
||||
* IMS, jss2a98aj, || dbp ||, roadhog360 for advice and moral support
|
||||
* Forge 1.12+
|
||||
* Some files have been taken from Minecraft Forge under the LGPL 2.1 license and are marked as such
|
||||
* FRAPI and Indigo
|
||||
* Model building API heavily inspired by/copied from Fabric's; upstream may use it under the original Apache 2.0
|
||||
license, see LICENSE in `com.gtnewhorizons.angelica.models`
|
||||
* Dynamic Lights
|
||||
* LambdAurora for [LambDynamicLights](https://github.com/LambdAurora/LambDynamicLights) under the MIT license, and the Forge port anthxnymc for [DynamicLightsReforged](https://github.com/anthxnymc/DynamicLightsReforged), also under the MIT license
|
||||
* Embeddedt and Ferri_Arnus for [glsl-transformation-lib](https://github.com/TauMC/glsl-transformation-lib)
|
||||
* Also for work on [Monocle](https://github.com/ferriarnus/Monocle) which was used as a reference for implementing glsl-transformation-lib
|
||||
* Code from both glsl-transformation-lib and Monocle taken under their respective LGPL 3.0 licenses
|
||||
* FalseTweaks
|
||||
* FalsePattern for [FalseTweaks](https://github.com/falsepattern/falsetweaks) - Item Rendering Optimizations taken from FalseTweaks under the LGPL 3.0 license
|
||||
* Beddium
|
||||
* Venn and Falsepattern for [Beddium](https://github.com/vfx-dev/Beddium) - MinimapRenderer, SafeChunkTracker, and some debug commands adapted under the LGPL 3.0 License
|
||||
@@ -1,21 +0,0 @@
|
||||
|
||||
configurations {
|
||||
compileStubs
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
compileStubsStubs
|
||||
compileStubs {
|
||||
compileClasspath += configurations.compileStubs
|
||||
}
|
||||
}
|
||||
|
||||
jar {
|
||||
manifest {
|
||||
attributes([
|
||||
"Manifest-Version" : 1.0,
|
||||
"TweakClass" : "com.gtnewhorizons.angelica.loading.ATweaker",
|
||||
"TweakOrder" : 1100,
|
||||
])
|
||||
}
|
||||
}
|
||||
-968
@@ -1,968 +0,0 @@
|
||||
//version: 1661114848
|
||||
/*
|
||||
DO NOT CHANGE THIS FILE!
|
||||
Also, you may replace this file at any time if there is an update available.
|
||||
Please check https://github.com/GTNewHorizons/ExampleMod1.7.10/blob/main/build.gradle for updates.
|
||||
*/
|
||||
|
||||
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ConfigureShadowRelocation
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
import org.gradle.internal.logging.text.StyledTextOutput.Style
|
||||
import org.gradle.internal.logging.text.StyledTextOutputFactory
|
||||
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Paths
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipInputStream
|
||||
import java.util.zip.ZipOutputStream
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
||||
maven {
|
||||
name 'forge'
|
||||
url 'https://maven.minecraftforge.net'
|
||||
}
|
||||
maven {
|
||||
// GTNH ForgeGradle Fork
|
||||
name = "GTNH Maven"
|
||||
url = "http://jenkins.usrv.eu:8081/nexus/content/groups/public/"
|
||||
}
|
||||
maven {
|
||||
name 'sonatype'
|
||||
url 'https://oss.sonatype.org/content/repositories/snapshots/'
|
||||
}
|
||||
maven {
|
||||
name 'Scala CI dependencies'
|
||||
url 'https://repo1.maven.org/maven2/'
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath 'net.minecraftforge.gradle:ForgeGradle:1.2.9'
|
||||
}
|
||||
}
|
||||
plugins {
|
||||
id 'java-library'
|
||||
id 'idea'
|
||||
id 'eclipse'
|
||||
id 'scala'
|
||||
id 'maven-publish'
|
||||
id 'org.jetbrains.kotlin.jvm' version '1.5.30' apply false
|
||||
id 'org.jetbrains.kotlin.kapt' version '1.5.30' apply false
|
||||
id 'com.google.devtools.ksp' version '1.5.30-1.0.0' apply false
|
||||
id 'org.ajoberstar.grgit' version '4.1.1'
|
||||
id 'com.github.johnrengelman.shadow' version '4.0.4'
|
||||
id 'com.palantir.git-version' version '0.13.0' apply false
|
||||
id 'de.undercouch.download' version '5.0.1'
|
||||
id 'com.github.gmazzo.buildconfig' version '3.0.3' apply false
|
||||
id 'com.diffplug.spotless' version '6.7.2' apply false
|
||||
}
|
||||
boolean settingsupdated = verifySettingsGradle()
|
||||
settingsupdated = verifyGitAttributes() || settingsupdated
|
||||
if (settingsupdated)
|
||||
throw new GradleException("Settings has been updated, please re-run task.")
|
||||
|
||||
dependencies {
|
||||
implementation 'com.diffplug:blowdryer:1.6.0'
|
||||
}
|
||||
|
||||
apply plugin: 'com.diffplug.blowdryer'
|
||||
|
||||
if (project.file('.git/HEAD').isFile()) {
|
||||
apply plugin: 'com.palantir.git-version'
|
||||
}
|
||||
|
||||
def out = services.get(StyledTextOutputFactory).create('an-output')
|
||||
|
||||
apply plugin: 'forge'
|
||||
|
||||
def projectJavaVersion = JavaLanguageVersion.of(8)
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion.set(projectJavaVersion)
|
||||
}
|
||||
}
|
||||
|
||||
idea {
|
||||
module {
|
||||
inheritOutputDirs = true
|
||||
downloadJavadoc = true
|
||||
downloadSources = true
|
||||
}
|
||||
}
|
||||
|
||||
boolean disableSpotless = project.hasProperty("disableSpotless") ? project.disableSpotless.toBoolean() : false
|
||||
|
||||
if (!disableSpotless) {
|
||||
apply plugin: 'com.diffplug.spotless'
|
||||
apply from: Blowdryer.file('spotless.gradle')
|
||||
}
|
||||
|
||||
if (JavaVersion.current() != JavaVersion.VERSION_1_8) {
|
||||
throw new GradleException("This project requires Java 8, but it's running on " + JavaVersion.current())
|
||||
}
|
||||
|
||||
checkPropertyExists("modName")
|
||||
checkPropertyExists("modId")
|
||||
checkPropertyExists("modGroup")
|
||||
checkPropertyExists("autoUpdateBuildScript")
|
||||
checkPropertyExists("minecraftVersion")
|
||||
checkPropertyExists("forgeVersion")
|
||||
checkPropertyExists("replaceGradleTokenInFile")
|
||||
checkPropertyExists("gradleTokenModId")
|
||||
checkPropertyExists("gradleTokenModName")
|
||||
checkPropertyExists("gradleTokenVersion")
|
||||
checkPropertyExists("gradleTokenGroupName")
|
||||
checkPropertyExists("apiPackage")
|
||||
checkPropertyExists("accessTransformersFile")
|
||||
checkPropertyExists("usesMixins")
|
||||
checkPropertyExists("mixinPlugin")
|
||||
checkPropertyExists("mixinsPackage")
|
||||
checkPropertyExists("coreModClass")
|
||||
checkPropertyExists("containsMixinsAndOrCoreModOnly")
|
||||
checkPropertyExists("usesShadowedDependencies")
|
||||
checkPropertyExists("developmentEnvironmentUserName")
|
||||
|
||||
boolean noPublishedSources = project.hasProperty("noPublishedSources") ? project.noPublishedSources.toBoolean() : false
|
||||
boolean usesMixinDebug = project.hasProperty('usesMixinDebug') ?: project.usesMixins.toBoolean()
|
||||
boolean forceEnableMixins = project.hasProperty('forceEnableMixins') ? project.forceEnableMixins.toBoolean() : false
|
||||
String channel = project.hasProperty('channel') ? project.channel : 'stable'
|
||||
String mappingsVersion = project.hasProperty('mappingsVersion') ? project.mappingsVersion : '12'
|
||||
String javaSourceDir = "src/main/java/"
|
||||
String scalaSourceDir = "src/main/scala/"
|
||||
String kotlinSourceDir = "src/main/kotlin/"
|
||||
|
||||
String targetPackageJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/")
|
||||
String targetPackageScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/")
|
||||
String targetPackageKotlin = kotlinSourceDir + modGroup.toString().replaceAll("\\.", "/")
|
||||
if (!(getFile(targetPackageJava).exists() || getFile(targetPackageScala).exists() || getFile(targetPackageKotlin).exists())) {
|
||||
throw new GradleException("Could not resolve \"modGroup\"! Could not find " + targetPackageJava + " or " + targetPackageScala + " or " + targetPackageKotlin)
|
||||
}
|
||||
|
||||
if (apiPackage) {
|
||||
targetPackageJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString().replaceAll("\\.", "/")
|
||||
targetPackageScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString().replaceAll("\\.", "/")
|
||||
targetPackageKotlin = kotlinSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString().replaceAll("\\.", "/")
|
||||
if (!(getFile(targetPackageJava).exists() || getFile(targetPackageScala).exists() || getFile(targetPackageKotlin).exists())) {
|
||||
throw new GradleException("Could not resolve \"apiPackage\"! Could not find " + targetPackageJava + " or " + targetPackageScala + " or " + targetPackageKotlin)
|
||||
}
|
||||
}
|
||||
|
||||
if (accessTransformersFile) {
|
||||
String targetFile = "src/main/resources/META-INF/" + accessTransformersFile
|
||||
if (!getFile(targetFile).exists()) {
|
||||
throw new GradleException("Could not resolve \"accessTransformersFile\"! Could not find " + targetFile)
|
||||
}
|
||||
}
|
||||
|
||||
if (usesMixins.toBoolean()) {
|
||||
if (mixinsPackage.isEmpty() || mixinPlugin.isEmpty()) {
|
||||
throw new GradleException("\"mixinPlugin\" requires \"mixinsPackage\" and \"mixinPlugin\" to be set!")
|
||||
}
|
||||
|
||||
targetPackageJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinsPackage.toString().replaceAll("\\.", "/")
|
||||
targetPackageScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinsPackage.toString().replaceAll("\\.", "/")
|
||||
targetPackageKotlin = kotlinSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinsPackage.toString().replaceAll("\\.", "/")
|
||||
if (!(getFile(targetPackageJava).exists() || getFile(targetPackageScala).exists() || getFile(targetPackageKotlin).exists())) {
|
||||
throw new GradleException("Could not resolve \"mixinsPackage\"! Could not find " + targetPackageJava + " or " + targetPackageScala + " or " + targetPackageKotlin)
|
||||
}
|
||||
|
||||
String targetFileJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinPlugin.toString().replaceAll("\\.", "/") + ".java"
|
||||
String targetFileScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinPlugin.toString().replaceAll("\\.", "/") + ".scala"
|
||||
String targetFileScalaJava = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinPlugin.toString().replaceAll("\\.", "/") + ".java"
|
||||
String targetFileKotlin = kotlinSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + mixinPlugin.toString().replaceAll("\\.", "/") + ".kt"
|
||||
if (!(getFile(targetFileJava).exists() || getFile(targetFileScala).exists() || getFile(targetFileScalaJava).exists() || getFile(targetFileKotlin).exists())) {
|
||||
throw new GradleException("Could not resolve \"mixinPlugin\"! Could not find " + targetFileJava + " or " + targetFileScala + " or " + targetFileScalaJava + " or " + targetFileKotlin)
|
||||
}
|
||||
}
|
||||
|
||||
if (coreModClass) {
|
||||
String targetFileJava = javaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + coreModClass.toString().replaceAll("\\.", "/") + ".java"
|
||||
String targetFileScala = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + coreModClass.toString().replaceAll("\\.", "/") + ".scala"
|
||||
String targetFileScalaJava = scalaSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + coreModClass.toString().replaceAll("\\.", "/") + ".java"
|
||||
String targetFileKotlin = kotlinSourceDir + modGroup.toString().replaceAll("\\.", "/") + "/" + coreModClass.toString().replaceAll("\\.", "/") + ".kt"
|
||||
if (!(getFile(targetFileJava).exists() || getFile(targetFileScala).exists() || getFile(targetFileScalaJava).exists() || getFile(targetFileKotlin).exists())) {
|
||||
throw new GradleException("Could not resolve \"coreModClass\"! Could not find " + targetFileJava + " or " + targetFileScala + " or " + targetFileScalaJava + " or " + targetFileKotlin)
|
||||
}
|
||||
}
|
||||
|
||||
configurations.all {
|
||||
resolutionStrategy.cacheChangingModulesFor(0, TimeUnit.SECONDS)
|
||||
|
||||
// Make sure GregTech build won't time out
|
||||
System.setProperty("org.gradle.internal.http.connectionTimeout", 120000 as String)
|
||||
System.setProperty("org.gradle.internal.http.socketTimeout", 120000 as String)
|
||||
}
|
||||
|
||||
// Fix Jenkins' Git: chmod a file should not be detected as a change and append a '.dirty' to the version
|
||||
try {
|
||||
'git config core.fileMode false'.execute()
|
||||
}
|
||||
catch (Exception ignored) {
|
||||
out.style(Style.Failure).println("git isn't installed at all")
|
||||
}
|
||||
|
||||
// Pulls version first from the VERSION env and then git tag
|
||||
String identifiedVersion
|
||||
String versionOverride = System.getenv("VERSION") ?: null
|
||||
try {
|
||||
identifiedVersion = versionOverride == null ? gitVersion() : versionOverride
|
||||
}
|
||||
catch (Exception ignored) {
|
||||
out.style(Style.Failure).text(
|
||||
'This mod must be version controlled by Git AND the repository must provide at least one tag,\n' +
|
||||
'or the VERSION override must be set! ').style(Style.SuccessHeader).text('(Do NOT download from GitHub using the ZIP option, instead\n' +
|
||||
'clone the repository, see ').style(Style.Info).text('https://gtnh.miraheze.org/wiki/Development').style(Style.SuccessHeader).println(' for details.)'
|
||||
)
|
||||
versionOverride = 'NO-GIT-TAG-SET'
|
||||
identifiedVersion = versionOverride
|
||||
}
|
||||
version = minecraftVersion + '-' + identifiedVersion
|
||||
ext {
|
||||
modVersion = identifiedVersion
|
||||
}
|
||||
|
||||
if (identifiedVersion == versionOverride) {
|
||||
out.style(Style.Failure).text('Override version to ').style(Style.Identifier).text(modVersion).style(Style.Failure).println('!\7')
|
||||
}
|
||||
|
||||
group = modGroup
|
||||
if (project.hasProperty("customArchiveBaseName") && customArchiveBaseName) {
|
||||
archivesBaseName = customArchiveBaseName
|
||||
} else {
|
||||
archivesBaseName = modId
|
||||
}
|
||||
|
||||
def arguments = []
|
||||
def jvmArguments = []
|
||||
|
||||
if (usesMixins.toBoolean() || forceEnableMixins) {
|
||||
arguments += [
|
||||
"--tweakClass org.spongepowered.asm.launch.MixinTweaker"
|
||||
]
|
||||
if (usesMixinDebug.toBoolean()) {
|
||||
jvmArguments += [
|
||||
"-Dmixin.debug.countInjections=true",
|
||||
"-Dmixin.debug.verbose=true",
|
||||
"-Dmixin.debug.export=true"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
minecraft {
|
||||
version = minecraftVersion + '-' + forgeVersion + '-' + minecraftVersion
|
||||
runDir = 'run'
|
||||
|
||||
if (replaceGradleTokenInFile) {
|
||||
replaceIn replaceGradleTokenInFile
|
||||
if (gradleTokenModId) {
|
||||
replace gradleTokenModId, modId
|
||||
}
|
||||
if (gradleTokenModName) {
|
||||
replace gradleTokenModName, modName
|
||||
}
|
||||
if (gradleTokenVersion) {
|
||||
replace gradleTokenVersion, modVersion
|
||||
}
|
||||
if (gradleTokenGroupName) {
|
||||
replace gradleTokenGroupName, modGroup
|
||||
}
|
||||
}
|
||||
|
||||
clientIntellijRun {
|
||||
args(arguments)
|
||||
jvmArgs(jvmArguments)
|
||||
|
||||
if (developmentEnvironmentUserName) {
|
||||
args("--username", developmentEnvironmentUserName)
|
||||
}
|
||||
}
|
||||
|
||||
serverIntellijRun {
|
||||
args(arguments)
|
||||
jvmArgs(jvmArguments)
|
||||
}
|
||||
}
|
||||
|
||||
if (file('addon.gradle').exists()) {
|
||||
apply from: 'addon.gradle'
|
||||
}
|
||||
|
||||
apply from: 'repositories.gradle'
|
||||
|
||||
configurations {
|
||||
implementation.extendsFrom(shadowImplementation) // TODO: remove after all uses are refactored
|
||||
implementation.extendsFrom(shadowCompile)
|
||||
implementation.extendsFrom(shadeCompile)
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
name 'Overmind forge repo mirror'
|
||||
url 'https://gregtech.overminddl1.com/'
|
||||
}
|
||||
if (usesMixins.toBoolean() || forceEnableMixins) {
|
||||
maven {
|
||||
name 'sponge'
|
||||
url 'https://repo.spongepowered.org/repository/maven-public'
|
||||
}
|
||||
maven {
|
||||
url 'https://jitpack.io'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
if (usesMixins.toBoolean()) {
|
||||
annotationProcessor('org.ow2.asm:asm-debug-all:5.0.3')
|
||||
annotationProcessor('com.google.guava:guava:24.1.1-jre')
|
||||
annotationProcessor('com.google.code.gson:gson:2.8.6')
|
||||
annotationProcessor('org.spongepowered:mixin:0.8-SNAPSHOT')
|
||||
}
|
||||
if (usesMixins.toBoolean() || forceEnableMixins) {
|
||||
// using 0.8 to workaround a issue in 0.7 which fails mixin application
|
||||
compile('com.github.GTNewHorizons:SpongePoweredMixin:0.7.12-GTNH') {
|
||||
// Mixin includes a lot of dependencies that are too up-to-date
|
||||
exclude module: 'launchwrapper'
|
||||
exclude module: 'guava'
|
||||
exclude module: 'gson'
|
||||
exclude module: 'commons-io'
|
||||
exclude module: 'log4j-core'
|
||||
}
|
||||
compile('com.github.GTNewHorizons:SpongeMixins:1.5.0')
|
||||
}
|
||||
}
|
||||
|
||||
apply from: 'dependencies.gradle'
|
||||
|
||||
def mixingConfigRefMap = 'mixins.' + modId + '.refmap.json'
|
||||
def refMap = "${tasks.compileJava.temporaryDir}" + File.separator + mixingConfigRefMap
|
||||
def mixinSrg = "${tasks.reobf.temporaryDir}" + File.separator + "mixins.srg"
|
||||
|
||||
task generateAssets {
|
||||
if (usesMixins.toBoolean()) {
|
||||
def mixinConfigFile = getFile("/src/main/resources/mixins." + modId + ".json");
|
||||
if (!mixinConfigFile.exists()) {
|
||||
mixinConfigFile.text = """{
|
||||
"required": true,
|
||||
"minVersion": "0.7.11",
|
||||
"package": "${modGroup}.${mixinsPackage}",
|
||||
"plugin": "${modGroup}.${mixinPlugin}",
|
||||
"refmap": "${mixingConfigRefMap}",
|
||||
"target": "@env(DEFAULT)",
|
||||
"compatibilityLevel": "JAVA_8",
|
||||
"mixins": [],
|
||||
"client": [],
|
||||
"server": []
|
||||
}
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task relocateShadowJar(type: ConfigureShadowRelocation) {
|
||||
target = tasks.shadowJar
|
||||
prefix = modGroup + ".shadow"
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
project.configurations.shadeCompile.each { dep ->
|
||||
from(project.zipTree(dep)) {
|
||||
exclude 'META-INF', 'META-INF/**'
|
||||
}
|
||||
}
|
||||
|
||||
manifest {
|
||||
attributes(getManifestAttributes())
|
||||
}
|
||||
|
||||
minimize() // This will only allow shading for actually used classes
|
||||
configurations = [
|
||||
project.configurations.shadowImplementation,
|
||||
project.configurations.shadowCompile
|
||||
]
|
||||
dependsOn(relocateShadowJar)
|
||||
}
|
||||
|
||||
jar {
|
||||
project.configurations.shadeCompile.each { dep ->
|
||||
from(project.zipTree(dep)) {
|
||||
exclude 'META-INF', 'META-INF/**'
|
||||
}
|
||||
}
|
||||
|
||||
manifest {
|
||||
attributes(getManifestAttributes())
|
||||
}
|
||||
|
||||
if (usesShadowedDependencies.toBoolean()) {
|
||||
dependsOn(shadowJar)
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
|
||||
reobf {
|
||||
if (usesMixins.toBoolean()) {
|
||||
addExtraSrgFile mixinSrg
|
||||
}
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
if (usesMixins.toBoolean()) {
|
||||
tasks.compileJava {
|
||||
options.compilerArgs += [
|
||||
"-AreobfSrgFile=${tasks.reobf.srg}",
|
||||
"-AoutSrgFile=${mixinSrg}",
|
||||
"-AoutRefMapFile=${refMap}",
|
||||
// Elan: from what I understand they are just some linter configs so you get some warning on how to properly code
|
||||
"-XDenableSunApiLintControl",
|
||||
"-XDignore.symbol.file"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
runClient {
|
||||
if (developmentEnvironmentUserName) {
|
||||
arguments += [
|
||||
"--username",
|
||||
developmentEnvironmentUserName
|
||||
]
|
||||
}
|
||||
|
||||
args(arguments)
|
||||
jvmArgs(jvmArguments)
|
||||
}
|
||||
|
||||
runServer {
|
||||
args(arguments)
|
||||
jvmArgs(jvmArguments)
|
||||
}
|
||||
|
||||
tasks.withType(JavaExec).configureEach {
|
||||
javaLauncher.set(
|
||||
javaToolchains.launcherFor {
|
||||
languageVersion = projectJavaVersion
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
processResources {
|
||||
// this will ensure that this task is redone when the versions change.
|
||||
inputs.property "version", project.version
|
||||
inputs.property "mcversion", project.minecraft.version
|
||||
exclude("spotless.gradle")
|
||||
|
||||
// replace stuff in mcmod.info, nothing else
|
||||
from(sourceSets.main.resources.srcDirs) {
|
||||
include 'mcmod.info'
|
||||
|
||||
// replace modVersion and minecraftVersion
|
||||
expand "minecraftVersion": project.minecraft.version,
|
||||
"modVersion": modVersion,
|
||||
"modId": modId,
|
||||
"modName": modName
|
||||
}
|
||||
|
||||
if (usesMixins.toBoolean()) {
|
||||
from refMap
|
||||
}
|
||||
|
||||
// copy everything else that's not the mcmod.info
|
||||
from(sourceSets.main.resources.srcDirs) {
|
||||
exclude 'mcmod.info'
|
||||
exclude 'spotless.gradle'
|
||||
}
|
||||
}
|
||||
|
||||
def getManifestAttributes() {
|
||||
def manifestAttributes = [:]
|
||||
if (!containsMixinsAndOrCoreModOnly.toBoolean() && (usesMixins.toBoolean() || coreModClass)) {
|
||||
manifestAttributes += ["FMLCorePluginContainsFMLMod": true]
|
||||
}
|
||||
|
||||
if (accessTransformersFile) {
|
||||
manifestAttributes += ["FMLAT": accessTransformersFile.toString()]
|
||||
}
|
||||
|
||||
if (coreModClass) {
|
||||
manifestAttributes += ["FMLCorePlugin": modGroup + "." + coreModClass]
|
||||
}
|
||||
|
||||
if (usesMixins.toBoolean()) {
|
||||
manifestAttributes += [
|
||||
"TweakClass" : "org.spongepowered.asm.launch.MixinTweaker",
|
||||
"MixinConfigs" : "mixins." + modId + ".json",
|
||||
"ForceLoadAsMod": !containsMixinsAndOrCoreModOnly.toBoolean()
|
||||
]
|
||||
}
|
||||
return manifestAttributes
|
||||
}
|
||||
|
||||
task sourcesJar(type: Jar) {
|
||||
from(sourceSets.main.allSource)
|
||||
from(file("$projectDir/LICENSE"))
|
||||
getArchiveClassifier().set('sources')
|
||||
}
|
||||
|
||||
task shadowDevJar(type: ShadowJar) {
|
||||
project.configurations.shadeCompile.each { dep ->
|
||||
from(project.zipTree(dep)) {
|
||||
exclude 'META-INF', 'META-INF/**'
|
||||
}
|
||||
}
|
||||
|
||||
from sourceSets.main.output
|
||||
getArchiveClassifier().set("dev")
|
||||
|
||||
manifest {
|
||||
attributes(getManifestAttributes())
|
||||
}
|
||||
|
||||
minimize() // This will only allow shading for actually used classes
|
||||
configurations = [
|
||||
project.configurations.shadowImplementation,
|
||||
project.configurations.shadowCompile
|
||||
]
|
||||
}
|
||||
|
||||
task relocateShadowDevJar(type: ConfigureShadowRelocation) {
|
||||
target = tasks.shadowDevJar
|
||||
prefix = modGroup + ".shadow"
|
||||
}
|
||||
|
||||
task circularResolverJar(type: Jar) {
|
||||
dependsOn(relocateShadowDevJar)
|
||||
dependsOn(shadowDevJar)
|
||||
enabled = false
|
||||
}
|
||||
|
||||
task devJar(type: Jar) {
|
||||
project.configurations.shadeCompile.each { dep ->
|
||||
from(project.zipTree(dep)) {
|
||||
exclude 'META-INF', 'META-INF/**'
|
||||
}
|
||||
}
|
||||
|
||||
from sourceSets.main.output
|
||||
getArchiveClassifier().set("dev")
|
||||
|
||||
manifest {
|
||||
attributes(getManifestAttributes())
|
||||
}
|
||||
|
||||
if (usesShadowedDependencies.toBoolean()) {
|
||||
dependsOn(circularResolverJar)
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
|
||||
task apiJar(type: Jar) {
|
||||
from(sourceSets.main.allSource) {
|
||||
include modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString().replaceAll("\\.", "/") + '/**'
|
||||
}
|
||||
|
||||
from(sourceSets.main.output) {
|
||||
include modGroup.toString().replaceAll("\\.", "/") + "/" + apiPackage.toString().replaceAll("\\.", "/") + '/**'
|
||||
}
|
||||
|
||||
from(sourceSets.main.resources.srcDirs) {
|
||||
include("LICENSE")
|
||||
}
|
||||
|
||||
getArchiveClassifier().set('api')
|
||||
}
|
||||
|
||||
artifacts {
|
||||
if (!noPublishedSources) {
|
||||
archives sourcesJar
|
||||
}
|
||||
archives devJar
|
||||
if (apiPackage) {
|
||||
archives apiJar
|
||||
}
|
||||
}
|
||||
|
||||
// The gradle metadata includes all of the additional deps that we disabled from POM generation (including forgeBin with no groupID),
|
||||
// and isn't strictly needed with the POM so just disable it.
|
||||
tasks.withType(GenerateModuleMetadata) {
|
||||
enabled = false
|
||||
}
|
||||
|
||||
// workaround variable hiding in pom processing
|
||||
def projectConfigs = project.configurations
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
maven(MavenPublication) {
|
||||
from components.java
|
||||
if (usesShadowedDependencies.toBoolean()) {
|
||||
artifact source: shadowJar, classifier: ""
|
||||
}
|
||||
if (!noPublishedSources) {
|
||||
artifact source: sourcesJar, classifier: "sources"
|
||||
}
|
||||
artifact source: usesShadowedDependencies.toBoolean() ? shadowDevJar : devJar, classifier: "dev"
|
||||
if (apiPackage) {
|
||||
artifact source: apiJar, classifier: "api"
|
||||
}
|
||||
|
||||
groupId = System.getenv("ARTIFACT_GROUP_ID") ?: "com.github.GTNewHorizons"
|
||||
artifactId = System.getenv("ARTIFACT_ID") ?: project.name
|
||||
// Using the identified version, not project.version as it has the prepended 1.7.10
|
||||
version = System.getenv("RELEASE_VERSION") ?: identifiedVersion
|
||||
|
||||
// remove extra garbage from minecraft and minecraftDeps configuration
|
||||
pom.withXml {
|
||||
def badArtifacts = [:].withDefault { [] as Set<String> }
|
||||
for (configuration in [
|
||||
projectConfigs.minecraft,
|
||||
projectConfigs.minecraftDeps
|
||||
]) {
|
||||
for (dependency in configuration.allDependencies) {
|
||||
badArtifacts[dependency.group == null ? "" : dependency.group] += dependency.name
|
||||
}
|
||||
}
|
||||
// example for specifying extra stuff to ignore
|
||||
// badArtifacts["org.example.group"] += "artifactName"
|
||||
|
||||
Node pomNode = asNode()
|
||||
pomNode.dependencies.'*'.findAll() {
|
||||
badArtifacts[it.groupId.text()].contains(it.artifactId.text())
|
||||
}.each() {
|
||||
it.parent().remove(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
url = "http://jenkins.usrv.eu:8081/nexus/content/repositories/releases"
|
||||
credentials {
|
||||
username = System.getenv("MAVEN_USER") ?: "NONE"
|
||||
password = System.getenv("MAVEN_PASSWORD") ?: "NONE"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Updating
|
||||
task updateBuildScript {
|
||||
doLast {
|
||||
if (performBuildScriptUpdate(projectDir.toString())) return
|
||||
|
||||
print("Build script already up-to-date!")
|
||||
}
|
||||
}
|
||||
|
||||
if (!project.getGradle().startParameter.isOffline() && isNewBuildScriptVersionAvailable(projectDir.toString())) {
|
||||
if (autoUpdateBuildScript.toBoolean()) {
|
||||
performBuildScriptUpdate(projectDir.toString())
|
||||
} else {
|
||||
out.style(Style.SuccessHeader).println("Build script update available! Run 'gradle updateBuildScript'")
|
||||
}
|
||||
}
|
||||
|
||||
static URL availableBuildScriptUrl() {
|
||||
new URL("https://raw.githubusercontent.com/GTNewHorizons/ExampleMod1.7.10/master/build.gradle")
|
||||
}
|
||||
|
||||
static URL exampleSettingsGradleUrl() {
|
||||
new URL("https://raw.githubusercontent.com/GTNewHorizons/ExampleMod1.7.10/master/settings.gradle.example")
|
||||
}
|
||||
|
||||
static URL exampleGitAttributesUrl() {
|
||||
new URL("https://raw.githubusercontent.com/GTNewHorizons/ExampleMod1.7.10/master/.gitattributes")
|
||||
}
|
||||
|
||||
|
||||
boolean verifyGitAttributes() {
|
||||
def gitattributesFile = getFile(".gitattributes")
|
||||
if (!gitattributesFile.exists()) {
|
||||
println("Downloading default .gitattributes")
|
||||
exampleGitAttributesUrl().withInputStream { i -> gitattributesFile.withOutputStream { it << i } }
|
||||
exec {
|
||||
workingDir '.'
|
||||
commandLine 'git', 'add', '--renormalize', '.'
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
boolean verifySettingsGradle() {
|
||||
def settingsFile = getFile("settings.gradle")
|
||||
if (!settingsFile.exists()) {
|
||||
println("Downloading default settings.gradle")
|
||||
exampleSettingsGradleUrl().withInputStream { i -> settingsFile.withOutputStream { it << i } }
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
boolean performBuildScriptUpdate(String projectDir) {
|
||||
if (isNewBuildScriptVersionAvailable(projectDir)) {
|
||||
def buildscriptFile = getFile("build.gradle")
|
||||
availableBuildScriptUrl().withInputStream { i -> buildscriptFile.withOutputStream { it << i } }
|
||||
out.style(Style.Success).print("Build script updated. Please REIMPORT the project or RESTART your IDE!")
|
||||
boolean settingsupdated = verifySettingsGradle()
|
||||
settingsupdated = verifyGitAttributes() || settingsupdated
|
||||
if (settingsupdated)
|
||||
throw new GradleException("Settings has been updated, please re-run task.")
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
boolean isNewBuildScriptVersionAvailable(String projectDir) {
|
||||
Map parameters = ["connectTimeout": 2000, "readTimeout": 2000]
|
||||
|
||||
String currentBuildScript = getFile("build.gradle").getText()
|
||||
String currentBuildScriptHash = getVersionHash(currentBuildScript)
|
||||
String availableBuildScript = availableBuildScriptUrl().newInputStream(parameters).getText()
|
||||
String availableBuildScriptHash = getVersionHash(availableBuildScript)
|
||||
|
||||
boolean isUpToDate = currentBuildScriptHash.empty || availableBuildScriptHash.empty || currentBuildScriptHash == availableBuildScriptHash
|
||||
return !isUpToDate
|
||||
}
|
||||
|
||||
static String getVersionHash(String buildScriptContent) {
|
||||
String versionLine = buildScriptContent.find("^//version: [a-z0-9]*")
|
||||
if (versionLine != null) {
|
||||
return versionLine.split(": ").last()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
configure(updateBuildScript) {
|
||||
group = 'forgegradle'
|
||||
description = 'Updates the build script to the latest version'
|
||||
}
|
||||
|
||||
// Parameter Deobfuscation
|
||||
|
||||
task deobfParams {
|
||||
doLast {
|
||||
|
||||
String mcpDir = "$project.gradle.gradleUserHomeDir/caches/minecraft/de/oceanlabs/mcp/mcp_$channel/$mappingsVersion"
|
||||
String mcpZIP = "$mcpDir/mcp_$channel-$mappingsVersion-${minecraftVersion}.zip"
|
||||
String paramsCSV = "$mcpDir/params.csv"
|
||||
|
||||
download.run {
|
||||
src "https://maven.minecraftforge.net/de/oceanlabs/mcp/mcp_$channel/$mappingsVersion-$minecraftVersion/mcp_$channel-$mappingsVersion-${minecraftVersion}.zip"
|
||||
dest mcpZIP
|
||||
overwrite false
|
||||
}
|
||||
|
||||
if (!file(paramsCSV).exists()) {
|
||||
println("Extracting MCP archive ...")
|
||||
unzip(mcpZIP, mcpDir)
|
||||
}
|
||||
|
||||
println("Parsing params.csv ...")
|
||||
Map<String, String> params = new HashMap<>()
|
||||
Files.lines(Paths.get(paramsCSV)).forEach { line ->
|
||||
String[] cells = line.split(",")
|
||||
if (cells.length > 2 && cells[0].matches("p_i?\\d+_\\d+_")) {
|
||||
params.put(cells[0], cells[1])
|
||||
}
|
||||
}
|
||||
|
||||
out.style(Style.Success).println("Modified ${replaceParams(file("$projectDir/src/main/java"), params)} files!")
|
||||
out.style(Style.Failure).println("Don't forget to verify that the code still works as before!\n It could be broken due to duplicate variables existing now\n or parameters taking priority over other variables.")
|
||||
}
|
||||
}
|
||||
|
||||
static int replaceParams(File file, Map<String, String> params) {
|
||||
int fileCount = 0
|
||||
|
||||
if (file.isDirectory()) {
|
||||
for (File f : file.listFiles()) {
|
||||
fileCount += replaceParams(f, params)
|
||||
}
|
||||
return fileCount
|
||||
}
|
||||
println("Visiting ${file.getName()} ...")
|
||||
try {
|
||||
String content = new String(Files.readAllBytes(file.toPath()))
|
||||
int hash = content.hashCode()
|
||||
params.forEach { key, value ->
|
||||
content = content.replaceAll(key, value)
|
||||
}
|
||||
if (hash != content.hashCode()) {
|
||||
Files.write(file.toPath(), content.getBytes("UTF-8"))
|
||||
return 1
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Credit: bitsnaps (https://gist.github.com/bitsnaps/00947f2dce66f4bbdabc67d7e7b33681)
|
||||
static unzip(String zipFileName, String outputDir) {
|
||||
byte[] buffer = new byte[16384]
|
||||
ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFileName))
|
||||
ZipEntry zipEntry = zis.getNextEntry()
|
||||
while (zipEntry != null) {
|
||||
File newFile = new File(outputDir + File.separator, zipEntry.name)
|
||||
if (zipEntry.isDirectory()) {
|
||||
if (!newFile.isDirectory() && !newFile.mkdirs()) {
|
||||
throw new IOException("Failed to create directory $newFile")
|
||||
}
|
||||
} else {
|
||||
// fix for Windows-created archives
|
||||
File parent = newFile.parentFile
|
||||
if (!parent.isDirectory() && !parent.mkdirs()) {
|
||||
throw new IOException("Failed to create directory $parent")
|
||||
}
|
||||
// write file content
|
||||
FileOutputStream fos = new FileOutputStream(newFile)
|
||||
int len = 0
|
||||
while ((len = zis.read(buffer)) > 0) {
|
||||
fos.write(buffer, 0, len)
|
||||
}
|
||||
fos.close()
|
||||
}
|
||||
zipEntry = zis.getNextEntry()
|
||||
}
|
||||
zis.closeEntry()
|
||||
zis.close()
|
||||
}
|
||||
|
||||
configure(deobfParams) {
|
||||
group = 'forgegradle'
|
||||
description = 'Rename all obfuscated parameter names inherited from Minecraft classes'
|
||||
}
|
||||
|
||||
// Dependency Deobfuscation
|
||||
|
||||
def deobf(String sourceURL) {
|
||||
try {
|
||||
URL url = new URL(sourceURL)
|
||||
String fileName = url.getFile()
|
||||
|
||||
//get rid of directories:
|
||||
int lastSlash = fileName.lastIndexOf("/")
|
||||
if (lastSlash > 0) {
|
||||
fileName = fileName.substring(lastSlash + 1)
|
||||
}
|
||||
//get rid of extension:
|
||||
if (fileName.endsWith(".jar") || fileName.endsWith(".litemod")) {
|
||||
fileName = fileName.substring(0, fileName.lastIndexOf("."))
|
||||
}
|
||||
|
||||
String hostName = url.getHost()
|
||||
if (hostName.startsWith("www.")) {
|
||||
hostName = hostName.substring(4)
|
||||
}
|
||||
List parts = Arrays.asList(hostName.split("\\."))
|
||||
Collections.reverse(parts)
|
||||
hostName = String.join(".", parts)
|
||||
|
||||
return deobf(sourceURL, "$hostName/$fileName")
|
||||
} catch (Exception e) {
|
||||
return deobf(sourceURL, "deobf/${sourceURL.hashCode()}")
|
||||
}
|
||||
}
|
||||
|
||||
// The method above is to be preferred. Use this method if the filename is not at the end of the URL.
|
||||
def deobf(String sourceURL, String rawFileName) {
|
||||
String bon2Version = "2.5.1"
|
||||
String fileName = URLDecoder.decode(rawFileName, "UTF-8")
|
||||
String cacheDir = "$project.gradle.gradleUserHomeDir/caches"
|
||||
String bon2Dir = "$cacheDir/forge_gradle/deobf"
|
||||
String bon2File = "$bon2Dir/BON2-${bon2Version}.jar"
|
||||
String obfFile = "$cacheDir/modules-2/files-2.1/${fileName}.jar"
|
||||
String deobfFile = "$cacheDir/modules-2/files-2.1/${fileName}-deobf.jar"
|
||||
|
||||
if (file(deobfFile).exists()) {
|
||||
return files(deobfFile)
|
||||
}
|
||||
|
||||
String mappingsVer
|
||||
String remoteMappings = project.hasProperty('remoteMappings') ? project.remoteMappings : 'https://raw.githubusercontent.com/MinecraftForge/FML/1.7.10/conf/'
|
||||
if (remoteMappings) {
|
||||
String id = "${forgeVersion.split("\\.")[3]}-$minecraftVersion"
|
||||
String mappingsZIP = "$cacheDir/forge_gradle/maven_downloader/de/oceanlabs/mcp/mcp_snapshot_nodoc/$id/mcp_snapshot_nodoc-${id}.zip"
|
||||
|
||||
zipMappings(mappingsZIP, remoteMappings, bon2Dir)
|
||||
|
||||
mappingsVer = "snapshot_$id"
|
||||
} else {
|
||||
mappingsVer = "${channel}_$mappingsVersion"
|
||||
}
|
||||
|
||||
download.run {
|
||||
src "http://jenkins.usrv.eu:8081/nexus/content/repositories/releases/com/github/parker8283/BON2/$bon2Version-CUSTOM/BON2-$bon2Version-CUSTOM-all.jar"
|
||||
dest bon2File
|
||||
quiet true
|
||||
overwrite false
|
||||
}
|
||||
|
||||
download.run {
|
||||
src sourceURL
|
||||
dest obfFile
|
||||
quiet true
|
||||
overwrite false
|
||||
}
|
||||
|
||||
exec {
|
||||
commandLine 'java', '-jar', bon2File, '--inputJar', obfFile, '--outputJar', deobfFile, '--mcVer', minecraftVersion, '--mappingsVer', mappingsVer, '--notch'
|
||||
workingDir bon2Dir
|
||||
standardOutput = new FileOutputStream("${deobfFile}.log")
|
||||
}
|
||||
|
||||
return files(deobfFile)
|
||||
}
|
||||
|
||||
def zipMappings(String zipPath, String url, String bon2Dir) {
|
||||
File zipFile = new File(zipPath)
|
||||
if (zipFile.exists()) {
|
||||
return
|
||||
}
|
||||
|
||||
String fieldsCache = "$bon2Dir/data/fields.csv"
|
||||
String methodsCache = "$bon2Dir/data/methods.csv"
|
||||
|
||||
download.run {
|
||||
src "${url}fields.csv"
|
||||
dest fieldsCache
|
||||
quiet true
|
||||
}
|
||||
download.run {
|
||||
src "${url}methods.csv"
|
||||
dest methodsCache
|
||||
quiet true
|
||||
}
|
||||
|
||||
zipFile.getParentFile().mkdirs()
|
||||
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile))
|
||||
|
||||
zos.putNextEntry(new ZipEntry("fields.csv"))
|
||||
Files.copy(Paths.get(fieldsCache), zos)
|
||||
zos.closeEntry()
|
||||
|
||||
zos.putNextEntry(new ZipEntry("methods.csv"))
|
||||
Files.copy(Paths.get(methodsCache), zos)
|
||||
zos.closeEntry()
|
||||
|
||||
zos.close()
|
||||
}
|
||||
|
||||
// Helper methods
|
||||
|
||||
def checkPropertyExists(String propertyName) {
|
||||
if (!project.hasProperty(propertyName)) {
|
||||
throw new GradleException("This project requires a property \"" + propertyName + "\"! Please add it your \"gradle.properties\". You can find all properties and their description here: https://github.com/GTNewHorizons/ExampleMod1.7.10/blob/main/gradle.properties")
|
||||
}
|
||||
}
|
||||
|
||||
def getFile(String relativePath) {
|
||||
return new File(projectDir, relativePath)
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
plugins {
|
||||
id("com.gtnewhorizons.gtnhconvention")
|
||||
}
|
||||
|
||||
minecraft {
|
||||
extraRunJvmArguments.add("-Dangelica.enableTestBlocks=true")
|
||||
extraRunJvmArguments.add("-Dangelica.dumpClass=true")
|
||||
// extraRunJvmArguments.addAll("-Dlegacy.debugClassLoadingSave=true")
|
||||
// extraRunJvmArguments.addAll("-Drfb.dumpLoadedClasses=true", "-Drfb.dumpLoadedClassesPerTransformer=true")
|
||||
//extraRunJvmArguments.add("-Dangelica.redirectorLogspam=true")
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
useJUnitPlatform()
|
||||
testLogging {
|
||||
events("passed", "skipped", "failed")
|
||||
}
|
||||
// On macOS ARM64, use an ARM64-compatible JVM for tests
|
||||
val isMacOsArm64 = System.getProperty("os.name").lowercase().contains("mac") &&
|
||||
System.getProperty("os.arch") == "aarch64"
|
||||
javaLauncher = javaToolchains.launcherFor {
|
||||
languageVersion = JavaLanguageVersion.of(8)
|
||||
if (isMacOsArm64) {
|
||||
vendor = JvmVendorSpec.AZUL
|
||||
}
|
||||
}
|
||||
dependsOn(tasks.extractNatives2)
|
||||
jvmArgs("-Djava.library.path=${tasks.extractNatives2.get().destinationFolder.asFile.get().path}")
|
||||
}
|
||||
|
||||
tasks.processResources {
|
||||
val projectVersion = project.version.toString()
|
||||
inputs.property("version", projectVersion)
|
||||
filesMatching("META-INF/rfb-plugin/*") {
|
||||
expand("version" to projectVersion)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register<Copy>("copyDependencies") {
|
||||
group = "Angelica"
|
||||
description = "Collect dependencies into the testDependencies folder"
|
||||
from(configurations.default)
|
||||
into("testDependencies")
|
||||
}
|
||||
|
||||
val embedOnly: Configuration by configurations
|
||||
|
||||
tasks.shadowJar {
|
||||
from(embedOnly.map(::zipTree))
|
||||
relocate("com.mitchej123", "com.mitchej123")
|
||||
relocate("org.embeddedt", "org.embeddedt")
|
||||
}
|
||||
|
||||
+140
-2
@@ -1,5 +1,143 @@
|
||||
/*
|
||||
* Add your dependencies here. Supported configurations:
|
||||
* - api("group:name:version:classifier"): if you use the types from this dependency in the public API of this mod
|
||||
* Available at runtime and compiletime for mods depending on this mod
|
||||
* - implementation("g:n:v:c"): if you need this for internal implementation details of the mod, but none of it is visible via the public API
|
||||
* Available at runtime but not compiletime for mods depending on this mod
|
||||
* - compileOnly("g:n:v:c"): if the mod you're building doesn't need this dependency during runtime at all, e.g. for optional mods
|
||||
* Not available at all for mods depending on this mod, only visible at compiletime for this mod
|
||||
* - compileOnlyApi("g:n:v:c"): like compileOnly, but also visible at compiletime for mods depending on this mod
|
||||
* Available at compiletime but not runtime for mods depending on this mod
|
||||
* - runtimeOnlyNonPublishable("g:n:v:c"): if you want to include a mod in this mod's runClient/runServer runs, but not publish it as a dependency
|
||||
* Not available at all for mods depending on this mod, only visible at runtime for this mod
|
||||
* - devOnlyNonPublishable("g:n:v:c"): a combination of runtimeOnlyNonPublishable and compileOnly for dependencies present at both compiletime and runtime,
|
||||
* but not published as Maven dependencies - useful for RFG-deobfuscated dependencies or local testing
|
||||
* - runtimeOnly("g:n:v:c"): if you don't need this at compile time, but want it to be present at runtime
|
||||
* Available at runtime for mods depending on this mod
|
||||
* - annotationProcessor("g:n:v:c"): mostly for java compiler plugins, if you know you need this, use it, otherwise don't worry
|
||||
* - testCONFIG("g:n:v:c") - replace CONFIG by one of the above (except api), same as above but for the test sources instead of main
|
||||
*
|
||||
* - shadowImplementation("g:n:v:c"): effectively the same as API, but the dependency is included in your jar under a renamed package name
|
||||
* Requires you to enable usesShadowedDependencies in gradle.properties
|
||||
*
|
||||
* - compile("g:n:v:c"): deprecated, replace with "api" (works like the old "compile") or "implementation" (can be more efficient)
|
||||
*
|
||||
* You can exclude transitive dependencies (dependencies of the chosen dependency) by appending { transitive = false } if needed,
|
||||
* but use this sparingly as it can break using your mod as another mod's dependency if you're not careful.
|
||||
*
|
||||
* To depend on obfuscated jars you can use `devOnlyNonPublishable(rfg.deobf("dep:spec:1.2.3"))` to fetch an obfuscated jar from maven,
|
||||
* or `devOnlyNonPublishable(rfg.deobf(project.files("libs/my-mod-jar.jar")))` to use a file.
|
||||
*
|
||||
* Gradle names for some of the configuration can be misleading, compileOnlyApi and runtimeOnly both get published as dependencies in Maven, but compileOnly does not.
|
||||
* The buildscript adds runtimeOnlyNonPublishable to also have a runtime dependency that's not published.
|
||||
*
|
||||
* For more details, see https://docs.gradle.org/8.0.1/userguide/java_library_plugin.html#sec:java_library_configurations_graph
|
||||
*/
|
||||
configurations {
|
||||
transformedMod // Mods that can be transformed - used for compiling angelica, but not necessary at runtime
|
||||
transformedMod.canBeConsumed = false
|
||||
transformedModCompileOnly
|
||||
transformedModCompileOnly.canBeConsumed = false
|
||||
|
||||
// Add the transformed mod dependencies to the compilation classpaths, but don't publish them in the Maven metadata
|
||||
compileClasspath.extendsFrom(transformedMod, transformedModCompileOnly)
|
||||
testCompileClasspath.extendsFrom(transformedMod, transformedModCompileOnly)
|
||||
|
||||
// Can be enabled for testing if desired
|
||||
// runtimeClasspath.extendsFrom(transformedMod)
|
||||
// testRuntimeClasspath.extendsFrom(transformedMod)
|
||||
|
||||
// Embed in JAR without relocation (compile only, shadowed into JAR)
|
||||
embedOnly
|
||||
embedOnly.canBeConsumed = false
|
||||
embedOnly.canBeResolved = true
|
||||
compileClasspath.extendsFrom(embedOnly)
|
||||
testCompileClasspath.extendsFrom(embedOnly)
|
||||
}
|
||||
|
||||
|
||||
// Exclude self-reference from all configurations - prevents transitive Angelica deps from resolving against this project
|
||||
configurations.all {
|
||||
exclude group: "com.github.GTNewHorizons", module: "Angelica"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(sourceSets.compileStubs.output)
|
||||
compileStubs(sourceSets.compileStubsStubs.output)
|
||||
compileOnly("com.github.GTNewHorizons:Hodgepodge:2.7.14:dev")
|
||||
|
||||
compileOnly("com.gtnewhorizons.retrofuturabootstrap:RetroFuturaBootstrap:1.0.7") { transitive = false }
|
||||
|
||||
compileOnly("org.projectlombok:lombok:1.18.42") { transitive = false }
|
||||
annotationProcessor("org.projectlombok:lombok:1.18.42")
|
||||
|
||||
// Iris Shaders
|
||||
compileOnly('org.jetbrains:annotations:26.0.2')
|
||||
api("com.github.GTNewHorizons:GTNHLib:0.9.0:dev")
|
||||
shadowImplementation("org.anarres:jcpp:1.4.14") // Apache 2.0
|
||||
shadowImplementation("org.taumc:glsl-transformation-lib:0.2.0-25.g3a943bb") {
|
||||
exclude module: "antlr4" // we only want to shadow the runtime module
|
||||
}
|
||||
shadowImplementation("org.antlr:antlr4-runtime:4.13.2")
|
||||
compileOnly "org.apache.ant:ant:1.8.2"
|
||||
|
||||
// Celeritas (transitive=false: deps provided by GTNHLib/runtime)
|
||||
embedOnly("org.embeddedt.celeritas:celeritas-common:2.5.2-GTNH") { transitive = false }
|
||||
embedOnly("org.embeddedt.celeritas:celeritas-lwjgl2-service:2.5.2-GTNH") { transitive = false }
|
||||
|
||||
// Because who doesn't want NEI
|
||||
devOnlyNonPublishable('com.github.GTNewHorizons:NotEnoughItems:2.8.35-GTNH:dev')
|
||||
devOnlyNonPublishable('com.github.GTNewHorizons:CodeChickenCore:1.4.7:dev')
|
||||
|
||||
// Notfine Deps
|
||||
compileOnly("thaumcraft:Thaumcraft:1.7.10-4.2.3.5:dev")
|
||||
devOnlyNonPublishable("com.github.GTNewHorizons:Baubles-Expanded:2.2.2-GTNH:dev")
|
||||
compileOnly("com.github.GTNewHorizons:twilightforest:2.7.13:dev") { transitive = false }
|
||||
compileOnly(rfg.deobf('curse.maven:witchery-69673:2234410'))
|
||||
compileOnly("com.github.GTNewHorizons:TinkersConstruct:1.14.6-GTNH:dev") { transitive = false }
|
||||
compileOnly("com.github.GTNewHorizons:Natura:2.8.9:dev")
|
||||
|
||||
compileOnly("com.github.GTNewHorizons:ThaumicHorizons:1.8.4:dev")
|
||||
|
||||
compileOnly("com.github.GTNewHorizons:Battlegear2:1.4.3:dev") { transitive = false }
|
||||
|
||||
compileOnly("com.falsepattern:chunkapi-mc1.7.10:0.5.1:api") { transitive = false }
|
||||
compileOnly("com.falsepattern:endlessids-mc1.7.10:1.5-beta0003:dev") { transitive = false }
|
||||
|
||||
compileOnly(rfg.deobf("curse.maven:extrautils-225561:2264383"))
|
||||
compileOnly(rfg.deobf("curse.maven:dynamiclights-227874:2337326"))
|
||||
|
||||
compileOnly("curse.maven:minefactory-reloaded-66672:2277486")
|
||||
|
||||
compileOnly("com.github.GTNewHorizons:NotEnoughIds:2.1.10:dev") // Mixin Version
|
||||
compileOnly("com.github.GTNewHorizons:NotEnoughIds-Legacy:1.4.7:dev") // ASM Version
|
||||
|
||||
compileOnly(rfg.deobf("curse.maven:ntm-space-1121235:6974420"))
|
||||
|
||||
compileOnly(rfg.deobf("curse.maven:campfirebackport-387444:4611675"))
|
||||
compileOnly(rfg.deobf("curse.maven:xaeros-minimap-263420:5060684"))
|
||||
compileOnly(rfg.deobf("curse.maven:security-craft-64760:2818228"))
|
||||
|
||||
// runtimeOnlyNonPublishable("com.github.GTNewHorizons:CoreTweaks:0.3.3.6-GTNH")
|
||||
// For testing alternative splash screens, can be sourced from https://github.com/MalTeeez/ModernSplash/releases
|
||||
//runtimeOnly(rfg.deobf(files("dependencies/modernsplash-1.7.10-1.2.2-dev.jar")))
|
||||
|
||||
// Hodgepodge
|
||||
transformedMod("net.industrial-craft:industrialcraft-2:2.2.828-experimental:dev")
|
||||
|
||||
// Better Crashes
|
||||
compileOnly("com.github.GTNewHorizons:BetterCrashes:1.4.0-GTNH:dev")
|
||||
|
||||
afterEvaluate {
|
||||
dependencies {
|
||||
testImplementation(platform('org.junit:junit-bom:5.14.1'))
|
||||
testImplementation('org.junit.jupiter:junit-jupiter')
|
||||
testImplementation("org.mockito:mockito-core:3.+")
|
||||
testImplementation("org.lwjgl.lwjgl:lwjgl:2.9.4-nightly-20150209")
|
||||
|
||||
testImplementation('org.junit.platform:junit-platform-engine')
|
||||
testImplementation('org.junit.platform:junit-platform-reporting')
|
||||
testImplementation('org.junit.platform:junit-platform-launcher')
|
||||
}
|
||||
}
|
||||
|
||||
compileOnly("mega:fluidlogged-mc1.7.10:0.1.2")
|
||||
}
|
||||
BIN
Binary file not shown.
@@ -0,0 +1,34 @@
|
||||
# A specification for models
|
||||
This is borrowed from [the unofficial Minecraft wiki](https://minecraft.wiki/w/Tutorials/Models) under the CC BY-NC-SA 3.0.
|
||||
|
||||
The folder `assets/<namespace>/models/block` holds the model files for all the specified variants. The names of the files can be changed, but must always correspond with the names used in the variant files.
|
||||
|
||||
* `[TAG_compound]` The root tag
|
||||
* `[TAG_string]` **parent**: Loads a different model from the given path, in form of a [resource location](https://minecraft.wiki/w/Tutorials/Models#File_path). If both `"parent"` and `"elements"` are set, the `"elements"` tag overrides the `"elements"` tag from the previous model.
|
||||
* Can be set to `"builtin/generated"` to use a model that is created out of the specified icon. Note that only the first layer is supported, and rotation can be achieved only by using block states files.
|
||||
* `[TAG_byte]` **ambientocclusion**: Whether to use [ambient occlusion](http://en.wikipedia.org/wiki/Ambient_occlusion) (`true` - default), or not (`false`). Note:only works on Parent file
|
||||
* `[TAG_object]` **display**: Holds the different places where item models are displayed.
|
||||
* `[TAG_compound]` ***Position***: Named `thirdperson_righthand`, `thirdperson_lefthand`, `firstperson_righthand`, `firstperson_lefthand`, `gui`, `head`, `ground`, or `fixed`. Place where an item model is displayed. Holds its rotation, translation and scale for the specified situation. '''fixed''' refers to item frames, while the rest are as their name states. Note that translations are applied to the model before rotations.
|
||||
* `[TAG_list]` **rotation**: Specifies the rotation of the model according to the scheme `[x, y, z]`.
|
||||
* `[TAG_list]` **translation**: Specifies the position of the model according to the scheme `[x, y, z]`. The values are clamped between -80 and 80.
|
||||
* `[TAG_list]` **scale**: Specifies the scale of the model according to the scheme `[x, y, z]`. If the value is greater than 4, it is displayed as 4.
|
||||
* `[TAG_compound]` **textures**: Holds the textures of the model, in form of a [resource location](https://minecraft.wiki/w/Tutorials/Models#File_path) or can be another texture variable.
|
||||
* `[TAG_string]` **particle**: What texture to load particles from. This texture is also used as an overlay if you are in a [nether portal](https://minecraft.wiki/w/Nether_portal), and used for [water](https://minecraft.wiki/w/water) and [lava](https://minecraft.wiki/w/Lava)'s still textures.<sup>[[1]](https://bugs.mojang.com/browse/MC-240042)</sup> This texture is also considered a texture variable that can be referenced as `"#particle"`. Note: All breaking particles from non-model blocks are hard-coded, such as for [barriers](https://minecraft.wiki/w/Barrier).
|
||||
* `[TAG_string]` ***Texture variable***: Defines a texture variable with `name` and assigns it to a texture or another variable.
|
||||
* `[TAG_list]` **elements**: Contains all the elements of the model. They can have only cubic forms. If both `"parent"` and `"elements"` are set, the `"elements"` tag overrides the `"elements"` tag from the previous model.
|
||||
* `[TAG_compound]` An element.
|
||||
* `[TAG_list]` **from**: Start point of a cuboid according to the scheme `[x, y, z]`. Values must be between -16 and 32.
|
||||
* `[TAG_list]` **to**: Stop point of a cuboid according to the scheme `[x, y, z]`. Values must be between -16 and 32.
|
||||
* `[TAG_compound]` **rotation**: Defines the rotation of an element.
|
||||
* `[TAG_list]` **origin**: Sets the center of the rotation according to the scheme `[x, y, z]`.
|
||||
* `[TAG_string]` **axis**: Specifies the direction of rotation, can be `"x"`, `"y"` or `"z"`.
|
||||
* `[TAG_float]` **angle**: Specifies the angle of rotation. Can be 45 through -45 degrees in 22.5 degree increments.
|
||||
* `[TAG_byte]` **rescale**: Specifies whether or not to scale the faces across the whole block. Can be true or false. Defaults to false.
|
||||
* `[TAG_byte]` **shade**: Defines if shadows are rendered (`true` - default), not (`false`).
|
||||
* `[TAG_compound]` **faces**: Holds all the faces of the cuboid. If a face is left out, it does not render.
|
||||
* `[TAG_compound]` ***Face***: Named `down`, `up`, `north`, `south`, `west` or `east`. Contains the properties of the specified face.
|
||||
* `[TAG_list]` **uv**: Defines the area of the texture to use according to the scheme `[x1, y1, x2, y2]`. The texture behavior is inconsistent if UV extends below 0 or above 16. If the numbers of `x1` and `x2` are swapped (e.g. from `0, 0, 16, 16` to `16, 0, 0, 16`), the texture flips. UV is optional, and if not supplied it automatically generates based on the element's position.
|
||||
* `[TAG_string]` **texture**: Specifies the texture in form of the texture variable prepended with a `#`.
|
||||
* `[TAG_string]` **cullface**: Specifies whether a face does not need to be rendered when there is a block touching it in the specified position. The position can be: `down`, `up`, `north`, `south`, `west`, or `east`. It also determines the side of the block to use the light level from for lighting the face, and if unset, defaults to the side.
|
||||
* `[TAG_int]` **rotation**: Rotates the texture clockwise by the specified number of degrees. Can be 0, 90, 180, or 270. Defaults to 0. Rotation does not affect which part of the texture is used. Instead, it amounts to permutation of the selected texture vertexes (selected implicitly, or explicitly though `uv`).
|
||||
* `[TAG_int]` **tintindex**: Determines whether to tint the texture using a hardcoded tint index. The default value, -1, indicates not to use the tint. Any other number is provided to BlockColors to get the tint value corresponding to that index. However, most blocks do not have a tint value defined (in which case white is used). Furthermore, no vanilla block currently uses multiple tint values, and thus the tint index value is ignored (as long as it is set to something other than -1); it could be used for modded blocks that need multiple distinct tint values in the same block though.
|
||||
File diff suppressed because it is too large.
Load diff
+185
-39
@@ -1,65 +1,126 @@
|
||||
# ExampleMod tag to use as Blowdryer (Spotless, etc.) settings version, leave empty to disable.
|
||||
# LOCAL to test local config updates.
|
||||
gtnh.settings.blowdryerTag = 0.2.2
|
||||
|
||||
# Human-readable mod name, available for mcmod.info population.
|
||||
modName = Angelica
|
||||
|
||||
# This is a case-sensitive string to identify your mod. Convention is to use lower case.
|
||||
# Case-sensitive identifier string, available for mcmod.info population and used for automatic mixin JSON generation.
|
||||
# Conventionally lowercase.
|
||||
modId = angelica
|
||||
|
||||
# Root package of the mod, used to find various classes in other properties,
|
||||
# mcmod.info substitution, enabling assertions in run tasks, etc.
|
||||
modGroup = com.gtnewhorizons.angelica
|
||||
|
||||
# WHY is there no version field?
|
||||
# The build script relies on git to provide a version via tags. It is super easy and will enable you to always know the
|
||||
# code base or your binary. Check out this tutorial: https://blog.mattclemente.com/2017/10/13/versioning-with-git-tags/
|
||||
# Whether to use modGroup as the maven publishing group.
|
||||
# When false, com.github.GTNewHorizons is used.
|
||||
useModGroupForPublishing = false
|
||||
|
||||
# Will update your build.gradle automatically whenever an update is available
|
||||
# Updates your build.gradle and settings.gradle automatically whenever an update is available.
|
||||
autoUpdateBuildScript = false
|
||||
|
||||
# Version of Minecraft to target
|
||||
minecraftVersion = 1.7.10
|
||||
|
||||
# Version of Minecraft Forge to target
|
||||
forgeVersion = 10.13.4.1614
|
||||
|
||||
# Specify a MCP channel and mappings version for dependency deobfuscation and the deobfParams task.
|
||||
# Specify an MCP channel for dependency deobfuscation and the deobfParams task.
|
||||
channel = stable
|
||||
|
||||
# Specify an MCP mappings version for dependency deobfuscation and the deobfParams task.
|
||||
mappingsVersion = 12
|
||||
|
||||
# Define other MCP mappings for dependency deobfuscation
|
||||
remoteMappings = https://raw.githubusercontent.com/MinecraftForge/FML/1.7.10/conf/
|
||||
# Defines other MCP mappings for dependency deobfuscation.
|
||||
remoteMappings = https\://raw.githubusercontent.com/MinecraftForge/FML/1.7.10/conf/
|
||||
|
||||
# Select a username for testing your mod with breakpoints. You may leave this empty for a random username each time you
|
||||
# restart Minecraft in development. Choose this dependent on your mod:
|
||||
# Do you need consistent player progressing (for example Thaumcraft)? -> Select a name
|
||||
# Do you need to test how your custom blocks interacts with a player that is not the owner? -> leave name empty
|
||||
# Select a default username for testing your mod. You can always override this per-run by running
|
||||
# `./gradlew runClient --username=AnotherPlayer`, or configuring this command in your IDE.
|
||||
developmentEnvironmentUserName = Developer
|
||||
|
||||
# Define a source file of your project with:
|
||||
# Enables modern Java syntax support. Valid values:
|
||||
# - false: No modern syntax, Java 8 only
|
||||
# - jabel: Jabel syntax-only support, compiles to J8 bytecode
|
||||
# - jvmDowngrader: Full modern Java via JVM Downgrader (syntax + stdlib APIs)
|
||||
# - modern: Native modern Java bytecode, no downgrading
|
||||
enableModernJavaSyntax = jvmDowngrader
|
||||
|
||||
# If set, ignores the above setting and compiles with the given toolchain. This may cause unexpected issues,
|
||||
# and should *not* be used in most situations. -1 disables this.
|
||||
# forceToolchainVersion = -1
|
||||
|
||||
# Target JVM version for JVM Downgrader bytecode downgrading.
|
||||
# Only used when enableModernJavaSyntax = jvmDowngrader
|
||||
# downgradeTargetVersion = 8
|
||||
|
||||
# Comma-separated list of Java versions for multi-release jar support (JVM Downgrader only).
|
||||
# Classes will be available in META-INF/versions/N/ for each version N in this list.
|
||||
# Default: "21,25" (J25+ gets native classes, J21-24 gets partial downgrade, J8-20 gets full downgrade).
|
||||
jvmDowngraderMultiReleaseVersions = 17, 21, 25
|
||||
|
||||
# Specifies how JVM Downgrader API stubs are provided. Options:
|
||||
# - shade: Shade minimized stubs into the jar
|
||||
# - gtnhlib: GTNHLib provides stubs at runtime (adds version constraint)
|
||||
# - external: Another dependency provides stubs (no constraint, no warning)
|
||||
# - (empty): Warning reminding you to configure stubs
|
||||
# Note: 'shade' option requires you to verify license compliance, see: https://github.com/unimined/JvmDowngrader/blob/main/LICENSE.md
|
||||
jvmDowngraderStubsProvider = gtnhlib
|
||||
|
||||
# Enables injecting missing generics into the decompiled source code for a better coding experience.
|
||||
# Turns most publicly visible List, Map, etc. into proper List<E>, Map<K, V> types.
|
||||
enableGenericInjection = true
|
||||
|
||||
# Generate a class with a String field for the mod version named as defined below.
|
||||
# If generateGradleTokenClass is empty or not missing, no such class will be generated.
|
||||
# If gradleTokenVersion is empty or missing, the field will not be present in the class.
|
||||
generateGradleTokenClass = com.gtnewhorizons.angelica.Tags
|
||||
|
||||
# Name of the token containing the project's current version to generate/replace.
|
||||
gradleTokenVersion = VERSION
|
||||
|
||||
# [DEPRECATED]
|
||||
# Multiple source files can be defined here by providing a comma-separated list: Class1.java,Class2.java,Class3.java
|
||||
# public static final String VERSION = "GRADLETOKEN_VERSION";
|
||||
# The string's content will be replaced with your mod's version when compiled. You should use this to specify your mod's
|
||||
# version in @Mod([...], version = VERSION, [...])
|
||||
# Leave these properties empty to skip individual token replacements
|
||||
replaceGradleTokenInFile = Tags.java
|
||||
gradleTokenModId = GRADLETOKEN_MODID
|
||||
gradleTokenModName = GRADLETOKEN_MODNAME
|
||||
gradleTokenVersion = GRADLETOKEN_VERSION
|
||||
gradleTokenGroupName = GRADLETOKEN_GROUPNAME
|
||||
# version in @Mod([...], version = VERSION, [...]).
|
||||
# Leave these properties empty to skip individual token replacements.
|
||||
# replaceGradleTokenInFile =
|
||||
|
||||
# In case your mod provides an API for other mods to implement you may declare its package here. Otherwise, you can
|
||||
# leave this property empty.
|
||||
# Example value: apiPackage = api + modGroup = com.myname.mymodid -> com.myname.mymodid.api
|
||||
apiPackage =
|
||||
# Example value: (apiPackage = api) + (modGroup = com.myname.mymodid) -> com.myname.mymodid.api
|
||||
apiPackage = api
|
||||
|
||||
# Specify the configuration file for Forge's access transformers here. It must be placed into /src/main/resources/META-INF/
|
||||
# Example value: mymodid_at.cfg
|
||||
accessTransformersFile =
|
||||
# There can be multiple files in a space-separated list.
|
||||
# Example value: mymodid_at.cfg nei_at.cfg
|
||||
accessTransformersFile = angelica_at.cfg notfine_at.cfg archaicfix_at.cfg mcpatcherforge_at.cfg
|
||||
|
||||
# Provides setup for Mixins if enabled. If you don't know what mixins are: Keep it disabled!
|
||||
usesMixins = false
|
||||
# Adds some debug arguments like verbose output and export
|
||||
usesMixins = true
|
||||
|
||||
# Set to a non-empty string to configure mixins in a separate source set under src/VALUE, instead of src/main.
|
||||
# This can speed up compile times thanks to not running the mixin annotation processor on all input sources.
|
||||
# Mixin classes will have access to "main" classes, but not the other way around.
|
||||
separateMixinSourceSet = mixin
|
||||
|
||||
# Adds some debug arguments like verbose output and class export.
|
||||
usesMixinDebug = false
|
||||
|
||||
# Specify the location of your implementation of IMixinConfigPlugin. Leave it empty otherwise.
|
||||
mixinPlugin =
|
||||
# Specify the package that contains all of your Mixins. You may only place Mixins in this package or the build will fail!
|
||||
mixinsPackage =
|
||||
|
||||
# Specify the package that contains all of your Mixins. The package must exist or
|
||||
# the build will fail. If you have a package property defined in your mixins.<modid>.json,
|
||||
# it must match with this or the build will fail.
|
||||
mixinsPackage = mixins
|
||||
|
||||
# Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin!
|
||||
# This parameter is for legacy compatibility only
|
||||
# Example value: coreModClass = asm.FMLPlugin + modGroup = com.myname.mymodid -> com.myname.mymodid.asm.FMLPlugin
|
||||
coreModClass =
|
||||
# Example value: (coreModClass = asm.FMLPlugin) + (modGroup = com.myname.mymodid) -> com.myname.mymodid.asm.FMLPlugin
|
||||
coreModClass = loading.AngelicaTweaker
|
||||
|
||||
# If your project is only a consolidation of mixins or a core mod and does NOT contain a 'normal' mod ( = some class
|
||||
# that is annotated with @Mod) you want this to be true. When in doubt: leave it on false!
|
||||
containsMixinsAndOrCoreModOnly = false
|
||||
@@ -67,18 +128,103 @@ containsMixinsAndOrCoreModOnly = false
|
||||
# Enables Mixins even if this mod doesn't use them, useful if one of the dependencies uses mixins.
|
||||
forceEnableMixins = false
|
||||
|
||||
# If enabled, you may use 'shadowCompile' for dependencies. They will be integrated in your jar. It is your
|
||||
# responsibility check the licence and request permission for distribution, if required.
|
||||
usesShadowedDependencies = false
|
||||
# If enabled, you may use 'shadowCompile' for dependencies. They will be integrated into your jar. It is your
|
||||
# responsibility to check the license and request permission for distribution if required.
|
||||
usesShadowedDependencies = true
|
||||
|
||||
# Optional parameter to customize the produced artifacts. Use this to preserver artifact naming when migrating older
|
||||
# If disabled, won't remove unused classes from shadowed dependencies. Some libraries use reflection to access
|
||||
# their own classes, making the minimization unreliable.
|
||||
minimizeShadowedDependencies = true
|
||||
|
||||
# If disabled, won't rename the shadowed classes.
|
||||
relocateShadowedDependencies = true
|
||||
|
||||
# Adds CurseMaven, Modrinth, and some more well-known 1.7.10 repositories.
|
||||
includeWellKnownRepositories = true
|
||||
|
||||
# A list of repositories to exclude from the includeWellKnownRepositories setting. Should be a space separated
|
||||
# list of strings, with the acceptable keys being(case does not matter):
|
||||
# cursemaven
|
||||
# modrinth
|
||||
excludeWellKnownRepositories =
|
||||
|
||||
# Change these to your Maven coordinates if you want to publish to a custom Maven repository instead of the default GTNH Maven.
|
||||
# Authenticate with the MAVEN_USER and MAVEN_PASSWORD environment variables.
|
||||
# If you need a more complex setup disable maven publishing here and add a publishing repository to addon.gradle.
|
||||
usesMavenPublishing = true
|
||||
|
||||
# Maven repository to publish the mod to.
|
||||
# mavenPublishUrl = https\://nexus.gtnewhorizons.com/repository/releases/
|
||||
|
||||
# Publishing to Modrinth requires you to set the MODRINTH_TOKEN environment variable to your current Modrinth API token.
|
||||
#
|
||||
# The project's ID on Modrinth. Can be either the slug or the ID.
|
||||
# Leave this empty if you don't want to publish to Modrinth.
|
||||
modrinthProjectId = angelica
|
||||
|
||||
# The project's relations on Modrinth. You can use this to refer to other projects on Modrinth.
|
||||
# Syntax: scope1-type1:name1;scope2-type2:name2;...
|
||||
# Where scope can be one of [required, optional, incompatible, embedded],
|
||||
# type can be one of [project, version],
|
||||
# and the name is the Modrinth project or version slug/id of the other mod.
|
||||
# Example: required-project:fplib;optional-project:gasstation;incompatible-project:gregtech
|
||||
# Note: UniMixins is automatically set as a required dependency if usesMixins = true.
|
||||
modrinthRelations = required-project\:gtnhlib
|
||||
|
||||
# Publishing to CurseForge requires you to set the CURSEFORGE_TOKEN environment variable to one of your CurseForge API tokens.
|
||||
#
|
||||
# The project's numeric ID on CurseForge. You can find this in the About Project box.
|
||||
# Leave this empty if you don't want to publish on CurseForge.
|
||||
curseForgeProjectId = 988067
|
||||
|
||||
# The project's relations on CurseForge. You can use this to refer to other projects on CurseForge.
|
||||
# Syntax: type1:name1;type2:name2;...
|
||||
# Where type can be one of [requiredDependency, embeddedLibrary, optionalDependency, tool, incompatible],
|
||||
# and the name is the CurseForge project slug of the other mod.
|
||||
# Example: requiredDependency:railcraft;embeddedLibrary:cofhlib;incompatible:buildcraft
|
||||
# Note: UniMixins is automatically set as a required dependency if usesMixins = true.
|
||||
curseForgeRelations = requiredDependency\:gtnhlib
|
||||
|
||||
# Optional parameter to customize the produced artifacts. Use this to preserve artifact naming when migrating older
|
||||
# projects. New projects should not use this parameter.
|
||||
#customArchiveBaseName =
|
||||
# customArchiveBaseName =
|
||||
|
||||
# Optional parameter to prevent the source code from being published
|
||||
# noPublishedSources =
|
||||
# Optional parameter to customize the default working directory used by the runClient* tasks. Relative to the project directory.
|
||||
# runClientWorkingDirectory = run/client
|
||||
|
||||
# Uncomment this to disable spotless checks
|
||||
# Optional parameter to customize the default working directory used by the runServer* tasks. Relative to the project directory.
|
||||
# runServerWorkingDirectory = run/server
|
||||
|
||||
# Optional parameter to have the build automatically fail if an illegal version is used.
|
||||
# This can be useful if you e.g. only want to allow versions in the form of '1.1.xxx'.
|
||||
# The check is ONLY performed if the version is a git tag.
|
||||
# Note: the specified string must be escaped, so e.g. 1\\.1\\.\\d+ instead of 1\.1\.\d+
|
||||
# versionPattern =
|
||||
|
||||
# Uncomment to prevent the source code from being published.
|
||||
# noPublishedSources = true
|
||||
|
||||
# Uncomment this to disable Spotless checks.
|
||||
# This should only be uncommented to keep it easier to sync with upstream/other forks.
|
||||
# That is, if there is no other active fork/upstream, NEVER change this.
|
||||
# disableSpotless = true
|
||||
disableSpotless = true
|
||||
|
||||
# Uncomment this to disable Checkstyle checks (currently wildcard import check).
|
||||
# disableCheckstyle = true
|
||||
|
||||
# Override the IDEA build type. Valid values are: "" (leave blank, do not override), "idea" (force use native IDEA build), "gradle"
|
||||
# (force use delegated build).
|
||||
# This is meant to be set in $HOME/.gradle/gradle.properties.
|
||||
# e.g. add "systemProp.org.gradle.project.ideaOverrideBuildType=idea" will override the build type to be native build.
|
||||
# WARNING: If you do use this option, it will overwrite whatever you have in your existing projects. This might not be what you want!
|
||||
# Usually there is no need to uncomment this here as other developers do not necessarily use the same build type as you.
|
||||
# ideaOverrideBuildType = idea
|
||||
|
||||
# Whether IDEA should run spotless checks when pressing the Build button.
|
||||
# This is meant to be set in $HOME/.gradle/gradle.properties.
|
||||
# ideaCheckSpotlessOnBuild = true
|
||||
|
||||
# Non-GTNH properties
|
||||
org.gradle.configuration-cache = true
|
||||
org.gradle.jvmargs = -Xmx2g
|
||||
org.gradle.parallel = true
|
||||
@@ -0,0 +1,12 @@
|
||||
#This file is generated by updateDaemonJvm
|
||||
toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/c5ee947fbfb70bc347d8d531e3a578c4/redirect
|
||||
toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/5ee463876563a46fff651cce1bc53a4c/redirect
|
||||
toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/c5ee947fbfb70bc347d8d531e3a578c4/redirect
|
||||
toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/5ee463876563a46fff651cce1bc53a4c/redirect
|
||||
toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/e1118b4c7c2858d28154d086dbff010e/redirect
|
||||
toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/59a9771cad43219260d9aac9a8ec4d6a/redirect
|
||||
toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/c5ee947fbfb70bc347d8d531e3a578c4/redirect
|
||||
toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/5ee463876563a46fff651cce1bc53a4c/redirect
|
||||
toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/832229f0f6f0be60ed817c5a5e5848eb/redirect
|
||||
toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/b96cb7670c095245220e7d01d5927b58/redirect
|
||||
toolchainVersion=25
|
||||
Vendored
BIN
Binary file not shown.
+3
-1
@@ -1,5 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env sh
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
# Copyright © 2015 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -15,80 +15,114 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# 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.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# 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"'
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# 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.
|
||||
MAX_FD="maximum"
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
@@ -97,92 +131,118 @@ Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
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.
|
||||
JAVACMD=java
|
||||
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
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# 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"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
Vendored
+27
-34
@@ -13,8 +13,10 @@
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@@ -25,10 +27,14 @@
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@@ -37,13 +43,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
@@ -51,48 +57,35 @@ goto fail
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 5.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
Executable
+2
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
magick convert logo-1x.png -scale 200% \( +clone -background black -shadow 60x6+0+0 \) +swap -background none -layers merge logo-readme.png
|
||||
+22
-1
@@ -1,5 +1,26 @@
|
||||
// Add any additional repositories for your dependencies here
|
||||
|
||||
repositories {
|
||||
|
||||
maven {
|
||||
name = 'mavenpattern'
|
||||
url = 'https://mvn.falsepattern.com/releases'
|
||||
content {
|
||||
includeGroup 'com.falsepattern'
|
||||
}
|
||||
}
|
||||
maven {
|
||||
name = 'mega'
|
||||
url = 'https://mvn.falsepattern.com/gtmega_releases/'
|
||||
content {
|
||||
includeGroup 'mega'
|
||||
}
|
||||
}
|
||||
maven {
|
||||
name = 'taumc'
|
||||
url = 'https://maven.taumc.org/releases'
|
||||
content {
|
||||
includeGroup 'org.taumc'
|
||||
}
|
||||
}
|
||||
mavenLocal()
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
plugins {
|
||||
id 'com.diffplug.blowdryerSetup' version '1.6.0'
|
||||
}
|
||||
|
||||
apply plugin: 'com.diffplug.blowdryerSetup'
|
||||
|
||||
blowdryerSetup {
|
||||
github('GTNewHorizons/ExampleMod1.7.10', 'tag', '0.1.5')
|
||||
//devLocal '.' // Use this when testing config updates locally
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
maven {
|
||||
// RetroFuturaGradle
|
||||
name = "GTNH Maven"
|
||||
url = uri("https://nexus.gtnewhorizons.com/repository/public/")
|
||||
mavenContent {
|
||||
includeGroup("com.gtnewhorizons")
|
||||
includeGroupByRegex("com\\.gtnewhorizons\\..+")
|
||||
}
|
||||
}
|
||||
gradlePluginPortal()
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id("com.gtnewhorizons.gtnhsettingsconvention") version("2.0.18")
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package net.minecraft.client.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ModelBase {
|
||||
public List boxList;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package net.minecraft.client.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ModelRenderer {
|
||||
|
||||
public List childModels;
|
||||
|
||||
public void resetDisplayList() {}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package net.minecraft.client.renderer;
|
||||
|
||||
public class EntityRenderer {
|
||||
|
||||
public static int anaglyphField;
|
||||
public static boolean anaglyphEnable;
|
||||
|
||||
/**
|
||||
* Render player hand
|
||||
*/
|
||||
public void renderHand(float p_78476_1_, int p_78476_2_) {}
|
||||
|
||||
public void renderWorld(float f, long l) {}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package net.minecraft.client.renderer;
|
||||
|
||||
public class RenderGlobal {
|
||||
|
||||
public WorldRenderer[] worldRenderers;
|
||||
|
||||
public void loadRenderers() {}
|
||||
}
|
||||
@@ -1,180 +0,0 @@
|
||||
package net.minecraft.client.renderer;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.ShortBuffer;
|
||||
import net.minecraft.client.shader.TesselatorVertexState;
|
||||
|
||||
public class Tessellator {
|
||||
private static int nativeBufferSize;
|
||||
private static int trivertsInBuffer;
|
||||
public static boolean renderingWorldRenderer;
|
||||
public boolean defaultTexture;
|
||||
private int rawBufferSize;
|
||||
public int textureID;
|
||||
|
||||
/** The byte buffer used for GL allocation. */
|
||||
public ByteBuffer byteBuffer;
|
||||
/** The same memory as byteBuffer, but referenced as an integer buffer. */
|
||||
public IntBuffer intBuffer;
|
||||
/** The same memory as byteBuffer, but referenced as an float buffer. */
|
||||
public FloatBuffer floatBuffer;
|
||||
/** The same memory as byteBuffer, but referenced as an short buffer. */
|
||||
public ShortBuffer shortBuffer;
|
||||
/** Raw integer array. */
|
||||
public int[] rawBuffer;
|
||||
/** The number of vertices to be drawn in the next draw call. Reset to 0 between draw calls. */
|
||||
public int vertexCount;
|
||||
/** The first coordinate to be used for the texture. */
|
||||
public double textureU;
|
||||
/** The second coordinate to be used for the texture. */
|
||||
public double textureV;
|
||||
|
||||
public int brightness;
|
||||
/** The color (RGBA) value to be used for the following draw call. */
|
||||
public int color;
|
||||
/** Whether the current draw object for this tessellator has color values. */
|
||||
public boolean hasColor;
|
||||
/** Whether the current draw object for this tessellator has texture coordinates. */
|
||||
public boolean hasTexture;
|
||||
|
||||
public boolean hasBrightness;
|
||||
/** Whether the current draw object for this tessellator has normal values. */
|
||||
public boolean hasNormals;
|
||||
/** The index into the raw buffer to be used for the next data. */
|
||||
public int rawBufferIndex;
|
||||
/**
|
||||
* The number of vertices manually added to the given draw call. This differs from vertexCount because it adds extra
|
||||
* vertices when converting quads to triangles.
|
||||
*/
|
||||
public int addedVertices;
|
||||
/** Disables all color information for the following draw call. */
|
||||
public boolean isColorDisabled;
|
||||
/** The draw mode currently being used by the tessellator. */
|
||||
public int drawMode;
|
||||
/** An offset to be applied along the x-axis for all vertices in this draw call. */
|
||||
public double xOffset;
|
||||
/** An offset to be applied along the y-axis for all vertices in this draw call. */
|
||||
public double yOffset;
|
||||
/** An offset to be applied along the z-axis for all vertices in this draw call. */
|
||||
public double zOffset;
|
||||
/** The normal to be applied to the face being drawn. */
|
||||
public int normal;
|
||||
/** The static instance of the Tessellator. */
|
||||
public static final Tessellator instance = new Tessellator();
|
||||
/** Whether this tessellator is currently in draw mode. */
|
||||
public boolean isDrawing;
|
||||
/** The size of the buffers used (in integers). */
|
||||
public int bufferSize;
|
||||
|
||||
public float midTextureU;
|
||||
public float midTextureV;
|
||||
public float normalX;
|
||||
public float normalY;
|
||||
public float normalZ;
|
||||
public float[] vertexPos = new float[16];
|
||||
|
||||
private Tessellator(int p_i1250_1_) {}
|
||||
|
||||
public Tessellator() {}
|
||||
|
||||
/**
|
||||
* Draws the data set up in this tessellator and resets the state to prepare for new drawing.
|
||||
*/
|
||||
public int draw() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public TesselatorVertexState getVertexState(float p_147564_1_, float p_147564_2_, float p_147564_3_) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setVertexState(TesselatorVertexState p_147565_1_) {}
|
||||
|
||||
/**
|
||||
* Clears the tessellator state in preparation for new drawing.
|
||||
*/
|
||||
public void reset() {}
|
||||
|
||||
/**
|
||||
* Sets draw mode in the tessellator to draw quads.
|
||||
*/
|
||||
public void startDrawingQuads() {}
|
||||
|
||||
/**
|
||||
* Resets tessellator state and prepares for drawing (with the specified draw mode).
|
||||
*/
|
||||
public void startDrawing(int p_78371_1_) {}
|
||||
|
||||
/**
|
||||
* Sets the texture coordinates.
|
||||
*/
|
||||
public void setTextureUV(double p_78385_1_, double p_78385_3_) {}
|
||||
|
||||
public void setBrightness(int p_78380_1_) {}
|
||||
|
||||
/**
|
||||
* Sets the RGB values as specified, converting from floats between 0 and 1 to integers from 0-255.
|
||||
*/
|
||||
public void setColorOpaque_F(float p_78386_1_, float p_78386_2_, float p_78386_3_) {}
|
||||
|
||||
/**
|
||||
* Sets the RGBA values for the color, converting from floats between 0 and 1 to integers from 0-255.
|
||||
*/
|
||||
public void setColorRGBA_F(float p_78369_1_, float p_78369_2_, float p_78369_3_, float p_78369_4_) {}
|
||||
|
||||
/**
|
||||
* Sets the RGB values as specified, and sets alpha to opaque.
|
||||
*/
|
||||
public void setColorOpaque(int p_78376_1_, int p_78376_2_, int p_78376_3_) {}
|
||||
|
||||
/**
|
||||
* Sets the RGBA values for the color. Also clamps them to 0-255.
|
||||
*/
|
||||
public void setColorRGBA(int p_78370_1_, int p_78370_2_, int p_78370_3_, int p_78370_4_) {}
|
||||
|
||||
public void func_154352_a(byte p_154352_1_, byte p_154352_2_, byte p_154352_3_) {}
|
||||
|
||||
/**
|
||||
* Adds a vertex specifying both x,y,z and the texture u,v for it.
|
||||
*/
|
||||
public void addVertexWithUV(
|
||||
double p_78374_1_, double p_78374_3_, double p_78374_5_, double p_78374_7_, double p_78374_9_) {}
|
||||
|
||||
/**
|
||||
* Adds a vertex with the specified x,y,z to the current draw call. It will trigger a draw() if the buffer gets
|
||||
* full.
|
||||
*/
|
||||
public void addVertex(double p_78377_1_, double p_78377_3_, double p_78377_5_) {}
|
||||
|
||||
/**
|
||||
* Sets the color to the given opaque value (stored as byte values packed in an integer).
|
||||
*/
|
||||
public void setColorOpaque_I(int p_78378_1_) {}
|
||||
|
||||
/**
|
||||
* Sets the color to the given color (packed as bytes in integer) and alpha values.
|
||||
*/
|
||||
public void setColorRGBA_I(int p_78384_1_, int p_78384_2_) {}
|
||||
|
||||
/**
|
||||
* Disables colors for the current draw call.
|
||||
*/
|
||||
public void disableColor() {}
|
||||
|
||||
/**
|
||||
* Sets the normal for the current draw call.
|
||||
*/
|
||||
public void setNormal(float p_78375_1_, float p_78375_2_, float p_78375_3_) {}
|
||||
|
||||
/**
|
||||
* Sets the translation for all vertices in the current draw call.
|
||||
*/
|
||||
public void setTranslation(double p_78373_1_, double p_78373_3_, double p_78373_5_) {}
|
||||
|
||||
/**
|
||||
* Offsets the translation for all vertices in the current draw call.
|
||||
*/
|
||||
public void addTranslation(float p_78372_1_, float p_78372_2_, float p_78372_3_) {}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package net.minecraft.client.renderer;
|
||||
|
||||
import net.minecraft.client.renderer.culling.ICamera;
|
||||
|
||||
public class WorldRenderer {
|
||||
public boolean isInFrustum;
|
||||
|
||||
public boolean skipAllRenderPasses() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void updateInFrustum(ICamera frustrum) {}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package net.minecraft.client.renderer.culling;
|
||||
|
||||
public class Frustrum implements ICamera {
|
||||
|
||||
public void setPosition(double x, double y, double z) {}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
package net.minecraft.client.renderer.culling;
|
||||
|
||||
public interface ICamera {}
|
||||
@@ -1,3 +0,0 @@
|
||||
package net.minecraft.client.renderer.entity;
|
||||
|
||||
public abstract class Render {}
|
||||
@@ -1,10 +0,0 @@
|
||||
package net.minecraft.client.renderer.entity;
|
||||
|
||||
import net.minecraft.client.model.ModelBase;
|
||||
|
||||
public abstract class RendererLivingEntity extends Render {
|
||||
|
||||
public ModelBase mainModel;
|
||||
/** The model to be used during the render passes. */
|
||||
public ModelBase renderPassModel;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package net.minecraft.client.renderer.texture;
|
||||
|
||||
import com.gtnewhorizons.angelica.client.MultiTexID;
|
||||
|
||||
public abstract class AbstractTexture implements ITextureObject {
|
||||
|
||||
public int glTextureId = -1;
|
||||
public MultiTexID multiTex;
|
||||
|
||||
public int getGlTextureId() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public MultiTexID getMultiTexID() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package net.minecraft.client.renderer.texture;
|
||||
|
||||
public class DynamicTexture extends AbstractTexture {
|
||||
public DynamicTexture(int i, int i1) {
|
||||
super();
|
||||
}
|
||||
|
||||
public int[] getTextureData() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void updateDynamicTexture() {}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package net.minecraft.client.renderer.texture;
|
||||
|
||||
import com.gtnewhorizons.angelica.client.MultiTexID;
|
||||
|
||||
public interface ITextureObject {
|
||||
|
||||
MultiTexID getMultiTexID();
|
||||
|
||||
int getGlTextureId();
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package net.minecraft.client.renderer.texture;
|
||||
|
||||
public class TextureAtlasSprite {
|
||||
|
||||
public boolean useAnisotropicFiltering;
|
||||
|
||||
public void updateAnimation() {}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package net.minecraft.client.renderer.texture;
|
||||
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public class TextureMap extends AbstractTexture {
|
||||
|
||||
public static ResourceLocation locationBlocksTexture;
|
||||
public int atlasWidth;
|
||||
public int atlasHeight;
|
||||
|
||||
public int getTextureType() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public ResourceLocation completeResourceLocation(ResourceLocation resourceLocation, int i) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
Stubs for the compile stubs
|
||||
@@ -1,3 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.client;
|
||||
|
||||
public class MultiTexID {}
|
||||
@@ -1,3 +0,0 @@
|
||||
package net.minecraft.client.shader;
|
||||
|
||||
public class TesselatorVertexState {}
|
||||
@@ -1,3 +0,0 @@
|
||||
package net.minecraft.util;
|
||||
|
||||
public class ResourceLocation {}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.gtnewhorizons.angelica;
|
||||
|
||||
import com.gtnewhorizon.gtnhmixins.ILateMixinLoader;
|
||||
import com.gtnewhorizon.gtnhmixins.LateMixin;
|
||||
import com.gtnewhorizon.gtnhmixins.builders.IMixins;
|
||||
import com.gtnewhorizons.angelica.mixins.Mixins;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@LateMixin
|
||||
@SuppressWarnings("unused")
|
||||
public class AngelicaLateMixins implements ILateMixinLoader {
|
||||
|
||||
@Override
|
||||
public String getMixinConfig() {
|
||||
int v = Runtime.version().feature();
|
||||
if (v >= 21) return "mixins.angelica.late.j21.json";
|
||||
if (v >= 17) return "mixins.angelica.late.j17.json";
|
||||
return "mixins.angelica.late.json";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getMixins(Set<String> loadedMods) {
|
||||
return IMixins.getLateMixins(Mixins.class, loadedMods);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.gtnewhorizons.angelica;
|
||||
|
||||
import static com.gtnewhorizons.angelica.AngelicaMod.MOD_ID;
|
||||
|
||||
import com.gtnewhorizons.angelica.common.BlockError;
|
||||
import com.gtnewhorizons.angelica.compat.ModStatus;
|
||||
import com.gtnewhorizons.angelica.proxy.CommonProxy;
|
||||
import com.gtnewhorizons.angelica.utils.AnimationMode;
|
||||
import com.gtnewhorizons.angelica.utils.ManagedEnum;
|
||||
import cpw.mods.fml.common.Mod;
|
||||
import cpw.mods.fml.common.SidedProxy;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import cpw.mods.fml.common.event.FMLInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
|
||||
|
||||
@Mod(
|
||||
modid = MOD_ID,
|
||||
name = "Angelica",
|
||||
version = Tags.VERSION,
|
||||
dependencies = """
|
||||
required-after:gtnhlib@[0.8.21,);\
|
||||
before:lwjgl3ify@[1.5.3,);\
|
||||
after:hodgepodge@[2.4.4,);\
|
||||
after:CodeChickenCore@[1.2.0,);\
|
||||
after:archaicfix@[0.7.0,);\
|
||||
""",
|
||||
acceptedMinecraftVersions = "[1.7.10]",
|
||||
acceptableRemoteVersions = "*",
|
||||
guiFactory = "com.gtnewhorizons.angelica.config.AngelicaGuiConfigFactory")
|
||||
public class AngelicaMod {
|
||||
public static final String MOD_ID = "angelica";
|
||||
public static final Logger LOGGER = LogManager.getLogger("Angelica");
|
||||
|
||||
@SidedProxy(clientSide = "com.gtnewhorizons.angelica.proxy.ClientProxy", serverSide = "com.gtnewhorizons.angelica.proxy.CommonProxy")
|
||||
public static CommonProxy proxy;
|
||||
|
||||
public static final boolean lwjglDebug = Boolean.parseBoolean(System.getProperty("org.lwjgl.util.Debug", "false"));
|
||||
|
||||
public static final ManagedEnum<AnimationMode> animationsMode = new ManagedEnum<>(AnimationMode.VISIBLE_ONLY);
|
||||
|
||||
public static BlockError blockError;
|
||||
|
||||
@Mod.EventHandler
|
||||
public void preInit(FMLPreInitializationEvent event) {
|
||||
ModStatus.preInit();
|
||||
proxy.preInit(event);
|
||||
blockError = new BlockError();
|
||||
}
|
||||
|
||||
@Mod.EventHandler
|
||||
public void init(FMLInitializationEvent event) {
|
||||
proxy.init(event);
|
||||
}
|
||||
|
||||
@Mod.EventHandler
|
||||
public void postInit(FMLPostInitializationEvent event) {
|
||||
proxy.postInit(event);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.gtnewhorizons.angelica;
|
||||
|
||||
// Use this class for Strings only. Do not import any classes here. It will lead to issues with Mixins if in use!
|
||||
|
||||
public class Tags {
|
||||
|
||||
// GRADLETOKEN_* will be replaced by your configuration values at build time
|
||||
public static final String MODID = "GRADLETOKEN_MODID";
|
||||
public static final String MODNAME = "GRADLETOKEN_MODNAME";
|
||||
public static final String VERSION = "GRADLETOKEN_VERSION";
|
||||
public static final String GROUPNAME = "GRADLETOKEN_GROUPNAME";
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.gtnewhorizons.angelica.api;
|
||||
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public interface IBlockAccessExtended extends IBlockAccess {
|
||||
World getWorld();
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.gtnewhorizons.angelica.api;
|
||||
|
||||
/**
|
||||
* To be used for modded items that don't have blocks. Baubles for example.
|
||||
*/
|
||||
public interface IDynamicLightProducer {
|
||||
int getLuminance();
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.gtnewhorizons.angelica.api;
|
||||
|
||||
import com.gtnewhorizons.angelica.mixins.interfaces.ITexturesCache;
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.SpriteExtension;
|
||||
import net.minecraft.client.renderer.RenderBlocks;
|
||||
import net.minecraft.util.IIcon;
|
||||
|
||||
/**
|
||||
* Exposes a method to the API that allow mods to add texture update compat
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class TextureServices {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static void updateBlockTextureAnimation(IIcon icon, RenderBlocks renderBlocks) {
|
||||
if (renderBlocks instanceof ITexturesCache texturesCache) {
|
||||
texturesCache.getRenderedTextures().add(icon);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static void updateTextureAnimation(IIcon icon) {
|
||||
if (icon instanceof SpriteExtension ext) {
|
||||
ext.celeritas$markActive();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.gtnewhorizons.angelica.api;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.TYPE;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* Marks an ISBRH as thread-safe, allowing Angelica to run it off-thread.
|
||||
*
|
||||
* <p>Note: Any tessellator access <i>must</i> be done within the methods of the ISBRH and not cached in the class.</p>
|
||||
*/
|
||||
@Documented
|
||||
@Target({ TYPE })
|
||||
@Retention(RUNTIME)
|
||||
public @interface ThreadSafeISBRH {
|
||||
/**
|
||||
* Specifies whether Angelica should create a thread local instance of the class for each thread.
|
||||
* <ul>
|
||||
* <li>If this is set to <tt>true</tt>, a new instance will be created using the default constructor on each thread.</li>
|
||||
* <ul>
|
||||
* <li>Note: If your renderer requires arguments to the constructor, do <i>not</i> use this annotation;
|
||||
* instead use the {@link ThreadSafeISBRHFactory} interface and implement the {@link ThreadSafeISBRHFactory#newInstance} method. </li>
|
||||
* </ul>
|
||||
* <li>If this is set to <tt>false</tt>, the main thread instance will be used on all threads.
|
||||
* Use this option if your renderer class has no state, and can be safely used from multiple threads as is.</li>
|
||||
* <ul>
|
||||
* <li>No state/non final variables should be stored in the ISBRH as it is not guaranteed to be thread safe.</li>
|
||||
* </ul>
|
||||
* </ul>
|
||||
*/
|
||||
boolean perThread();
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.gtnewhorizons.angelica.api;
|
||||
|
||||
import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler;
|
||||
|
||||
/**
|
||||
* Marks an ISBRH as thread-safe using a thread local instance, allowing Angelica to run it off-thread.
|
||||
* Use this when your ISBRH uses a non-default constructor.
|
||||
* <p>To avoid a hard dependency on Angelica, you will likely want to mark this as an optional interface using:</p>
|
||||
* <pre>
|
||||
* @Optional.Interface(modid = "angelica", iface = "com.gtnewhorizons.angelica.api.ThreadSafeISBRHFactory")
|
||||
* </pre>
|
||||
*
|
||||
* <p><b>Notes</b></p>
|
||||
* <ul>
|
||||
* <li>Any tessellator access <i>must</i> be done within the methods of the ISBRH and not cached in the class.</li>
|
||||
* <li>If your class uses a default constructor or is thread-safe by default, consider using the simpler {@link ThreadSafeISBRH}
|
||||
* annotation instead.
|
||||
* </ul>
|
||||
*/
|
||||
public interface ThreadSafeISBRHFactory extends ISimpleBlockRenderingHandler {
|
||||
ThreadSafeISBRHFactory newInstance();
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.client;
|
||||
|
||||
import net.minecraft.client.renderer.texture.AbstractTexture;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
|
||||
public class DefaultTexture extends AbstractTexture {
|
||||
|
||||
public DefaultTexture() {
|
||||
loadTexture(null);
|
||||
}
|
||||
|
||||
public void loadTexture(IResourceManager resourcemanager) {
|
||||
int[] aint = ShadersTex.createAIntImage(1, 0xFFFFFFFF);
|
||||
ShadersTex.setupTexture(this.getMultiTexID(), aint, 1, 1, false, false);
|
||||
}
|
||||
}
|
||||
@@ -1,354 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.client;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.settings.GameSettings;
|
||||
import org.lwjgl.Sys;
|
||||
|
||||
public class GuiShaders extends GuiScreen {
|
||||
/** This GUI's parent GUI. */
|
||||
protected GuiScreen parentGui;
|
||||
|
||||
private int updateTimer = -1;
|
||||
public boolean needReinit;
|
||||
|
||||
/*
|
||||
private class GuiListShaderpacks {
|
||||
int posX,posY,sizeX,sizeY;
|
||||
int viewPosY;
|
||||
int itemHeight = 20;
|
||||
int selection;
|
||||
ArrayList<String> listShaderpacks;
|
||||
public void draw() {
|
||||
Tessellator tess = Tessellator.instance;
|
||||
int listSize = listShaderpacks.size();
|
||||
int i,j;
|
||||
for (i=viewPosY/itemHeight, j=Math.min((viewPosY+sizeY)/itemHeight,listSize); i<j; ++i)
|
||||
{
|
||||
int itemY = posY-viewPosY+itemHeight*i;
|
||||
boolean selected = i==selection;
|
||||
tess.startDrawingQuads();
|
||||
tess.setColorRGBA(0,0,selected?128:0,128);
|
||||
tess.addVertex(posX,itemY,0);
|
||||
tess.addVertex(posX,itemY+itemHeight,0);
|
||||
tess.addVertex(posX+sizeX,itemY+itemHeight,0);
|
||||
tess.addVertex(posX+sizeX,itemY,0);
|
||||
tess.draw();
|
||||
field_146289_q.drawString(listShaderpacks.get(i), posX, itemY, 0xFFFFFFFF, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
private GuiListShaderpacks guiListShaderpacks;
|
||||
*/
|
||||
|
||||
private GuiSlotShaders shaderList;
|
||||
|
||||
/** This GUI's 'Done' button. */
|
||||
// private GuiSmallButton doneButton;
|
||||
|
||||
public GuiShaders(GuiScreen par1GuiScreen, GameSettings par2GameSettings) {
|
||||
this.parentGui = par1GuiScreen;
|
||||
}
|
||||
|
||||
private static String toStringOnOff(boolean value) {
|
||||
return value ? "On" : "Off";
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Adds the buttons (and other controls) to the screen in question.
|
||||
*/
|
||||
public void initGui() {
|
||||
if (Shaders.shadersConfig == null) Shaders.loadConfig();
|
||||
List buttonList = this.buttonList;
|
||||
int width = this.width;
|
||||
int height = this.height;
|
||||
buttonList.add(new GuiButton(
|
||||
17, width * 3 / 4 - 60, 30, 160, 18, "NormapMap: " + toStringOnOff(Shaders.configNormalMap)));
|
||||
buttonList.add(new GuiButton(
|
||||
18, width * 3 / 4 - 60, 50, 160, 18, "SpecularMap: " + toStringOnOff(Shaders.configSpecularMap)));
|
||||
buttonList.add(new GuiButton(
|
||||
15,
|
||||
width * 3 / 4 - 60,
|
||||
70,
|
||||
160,
|
||||
18,
|
||||
"RenderResMul: " + String.format("%.04f", Shaders.configRenderResMul)));
|
||||
buttonList.add(new GuiButton(
|
||||
16,
|
||||
width * 3 / 4 - 60,
|
||||
90,
|
||||
160,
|
||||
18,
|
||||
"ShadowResMul: " + String.format("%.04f", Shaders.configShadowResMul)));
|
||||
buttonList.add(new GuiButton(
|
||||
10,
|
||||
width * 3 / 4 - 60,
|
||||
110,
|
||||
160,
|
||||
18,
|
||||
"HandDepth: " + String.format("%.04f", Shaders.configHandDepthMul)));
|
||||
buttonList.add(new GuiButton(
|
||||
9, width * 3 / 4 - 60, 130, 160, 18, "CloudShadow: " + toStringOnOff(Shaders.configCloudShadow)));
|
||||
// buttonList.add(new GuiButton(14, width *3 /4 -60, 150, 160, 18, "ShadowClipFrustrum: "
|
||||
// +toStringOnOff(Shaders.configShadowClipFrustrum)));
|
||||
buttonList.add(new GuiButton(
|
||||
4,
|
||||
width * 3 / 4 - 60,
|
||||
170,
|
||||
160,
|
||||
18,
|
||||
"tweakBlockDamage: " + toStringOnOff(Shaders.configTweakBlockDamage)));
|
||||
buttonList.add(new GuiButton(
|
||||
19, width * 3 / 4 - 60, 190, 160, 18, "OldLighting: " + toStringOnOff(Shaders.configOldLighting)));
|
||||
// buttonList.add(new GuiButton(11, width *3 /4 -60, 210, 160, 18, "Tex Min: "
|
||||
// +Shaders.texMinFilDesc[Shaders.configTexMinFilB]));
|
||||
// buttonList.add(new GuiButton(12, width *3 /4 -60, 230, 160, 18, "Tex_n Mag: "
|
||||
// +Shaders.texMagFilDesc[Shaders.configTexMagFilN]));
|
||||
// buttonList.add(new GuiButton(13, width *3 /4 -60, 250, 160, 18, "Tex_s Mag: "
|
||||
// +Shaders.texMagFilDesc[Shaders.configTexMagFilS]));
|
||||
buttonList.add(new GuiButton(6, width * 3 / 4 - 60, height - 25, 160, 20, "Done"));
|
||||
buttonList.add(new GuiButton(5, width / 4 - 80, height - 25, 160, 20, "Open shaderpacks folder"));
|
||||
this.shaderList = new GuiSlotShaders(this);
|
||||
this.shaderList.registerScrollButtons(7, 8); // registerScrollButtons(7, 8);
|
||||
this.needReinit = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
/** actionPerformed
|
||||
* Fired when a control is clicked. This is the equivalent of ActionListener.actionPerformed(ActionEvent e).
|
||||
*/
|
||||
protected void actionPerformed(GuiButton par1GuiButton) {
|
||||
if (par1GuiButton.enabled) // enabled
|
||||
{
|
||||
switch (par1GuiButton.id) // id
|
||||
{
|
||||
case 4: /* New block breaking */
|
||||
Shaders.configTweakBlockDamage = !Shaders.configTweakBlockDamage;
|
||||
// displayString
|
||||
par1GuiButton.displayString = "tweakBlockDamage: " + toStringOnOff(Shaders.configTweakBlockDamage);
|
||||
break;
|
||||
|
||||
case 9: /* Cloud shadow */
|
||||
Shaders.configCloudShadow = !Shaders.configCloudShadow;
|
||||
par1GuiButton.displayString = "CloudShadow: " + toStringOnOff(Shaders.configCloudShadow);
|
||||
break;
|
||||
|
||||
case 10: /* Hand Depth */ {
|
||||
float val = Shaders.configHandDepthMul;
|
||||
float[] choices = {0.0625f, 0.125f, 0.25f, 0.5f, 1.0f};
|
||||
int i;
|
||||
if (!isShiftKeyDown()) { // isShiftKeyDown
|
||||
for (i = 0; i < choices.length && choices[i] <= val; ++i) {}
|
||||
if (i == choices.length) i = 0;
|
||||
} else {
|
||||
for (i = choices.length - 1; i >= 0 && val <= choices[i]; --i) {}
|
||||
if (i < 0) i = choices.length - 1;
|
||||
}
|
||||
Shaders.configHandDepthMul = choices[i];
|
||||
par1GuiButton.displayString = "HandDepth: " + String.format("%.4f", Shaders.configHandDepthMul);
|
||||
break;
|
||||
}
|
||||
|
||||
case 15: /* Render Resolution Multiplier */ {
|
||||
float val = Shaders.configRenderResMul;
|
||||
float[] choices = {0.25f, 0.3333333333f, 0.5f, 0.7071067812f, 1.0f, 1.414213562f, 2.0f};
|
||||
int i;
|
||||
if (!isShiftKeyDown()) {
|
||||
for (i = 0; i < choices.length && choices[i] <= val; ++i) {}
|
||||
if (i == choices.length) i = 0;
|
||||
} else {
|
||||
for (i = choices.length - 1; i >= 0 && val <= choices[i]; --i) {}
|
||||
if (i < 0) i = choices.length - 1;
|
||||
}
|
||||
Shaders.configRenderResMul = choices[i];
|
||||
par1GuiButton.displayString = "RenderResMul: " + String.format("%.4f", Shaders.configRenderResMul);
|
||||
Shaders.scheduleResize();
|
||||
break;
|
||||
}
|
||||
|
||||
case 16: /* Shadow Resolution Multiplier */ {
|
||||
float val = Shaders.configShadowResMul;
|
||||
float[] choices = {0.25f, 0.3333333333f, 0.5f, 0.7071067812f, 1.0f, 1.414213562f, 2.0f, 3.0f, 4.0f};
|
||||
int i;
|
||||
if (!isShiftKeyDown()) {
|
||||
for (i = 0; i < choices.length && choices[i] <= val; ++i) {}
|
||||
if (i == choices.length) i = 0;
|
||||
} else {
|
||||
for (i = choices.length - 1; i >= 0 && val <= choices[i]; --i) {}
|
||||
if (i < 0) i = choices.length - 1;
|
||||
}
|
||||
Shaders.configShadowResMul = choices[i];
|
||||
par1GuiButton.displayString = "ShadowResMul: " + String.format("%.4f", Shaders.configShadowResMul);
|
||||
Shaders.scheduleResizeShadow();
|
||||
break;
|
||||
}
|
||||
|
||||
case 17: /* Normal Map */ {
|
||||
Shaders.configNormalMap = !Shaders.configNormalMap;
|
||||
// displayString
|
||||
par1GuiButton.displayString = "NormapMap: " + toStringOnOff(Shaders.configNormalMap);
|
||||
mc.scheduleResourcesRefresh(); // schedule refresh texture
|
||||
break;
|
||||
}
|
||||
|
||||
case 18: /* Normal Map */ {
|
||||
Shaders.configSpecularMap = !Shaders.configSpecularMap;
|
||||
// displayString
|
||||
par1GuiButton.displayString = "SpecularMap: " + toStringOnOff(Shaders.configSpecularMap);
|
||||
mc.scheduleResourcesRefresh(); // schedule refresh texture
|
||||
break;
|
||||
}
|
||||
|
||||
case 19: /* old Lighting */ {
|
||||
Shaders.configOldLighting = !Shaders.configOldLighting;
|
||||
// displayString
|
||||
par1GuiButton.displayString = "OldLighting: " + toStringOnOff(Shaders.configOldLighting);
|
||||
Shaders.updateBlockLightLevel();
|
||||
mc.renderGlobal.loadRenderers();
|
||||
break;
|
||||
}
|
||||
|
||||
case 11: /* texture filter */ {
|
||||
Shaders.configTexMinFilB = (Shaders.configTexMinFilB + 1) % Shaders.texMinFilRange;
|
||||
Shaders.configTexMinFilN = Shaders.configTexMinFilS = Shaders.configTexMinFilB;
|
||||
par1GuiButton.displayString = "Tex Min: " + Shaders.texMinFilDesc[Shaders.configTexMinFilB];
|
||||
ShadersTex.updateTextureMinMagFilter();
|
||||
break;
|
||||
}
|
||||
|
||||
case 12: /* texture filter */ {
|
||||
Shaders.configTexMagFilN = (Shaders.configTexMagFilN + 1) % Shaders.texMagFilRange;
|
||||
par1GuiButton.displayString = "Tex_n Mag: " + Shaders.texMagFilDesc[Shaders.configTexMagFilN];
|
||||
ShadersTex.updateTextureMinMagFilter();
|
||||
break;
|
||||
}
|
||||
|
||||
case 13: /* texture filter */ {
|
||||
Shaders.configTexMagFilS = (Shaders.configTexMagFilS + 1) % Shaders.texMagFilRange;
|
||||
par1GuiButton.displayString = "Tex_s Mag: " + Shaders.texMagFilDesc[Shaders.configTexMagFilS];
|
||||
ShadersTex.updateTextureMinMagFilter();
|
||||
break;
|
||||
}
|
||||
|
||||
case 14: /* shadow frustum clipping */ {
|
||||
Shaders.configShadowClipFrustrum = !Shaders.configShadowClipFrustrum;
|
||||
par1GuiButton.displayString =
|
||||
"ShadowClipFrustrum: " + toStringOnOff(Shaders.configShadowClipFrustrum);
|
||||
ShadersTex.updateTextureMinMagFilter();
|
||||
break;
|
||||
}
|
||||
|
||||
case 5: /* Open shaderpacks folder */
|
||||
switch (net.minecraft.util.Util.getOSType()) {
|
||||
case OSX:
|
||||
{
|
||||
try {
|
||||
Runtime.getRuntime().exec(new String[] {
|
||||
"/usr/bin/open", Shaders.shaderpacksdir.getAbsolutePath()
|
||||
});
|
||||
return;
|
||||
} catch (IOException var7) {
|
||||
var7.printStackTrace();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WINDOWS:
|
||||
{
|
||||
String var2 = String.format(
|
||||
"cmd.exe /C start \"Open file\" \"%s\"",
|
||||
new Object[] {Shaders.shaderpacksdir.getAbsolutePath()});
|
||||
|
||||
try {
|
||||
Runtime.getRuntime().exec(var2);
|
||||
return;
|
||||
} catch (IOException var6) {
|
||||
var6.printStackTrace();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
boolean var8 = false;
|
||||
|
||||
try {
|
||||
Class var3 = Class.forName("java.awt.Desktop");
|
||||
Object var4 = var3.getMethod("getDesktop", new Class[0]).invoke((Object) null, new Object[0]);
|
||||
var3.getMethod("browse", new Class[] {URI.class})
|
||||
.invoke(var4, new Object[] {(new File(mc.mcDataDir, Shaders.shaderpacksdirname)).toURI()
|
||||
});
|
||||
} catch (Throwable var5) {
|
||||
var5.printStackTrace();
|
||||
var8 = true;
|
||||
}
|
||||
|
||||
if (var8) {
|
||||
System.out.println("Opening via system class!");
|
||||
Sys.openURL("file://" + Shaders.shaderpacksdir.getAbsolutePath());
|
||||
}
|
||||
break;
|
||||
|
||||
case 6: /* Done */
|
||||
File confshader = new File(Shaders.shadersdir, "current.cfg");
|
||||
try {
|
||||
Shaders.storeConfig();
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
if (needReinit) {
|
||||
needReinit = false;
|
||||
Shaders.loadShaderPack();
|
||||
Shaders.uninit();
|
||||
this.mc.renderGlobal.loadRenderers();
|
||||
}
|
||||
this.mc.displayGuiScreen(this.parentGui); // displayGuiScreen
|
||||
break;
|
||||
|
||||
default:
|
||||
this.shaderList.actionPerformed(par1GuiButton); // actionPerformed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Draws the screen and all the components in it.
|
||||
*/
|
||||
public void drawScreen(int par1, int par2, float par3) {
|
||||
drawDefaultBackground(); // background
|
||||
this.shaderList.drawScreen(par1, par2, par3); // drawScreen
|
||||
|
||||
if (this.updateTimer <= 0) {
|
||||
this.shaderList.updateList();
|
||||
this.updateTimer += 20;
|
||||
}
|
||||
|
||||
this.drawCenteredString(this.fontRendererObj, "Shaders ", this.width / 2, 16, 0xffffff);
|
||||
this.drawCenteredString(this.fontRendererObj, " v" + Shaders.versionString, this.width - 40, 10, 0x808080);
|
||||
// this.drawCenteredString(this.fontRenderer, "( Place zipped Shader files here. )", this.width / 4 + 10,
|
||||
// this.height - 26, 0x808080);
|
||||
super.drawScreen(par1, par2, par3);
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Called from the main game loop to update the screen.
|
||||
*/
|
||||
public void updateScreen() {
|
||||
super.updateScreen();
|
||||
--this.updateTimer;
|
||||
}
|
||||
|
||||
public Minecraft getMc() {
|
||||
return this.mc;
|
||||
}
|
||||
|
||||
public void drawCenteredString(String par1, int par2, int par3, int par4) {
|
||||
this.drawCenteredString(this.fontRendererObj, par1, par2, par3, par4);
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.client;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import net.minecraft.client.gui.GuiSlot;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
|
||||
class GuiSlotShaders extends GuiSlot {
|
||||
private ArrayList shaderslist;
|
||||
|
||||
final GuiShaders shadersGui;
|
||||
|
||||
public GuiSlotShaders(GuiShaders par1GuiShaders) {
|
||||
// super(par1GuiShaders.getMc(), par1GuiShaders.width / 2 + 20, par1GuiShaders.height, 40, par1GuiShaders.height
|
||||
// - 70, 16);
|
||||
super(
|
||||
par1GuiShaders.getMc(),
|
||||
par1GuiShaders.width / 2 + 20,
|
||||
par1GuiShaders.height,
|
||||
40,
|
||||
par1GuiShaders.height - 70,
|
||||
16);
|
||||
this.shadersGui = par1GuiShaders;
|
||||
this.shaderslist = Shaders.listofShaders();
|
||||
}
|
||||
|
||||
public void updateList() {
|
||||
this.shaderslist = Shaders.listofShaders();
|
||||
}
|
||||
|
||||
@Override
|
||||
/** getSize */
|
||||
protected int getSize() {
|
||||
return this.shaderslist.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
/** elementClicked */
|
||||
protected void elementClicked(int par1, boolean par2, int par3, int par4) {
|
||||
Shaders.setShaderPack((String) shaderslist.get(par1));
|
||||
shadersGui.needReinit = false;
|
||||
Shaders.loadShaderPack();
|
||||
Shaders.uninit();
|
||||
}
|
||||
|
||||
@Override
|
||||
/** isSelected */
|
||||
protected boolean isSelected(int par1) {
|
||||
return ((String) this.shaderslist.get(par1)).equals(Shaders.currentshadername);
|
||||
}
|
||||
|
||||
@Override
|
||||
/** getScrollBarX */
|
||||
protected int getScrollBarX() {
|
||||
return this.width - 6;
|
||||
}
|
||||
|
||||
@Override
|
||||
/** getContentHeight */
|
||||
protected int getContentHeight() {
|
||||
return this.getSize() * 18;
|
||||
}
|
||||
|
||||
@Override
|
||||
/** drawBackground */
|
||||
protected void drawBackground() {
|
||||
// this.shadersGui.drawDefaultBackground();
|
||||
}
|
||||
|
||||
@Override
|
||||
/** drawSlot */
|
||||
protected void drawSlot(int par1, int par2, int par3, int par4, Tessellator par5, int par6, int par7) {
|
||||
this.shadersGui.drawCenteredString(
|
||||
(String) this.shaderslist.get(par1), this.shadersGui.width / 4 + 10, par3 + 1, 0xffffff);
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.client;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Nathanael Lane
|
||||
*/
|
||||
public class HFNoiseTexture {
|
||||
public int texID;
|
||||
public int textureUnit;
|
||||
|
||||
public HFNoiseTexture(int width, int height) {
|
||||
texID = GL11.glGenTextures();
|
||||
textureUnit = 15;
|
||||
|
||||
byte[] image = genHFNoiseImage(width, height);
|
||||
ByteBuffer data = BufferUtils.createByteBuffer(image.length);
|
||||
data.put(image);
|
||||
data.flip();
|
||||
|
||||
// GL13.glActiveTexture(GL13.GL_TEXTURE0 + this.textureUnit);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texID);
|
||||
GL11.glTexImage2D(
|
||||
GL11.GL_TEXTURE_2D, 0, GL11.GL_RGB, width, height, 0, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, data);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR);
|
||||
// GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
public int getID() {
|
||||
return texID;
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
GL11.glDeleteTextures(texID);
|
||||
texID = 0;
|
||||
}
|
||||
|
||||
// from George Marsaglia's paper on XORshift PRNGs
|
||||
private int random(int seed) {
|
||||
seed ^= (seed << 13);
|
||||
seed ^= (seed >> 17);
|
||||
seed ^= (seed << 5);
|
||||
return seed;
|
||||
}
|
||||
|
||||
private byte random(int x, int y, int z) {
|
||||
int seed = (random(x) + random(y * 19)) * random(z * 23) - z;
|
||||
return (byte) (random(seed) % 128);
|
||||
}
|
||||
|
||||
/*
|
||||
* Just a random value for each pixel to get maximum frequency
|
||||
*/
|
||||
private byte[] genHFNoiseImage(int width, int height) {
|
||||
|
||||
byte[] image = new byte[width * height * 3];
|
||||
int index = 0;
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
for (int z = 1; z < 4; z++) {
|
||||
image[index++] = random(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.client;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
public interface IShaderPack {
|
||||
|
||||
void close();
|
||||
|
||||
InputStream getResourceAsStream(String resName);
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.client;
|
||||
|
||||
public class MultiTexID {
|
||||
public int base;
|
||||
public int norm;
|
||||
public int spec;
|
||||
|
||||
public MultiTexID(int baseTex, int normTex, int specTex) {
|
||||
base = baseTex;
|
||||
norm = normTex;
|
||||
spec = specTex;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.client;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
public class ShaderPackDefault implements IShaderPack {
|
||||
|
||||
public ShaderPackDefault() {}
|
||||
|
||||
@Override
|
||||
public void close() {}
|
||||
|
||||
@Override
|
||||
public InputStream getResourceAsStream(String resName) {
|
||||
return ShaderPackDefault.class.getResourceAsStream(resName);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.client;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class ShaderPackFolder implements IShaderPack {
|
||||
|
||||
protected File packFile;
|
||||
|
||||
public ShaderPackFolder(String name, File file) {
|
||||
packFile = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {}
|
||||
|
||||
@Override
|
||||
public InputStream getResourceAsStream(String resName) {
|
||||
try {
|
||||
File resFile = new File(packFile, resName.substring(1));
|
||||
if (resFile != null) {
|
||||
return new BufferedInputStream(new FileInputStream(resFile));
|
||||
}
|
||||
} catch (Exception excp) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.client;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
public class ShaderPackNone implements IShaderPack {
|
||||
|
||||
public ShaderPackNone() {}
|
||||
|
||||
@Override
|
||||
public void close() {}
|
||||
|
||||
@Override
|
||||
public InputStream getResourceAsStream(String resName) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.client;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
public class ShaderPackZip implements IShaderPack {
|
||||
|
||||
protected File packFile;
|
||||
protected ZipFile packZipFile;
|
||||
|
||||
public ShaderPackZip(String name, File file) {
|
||||
packFile = file;
|
||||
packZipFile = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (packZipFile != null) {
|
||||
try {
|
||||
packZipFile.close();
|
||||
} catch (Exception excp) {
|
||||
}
|
||||
packZipFile = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getResourceAsStream(String resName) {
|
||||
if (packZipFile == null) {
|
||||
try {
|
||||
packZipFile = new ZipFile(packFile);
|
||||
} catch (Exception excp) {
|
||||
}
|
||||
}
|
||||
if (packZipFile != null) {
|
||||
try {
|
||||
ZipEntry entry = packZipFile.getEntry(resName.substring(1));
|
||||
if (entry != null) {
|
||||
return packZipFile.getInputStream(entry);
|
||||
}
|
||||
} catch (Exception excp) {
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,87 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.client;
|
||||
|
||||
import java.nio.IntBuffer;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockIce;
|
||||
import net.minecraft.client.renderer.EntityRenderer;
|
||||
import net.minecraft.client.renderer.ItemRenderer;
|
||||
import net.minecraft.client.renderer.RenderGlobal;
|
||||
import net.minecraft.client.renderer.WorldRenderer;
|
||||
import net.minecraft.client.renderer.culling.Frustrum;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemBlock;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
public class ShadersRender {
|
||||
|
||||
public static void setFrustrumPosition(Frustrum frustrum, double x, double y, double z) {
|
||||
frustrum.setPosition(x, y, z);
|
||||
}
|
||||
|
||||
public static void clipRenderersByFrustrum(RenderGlobal renderGlobal, Frustrum frustrum, float par2) {
|
||||
Shaders.checkGLError("pre clip");
|
||||
if (!Shaders.isShadowPass) {
|
||||
WorldRenderer[] worldRenderers = renderGlobal.worldRenderers;
|
||||
for (int i = 0; i < worldRenderers.length; ++i) {
|
||||
if (!worldRenderers[i].skipAllRenderPasses()) {
|
||||
worldRenderers[i].updateInFrustum(frustrum);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
WorldRenderer[] worldRenderers = renderGlobal.worldRenderers;
|
||||
for (int i = 0; i < worldRenderers.length; ++i) {
|
||||
if (!worldRenderers[i].skipAllRenderPasses()) {
|
||||
worldRenderers[i].isInFrustum = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void renderHand0(EntityRenderer er, float par1, int par2) {
|
||||
if (!Shaders.isShadowPass) {
|
||||
Item item = (Shaders.itemToRender != null) ? Shaders.itemToRender.getItem() : null;
|
||||
Block block = (item instanceof ItemBlock) ? ((ItemBlock) item).field_150939_a : null;
|
||||
// ItemCloth is for semitransparent block : stained glass, wool
|
||||
if (!(item instanceof ItemBlock) && !(block instanceof BlockIce)) {
|
||||
Shaders.readCenterDepth();
|
||||
Shaders.beginHand();
|
||||
er.renderHand(par1, par2);
|
||||
Shaders.endHand();
|
||||
Shaders.isHandRendered = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void renderHand1(EntityRenderer er, float par1, int par2) {
|
||||
if (!Shaders.isShadowPass) {
|
||||
if (!Shaders.isHandRendered) {
|
||||
Shaders.readCenterDepth();
|
||||
GL11.glEnable(GL11.GL_BLEND);
|
||||
Shaders.beginHand();
|
||||
er.renderHand(par1, par2);
|
||||
Shaders.endHand();
|
||||
Shaders.isHandRendered = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void renderItemFP(ItemRenderer itemRenderer, float par1) {
|
||||
// clear depth buffer locally
|
||||
GL11.glDepthFunc(GL11.GL_GEQUAL);
|
||||
GL11.glPushMatrix();
|
||||
IntBuffer drawBuffers = Shaders.activeDrawBuffers;
|
||||
Shaders.setDrawBuffers(Shaders.drawBuffersNone);
|
||||
itemRenderer.renderItemInFirstPerson(par1);
|
||||
Shaders.setDrawBuffers(drawBuffers);
|
||||
GL11.glPopMatrix();
|
||||
GL11.glDepthFunc(GL11.GL_LEQUAL);
|
||||
// really render item or hand
|
||||
itemRenderer.renderItemInFirstPerson(par1);
|
||||
}
|
||||
|
||||
public static void renderFPOverlay(EntityRenderer er, float par1, int par2) {
|
||||
Shaders.beginFPOverlay();
|
||||
er.renderHand(par1, par2);
|
||||
Shaders.endFPOverlay();
|
||||
}
|
||||
}
|
||||
@@ -1,243 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.client;
|
||||
|
||||
import static org.lwjgl.opengl.ARBVertexShader.glDisableVertexAttribArrayARB;
|
||||
import static org.lwjgl.opengl.ARBVertexShader.glEnableVertexAttribArrayARB;
|
||||
import static org.lwjgl.opengl.ARBVertexShader.glVertexAttribPointerARB;
|
||||
|
||||
import com.gtnewhorizons.angelica.transform.ALog;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.ShortBuffer;
|
||||
import java.util.Arrays;
|
||||
import net.minecraft.client.renderer.OpenGlHelper;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
|
||||
public class ShadersTess {
|
||||
|
||||
public static final int vertexStride = 16;
|
||||
|
||||
public static int draw(Tessellator tess) {
|
||||
if (!tess.isDrawing) {
|
||||
throw new IllegalStateException("Not tesselating!");
|
||||
} else {
|
||||
tess.isDrawing = false;
|
||||
if (tess.drawMode == GL11.GL_QUADS && tess.vertexCount % 4 != 0) {
|
||||
ALog.warning("%s", "bad vertexCount");
|
||||
}
|
||||
int voffset = 0;
|
||||
int realDrawMode = tess.drawMode;
|
||||
while (voffset < tess.vertexCount) {
|
||||
int vcount;
|
||||
vcount = Math.min(tess.vertexCount - voffset, tess.byteBuffer.capacity() / (vertexStride * 4));
|
||||
if (realDrawMode == GL11.GL_QUADS) vcount = vcount / 4 * 4;
|
||||
tess.floatBuffer.clear();
|
||||
tess.shortBuffer.clear();
|
||||
tess.intBuffer.clear();
|
||||
tess.intBuffer.put(tess.rawBuffer, voffset * vertexStride, vcount * vertexStride);
|
||||
tess.byteBuffer.position(0);
|
||||
tess.byteBuffer.limit(vcount * (vertexStride * 4));
|
||||
voffset += vcount;
|
||||
|
||||
if (tess.hasTexture) {
|
||||
tess.floatBuffer.position(3);
|
||||
GL11.glTexCoordPointer(2, (vertexStride * 4), tess.floatBuffer);
|
||||
GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
|
||||
}
|
||||
if (tess.hasBrightness) {
|
||||
OpenGlHelper.setClientActiveTexture(OpenGlHelper.lightmapTexUnit);
|
||||
tess.shortBuffer.position(6 * 2);
|
||||
GL11.glTexCoordPointer(2, (vertexStride * 4), tess.shortBuffer);
|
||||
GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
|
||||
OpenGlHelper.setClientActiveTexture(OpenGlHelper.defaultTexUnit);
|
||||
}
|
||||
if (tess.hasColor) {
|
||||
tess.byteBuffer.position(5 * 4);
|
||||
GL11.glColorPointer(4, true, (vertexStride * 4), tess.byteBuffer);
|
||||
GL11.glEnableClientState(GL11.GL_COLOR_ARRAY);
|
||||
}
|
||||
if (tess.hasNormals) {
|
||||
tess.floatBuffer.position(9);
|
||||
GL11.glNormalPointer((vertexStride * 4), tess.floatBuffer);
|
||||
GL11.glEnableClientState(GL11.GL_NORMAL_ARRAY);
|
||||
}
|
||||
tess.floatBuffer.position(0);
|
||||
GL11.glVertexPointer(3, (vertexStride * 4), tess.floatBuffer);
|
||||
ShadersTess.preDrawArray(tess);
|
||||
|
||||
GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
|
||||
GL11.glDrawArrays(realDrawMode, 0, vcount);
|
||||
}
|
||||
// end loop
|
||||
|
||||
GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY);
|
||||
ShadersTess.postDrawArray(tess);
|
||||
if (tess.hasTexture) {
|
||||
GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
|
||||
}
|
||||
if (tess.hasBrightness) {
|
||||
OpenGlHelper.setClientActiveTexture(OpenGlHelper.lightmapTexUnit);
|
||||
GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
|
||||
OpenGlHelper.setClientActiveTexture(OpenGlHelper.defaultTexUnit);
|
||||
}
|
||||
if (tess.hasColor) {
|
||||
GL11.glDisableClientState(GL11.GL_COLOR_ARRAY);
|
||||
}
|
||||
if (tess.hasNormals) {
|
||||
GL11.glDisableClientState(GL11.GL_NORMAL_ARRAY);
|
||||
}
|
||||
|
||||
int n = tess.rawBufferIndex * 4;
|
||||
tess.reset();
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
public static void preDrawArray(Tessellator tess) {
|
||||
// Shaders.checkGLError("preDrawArray");
|
||||
if (Shaders.useMultiTexCoord3Attrib && tess.hasTexture) {
|
||||
GL13.glClientActiveTexture(GL13.GL_TEXTURE3);
|
||||
GL11.glTexCoordPointer(2, (vertexStride * 4), (FloatBuffer) tess.floatBuffer.position(12));
|
||||
GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
|
||||
GL13.glClientActiveTexture(GL13.GL_TEXTURE0);
|
||||
}
|
||||
if (Shaders.useMidTexCoordAttrib && tess.hasTexture) {
|
||||
glVertexAttribPointerARB(
|
||||
Shaders.midTexCoordAttrib, 2, false, vertexStride * 4, (FloatBuffer) tess.floatBuffer.position(12));
|
||||
glEnableVertexAttribArrayARB(Shaders.midTexCoordAttrib);
|
||||
}
|
||||
if (Shaders.useEntityAttrib) {
|
||||
glVertexAttribPointerARB(Shaders.entityAttrib, 3, false, false, vertexStride * 4, (ShortBuffer)
|
||||
tess.shortBuffer.position(7 * 2));
|
||||
glEnableVertexAttribArrayARB(Shaders.entityAttrib);
|
||||
}
|
||||
// Shaders.checkGLError("preDrawArray");
|
||||
}
|
||||
|
||||
public static void preDrawArrayVBO(Tessellator tess) {
|
||||
// Shaders.checkGLError("preDrawArray");
|
||||
if (Shaders.useMultiTexCoord3Attrib && tess.hasTexture) {
|
||||
GL13.glClientActiveTexture(GL13.GL_TEXTURE3);
|
||||
GL11.glTexCoordPointer(2, GL11.GL_FLOAT, (vertexStride * 4), 12 * 4L);
|
||||
GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
|
||||
GL13.glClientActiveTexture(GL13.GL_TEXTURE0);
|
||||
}
|
||||
if (Shaders.useMidTexCoordAttrib && tess.hasTexture) {
|
||||
glVertexAttribPointerARB(Shaders.midTexCoordAttrib, 2, GL11.GL_FLOAT, false, vertexStride * 4, 12 * 4L);
|
||||
glEnableVertexAttribArrayARB(Shaders.midTexCoordAttrib);
|
||||
}
|
||||
if (Shaders.useEntityAttrib) {
|
||||
glVertexAttribPointerARB(Shaders.entityAttrib, 3, GL11.GL_SHORT, false, vertexStride * 4, 7 * 4L);
|
||||
glEnableVertexAttribArrayARB(Shaders.entityAttrib);
|
||||
}
|
||||
// Shaders.checkGLError("preDrawArray");
|
||||
}
|
||||
|
||||
public static void postDrawArray(Tessellator tess) {
|
||||
// Shaders.checkGLError("postDrawArray");
|
||||
if (Shaders.useEntityAttrib) {
|
||||
glDisableVertexAttribArrayARB(Shaders.entityAttrib);
|
||||
}
|
||||
if (Shaders.useMidTexCoordAttrib && tess.hasTexture) {
|
||||
glDisableVertexAttribArrayARB(Shaders.midTexCoordAttrib);
|
||||
}
|
||||
if (Shaders.useMultiTexCoord3Attrib && tess.hasTexture) {
|
||||
GL13.glClientActiveTexture(GL13.GL_TEXTURE3);
|
||||
GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
|
||||
GL13.glClientActiveTexture(GL13.GL_TEXTURE0);
|
||||
}
|
||||
// Shaders.checkGLError("postDrawArray");
|
||||
}
|
||||
|
||||
public static void addVertex(Tessellator tess, double parx, double pary, double parz) {
|
||||
int[] rawBuffer = tess.rawBuffer;
|
||||
int rbi = tess.rawBufferIndex;
|
||||
float fx = (float) (parx + tess.xOffset);
|
||||
float fy = (float) (pary + tess.yOffset);
|
||||
float fz = (float) (parz + tess.zOffset);
|
||||
// Check if buffer is nearly full
|
||||
if (rbi >= tess.bufferSize - vertexStride * 4) {
|
||||
if (tess.bufferSize >= 0x1000000) {
|
||||
// Max size reached. Just draw.
|
||||
if (tess.addedVertices % 4 == 0) {
|
||||
tess.draw();
|
||||
tess.isDrawing = true;
|
||||
}
|
||||
} else if (tess.bufferSize > 0) {
|
||||
// Expand
|
||||
tess.bufferSize *= 2;
|
||||
tess.rawBuffer = rawBuffer = Arrays.copyOf(tess.rawBuffer, tess.bufferSize);
|
||||
System.out.format("Expand tesselator buffer %d\n", tess.bufferSize);
|
||||
} else {
|
||||
// Initialize
|
||||
tess.bufferSize = 0x10000;
|
||||
tess.rawBuffer = rawBuffer = new int[tess.bufferSize];
|
||||
}
|
||||
}
|
||||
|
||||
// shaders mod calculate normal and mid UV
|
||||
if (tess.drawMode == 7) {
|
||||
int i = tess.addedVertices % 4;
|
||||
float[] vertexPos = tess.vertexPos;
|
||||
vertexPos[i * 4 + 0] = fx;
|
||||
vertexPos[i * 4 + 1] = fy;
|
||||
vertexPos[i * 4 + 2] = fz;
|
||||
if (i == 3) {
|
||||
// calculate normal
|
||||
float x1 = vertexPos[8 + 0] - vertexPos[+0];
|
||||
float y1 = vertexPos[8 + 1] - vertexPos[+1];
|
||||
float z1 = vertexPos[8 + 2] - vertexPos[+2];
|
||||
float x2 = vertexPos[12 + 0] - vertexPos[4 + 0];
|
||||
float y2 = vertexPos[12 + 1] - vertexPos[4 + 1];
|
||||
float z2 = vertexPos[12 + 2] - vertexPos[4 + 2];
|
||||
float vnx = y1 * z2 - y2 * z1;
|
||||
float vny = z1 * x2 - z2 * x1;
|
||||
float vnz = x1 * y2 - x2 * y1;
|
||||
float lensq = vnx * vnx + vny * vny + vnz * vnz;
|
||||
float mult = (lensq != 0.0) ? (float) (1f / Math.sqrt(lensq)) : 1f;
|
||||
rawBuffer[rbi + (9 - vertexStride * 3)] = rawBuffer[rbi + (9 - vertexStride * 2)] =
|
||||
rawBuffer[rbi + (9 - vertexStride * 1)] = Float.floatToRawIntBits(tess.normalX = vnx * mult);
|
||||
rawBuffer[rbi + (10 - vertexStride * 3)] = rawBuffer[rbi + (10 - vertexStride * 2)] =
|
||||
rawBuffer[rbi + (10 - vertexStride * 1)] = Float.floatToRawIntBits(tess.normalY = vny * mult);
|
||||
rawBuffer[rbi + (11 - vertexStride * 3)] = rawBuffer[rbi + (11 - vertexStride * 2)] =
|
||||
rawBuffer[rbi + (11 - vertexStride * 1)] = Float.floatToRawIntBits(tess.normalZ = vnz * mult);
|
||||
tess.hasNormals = true;
|
||||
// mid UV
|
||||
tess.midTextureU = (Float.intBitsToFloat(rawBuffer[rbi + (3 - vertexStride * 3)])
|
||||
+ Float.intBitsToFloat(rawBuffer[rbi + (3 - vertexStride * 2)])
|
||||
+ Float.intBitsToFloat(rawBuffer[rbi + (3 - vertexStride * 1)])
|
||||
+ (float) tess.textureU)
|
||||
/ 4;
|
||||
tess.midTextureV = (Float.intBitsToFloat(rawBuffer[rbi + (4 - vertexStride * 3)])
|
||||
+ Float.intBitsToFloat(rawBuffer[rbi + (4 - vertexStride * 2)])
|
||||
+ Float.intBitsToFloat(rawBuffer[rbi + (4 - vertexStride * 1)])
|
||||
+ (float) tess.textureV)
|
||||
/ 4;
|
||||
rawBuffer[rbi + (12 - vertexStride * 3)] = rawBuffer[rbi + (12 - vertexStride * 2)] =
|
||||
rawBuffer[rbi + (12 - vertexStride * 1)] = Float.floatToRawIntBits(tess.midTextureU);
|
||||
rawBuffer[rbi + (13 - vertexStride * 3)] = rawBuffer[rbi + (13 - vertexStride * 2)] =
|
||||
rawBuffer[rbi + (13 - vertexStride * 1)] = Float.floatToRawIntBits(tess.midTextureV);
|
||||
}
|
||||
}
|
||||
// end normal and mid UV calculation
|
||||
|
||||
++tess.addedVertices;
|
||||
rawBuffer[rbi + 0] = Float.floatToRawIntBits((float) fx);
|
||||
rawBuffer[rbi + 1] = Float.floatToRawIntBits((float) fy);
|
||||
rawBuffer[rbi + 2] = Float.floatToRawIntBits((float) fz);
|
||||
rawBuffer[rbi + 3] = Float.floatToRawIntBits((float) tess.textureU);
|
||||
rawBuffer[rbi + 4] = Float.floatToRawIntBits((float) tess.textureV);
|
||||
rawBuffer[rbi + 5] = tess.color;
|
||||
rawBuffer[rbi + 6] = tess.brightness;
|
||||
rawBuffer[rbi + 7] = Shaders.getEntityData();
|
||||
rawBuffer[rbi + 8] = Shaders.getEntityData2();
|
||||
rawBuffer[rbi + 9] = Float.floatToRawIntBits((float) tess.normalX);
|
||||
rawBuffer[rbi + 10] = Float.floatToRawIntBits((float) tess.normalY);
|
||||
rawBuffer[rbi + 11] = Float.floatToRawIntBits((float) tess.normalZ);
|
||||
rawBuffer[rbi + 12] = Float.floatToRawIntBits((float) tess.midTextureU);
|
||||
rawBuffer[rbi + 13] = Float.floatToRawIntBits((float) tess.midTextureV);
|
||||
|
||||
tess.rawBufferIndex = rbi += vertexStride;
|
||||
++tess.vertexCount;
|
||||
}
|
||||
}
|
||||
@@ -1,988 +0,0 @@
|
||||
package com.gtnewhorizons.angelica.client;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.imageio.ImageIO;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.texture.AbstractTexture;
|
||||
import net.minecraft.client.renderer.texture.DynamicTexture;
|
||||
import net.minecraft.client.renderer.texture.ITextureObject;
|
||||
import net.minecraft.client.renderer.texture.LayeredTexture;
|
||||
import net.minecraft.client.renderer.texture.Stitcher;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.texture.TextureManager;
|
||||
import net.minecraft.client.renderer.texture.TextureMap;
|
||||
import net.minecraft.client.renderer.texture.TextureUtil;
|
||||
import net.minecraft.client.resources.IResource;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL12;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
import org.lwjgl.opengl.GL30.*;
|
||||
|
||||
public class ShadersTex {
|
||||
public static final int initialBufferSize = 1048576;
|
||||
public static ByteBuffer byteBuffer = BufferUtils.createByteBuffer(initialBufferSize * 4);
|
||||
public static IntBuffer intBuffer = byteBuffer.asIntBuffer();
|
||||
public static int[] intArray = new int[initialBufferSize];
|
||||
public static final int defBaseTexColor = 0x00000000;
|
||||
public static final int defNormTexColor = 0xFF7F7FFF;
|
||||
public static final int defSpecTexColor = 0x00000000;
|
||||
public static Map<Integer, MultiTexID> multiTexMap = new HashMap();
|
||||
public static TextureMap updatingTextureMap = null;
|
||||
public static TextureAtlasSprite updatingSprite = null;
|
||||
public static MultiTexID updatingTex = null;
|
||||
public static MultiTexID boundTex = null;
|
||||
public static int updatingPage = 0;
|
||||
public static String iconName = null;
|
||||
|
||||
public static IntBuffer getIntBuffer(int size) {
|
||||
if (intBuffer.capacity() < size) {
|
||||
int bufferSize = roundUpPOT(size);
|
||||
byteBuffer = BufferUtils.createByteBuffer(bufferSize * 4);
|
||||
intBuffer = byteBuffer.asIntBuffer();
|
||||
}
|
||||
return intBuffer;
|
||||
}
|
||||
|
||||
public static int[] getIntArray(int size) {
|
||||
if (intArray.length < size) {
|
||||
intArray = null;
|
||||
intArray = new int[roundUpPOT(size)];
|
||||
}
|
||||
return intArray;
|
||||
}
|
||||
|
||||
public static int roundUpPOT(int x) {
|
||||
int i = x - 1;
|
||||
i |= (i >> 1);
|
||||
i |= (i >> 2);
|
||||
i |= (i >> 4);
|
||||
i |= (i >> 8);
|
||||
i |= (i >> 16);
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
public static IntBuffer fillIntBuffer(int size, int value) {
|
||||
int[] aint = getIntArray(size);
|
||||
IntBuffer intBuf = getIntBuffer(size);
|
||||
Arrays.fill(intArray, 0, size, value);
|
||||
intBuffer.put(intArray, 0, size);
|
||||
return intBuffer;
|
||||
}
|
||||
|
||||
public static int[] createAIntImage(int size) {
|
||||
int[] aint = new int[size * 3];
|
||||
Arrays.fill(aint, 0, size, defBaseTexColor);
|
||||
Arrays.fill(aint, size, size * 2, defNormTexColor);
|
||||
Arrays.fill(aint, size * 2, size * 3, defSpecTexColor);
|
||||
return aint;
|
||||
}
|
||||
|
||||
public static int[] createAIntImage(int size, int color) {
|
||||
int[] aint = new int[size * 3];
|
||||
Arrays.fill(aint, 0, size, color);
|
||||
Arrays.fill(aint, size, size * 2, defNormTexColor);
|
||||
Arrays.fill(aint, size * 2, size * 3, defSpecTexColor);
|
||||
return aint;
|
||||
}
|
||||
|
||||
public static MultiTexID getMultiTexID(AbstractTexture tex) {
|
||||
MultiTexID multiTex = tex.multiTex;
|
||||
if (multiTex == null) {
|
||||
int baseTex = tex.getGlTextureId();
|
||||
multiTex = multiTexMap.get(Integer.valueOf(baseTex));
|
||||
if (multiTex == null) {
|
||||
multiTex = new MultiTexID(baseTex, GL11.glGenTextures(), GL11.glGenTextures());
|
||||
multiTexMap.put(baseTex, multiTex);
|
||||
}
|
||||
tex.multiTex = multiTex;
|
||||
}
|
||||
return multiTex;
|
||||
}
|
||||
|
||||
public static void deleteTextures(AbstractTexture atex) {
|
||||
int texid = atex.glTextureId;
|
||||
if (texid != -1) {
|
||||
GL11.glDeleteTextures(texid);
|
||||
atex.glTextureId = -1;
|
||||
}
|
||||
MultiTexID multiTex = atex.multiTex;
|
||||
if (multiTex != null) {
|
||||
atex.multiTex = null;
|
||||
multiTexMap.remove(Integer.valueOf(multiTex.base));
|
||||
GL11.glDeleteTextures(multiTex.norm);
|
||||
GL11.glDeleteTextures(multiTex.spec);
|
||||
if (multiTex.base != texid) {
|
||||
System.err.println("Error : MultiTexID.base mismatch.");
|
||||
GL11.glDeleteTextures(multiTex.base);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Remove MultiTexID object reference and delete textures */
|
||||
public static int deleteMultiTex(ITextureObject tex) {
|
||||
if (tex instanceof AbstractTexture) {
|
||||
deleteTextures((AbstractTexture) tex);
|
||||
} else {
|
||||
GL11.glDeleteTextures(tex.getGlTextureId());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static void bindNSTextures(int normTex, int specTex) {
|
||||
// Shaders.checkGLError("pre bindNSTextures");
|
||||
if (Shaders.isRenderingWorld && Shaders.activeTexUnit == GL13.GL_TEXTURE0) {
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE2);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, normTex);
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE3);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, specTex);
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE0);
|
||||
}
|
||||
// Shaders.checkGLError("bindNSTextures");
|
||||
}
|
||||
|
||||
public static void bindNSTextures(MultiTexID multiTex) {
|
||||
bindNSTextures(multiTex.norm, multiTex.spec);
|
||||
}
|
||||
|
||||
public static void bindTextures(int baseTex, int normTex, int specTex) {
|
||||
// Shaders.checkGLError("pre bindTextures");
|
||||
if (Shaders.isRenderingWorld && Shaders.activeTexUnit == GL13.GL_TEXTURE0) {
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE2);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, normTex);
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE3);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, specTex);
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE0);
|
||||
}
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, baseTex);
|
||||
// Shaders.checkGLError("bindTextures");
|
||||
}
|
||||
|
||||
public static void bindTextures(MultiTexID multiTex) {
|
||||
boundTex = multiTex;
|
||||
if (Shaders.isRenderingWorld && Shaders.activeTexUnit == GL13.GL_TEXTURE0) {
|
||||
if (Shaders.configNormalMap) {
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE2);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm);
|
||||
}
|
||||
if (Shaders.configSpecularMap) {
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE3);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.spec);
|
||||
}
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE0);
|
||||
}
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.base);
|
||||
}
|
||||
|
||||
public static void bindTexture(ITextureObject tex) {
|
||||
if (tex instanceof TextureMap) {
|
||||
Shaders.atlasSizeX = ((TextureMap) tex).atlasWidth;
|
||||
Shaders.atlasSizeY = ((TextureMap) tex).atlasHeight;
|
||||
} else {
|
||||
Shaders.atlasSizeX = 0;
|
||||
Shaders.atlasSizeY = 0;
|
||||
}
|
||||
bindTextures(tex.getMultiTexID());
|
||||
}
|
||||
|
||||
/** not used */
|
||||
public static void bindTextures(int baseTex) {
|
||||
MultiTexID multiTex = multiTexMap.get(Integer.valueOf(baseTex));
|
||||
bindTextures(multiTex);
|
||||
}
|
||||
|
||||
public static void allocTexStorage(int width, int height, int maxLevel) {
|
||||
Shaders.checkGLError("pre allocTexStorage");
|
||||
int level;
|
||||
for (level = 0; (width >> level) > 0 && (height >> level) > 0 /*&& level<=maxLevel*/; ++level) {
|
||||
GL11.glTexImage2D(
|
||||
GL11.GL_TEXTURE_2D,
|
||||
level,
|
||||
GL11.GL_RGBA,
|
||||
(width >> level),
|
||||
(height >> level),
|
||||
0,
|
||||
GL12.GL_BGRA,
|
||||
GL12.GL_UNSIGNED_INT_8_8_8_8_REV,
|
||||
(IntBuffer) null);
|
||||
}
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LEVEL, level - 1);
|
||||
Shaders.checkGLError("allocTexStorage");
|
||||
// clear unused level otherwise glTexSubImage2D will crash on AMD when reallocation texture of different size.
|
||||
// for ( ; level < 16 ; ++level) {
|
||||
// GL11.glTexImage2D(GL11.GL_TEXTURE_2D, level, GL11.GL_RGBA, 0, 0, 0, GL12.GL_BGRA,
|
||||
// GL12.GL_UNSIGNED_INT_8_8_8_8_REV, (IntBuffer)null);
|
||||
// }
|
||||
GL11.glGetError(); // It usually returns error 0x0501 Invalid value for width 0 height 0. Ignore it.
|
||||
}
|
||||
|
||||
// for Dynamic Texture
|
||||
public static void initDynamicTexture(int texID, int width, int height, DynamicTexture tex) {
|
||||
MultiTexID multiTex = tex.getMultiTexID();
|
||||
int[] aint = tex.getTextureData();
|
||||
int size = width * height;
|
||||
Arrays.fill(aint, size, size * 2, defNormTexColor);
|
||||
Arrays.fill(aint, size * 2, size * 3, defSpecTexColor);
|
||||
// base texture
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.base);
|
||||
allocTexStorage(width, height, 0);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LEVEL, 0);
|
||||
|
||||
// norm texture
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm);
|
||||
allocTexStorage(width, height, 0);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LEVEL, 0);
|
||||
|
||||
// spec texture
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.spec);
|
||||
allocTexStorage(width, height, 0);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL12.GL_TEXTURE_MAX_LEVEL, 0);
|
||||
|
||||
// base texture
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.base);
|
||||
}
|
||||
|
||||
public static ITextureObject createDefaultTexture() {
|
||||
DynamicTexture tex = new DynamicTexture(1, 1);
|
||||
tex.getTextureData()[0] = 0xffffffff;
|
||||
tex.updateDynamicTexture();
|
||||
return tex;
|
||||
}
|
||||
|
||||
// for TextureMap
|
||||
public static void allocateTextureMap(
|
||||
int texID, int mipmapLevels, int width, int height, float anisotropy, Stitcher stitcher, TextureMap tex) {
|
||||
System.out.println("allocateTextureMap " + tex.getTextureType() + " " + mipmapLevels + " " + width + " "
|
||||
+ height + " " + anisotropy + " ");
|
||||
updatingTextureMap = tex;
|
||||
tex.atlasWidth = width;
|
||||
tex.atlasHeight = height;
|
||||
MultiTexID multiTex = getMultiTexID(tex);
|
||||
updatingTex = multiTex;
|
||||
TextureUtil.allocateTextureImpl(multiTex.base, mipmapLevels, width, height, anisotropy);
|
||||
if (Shaders.configNormalMap)
|
||||
TextureUtil.allocateTextureImpl(multiTex.norm, mipmapLevels, width, height, anisotropy);
|
||||
if (Shaders.configSpecularMap)
|
||||
TextureUtil.allocateTextureImpl(multiTex.spec, mipmapLevels, width, height, anisotropy);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texID);
|
||||
}
|
||||
|
||||
public static TextureAtlasSprite setSprite(TextureAtlasSprite tas) {
|
||||
return updatingSprite = tas;
|
||||
}
|
||||
|
||||
public static String setIconName(String name) {
|
||||
return iconName = name;
|
||||
}
|
||||
|
||||
public static void uploadTexSubForLoadAtlas(
|
||||
int[][] data, int width, int height, int xoffset, int yoffset, boolean linear, boolean clamp) {
|
||||
TextureUtil.uploadTextureMipmap(data, width, height, xoffset, yoffset, linear, clamp);
|
||||
boolean border = updatingSprite.useAnisotropicFiltering;
|
||||
int[][] aaint;
|
||||
//
|
||||
if (Shaders.configNormalMap) {
|
||||
aaint = readImageAndMipmaps(iconName + "_n", width, height, data.length, border, defNormTexColor);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, updatingTex.norm);
|
||||
TextureUtil.uploadTextureMipmap(aaint, width, height, xoffset, yoffset, linear, clamp);
|
||||
}
|
||||
//
|
||||
if (Shaders.configSpecularMap) {
|
||||
aaint = readImageAndMipmaps(iconName + "_s", width, height, data.length, border, defSpecTexColor);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, updatingTex.spec);
|
||||
TextureUtil.uploadTextureMipmap(aaint, width, height, xoffset, yoffset, linear, clamp);
|
||||
}
|
||||
//
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, updatingTex.base);
|
||||
}
|
||||
|
||||
public static int[][] readImageAndMipmaps(
|
||||
String name, int width, int height, int numLevels, boolean border, int defColor) {
|
||||
int[][] aaint = new int[numLevels][];
|
||||
int[] aint;
|
||||
aaint[0] = aint = new int[width * height];
|
||||
boolean goodImage = false;
|
||||
BufferedImage image = readImage(updatingTextureMap.completeResourceLocation(new ResourceLocation(name), 0));
|
||||
if (image != null) {
|
||||
int imageWidth = image.getWidth();
|
||||
int imageHeight = image.getHeight();
|
||||
if (imageWidth + (border ? 16 : 0) == width) {
|
||||
goodImage = true;
|
||||
image.getRGB(0, 0, imageWidth, imageWidth, aint, 0, imageWidth);
|
||||
if (border) TextureUtil.prepareAnisotropicData(aint, imageWidth, imageWidth, 8);
|
||||
}
|
||||
}
|
||||
if (!goodImage) {
|
||||
Arrays.fill(aint, defColor);
|
||||
}
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, updatingTex.spec);
|
||||
aaint = genMipmapsSimple(aaint.length - 1, width, aaint);
|
||||
return aaint;
|
||||
}
|
||||
|
||||
public static BufferedImage readImage(ResourceLocation resLoc) {
|
||||
BufferedImage image = null;
|
||||
InputStream istr = null;
|
||||
if (resManager != null) {
|
||||
try {
|
||||
istr = resManager.getResource(resLoc).getInputStream();
|
||||
image = ImageIO.read(istr);
|
||||
} catch (IOException e) {
|
||||
}
|
||||
if (istr != null) {
|
||||
try {
|
||||
istr.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
istr = null;
|
||||
}
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
public static int[][] genMipmapsSimple(int maxLevel, int width, int[][] data) {
|
||||
int level;
|
||||
for (level = 1; level <= maxLevel; ++level) {
|
||||
if (data[level] == null) {
|
||||
int cw = width >> level;
|
||||
int pw = cw * 2;
|
||||
int[] aintp = data[level - 1];
|
||||
int[] aintc = data[level] = new int[cw * cw];
|
||||
int x, y;
|
||||
for (y = 0; y < cw; ++y) {
|
||||
for (x = 0; x < cw; ++x) {
|
||||
int ppos = y * 2 * pw + x * 2;
|
||||
aintc[y * cw + x] =
|
||||
blend4Simple(aintp[ppos], aintp[ppos + 1], aintp[ppos + pw], aintp[ppos + pw + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public static void uploadTexSub(
|
||||
int[][] data, int width, int height, int xoffset, int yoffset, boolean linear, boolean clamp) {
|
||||
TextureUtil.uploadTextureMipmap(data, width, height, xoffset, yoffset, linear, clamp);
|
||||
}
|
||||
|
||||
public static int blend4Alpha(int c0, int c1, int c2, int c3) {
|
||||
int a0 = (c0 >>> 24) & 255;
|
||||
int a1 = (c1 >>> 24) & 255;
|
||||
int a2 = (c2 >>> 24) & 255;
|
||||
int a3 = (c3 >>> 24) & 255;
|
||||
int as = a0 + a1 + a2 + a3;
|
||||
int an = (as + 2) / 4;
|
||||
// int an = Math.min(Math.min(Math.min(a0,a1),a2),a3);
|
||||
int dv;
|
||||
if (as != 0) {
|
||||
dv = as;
|
||||
} else {
|
||||
dv = 4;
|
||||
a3 = a2 = a1 = a0 = 1;
|
||||
}
|
||||
int frac = (dv + 1) / 2;
|
||||
// return (((Math.min(Math.min(Math.min(a0,a1),a2),a3)/ 4) << 24) |
|
||||
int color = (an << 24)
|
||||
| (((((c0 >>> 16) & 255) * a0
|
||||
+ ((c1 >>> 16) & 255) * a1
|
||||
+ ((c2 >>> 16) & 255) * a2
|
||||
+ ((c3 >>> 16) & 255) * a3
|
||||
+ frac)
|
||||
/ dv)
|
||||
<< 16)
|
||||
| (((((c0 >>> 8) & 255) * a0
|
||||
+ ((c1 >>> 8) & 255) * a1
|
||||
+ ((c2 >>> 8) & 255) * a2
|
||||
+ ((c3 >>> 8) & 255) * a3
|
||||
+ frac)
|
||||
/ dv)
|
||||
<< 8)
|
||||
| (((((c0 >>> 0) & 255) * a0
|
||||
+ ((c1 >>> 0) & 255) * a1
|
||||
+ ((c2 >>> 0) & 255) * a2
|
||||
+ ((c3 >>> 0) & 255) * a3
|
||||
+ frac)
|
||||
/ dv)
|
||||
<< 0);
|
||||
return color;
|
||||
}
|
||||
|
||||
public static int blend4Simple(int c0, int c1, int c2, int c3) {
|
||||
int color = (((((c0 >>> 24) & 255) + ((c1 >>> 24) & 255) + ((c2 >>> 24) & 255) + ((c3 >>> 24) & 255) + 2) / 4)
|
||||
<< 24)
|
||||
| (((((c0 >>> 16) & 255) + ((c1 >>> 16) & 255) + ((c2 >>> 16) & 255) + ((c3 >>> 16) & 255) + 2) / 4)
|
||||
<< 16)
|
||||
| (((((c0 >>> 8) & 255) + ((c1 >>> 8) & 255) + ((c2 >>> 8) & 255) + ((c3 >>> 8) & 255) + 2) / 4) << 8)
|
||||
| (((((c0 >>> 0) & 255) + ((c1 >>> 0) & 255) + ((c2 >>> 0) & 255) + ((c3 >>> 0) & 255) + 2) / 4) << 0);
|
||||
return color;
|
||||
}
|
||||
|
||||
public static void genMipmapAlpha(int[] aint, int offset, int width, int height) {
|
||||
int minwh = Math.min(width, height);
|
||||
int level;
|
||||
int w1, w2, h1, h2, o1, o2;
|
||||
w1 = w2 = width;
|
||||
h1 = h2 = height;
|
||||
o1 = o2 = offset;
|
||||
// generate mipmap from big to small
|
||||
o2 = offset;
|
||||
w2 = width;
|
||||
h2 = height;
|
||||
o1 = 0;
|
||||
w1 = 0;
|
||||
h1 = 0;
|
||||
for (level = 0; w2 > 1 && h2 > 1; ++level, w2 = w1, h2 = h1, o2 = o1) {
|
||||
o1 = o2 + w2 * h2;
|
||||
w1 = w2 / 2;
|
||||
h1 = h2 / 2;
|
||||
for (int y = 0; y < h1; ++y) {
|
||||
int p1 = o1 + y * w1;
|
||||
int p2 = o2 + y * 2 * w2;
|
||||
for (int x = 0; x < w1; ++x) {
|
||||
aint[p1 + x] = blend4Alpha(
|
||||
aint[p2 + (x * 2)],
|
||||
aint[p2 + (x * 2 + 1)],
|
||||
aint[p2 + w2 + (x * 2)],
|
||||
aint[p2 + w2 + (x * 2 + 1)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// fix black pixels from small to big
|
||||
while (level > 0) {
|
||||
--level;
|
||||
w2 = width >> level;
|
||||
h2 = height >> level;
|
||||
o2 = o1 - w2 * h2;
|
||||
int p2 = o2;
|
||||
for (int y = 0; y < h2; ++y) {
|
||||
for (int x = 0; x < w2; ++x) {
|
||||
// p2 = o2 + y*w2 + x;
|
||||
if (aint[p2] == 0) {
|
||||
aint[p2] = aint[o1 + (y / 2) * w1 + (x / 2)] & 0x00ffffff;
|
||||
}
|
||||
++p2;
|
||||
}
|
||||
}
|
||||
o1 = o2;
|
||||
w1 = w2;
|
||||
h1 = h2;
|
||||
}
|
||||
}
|
||||
|
||||
public static void genMipmapSimple(int[] aint, int offset, int width, int height) {
|
||||
int minwh = Math.min(width, height);
|
||||
int level;
|
||||
int w1, w2, h1, h2, o1, o2;
|
||||
w1 = w2 = width;
|
||||
h1 = h2 = height;
|
||||
o1 = o2 = offset;
|
||||
// generate mipmap from big to small
|
||||
o2 = offset;
|
||||
w2 = width;
|
||||
h2 = height;
|
||||
o1 = 0;
|
||||
w1 = 0;
|
||||
h1 = 0;
|
||||
for (level = 0; w2 > 1 && h2 > 1; ++level, w2 = w1, h2 = h1, o2 = o1) {
|
||||
o1 = o2 + w2 * h2;
|
||||
w1 = w2 / 2;
|
||||
h1 = h2 / 2;
|
||||
for (int y = 0; y < h1; ++y) {
|
||||
int p1 = o1 + y * w1;
|
||||
int p2 = o2 + y * 2 * w2;
|
||||
for (int x = 0; x < w1; ++x) {
|
||||
aint[p1 + x] = blend4Simple(
|
||||
aint[p2 + (x * 2)],
|
||||
aint[p2 + (x * 2 + 1)],
|
||||
aint[p2 + w2 + (x * 2)],
|
||||
aint[p2 + w2 + (x * 2 + 1)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// fix black pixels from small to big
|
||||
while (level > 0) {
|
||||
--level;
|
||||
w2 = width >> level;
|
||||
h2 = height >> level;
|
||||
o2 = o1 - w2 * h2;
|
||||
int p2 = o2;
|
||||
for (int y = 0; y < h2; ++y) {
|
||||
for (int x = 0; x < w2; ++x) {
|
||||
// p2 = o2 + y*w2 + x;
|
||||
if (aint[p2] == 0) {
|
||||
aint[p2] = aint[o1 + (y / 2) * w1 + (x / 2)] & 0x00ffffff;
|
||||
}
|
||||
++p2;
|
||||
}
|
||||
}
|
||||
o1 = o2;
|
||||
w1 = w2;
|
||||
h1 = h2;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isSemiTransparent(int[] aint, int width, int height) {
|
||||
int size = width * height;
|
||||
// grass side texture ?;
|
||||
if (aint[0] >>> 24 == 255 && aint[size - 1] == 0) return true;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
int alpha = aint[i] >>> 24;
|
||||
if (alpha != 0 && alpha != 255) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void updateSubImage1(int[] src, int width, int height, int posX, int posY, int page, int color) {
|
||||
int size = width * height;
|
||||
IntBuffer intBuf = getIntBuffer(size);
|
||||
int[] aint = getIntArray((size * 4 + 2) / 3);
|
||||
if (src.length >= size * (page + 1)) {
|
||||
System.arraycopy(src, size * page, aint, 0, size);
|
||||
} else {
|
||||
Arrays.fill(aint, color);
|
||||
}
|
||||
//
|
||||
// if (page == 0)
|
||||
genMipmapAlpha(aint, 0, width, height);
|
||||
// else
|
||||
// genMipmapSimple(aint,0,width,height);
|
||||
//
|
||||
for (int level = 0, offset = 0, lw = width, lh = height, px = posX, py = posY; lw > 0 && lh > 0; ++level) {
|
||||
int lsize = lw * lh;
|
||||
intBuf.clear();
|
||||
intBuf.put(aint, offset, lsize).position(0).limit(lsize);
|
||||
GL11.glTexSubImage2D(
|
||||
GL11.GL_TEXTURE_2D, level, px, py, lw, lh, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, intBuf);
|
||||
offset += lsize;
|
||||
lw /= 2;
|
||||
lh /= 2;
|
||||
px /= 2;
|
||||
py /= 2;
|
||||
}
|
||||
intBuf.clear();
|
||||
}
|
||||
|
||||
public static void updateSubTex1(int[] src, int width, int height, int posX, int posY) {
|
||||
int level;
|
||||
int cw;
|
||||
int ch;
|
||||
int cx;
|
||||
int cy;
|
||||
for (level = 0, cw = width, ch = height, cx = posX, cy = posY;
|
||||
cw > 0 && ch > 0;
|
||||
++level, cw /= 2, ch /= 2, cx /= 2, cy /= 2) {
|
||||
GL11.glCopyTexSubImage2D(GL11.GL_TEXTURE_2D, level, cx, cy, 0, 0, cw, ch);
|
||||
}
|
||||
}
|
||||
|
||||
/* updateSubImage for single Texture with mipmap */
|
||||
public static void updateSubImage1(int[][] src, int width, int height, int posX, int posY, int page, int color) {
|
||||
int size = width * height;
|
||||
IntBuffer intBuf = getIntBuffer(size);
|
||||
int numLevel = src.length;
|
||||
for (int level = 0, // offset=0,
|
||||
lw = width,
|
||||
lh = height,
|
||||
px = posX,
|
||||
py = posY;
|
||||
lw > 0 && lh > 0 && level < numLevel;
|
||||
++level) {
|
||||
int lsize = lw * lh;
|
||||
intBuf.clear();
|
||||
intBuf.put(src[level], 0 /*offset*/, lsize).position(0).limit(lsize);
|
||||
GL11.glTexSubImage2D(
|
||||
GL11.GL_TEXTURE_2D, level, px, py, lw, lh, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, intBuf);
|
||||
// offset += lsize;
|
||||
lw /= 2;
|
||||
lh /= 2;
|
||||
px /= 2;
|
||||
py /= 2;
|
||||
}
|
||||
intBuf.clear();
|
||||
}
|
||||
|
||||
public static void setupTextureMipmap(TextureMap tex) {
|
||||
/*
|
||||
MultiTexID multiTex = tex.getMultiTexID();
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm);
|
||||
GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.spec);
|
||||
GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.base);
|
||||
GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D);
|
||||
*/
|
||||
}
|
||||
|
||||
public static void updateDynamicTexture(int texID, int[] src, int width, int height, DynamicTexture tex) {
|
||||
MultiTexID multiTex = tex.getMultiTexID();
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm);
|
||||
updateSubImage1(src, width, height, 0, 0, 1, defNormTexColor);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.spec);
|
||||
updateSubImage1(src, width, height, 0, 0, 2, defSpecTexColor);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.base);
|
||||
updateSubImage1(src, width, height, 0, 0, 0, defBaseTexColor);
|
||||
}
|
||||
|
||||
public static void updateSubImage(
|
||||
int[] src, int width, int height, int posX, int posY, boolean linear, boolean clamp) {
|
||||
if (updatingTex != null) {
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, updatingTex.norm);
|
||||
updateSubImage1(src, width, height, posX, posY, 1, defNormTexColor);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, updatingTex.spec);
|
||||
updateSubImage1(src, width, height, posX, posY, 2, defSpecTexColor);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, updatingTex.base);
|
||||
}
|
||||
updateSubImage1(src, width, height, posX, posY, 0, defBaseTexColor);
|
||||
}
|
||||
|
||||
// not used
|
||||
public static void updateAnimationTextureMap(TextureMap tex, List tasList) {
|
||||
Iterator<TextureAtlasSprite> iterator;
|
||||
MultiTexID multiTex = tex.getMultiTexID();
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm);
|
||||
for (iterator = tasList.iterator(); iterator.hasNext(); ) {
|
||||
TextureAtlasSprite tas = iterator.next();
|
||||
tas.updateAnimation();
|
||||
}
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm);
|
||||
for (iterator = tasList.iterator(); iterator.hasNext(); ) {
|
||||
TextureAtlasSprite tas = iterator.next();
|
||||
tas.updateAnimation();
|
||||
}
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm);
|
||||
for (iterator = tasList.iterator(); iterator.hasNext(); ) {
|
||||
TextureAtlasSprite tas = iterator.next();
|
||||
tas.updateAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
public static void setupTexture(
|
||||
MultiTexID multiTex, int[] src, int width, int height, boolean linear, boolean clamp) {
|
||||
int mmfilter = linear ? GL11.GL_LINEAR : GL11.GL_NEAREST;
|
||||
int wraptype = clamp ? GL11.GL_CLAMP : GL11.GL_REPEAT;
|
||||
int size = width * height;
|
||||
IntBuffer intBuf = getIntBuffer(size);
|
||||
//
|
||||
intBuf.clear();
|
||||
intBuf.put(src, 0, size).position(0).limit(size);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.base);
|
||||
GL11.glTexImage2D(
|
||||
GL11.GL_TEXTURE_2D,
|
||||
0,
|
||||
GL11.GL_RGBA,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
GL12.GL_BGRA,
|
||||
GL12.GL_UNSIGNED_INT_8_8_8_8_REV,
|
||||
intBuf);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, mmfilter);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, mmfilter);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, wraptype);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, wraptype);
|
||||
//
|
||||
intBuf.put(src, size, size).position(0).limit(size);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm);
|
||||
GL11.glTexImage2D(
|
||||
GL11.GL_TEXTURE_2D,
|
||||
0,
|
||||
GL11.GL_RGBA,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
GL12.GL_BGRA,
|
||||
GL12.GL_UNSIGNED_INT_8_8_8_8_REV,
|
||||
intBuf);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, mmfilter);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, mmfilter);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, wraptype);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, wraptype);
|
||||
//
|
||||
intBuf.put(src, size * 2, size).position(0).limit(size);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.spec);
|
||||
GL11.glTexImage2D(
|
||||
GL11.GL_TEXTURE_2D,
|
||||
0,
|
||||
GL11.GL_RGBA,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
GL12.GL_BGRA,
|
||||
GL12.GL_UNSIGNED_INT_8_8_8_8_REV,
|
||||
intBuf);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, mmfilter);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, mmfilter);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, wraptype);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, wraptype);
|
||||
//
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.base);
|
||||
}
|
||||
|
||||
/* currently not used */
|
||||
public static void updateSubImage(
|
||||
MultiTexID multiTex, int[] src, int width, int height, int posX, int posY, boolean linear, boolean clamp) {
|
||||
int size = width * height;
|
||||
IntBuffer intBuf = getIntBuffer(size);
|
||||
//
|
||||
intBuf.clear();
|
||||
intBuf.put(src, 0, size);
|
||||
intBuf.position(0).limit(size);
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.base);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
|
||||
GL11.glTexSubImage2D(
|
||||
GL11.GL_TEXTURE_2D,
|
||||
0,
|
||||
posX,
|
||||
posY,
|
||||
width,
|
||||
height,
|
||||
GL12.GL_BGRA,
|
||||
GL12.GL_UNSIGNED_INT_8_8_8_8_REV,
|
||||
intBuf);
|
||||
if (src.length == size * 3) {
|
||||
intBuf.clear();
|
||||
intBuf.put(src, size, size).position(0);
|
||||
intBuf.position(0).limit(size);
|
||||
}
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
|
||||
GL11.glTexSubImage2D(
|
||||
GL11.GL_TEXTURE_2D,
|
||||
0,
|
||||
posX,
|
||||
posY,
|
||||
width,
|
||||
height,
|
||||
GL12.GL_BGRA,
|
||||
GL12.GL_UNSIGNED_INT_8_8_8_8_REV,
|
||||
intBuf);
|
||||
if (src.length == size * 3) {
|
||||
intBuf.clear();
|
||||
intBuf.put(src, size * 2, size);
|
||||
intBuf.position(0).limit(size);
|
||||
}
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.spec);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT);
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT);
|
||||
GL11.glTexSubImage2D(
|
||||
GL11.GL_TEXTURE_2D,
|
||||
0,
|
||||
posX,
|
||||
posY,
|
||||
width,
|
||||
height,
|
||||
GL12.GL_BGRA,
|
||||
GL12.GL_UNSIGNED_INT_8_8_8_8_REV,
|
||||
intBuf);
|
||||
GL13.glActiveTexture(GL13.GL_TEXTURE0);
|
||||
}
|
||||
|
||||
public static ResourceLocation getNSMapLocation(ResourceLocation location, String mapName) {
|
||||
String basename = location.getResourcePath();
|
||||
String[] basenameParts = basename.split(".png");
|
||||
String basenameNoFileType = basenameParts[0];
|
||||
return new ResourceLocation(location.getResourceDomain(), basenameNoFileType + "_" + mapName + ".png");
|
||||
}
|
||||
|
||||
public static void loadNSMap(
|
||||
IResourceManager manager, ResourceLocation location, int width, int height, int[] aint) {
|
||||
if (Shaders.configNormalMap)
|
||||
ShadersTex.loadNSMap1(
|
||||
manager, getNSMapLocation(location, "n"), width, height, aint, width * height, defNormTexColor);
|
||||
if (Shaders.configSpecularMap)
|
||||
ShadersTex.loadNSMap1(
|
||||
manager, getNSMapLocation(location, "s"), width, height, aint, width * height * 2, defSpecTexColor);
|
||||
}
|
||||
|
||||
public static void loadNSMap1(
|
||||
IResourceManager manager,
|
||||
ResourceLocation location,
|
||||
int width,
|
||||
int height,
|
||||
int[] aint,
|
||||
int offset,
|
||||
int defaultColor) {
|
||||
boolean good = false;
|
||||
try {
|
||||
IResource res = manager.getResource(location);
|
||||
BufferedImage bufferedimage = ImageIO.read(res.getInputStream());
|
||||
if (bufferedimage.getWidth() == width && bufferedimage.getHeight() == height) {
|
||||
bufferedimage.getRGB(0, 0, width, height, aint, offset, width);
|
||||
good = true;
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
if (!good) {
|
||||
java.util.Arrays.fill(aint, offset, offset + width * height, defaultColor);
|
||||
}
|
||||
}
|
||||
|
||||
/** init and upload from BufferedImage */
|
||||
/* Replacement for TextureUtil.func_110989_a call in SimpleTexture.func_110551_a.
|
||||
Keep par0...par5 the same as func_110989_a for easy patching.
|
||||
More parameters added for reading N-S-Map. */
|
||||
public static int loadSimpleTexture(
|
||||
int textureID,
|
||||
BufferedImage bufferedimage,
|
||||
boolean linear,
|
||||
boolean clamp,
|
||||
IResourceManager resourceManager,
|
||||
ResourceLocation location,
|
||||
MultiTexID multiTex) {
|
||||
int width = bufferedimage.getWidth();
|
||||
int height = bufferedimage.getHeight();
|
||||
int size = width * height;
|
||||
int[] aint = getIntArray(size * 3);
|
||||
bufferedimage.getRGB(0, 0, width, height, aint, 0, width);
|
||||
loadNSMap(resourceManager, location, width, height, aint);
|
||||
setupTexture(multiTex, aint, width, height, linear, clamp);
|
||||
return textureID;
|
||||
}
|
||||
|
||||
public static void mergeImage(int[] aint, int dstoff, int srcoff, int size) {}
|
||||
|
||||
public static int blendColor(int color1, int color2, int factor1) {
|
||||
int factor2 = 255 - factor1;
|
||||
return (((((color1 >>> 24) & 255) * factor1 + ((color2 >>> 24) & 255) * factor2) / 255) << 24)
|
||||
| (((((color1 >>> 16) & 255) * factor1 + ((color2 >>> 16) & 255) * factor2) / 255) << 16)
|
||||
| (((((color1 >>> 8) & 255) * factor1 + ((color2 >>> 8) & 255) * factor2) / 255) << 8)
|
||||
| (((((color1 >>> 0) & 255) * factor1 + ((color2 >>> 0) & 255) * factor2) / 255) << 0);
|
||||
}
|
||||
|
||||
public static void loadLayeredTexture(LayeredTexture tex, IResourceManager manager, List list) {
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
int size = 0;
|
||||
int[] image = null;
|
||||
Iterator<String> iterator;
|
||||
for (iterator = list.iterator(); iterator.hasNext(); ) {
|
||||
String s = iterator.next();
|
||||
if (s != null) {
|
||||
try {
|
||||
ResourceLocation location = new ResourceLocation(s);
|
||||
InputStream inputstream = manager.getResource(location).getInputStream();
|
||||
BufferedImage bufimg = ImageIO.read(inputstream);
|
||||
|
||||
if (size == 0) {
|
||||
width = bufimg.getWidth();
|
||||
height = bufimg.getHeight();
|
||||
size = width * height;
|
||||
image = createAIntImage(size, 0x00000000);
|
||||
}
|
||||
int[] aint = getIntArray(size * 3);
|
||||
bufimg.getRGB(0, 0, width, height, aint, 0, width);
|
||||
loadNSMap(manager, location, width, height, aint);
|
||||
// merge
|
||||
for (int i = 0; i < size; ++i) {
|
||||
int alpha = (aint[i] >>> 24) & 255;
|
||||
image[size * 0 + i] = blendColor(aint[size * 0 + i], image[size * 0 + i], alpha);
|
||||
image[size * 1 + i] = blendColor(aint[size * 1 + i], image[size * 1 + i], alpha);
|
||||
image[size * 2 + i] = blendColor(aint[size * 2 + i], image[size * 2 + i], alpha);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
// init and upload
|
||||
setupTexture(tex.getMultiTexID(), image, width, height, false, false);
|
||||
}
|
||||
|
||||
/* update block texture filter +/- items texture */
|
||||
static void updateTextureMinMagFilter() {
|
||||
TextureManager texman = Minecraft.getMinecraft().getTextureManager();
|
||||
ITextureObject texObj = texman.getTexture(TextureMap.locationBlocksTexture);
|
||||
if (texObj != null) {
|
||||
MultiTexID multiTex = texObj.getMultiTexID();
|
||||
// base texture
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.base);
|
||||
GL11.glTexParameteri(
|
||||
GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, Shaders.texMinFilValue[Shaders.configTexMinFilB]);
|
||||
GL11.glTexParameteri(
|
||||
GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, Shaders.texMagFilValue[Shaders.configTexMagFilB]);
|
||||
// norm texture
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.norm);
|
||||
GL11.glTexParameteri(
|
||||
GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, Shaders.texMinFilValue[Shaders.configTexMinFilN]);
|
||||
GL11.glTexParameteri(
|
||||
GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, Shaders.texMagFilValue[Shaders.configTexMagFilN]);
|
||||
|
||||
// spec texture
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, multiTex.spec);
|
||||
GL11.glTexParameteri(
|
||||
GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, Shaders.texMinFilValue[Shaders.configTexMinFilS]);
|
||||
GL11.glTexParameteri(
|
||||
GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, Shaders.texMagFilValue[Shaders.configTexMagFilS]);
|
||||
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static IResourceManager resManager = null;
|
||||
static ResourceLocation resLocation = null;
|
||||
static int imageSize = 0;
|
||||
|
||||
public static IResource loadResource(IResourceManager manager, ResourceLocation location) throws IOException {
|
||||
resManager = manager;
|
||||
resLocation = location;
|
||||
return manager.getResource(location);
|
||||
}
|
||||
|
||||
public static int[] loadAtlasSprite(
|
||||
BufferedImage bufferedimage, int startX, int startY, int w, int h, int[] aint, int offset, int scansize) {
|
||||
imageSize = w * h;
|
||||
bufferedimage.getRGB(startX, startY, w, h, aint, offset, scansize);
|
||||
loadNSMap(resManager, resLocation, w, h, aint);
|
||||
return aint;
|
||||
}
|
||||
|
||||
public static int[] extractFrame(int[] src, int width, int height, int frameIndex) {
|
||||
int srcSize = imageSize;
|
||||
int frameSize = width * height;
|
||||
int[] dst = new int[frameSize * 3];
|
||||
int srcPos = frameSize * frameIndex;
|
||||
int dstPos = 0;
|
||||
System.arraycopy(src, srcPos, dst, dstPos, frameSize);
|
||||
srcPos += srcSize;
|
||||
dstPos += frameSize;
|
||||
System.arraycopy(src, srcPos, dst, dstPos, frameSize);
|
||||
srcPos += srcSize;
|
||||
dstPos += frameSize;
|
||||
System.arraycopy(src, srcPos, dst, dstPos, frameSize);
|
||||
return dst;
|
||||
}
|
||||
|
||||
public static void fixTransparentColor(TextureAtlasSprite tas, int[] aint) {}
|
||||
}
|
||||
@@ -0,0 +1,632 @@
|
||||
package com.gtnewhorizons.angelica.client.font;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.gtnewhorizon.gtnhlib.util.font.GlyphReplacements;
|
||||
import com.gtnewhorizons.angelica.config.FontConfig;
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.mixins.interfaces.FontRendererAccessor;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import net.coderbot.iris.gl.program.Program;
|
||||
import net.coderbot.iris.gl.program.ProgramBuilder;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.util.MathHelper;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
import org.lwjgl.opengl.GL13;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Comparator;
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.gtnewhorizon.gtnhlib.bytebuf.MemoryUtilities.*;
|
||||
|
||||
/**
|
||||
* A batching replacement for {@code FontRenderer}
|
||||
*
|
||||
* @author eigenraven
|
||||
*/
|
||||
public class BatchingFontRenderer {
|
||||
|
||||
/** The underlying FontRenderer object that's being accelerated */
|
||||
protected FontRenderer underlying;
|
||||
/** Array of width of all the characters in default.png */
|
||||
protected int[] charWidth = new int[256];
|
||||
/** Array of the start/end column (in upper/lower nibble) for every glyph in the /font directory. */
|
||||
protected byte[] glyphWidth;
|
||||
/**
|
||||
* Array of RGB triplets defining the 16 standard chat colors followed by 16 darker version of the same colors for
|
||||
* drop shadows.
|
||||
*/
|
||||
private int[] colorCode;
|
||||
/** Location of the primary font atlas to bind. */
|
||||
protected final ResourceLocation locationFontTexture;
|
||||
|
||||
private final int AAMode;
|
||||
private final int AAStrength;
|
||||
private final int texBoundAttrLocation;
|
||||
private final int fontShaderId;
|
||||
|
||||
final boolean isSGA;
|
||||
final boolean isSplash;
|
||||
|
||||
private static class FontAAShader {
|
||||
|
||||
private static Program fontShader = null;
|
||||
public static Program getProgram() {
|
||||
if (fontShader == null) {
|
||||
String vsh, fsh;
|
||||
try {
|
||||
fsh = new String(IOUtils.toByteArray(Objects.requireNonNull(FontAAShader.class.getResourceAsStream("/assets/angelica/shaders/fontFilter.fsh"))), StandardCharsets.UTF_8);
|
||||
vsh = new String(IOUtils.toByteArray(Objects.requireNonNull(FontAAShader.class.getResourceAsStream("/assets/angelica/shaders/fontFilter.vsh"))), StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
ProgramBuilder builder = ProgramBuilder.begin("fontFilter", vsh, null, fsh, ImmutableSet.of(0));
|
||||
fontShader = builder.build();
|
||||
}
|
||||
return fontShader;
|
||||
}
|
||||
}
|
||||
|
||||
public BatchingFontRenderer(FontRenderer underlying, int[] charWidth, byte[] glyphWidth,
|
||||
int[] colorCode, ResourceLocation locationFontTexture) {
|
||||
this.underlying = underlying;
|
||||
this.charWidth = charWidth;
|
||||
this.glyphWidth = glyphWidth;
|
||||
this.colorCode = colorCode;
|
||||
this.locationFontTexture = locationFontTexture;
|
||||
|
||||
for (int i = 0; i < 64; i++) {
|
||||
batchCommandPool.add(new FontDrawCmd());
|
||||
}
|
||||
|
||||
this.isSGA = Objects.equals(this.locationFontTexture.getResourcePath(), "textures/font/ascii_sga.png");
|
||||
this.isSplash = FontStrategist.isSplashFontRendererActive(underlying);
|
||||
|
||||
FontProviderMC.get(this.isSGA).charWidth = this.charWidth;
|
||||
FontProviderMC.get(this.isSGA).locationFontTexture = this.locationFontTexture;
|
||||
FontProviderUnicode.get().glyphWidth = this.glyphWidth;
|
||||
|
||||
//noinspection deprecation
|
||||
fontShaderId = FontAAShader.getProgram().getProgramId();
|
||||
AAMode = GL20.glGetUniformLocation(fontShaderId, "aaMode");
|
||||
AAStrength = GL20.glGetUniformLocation(fontShaderId, "strength");
|
||||
texBoundAttrLocation = GL20.glGetAttribLocation(fontShaderId, "texBounds");
|
||||
}
|
||||
|
||||
// === Batched rendering
|
||||
|
||||
private int batchDepth = 0;
|
||||
|
||||
private int vtxWriterIndex = 0;
|
||||
private int idxWriterIndex = 0;
|
||||
private static final int INITIAL_BATCH_SIZE = 256;
|
||||
private static final ResourceLocation DUMMY_RESOURCE_LOCATION = new ResourceLocation("angelica$dummy",
|
||||
"this is invalid!");
|
||||
private FloatBuffer batchVtxPositions = memAllocFloat(INITIAL_BATCH_SIZE * 2);
|
||||
private ByteBuffer batchVtxColors = memAlloc(INITIAL_BATCH_SIZE * 4);
|
||||
private FloatBuffer batchVtxTexCoords = memAllocFloat(INITIAL_BATCH_SIZE * 2);
|
||||
private IntBuffer batchIndices = memAllocInt(INITIAL_BATCH_SIZE / 2 * 3);
|
||||
private FloatBuffer batchVtxTexBounds = memAllocFloat(INITIAL_BATCH_SIZE * 4);
|
||||
private final ObjectArrayList<FontDrawCmd> batchCommands = ObjectArrayList.wrap(new FontDrawCmd[64], 0);
|
||||
private final ObjectArrayList<FontDrawCmd> batchCommandPool = ObjectArrayList.wrap(new FontDrawCmd[64], 0);
|
||||
|
||||
private int blendSrcRGB = GL11.GL_SRC_ALPHA;
|
||||
private int blendDstRGB = GL11.GL_ONE_MINUS_SRC_ALPHA;
|
||||
|
||||
/** */
|
||||
private void pushVtx(float x, float y, int rgba, float u, float v, float uMin, float uMax, float vMin, float vMax) {
|
||||
final int oldCap = batchVtxPositions.capacity() / 2;
|
||||
if (vtxWriterIndex >= oldCap) {
|
||||
final int newCap = oldCap * 2;
|
||||
batchVtxPositions = memRealloc(batchVtxPositions, newCap * 2);
|
||||
batchVtxColors = memRealloc(batchVtxColors, newCap * 4);
|
||||
batchVtxTexCoords = memRealloc(batchVtxTexCoords, newCap * 2);
|
||||
batchVtxTexBounds = memRealloc(batchVtxTexBounds, newCap * 4);
|
||||
final int oldIdxCap = batchIndices.capacity();
|
||||
final int newIdxCap = oldIdxCap * 2;
|
||||
batchIndices = memRealloc(batchIndices, newIdxCap);
|
||||
}
|
||||
final int idx = vtxWriterIndex;
|
||||
final int idx2 = idx * 2;
|
||||
final int idx4 = idx * 4;
|
||||
batchVtxPositions.put(idx2, x);
|
||||
batchVtxPositions.put(idx2 + 1, y);
|
||||
// 0xAARRGGBB
|
||||
batchVtxColors.put(idx4, (byte) ((rgba >> 16) & 0xFF));
|
||||
batchVtxColors.put(idx4 + 1, (byte) ((rgba >> 8) & 0xFF));
|
||||
batchVtxColors.put(idx4 + 2, (byte) (rgba & 0xFF));
|
||||
batchVtxColors.put(idx4 + 3, (byte) ((rgba >> 24) & 0xFF));
|
||||
batchVtxTexCoords.put(idx2, u);
|
||||
batchVtxTexCoords.put(idx2 + 1, v);
|
||||
batchVtxTexBounds.put(idx4, uMin);
|
||||
batchVtxTexBounds.put(idx4 + 1, uMax);
|
||||
batchVtxTexBounds.put(idx4 + 2, vMin);
|
||||
batchVtxTexBounds.put(idx4 + 3, vMax);
|
||||
vtxWriterIndex++;
|
||||
}
|
||||
|
||||
private void pushUntexRect(float x, float y, float w, float h, int rgba) {
|
||||
final int vtxId = vtxWriterIndex;
|
||||
pushVtx(x, y, rgba, 0, 0, 0, 0, 0, 0);
|
||||
pushVtx(x, y + h, rgba, 0, 0, 0, 0, 0, 0);
|
||||
pushVtx(x + w, y, rgba, 0, 0, 0, 0, 0, 0);
|
||||
pushVtx(x + w, y + h, rgba, 0, 0, 0, 0, 0, 0);
|
||||
pushQuadIdx(vtxId);
|
||||
}
|
||||
|
||||
private void pushTexRect(float x, float y, float w, float h, float itOff, int rgba, float uStart, float vStart, float uSz, float vSz) {
|
||||
final int vtxId = vtxWriterIndex;
|
||||
pushVtx(x + itOff, y, rgba, uStart, vStart, uStart, uStart + uSz, vStart, vStart + vSz);
|
||||
pushVtx(x - itOff, y + h, rgba, uStart, vStart + vSz, uStart, uStart + uSz, vStart, vStart + vSz);
|
||||
pushVtx(x + itOff + w, y, rgba, uStart + uSz, vStart, uStart, uStart + uSz, vStart, vStart + vSz);
|
||||
pushVtx(x - itOff + w, y + h, rgba, uStart + uSz, vStart + vSz, uStart, uStart + uSz, vStart, vStart + vSz);
|
||||
pushQuadIdx(vtxId);
|
||||
}
|
||||
|
||||
private int pushQuadIdx(int startV) {
|
||||
final int idx = idxWriterIndex;
|
||||
batchIndices.put(idx, startV);
|
||||
batchIndices.put(idx + 1, startV + 1);
|
||||
batchIndices.put(idx + 2, startV + 2);
|
||||
//
|
||||
batchIndices.put(idx + 3, startV + 2);
|
||||
batchIndices.put(idx + 4, startV + 1);
|
||||
batchIndices.put(idx + 5, startV + 3);
|
||||
idxWriterIndex += 6;
|
||||
return idx;
|
||||
}
|
||||
|
||||
private void pushDrawCmd(int startIdx, int idxCount, ResourceLocation texture, boolean isUnicode) {
|
||||
if (!batchCommands.isEmpty()) {
|
||||
final FontDrawCmd lastCmd = batchCommands.get(batchCommands.size() - 1);
|
||||
final int prevEndVtx = lastCmd.startVtx + lastCmd.idxCount;
|
||||
if (prevEndVtx == startIdx && lastCmd.texture == texture) {
|
||||
// Coalesce into one
|
||||
lastCmd.idxCount += idxCount;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (batchCommandPool.isEmpty()) {
|
||||
for (int i = 0; i < 64; i++) {
|
||||
batchCommandPool.add(new FontDrawCmd());
|
||||
}
|
||||
}
|
||||
final FontDrawCmd cmd = batchCommandPool.pop();
|
||||
cmd.reset(startIdx, idxCount, texture, isUnicode);
|
||||
batchCommands.add(cmd);
|
||||
}
|
||||
|
||||
private static final class FontDrawCmd {
|
||||
|
||||
public int startVtx;
|
||||
public int idxCount;
|
||||
public boolean isUnicode;
|
||||
public ResourceLocation texture;
|
||||
|
||||
public void reset(int startVtx, int vtxCount, ResourceLocation texture, boolean isUnicode) {
|
||||
this.startVtx = startVtx;
|
||||
this.idxCount = vtxCount;
|
||||
this.texture = texture;
|
||||
this.isUnicode = isUnicode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) return true;
|
||||
if (obj == null || obj.getClass() != this.getClass()) return false;
|
||||
var that = (FontDrawCmd) obj;
|
||||
return this.startVtx == that.startVtx && this.idxCount == that.idxCount && Objects.equals(this.texture,
|
||||
that.texture);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(startVtx, idxCount, texture);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FontDrawCmd["
|
||||
+ "startVtx="
|
||||
+ startVtx
|
||||
+ ", "
|
||||
+ "vtxCount="
|
||||
+ idxCount
|
||||
+ ", "
|
||||
+ "texture="
|
||||
+ texture
|
||||
+ ']';
|
||||
}
|
||||
|
||||
public static final Comparator<FontDrawCmd> DRAW_ORDER_COMPARATOR = Comparator.comparing((FontDrawCmd fdc) -> fdc.texture,
|
||||
Comparator.nullsLast(Comparator.comparing(ResourceLocation::getResourceDomain)
|
||||
.thenComparing(ResourceLocation::getResourcePath))).thenComparing(fdc -> fdc.startVtx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a new batch of font rendering operations. Can be called from within another batch with a matching end, to
|
||||
* allow for easier optimizing of blocks of font rendering code.
|
||||
*/
|
||||
public void beginBatch() {
|
||||
if (batchDepth == Integer.MAX_VALUE) {
|
||||
throw new StackOverflowError("More than Integer.MAX_VALUE nested font rendering batch operations");
|
||||
}
|
||||
batchDepth++;
|
||||
}
|
||||
|
||||
public void endBatch() {
|
||||
if (batchDepth <= 0) {
|
||||
batchDepth = 0;
|
||||
return;
|
||||
}
|
||||
batchDepth--;
|
||||
if (batchDepth == 0) {
|
||||
// We finished any nested batches
|
||||
flushBatch();
|
||||
}
|
||||
}
|
||||
|
||||
int lastActiveProgram;
|
||||
int fontAAModeLast = -1;
|
||||
int fontAAStrengthLast = -1;
|
||||
private void flushBatch() {
|
||||
final int prevProgram = GLStateManager.glGetInteger(GL20.GL_CURRENT_PROGRAM);
|
||||
|
||||
// Sort&Draw
|
||||
batchCommands.sort(FontDrawCmd.DRAW_ORDER_COMPARATOR);
|
||||
|
||||
final boolean isTextureEnabledBefore = GLStateManager.glIsEnabled(GL11.GL_TEXTURE_2D);
|
||||
final int boundTextureBefore = GLStateManager.glGetInteger(GL11.GL_TEXTURE_BINDING_2D);
|
||||
boolean textureChanged = false;
|
||||
|
||||
ResourceLocation lastTexture = DUMMY_RESOURCE_LOCATION;
|
||||
GLStateManager.enableTexture();
|
||||
GLStateManager.enableAlphaTest();
|
||||
GLStateManager.enableBlend();
|
||||
GLStateManager.tryBlendFuncSeparate(blendSrcRGB, blendDstRGB, GL11.GL_ONE, GL11.GL_ZERO);
|
||||
GLStateManager.glShadeModel(GL11.GL_FLAT);
|
||||
|
||||
final boolean canUseAA = FontConfig.fontAAMode != 0 && prevProgram == 0;
|
||||
if (canUseAA) {
|
||||
GL20.glVertexAttribPointer(texBoundAttrLocation, 4, false, 0, batchVtxTexBounds);
|
||||
GL20.glEnableVertexAttribArray(texBoundAttrLocation);
|
||||
lastActiveProgram = prevProgram;
|
||||
GLStateManager.glUseProgram(fontShaderId);
|
||||
if (FontConfig.fontAAMode != fontAAModeLast) {
|
||||
fontAAModeLast = FontConfig.fontAAMode;
|
||||
GL20.glUniform1i(AAMode, FontConfig.fontAAMode);
|
||||
}
|
||||
if (FontConfig.fontAAStrength != fontAAStrengthLast) {
|
||||
fontAAStrengthLast = FontConfig.fontAAStrength;
|
||||
GL20.glUniform1f(AAStrength, FontConfig.fontAAStrength / 120.f);
|
||||
}
|
||||
}
|
||||
|
||||
GL13.glClientActiveTexture(GL13.GL_TEXTURE0);
|
||||
GL11.glTexCoordPointer(2, 0, batchVtxTexCoords);
|
||||
GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
|
||||
GL11.glColorPointer(4, GL11.GL_UNSIGNED_BYTE, 0, batchVtxColors);
|
||||
GL11.glEnableClientState(GL11.GL_COLOR_ARRAY);
|
||||
GL11.glVertexPointer(2, 0, batchVtxPositions);
|
||||
GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
|
||||
GLStateManager.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
GL11.glDisableClientState(GL11.GL_NORMAL_ARRAY);
|
||||
GL11.glNormal3f(0.0f, 0.0f, 1.0f);
|
||||
|
||||
// Use plain for loop to avoid allocations
|
||||
final FontDrawCmd[] cmdsData = batchCommands.elements();
|
||||
final int cmdsSize = batchCommands.size();
|
||||
for (int i = 0; i < cmdsSize; i++) {
|
||||
final FontDrawCmd cmd = cmdsData[i];
|
||||
if (!Objects.equals(lastTexture, cmd.texture)) {
|
||||
if (lastTexture == null) {
|
||||
GLStateManager.glEnable(GL11.GL_TEXTURE_2D);
|
||||
} else if (cmd.texture == null) {
|
||||
GLStateManager.glDisable(GL11.GL_TEXTURE_2D);
|
||||
}
|
||||
if (cmd.texture != null) {
|
||||
((FontRendererAccessor) underlying).angelica$bindTexture(cmd.texture);
|
||||
textureChanged = true;
|
||||
}
|
||||
lastTexture = cmd.texture;
|
||||
}
|
||||
batchIndices.limit(cmd.startVtx + cmd.idxCount);
|
||||
batchIndices.position(cmd.startVtx);
|
||||
|
||||
GL11.glDrawElements(GL11.GL_TRIANGLES, batchIndices);
|
||||
}
|
||||
if (canUseAA) {
|
||||
GLStateManager.glUseProgram(lastActiveProgram);
|
||||
GL20.glDisableVertexAttribArray(texBoundAttrLocation);
|
||||
}
|
||||
|
||||
GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
|
||||
GL11.glDisableClientState(GL11.GL_COLOR_ARRAY);
|
||||
GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY);
|
||||
|
||||
if (isTextureEnabledBefore) {
|
||||
GLStateManager.glEnable(GL11.GL_TEXTURE_2D);
|
||||
}
|
||||
if (textureChanged) {
|
||||
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, boundTextureBefore);
|
||||
}
|
||||
|
||||
// Clear for the next batch
|
||||
batchCommandPool.addAll(batchCommands);
|
||||
batchCommands.clear();
|
||||
vtxWriterIndex = 0;
|
||||
idxWriterIndex = 0;
|
||||
batchIndices.limit(batchIndices.capacity());
|
||||
batchIndices.position(0);
|
||||
}
|
||||
|
||||
// === Actual text mesh generation
|
||||
|
||||
public static boolean charInRange(char what, char fromInclusive, char toInclusive) {
|
||||
return (what >= fromInclusive) && (what <= toInclusive);
|
||||
}
|
||||
|
||||
public boolean forceDefaults() {
|
||||
return this.isSGA || this.isSplash;
|
||||
}
|
||||
|
||||
public float getGlyphScaleX() {
|
||||
return forceDefaults() ? 1 : (float) (FontConfig.glyphScale * Math.pow(2, FontConfig.glyphAspect));
|
||||
}
|
||||
|
||||
public float getGlyphScaleY() {
|
||||
return forceDefaults() ? 1 : (float) (FontConfig.glyphScale / Math.pow(2, FontConfig.glyphAspect));
|
||||
}
|
||||
|
||||
public float getGlyphSpacing() {
|
||||
return forceDefaults() ? 0 : FontConfig.glyphSpacing;
|
||||
}
|
||||
|
||||
public float getWhitespaceScale() {
|
||||
return forceDefaults() ? 1 : FontConfig.whitespaceScale;
|
||||
}
|
||||
|
||||
public float getShadowOffset() {
|
||||
return forceDefaults() ? 1 : FontConfig.fontShadowOffset;
|
||||
}
|
||||
|
||||
private static final char FORMATTING_CHAR = 167; // §
|
||||
|
||||
public float drawString(final float anchorX, final float anchorY, final int color, final boolean enableShadow,
|
||||
final boolean unicodeFlag, final CharSequence string, int stringOffset, int stringLength) {
|
||||
// noinspection SizeReplaceableByIsEmpty
|
||||
if (string == null || string.length() == 0) {
|
||||
return anchorX + (enableShadow ? 1.0f : 0.0f);
|
||||
}
|
||||
final int shadowColor = (color & 0xfcfcfc) >> 2 | color & 0xff000000;
|
||||
|
||||
FontProviderMC.get(this.isSGA).charWidth = this.charWidth;
|
||||
FontProviderMC.get(this.isSGA).locationFontTexture = this.locationFontTexture;
|
||||
|
||||
this.beginBatch();
|
||||
float curX = anchorX;
|
||||
try {
|
||||
final int totalStringLength = string.length();
|
||||
stringOffset = MathHelper.clamp_int(stringOffset, 0, totalStringLength);
|
||||
stringLength = MathHelper.clamp_int(stringLength, 0, totalStringLength - stringOffset);
|
||||
if (stringLength <= 0) {
|
||||
return 0;
|
||||
}
|
||||
final int stringEnd = stringOffset + stringLength;
|
||||
|
||||
int curColor = color;
|
||||
int curShadowColor = shadowColor;
|
||||
boolean curItalic = false;
|
||||
boolean curRandom = false;
|
||||
boolean curBold = false;
|
||||
boolean curStrikethrough = false;
|
||||
boolean curUnderline = false;
|
||||
|
||||
float glyphScaleY = getGlyphScaleY();
|
||||
float heightNorth = anchorY + (underlying.FONT_HEIGHT - 1.0f) * (0.5f - glyphScaleY / 2);
|
||||
|
||||
final float underlineY = heightNorth + (underlying.FONT_HEIGHT - 1.0f) * glyphScaleY;
|
||||
float underlineStartX = 0.0f;
|
||||
float underlineEndX = 0.0f;
|
||||
|
||||
final float strikethroughY = heightNorth + ((float) (underlying.FONT_HEIGHT / 2) - 1.0f) * glyphScaleY;
|
||||
float strikethroughStartX = 0.0f;
|
||||
float strikethroughEndX = 0.0f;
|
||||
|
||||
for (int charIdx = stringOffset; charIdx < stringEnd; charIdx++) {
|
||||
char chr = string.charAt(charIdx);
|
||||
if (chr == FORMATTING_CHAR && (charIdx + 1) < stringEnd) {
|
||||
final char fmtCode = Character.toLowerCase(string.charAt(charIdx + 1));
|
||||
charIdx++;
|
||||
|
||||
if (curUnderline && underlineStartX != underlineEndX) {
|
||||
final int ulIdx = idxWriterIndex;
|
||||
pushUntexRect(underlineStartX, underlineY, underlineEndX - underlineStartX, glyphScaleY, curColor);
|
||||
pushDrawCmd(ulIdx, 6, null, false);
|
||||
underlineStartX = underlineEndX;
|
||||
}
|
||||
if (curStrikethrough && strikethroughStartX != strikethroughEndX) {
|
||||
final int ulIdx = idxWriterIndex;
|
||||
pushUntexRect(
|
||||
strikethroughStartX,
|
||||
strikethroughY,
|
||||
strikethroughEndX - strikethroughStartX,
|
||||
glyphScaleY,
|
||||
curColor);
|
||||
pushDrawCmd(ulIdx, 6, null, false);
|
||||
strikethroughStartX = strikethroughEndX;
|
||||
}
|
||||
|
||||
final boolean is09 = charInRange(fmtCode, '0', '9');
|
||||
final boolean isAF = charInRange(fmtCode, 'a', 'f');
|
||||
if (is09 || isAF) {
|
||||
curRandom = false;
|
||||
curBold = false;
|
||||
curStrikethrough = false;
|
||||
curUnderline = false;
|
||||
curItalic = false;
|
||||
|
||||
final int colorIdx = is09 ? (fmtCode - '0') : (fmtCode - 'a' + 10);
|
||||
final int rgb = this.colorCode[colorIdx];
|
||||
curColor = (curColor & 0xFF000000) | (rgb & 0x00FFFFFF);
|
||||
final int shadowRgb = this.colorCode[colorIdx + 16];
|
||||
curShadowColor = (curShadowColor & 0xFF000000) | (shadowRgb & 0x00FFFFFF);
|
||||
} else if (fmtCode == 'k') {
|
||||
curRandom = true;
|
||||
} else if (fmtCode == 'l') {
|
||||
curBold = true;
|
||||
} else if (fmtCode == 'm') {
|
||||
curStrikethrough = true;
|
||||
strikethroughStartX = curX - 1.0f;
|
||||
strikethroughEndX = strikethroughStartX;
|
||||
} else if (fmtCode == 'n') {
|
||||
curUnderline = true;
|
||||
underlineStartX = curX - 1.0f;
|
||||
underlineEndX = underlineStartX;
|
||||
} else if (fmtCode == 'o') {
|
||||
curItalic = true;
|
||||
} else if (fmtCode == 'r') {
|
||||
curRandom = false;
|
||||
curBold = false;
|
||||
curStrikethrough = false;
|
||||
curUnderline = false;
|
||||
curItalic = false;
|
||||
curColor = color;
|
||||
curShadowColor = shadowColor;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (FontConfig.enableCustomFont && FontConfig.enableGlyphReplacements) {
|
||||
String chrReplacement = GlyphReplacements.customGlyphs.get(String.valueOf(chr));
|
||||
if (chrReplacement != null) {
|
||||
char replacement = chrReplacement.charAt(0);
|
||||
boolean isReplacementCharAvailable =
|
||||
FontProviderCustom.getPrimary().isGlyphAvailable(replacement)
|
||||
|| FontProviderCustom.getFallback().isGlyphAvailable(replacement);
|
||||
if (isReplacementCharAvailable) {
|
||||
chr = replacement;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (curRandom) {
|
||||
chr = FontProviderMC.get(this.isSGA).getRandomReplacement(chr);
|
||||
}
|
||||
|
||||
FontProvider fontProvider = FontStrategist.getFontProvider(this, chr, FontConfig.enableCustomFont, unicodeFlag);
|
||||
|
||||
heightNorth = anchorY + (underlying.FONT_HEIGHT - 1.0f) * (0.5f - glyphScaleY * fontProvider.getYScaleMultiplier() / 2);
|
||||
float heightSouth = (underlying.FONT_HEIGHT - 1.0f) * glyphScaleY * fontProvider.getYScaleMultiplier();
|
||||
|
||||
// Check ASCII space, NBSP, NNBSP
|
||||
if (chr == ' ' || chr == '\u00A0' || chr == '\u202F') {
|
||||
curX += 4 * this.getWhitespaceScale();
|
||||
continue;
|
||||
}
|
||||
|
||||
final float uStart = fontProvider.getUStart(chr);
|
||||
final float vStart = fontProvider.getVStart(chr);
|
||||
final float xAdvance = fontProvider.getXAdvance(chr) * getGlyphScaleX();
|
||||
final float glyphW = fontProvider.getGlyphW(chr) * getGlyphScaleX();
|
||||
final float uSz = fontProvider.getUSize(chr);
|
||||
final float vSz = fontProvider.getVSize(chr);
|
||||
final float itOff = curItalic ? 1.0F : 0.0F; // italic offset
|
||||
final float shadowOffset = fontProvider.getShadowOffset();
|
||||
final int shadowCopies = FontConfig.shadowCopies;
|
||||
final int boldCopies = FontConfig.boldCopies;
|
||||
final ResourceLocation texture = fontProvider.getTexture(chr);
|
||||
final int idxId = idxWriterIndex;
|
||||
|
||||
if (enableShadow) {
|
||||
for (int n = 1; n <= shadowCopies; n++) {
|
||||
final float shadowOffsetPart = shadowOffset * ((float) n / shadowCopies);
|
||||
pushTexRect(curX + shadowOffsetPart, heightNorth + shadowOffsetPart, glyphW - 1.0f, heightSouth, itOff, curShadowColor, uStart, vStart, uSz, vSz);
|
||||
|
||||
if (curBold) {
|
||||
pushTexRect(curX + 2.0f * shadowOffsetPart, heightNorth + shadowOffsetPart, glyphW - 1.0f, heightSouth, itOff, curShadowColor, uStart, vStart, uSz, vSz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pushTexRect(curX, heightNorth, glyphW - 1.0f, heightSouth, itOff, curColor, uStart, vStart, uSz, vSz);
|
||||
|
||||
if (curBold) {
|
||||
for (int n = 1; n <= boldCopies; n++) {
|
||||
final float shadowOffsetPart = shadowOffset * ((float) n / boldCopies);
|
||||
pushTexRect(curX + shadowOffsetPart, heightNorth, glyphW - 1.0f, heightSouth, itOff, curColor, uStart, vStart, uSz, vSz);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Vertex-per-char counts for different configurations
|
||||
default: 4
|
||||
shadow only: 4(1 + shadowCopies)
|
||||
bold only: 4(1 + boldCopies)
|
||||
both: 4(1 + 2 * shadowCopies + boldCopies)
|
||||
*/
|
||||
int charCount = 1;
|
||||
if (enableShadow) { charCount += shadowCopies * (curBold ? 2 : 1); }
|
||||
if (curBold) { charCount += boldCopies; }
|
||||
final int vtxCount = 4 * charCount;
|
||||
pushDrawCmd(idxId, vtxCount / 2 * 3, texture, chr > 255);
|
||||
|
||||
curX += (xAdvance + (curBold ? shadowOffset : 0.0f)) + getGlyphSpacing();
|
||||
underlineEndX = curX;
|
||||
strikethroughEndX = curX;
|
||||
}
|
||||
|
||||
if (curUnderline && underlineStartX != underlineEndX) {
|
||||
final int ulIdx = idxWriterIndex;
|
||||
pushUntexRect(underlineStartX, underlineY, underlineEndX - underlineStartX, glyphScaleY, curColor);
|
||||
pushDrawCmd(ulIdx, 6, null, false);
|
||||
}
|
||||
if (curStrikethrough && strikethroughStartX != strikethroughEndX) {
|
||||
final int ulIdx = idxWriterIndex;
|
||||
pushUntexRect(
|
||||
strikethroughStartX,
|
||||
strikethroughY,
|
||||
strikethroughEndX - strikethroughStartX,
|
||||
glyphScaleY,
|
||||
curColor);
|
||||
pushDrawCmd(ulIdx, 6, null, false);
|
||||
}
|
||||
|
||||
} finally {
|
||||
this.endBatch();
|
||||
}
|
||||
return curX + (enableShadow ? 1.0f : 0.0f);
|
||||
}
|
||||
|
||||
public float getCharWidthFine(char chr) {
|
||||
if (chr == FORMATTING_CHAR) { return -1; }
|
||||
|
||||
if (chr == ' ' || chr == '\u00A0' || chr == '\u202F') {
|
||||
return 4 * this.getWhitespaceScale();
|
||||
}
|
||||
|
||||
FontProvider fp = FontStrategist.getFontProvider(this, chr, FontConfig.enableCustomFont, underlying.getUnicodeFlag());
|
||||
|
||||
return fp.getXAdvance(chr) * this.getGlyphScaleX();
|
||||
}
|
||||
|
||||
public void overrideBlendFunc(int srcRgb, int dstRgb) {
|
||||
blendSrcRGB = srcRgb;
|
||||
blendDstRGB = dstRgb;
|
||||
}
|
||||
|
||||
public void resetBlendFunc() {
|
||||
blendSrcRGB = GL11.GL_SRC_ALPHA;
|
||||
blendDstRGB = GL11.GL_ONE_MINUS_SRC_ALPHA;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.gtnewhorizons.angelica.client.font;
|
||||
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public interface FontProvider {
|
||||
|
||||
/**
|
||||
* For use with §k. Should fetch a character of the same width as provided.
|
||||
*/
|
||||
char getRandomReplacement(char chr);
|
||||
boolean isGlyphAvailable(char chr);
|
||||
float getUStart(char chr);
|
||||
float getVStart(char chr);
|
||||
float getXAdvance(char chr);
|
||||
float getGlyphW(char chr);
|
||||
float getUSize(char chr);
|
||||
float getVSize(char chr);
|
||||
float getShadowOffset();
|
||||
ResourceLocation getTexture(char chr);
|
||||
float getYScaleMultiplier();
|
||||
}
|
||||
@@ -0,0 +1,299 @@
|
||||
package com.gtnewhorizons.angelica.client.font;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.config.ConfigurationManager;
|
||||
import com.gtnewhorizons.angelica.config.FontConfig;
|
||||
import lombok.Setter;
|
||||
import lombok.Value;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.texture.ITextureObject;
|
||||
import net.minecraft.client.renderer.texture.TextureManager;
|
||||
import net.minecraft.client.renderer.texture.TextureUtil;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public final class FontProviderCustom implements FontProvider {
|
||||
|
||||
public static final Logger LOGGER = LogManager.getLogger("Angelica");
|
||||
public static final String FONT_DIR = "fonts/custom/";
|
||||
static final int ATLAS_SIZE = 128;
|
||||
static final int ATLAS_COUNT = 512;
|
||||
private final byte id; // 0 - primary font, 1 - fallback font
|
||||
private FontAtlas[] fontAtlases = new FontAtlas[ATLAS_COUNT];
|
||||
private float currentFontQuality = FontConfig.customFontQuality;
|
||||
@Setter
|
||||
private Font font;
|
||||
|
||||
private FontProviderCustom(byte id) {
|
||||
this.id = id;
|
||||
Font[] availableFonts = FontStrategist.getAvailableFonts();
|
||||
String myFontName = switch (this.id) {
|
||||
case 0 -> FontConfig.customFontNamePrimary;
|
||||
case 1 -> FontConfig.customFontNameFallback;
|
||||
default -> null;
|
||||
};
|
||||
if (Objects.equals(myFontName, "(none)")) {
|
||||
font = null;
|
||||
return;
|
||||
}
|
||||
int fontPos = -1;
|
||||
for (int i = 0; i < availableFonts.length; i++) {
|
||||
if (Objects.equals(myFontName, availableFonts[i].getFontName())) {
|
||||
fontPos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fontPos == -1) {
|
||||
LOGGER.info("Could not find previously set font \"{}\". ", myFontName);
|
||||
font = null;
|
||||
return;
|
||||
}
|
||||
font = availableFonts[fontPos].deriveFont(currentFontQuality);
|
||||
}
|
||||
private static class InstLoader {
|
||||
static final FontProviderCustom instance0 = new FontProviderCustom((byte)0);
|
||||
static final FontProviderCustom instance1 = new FontProviderCustom((byte)1);
|
||||
}
|
||||
public static FontProviderCustom getPrimary() { return InstLoader.instance0; }
|
||||
public static FontProviderCustom getFallback() { return InstLoader.instance1; }
|
||||
|
||||
public void reloadFont(int fontID) {
|
||||
currentFontQuality = FontConfig.customFontQuality;
|
||||
font = FontStrategist.getAvailableFonts()[fontID].deriveFont(currentFontQuality);
|
||||
|
||||
File[] files = new File(getFontDir()).listFiles();
|
||||
if (files != null) {
|
||||
for (File f : files) {
|
||||
if (!Files.isSymbolicLink(f.toPath())) {
|
||||
f.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextureManager tm = Minecraft.getMinecraft().getTextureManager();
|
||||
Map mapTextureObjects = tm.mapTextureObjects;
|
||||
for (int i = 0; i < ATLAS_COUNT; i++) {
|
||||
ResourceLocation key = new ResourceLocation(getAtlasResourceName(i));
|
||||
if (mapTextureObjects.containsKey(key)) {
|
||||
ITextureObject obj = (ITextureObject) mapTextureObjects.get(key);
|
||||
TextureUtil.deleteTexture(obj.getGlTextureId());
|
||||
mapTextureObjects.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
fontAtlases = new FontAtlas[ATLAS_COUNT];
|
||||
}
|
||||
|
||||
private String getFontDir() {
|
||||
return FONT_DIR + "f" + this.id + "/";
|
||||
}
|
||||
|
||||
private String getAtlasFilename(int atlasId) {
|
||||
return "f" + this.id + "p" + atlasId;
|
||||
}
|
||||
|
||||
String getAtlasResourceName(int atlasId) {
|
||||
return "minecraft:angelica_c" + getAtlasFilename(atlasId);
|
||||
}
|
||||
|
||||
String getAtlasFullPath(int atlasId) {
|
||||
return getFontDir() + getAtlasFilename(atlasId) + ".png";
|
||||
}
|
||||
|
||||
@Value
|
||||
private class GlyphData {
|
||||
float uStart;
|
||||
float vStart;
|
||||
float xAdvance;
|
||||
float glyphW;
|
||||
float uSz;
|
||||
float vSz;
|
||||
}
|
||||
|
||||
private class FontAtlas {
|
||||
|
||||
GlyphData[] glyphData = new GlyphData[ATLAS_SIZE];
|
||||
private ResourceLocation texture;
|
||||
private final int id;
|
||||
|
||||
FontAtlas(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
void construct(Font font) {
|
||||
float separator = currentFontQuality / 3f;
|
||||
|
||||
BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g2d = image.createGraphics();
|
||||
g2d.setFont(font);
|
||||
FontMetrics fm = g2d.getFontMetrics();
|
||||
g2d.dispose();
|
||||
int width = 0;
|
||||
int actualChars = 0;
|
||||
for (int i = 0; i < ATLAS_SIZE; i++) {
|
||||
final char ch = (char)(i + ATLAS_SIZE * this.id);
|
||||
if (font.canDisplay(ch)) {
|
||||
width += (int) (separator + fm.charWidth(ch));
|
||||
actualChars++;
|
||||
}
|
||||
}
|
||||
if (actualChars == 0) {
|
||||
return;
|
||||
}
|
||||
final int atlasTilesX = (int) Math.ceil(Math.sqrt(actualChars) * 1.5f);
|
||||
final int atlasTilesY = (int) Math.ceil((double) actualChars / atlasTilesX);
|
||||
LOGGER.info("constructing custom font atlas (ID {}) of nominal size {} chars, actual: {}, {} rows by {} columns",
|
||||
this.id, ATLAS_SIZE, actualChars, atlasTilesX, atlasTilesY);
|
||||
width = 0;
|
||||
actualChars = 0;
|
||||
int maxRowWidth = 0;
|
||||
for (int i = 0; i < ATLAS_SIZE; i++) {
|
||||
if (actualChars % atlasTilesX == 0) {
|
||||
maxRowWidth = Math.max(maxRowWidth, width);
|
||||
width = 0;
|
||||
}
|
||||
final char ch = (char)(i + ATLAS_SIZE * this.id);
|
||||
if (font.canDisplay(ch)) {
|
||||
width += (int) (separator + fm.charWidth(ch));
|
||||
actualChars++;
|
||||
}
|
||||
}
|
||||
maxRowWidth = Math.max(maxRowWidth, width);
|
||||
|
||||
final int lineHeight = fm.getHeight();
|
||||
final float desc = fm.getDescent();
|
||||
|
||||
final int imageWidth = (int) (maxRowWidth + separator);
|
||||
final int imageHeight = (int) ((separator + lineHeight) * atlasTilesY + separator);
|
||||
|
||||
image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_ARGB);
|
||||
g2d = image.createGraphics();
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||
g2d.setFont(font);
|
||||
fm = g2d.getFontMetrics();
|
||||
|
||||
int tileX = 0, tileY = 0; // position in atlas tiles
|
||||
int imgX = (int) separator; // position in pixels
|
||||
|
||||
for (int i = 0; i < ATLAS_SIZE; i++) {
|
||||
final char ch = (char)(i + ATLAS_SIZE * this.id);
|
||||
if (!font.canDisplay(ch)) { continue; }
|
||||
|
||||
if (tileX >= atlasTilesX) {
|
||||
tileX = 0;
|
||||
imgX = (int) separator;
|
||||
tileY++;
|
||||
}
|
||||
|
||||
final int charWidth = fm.charWidth(ch);
|
||||
final float charAspectRatio = (float) charWidth / lineHeight;
|
||||
final float inset = currentFontQuality / 16;
|
||||
g2d.drawString(Character.toString(ch), imgX, (lineHeight + separator) * (tileY + 1) - desc);
|
||||
final float uStart = (float) (imgX - inset * charAspectRatio) / imageWidth;
|
||||
final float vStart = ((lineHeight + separator) * (tileY + 1) - lineHeight - inset) / imageHeight;
|
||||
final float xAdvance = charAspectRatio * 8 * charWidth / (charWidth + 2 * inset * charAspectRatio);
|
||||
final float glyphW = charAspectRatio * 8 + 1;
|
||||
final float uSz = (float) (charWidth + 2 * inset * charAspectRatio) / imageWidth;
|
||||
final float vSz = (float) (lineHeight + 2 * inset) / imageHeight;
|
||||
glyphData[i] = new GlyphData(uStart, vStart, xAdvance, glyphW, uSz, vSz);
|
||||
imgX += (int) (charWidth + separator);
|
||||
tileX++;
|
||||
}
|
||||
g2d.dispose();
|
||||
try {
|
||||
LOGGER.info("writing custom font atlas texture ({}x{} px) to {}", imageWidth, imageHeight, getAtlasFullPath(this.id));
|
||||
Files.createDirectories(Paths.get(getFontDir()));
|
||||
ImageIO.write(image, "png", new File(getAtlasFullPath(this.id)));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
this.texture = new ResourceLocation(getAtlasResourceName(this.id));
|
||||
}
|
||||
}
|
||||
|
||||
private FontAtlas getAtlas(char chr) {
|
||||
int id = chr / ATLAS_SIZE;
|
||||
FontAtlas fa = fontAtlases[id];
|
||||
if (fa == null) {
|
||||
fa = new FontAtlas(id);
|
||||
fa.construct(font);
|
||||
}
|
||||
fontAtlases[id] = fa;
|
||||
return fa;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGlyphAvailable(char chr) {
|
||||
if (font == null) { return false; }
|
||||
return (getAtlas(chr).glyphData[chr % ATLAS_SIZE] != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getRandomReplacement(char chr) {
|
||||
return chr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getUStart(char chr) {
|
||||
return getAtlas(chr).glyphData[chr % ATLAS_SIZE].uStart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getVStart(char chr) {
|
||||
return getAtlas(chr).glyphData[chr % ATLAS_SIZE].vStart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getXAdvance(char chr) {
|
||||
return getAtlas(chr).glyphData[chr % ATLAS_SIZE].xAdvance * FontConfig.customFontScale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getGlyphW(char chr) {
|
||||
return getAtlas(chr).glyphData[chr % ATLAS_SIZE].glyphW * FontConfig.customFontScale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getUSize(char chr) {
|
||||
return getAtlas(chr).glyphData[chr % ATLAS_SIZE].uSz;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getVSize(char chr) {
|
||||
return getAtlas(chr).glyphData[chr % ATLAS_SIZE].vSz;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getShadowOffset() {
|
||||
return FontConfig.fontShadowOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getTexture(char chr) {
|
||||
return getAtlas(chr).texture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getYScaleMultiplier() {
|
||||
return FontConfig.customFontScale;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package com.gtnewhorizons.angelica.client.font;
|
||||
|
||||
import com.gtnewhorizons.angelica.config.FontConfig;
|
||||
import it.unimi.dsi.fastutil.chars.Char2ShortOpenHashMap;
|
||||
import jss.util.RandomXoshiro256StarStar;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public final class FontProviderMC implements FontProvider {
|
||||
|
||||
/**
|
||||
* The full list of characters present in the default Minecraft font, excluding the Unicode font
|
||||
*/
|
||||
@SuppressWarnings("UnnecessaryUnicodeEscape")
|
||||
private static final String MCFONT_CHARS = "\u00c0\u00c1\u00c2\u00c8\u00ca\u00cb\u00cd\u00d3\u00d4\u00d5\u00da\u00df\u00e3\u00f5\u011f\u0130\u0131\u0152\u0153\u015e\u015f\u0174\u0175\u017e\u0207\u0000\u0000\u0000\u0000\u0000\u0000\u0000 !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u2302\u00c7\u00fc\u00e9\u00e2\u00e4\u00e0\u00e5\u00e7\u00ea\u00eb\u00e8\u00ef\u00ee\u00ec\u00c4\u00c5\u00c9\u00e6\u00c6\u00f4\u00f6\u00f2\u00fb\u00f9\u00ff\u00d6\u00dc\u00f8\u00a3\u00d8\u00d7\u0192\u00e1\u00ed\u00f3\u00fa\u00f1\u00d1\u00aa\u00ba\u00bf\u00ae\u00ac\u00bd\u00bc\u00a1\u00ab\u00bb\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c\u2588\u2584\u258c\u2590\u2580\u03b1\u03b2\u0393\u03c0\u03a3\u03c3\u03bc\u03c4\u03a6\u0398\u03a9\u03b4\u221e\u2205\u2208\u2229\u2261\u00b1\u2265\u2264\u2320\u2321\u00f7\u2248\u00b0\u2219\u00b7\u221a\u207f\u00b2\u25a0\u0000";
|
||||
|
||||
private FontProviderMC() {}
|
||||
private static class InstLoader {
|
||||
static final FontProviderMC instance = new FontProviderMC();
|
||||
static final FontProviderMC instanceSGA = new FontProviderMC();
|
||||
}
|
||||
public static FontProviderMC get(boolean isSGA) {
|
||||
return (isSGA ? InstLoader.instanceSGA : InstLoader.instance);
|
||||
}
|
||||
|
||||
private static final Char2ShortOpenHashMap MCFONT_ASCII_MAP = new Char2ShortOpenHashMap();
|
||||
ResourceLocation locationFontTexture = null;
|
||||
private final RandomXoshiro256StarStar fontRandom = new RandomXoshiro256StarStar();
|
||||
public int[] charWidth;
|
||||
|
||||
static {
|
||||
for (short i = 0; i < MCFONT_CHARS.length(); i++) {
|
||||
MCFONT_ASCII_MAP.put(MCFONT_CHARS.charAt(i), i);
|
||||
}
|
||||
}
|
||||
|
||||
public int lookupMcFontPosition(char ch) {
|
||||
if (isGlyphAvailable(ch)) {
|
||||
return MCFONT_ASCII_MAP.get(ch);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGlyphAvailable(char chr) {
|
||||
return MCFONT_ASCII_MAP.containsKey(chr);
|
||||
}
|
||||
|
||||
public char getRandomReplacement(char chr){
|
||||
int lutIndex = lookupMcFontPosition(chr);
|
||||
if (lutIndex != -1) {
|
||||
int randomReplacementIndex;
|
||||
do {
|
||||
randomReplacementIndex = fontRandom.nextInt(this.charWidth.length);
|
||||
} while (this.charWidth[lutIndex] != this.charWidth[randomReplacementIndex]);
|
||||
|
||||
lutIndex = randomReplacementIndex;
|
||||
return MCFONT_CHARS.charAt(lutIndex);
|
||||
}
|
||||
return chr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getUStart(char chr) {
|
||||
int lutIndex = lookupMcFontPosition(chr);
|
||||
return ((lutIndex % 16) * 8) / 128.0F;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getVStart(char chr) {
|
||||
int lutIndex = lookupMcFontPosition(chr);
|
||||
return (float) ((lutIndex / 16) * 8) / 128.0F;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getXAdvance(char chr) {
|
||||
int lutIndex = lookupMcFontPosition(chr);
|
||||
return charWidth[lutIndex];
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getGlyphW(char chr) {
|
||||
int lutIndex = lookupMcFontPosition(chr);
|
||||
return charWidth[lutIndex] - 0.01F;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getUSize(char chr) {
|
||||
int lutIndex = lookupMcFontPosition(chr);
|
||||
return (charWidth[lutIndex] - 1.01F) / 128.0F;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getVSize(char chr) {
|
||||
return 7.99F / 128.0F;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getShadowOffset() {
|
||||
return FontConfig.fontShadowOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getTexture(char chr) {
|
||||
return locationFontTexture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getYScaleMultiplier() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.gtnewhorizons.angelica.client.font;
|
||||
|
||||
import com.gtnewhorizons.angelica.config.FontConfig;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public final class FontProviderUnicode implements FontProvider {
|
||||
|
||||
private FontProviderUnicode() {}
|
||||
private static class InstLoader { static final FontProviderUnicode instance = new FontProviderUnicode(); }
|
||||
public static FontProviderUnicode get() { return FontProviderUnicode.InstLoader.instance; }
|
||||
|
||||
private static final ResourceLocation[] unicodePageLocations = new ResourceLocation[256];
|
||||
public byte[] glyphWidth;
|
||||
|
||||
private ResourceLocation getUnicodePageLocation(int page) {
|
||||
final ResourceLocation lookup = unicodePageLocations[page];
|
||||
if (lookup == null) {
|
||||
final ResourceLocation rl = new ResourceLocation(String.format(
|
||||
"textures/font/unicode_page_%02x.png",
|
||||
page));
|
||||
unicodePageLocations[page] = rl;
|
||||
return rl;
|
||||
} else {
|
||||
return lookup;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGlyphAvailable(char chr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getRandomReplacement(char chr) {
|
||||
return chr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getUStart(char chr) {
|
||||
final float startColumnF = (float)((this.glyphWidth[chr] >>> 4) & 15);
|
||||
return ((float) (chr % 16 * 16) + startColumnF + 0.21f) / 256.0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getVStart(char chr) {
|
||||
return ((float) ((chr & 255) / 16 * 16) + 0.21f) / 256.0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getXAdvance(char chr) {
|
||||
final int startColumn = (this.glyphWidth[chr] >>> 4) & 15;
|
||||
final int endColumn = this.glyphWidth[chr] & 15;
|
||||
final float startColumnF = (float) startColumn;
|
||||
final float endColumnF = (float) (endColumn + 1);
|
||||
return (endColumnF - startColumnF) / 2.0F + 1.0F;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getGlyphW(char chr) {
|
||||
final int startColumn = (this.glyphWidth[chr] >>> 4) & 15;
|
||||
final int endColumn = this.glyphWidth[chr] & 15;
|
||||
final float startColumnF = (float) startColumn;
|
||||
final float endColumnF = (float) (endColumn + 1);
|
||||
final float chrWidth = endColumnF - startColumnF - 0.02F;
|
||||
return chrWidth / 2.0f + 1.0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getUSize(char chr) {
|
||||
final int startColumn = (this.glyphWidth[chr] >>> 4) & 15;
|
||||
final int endColumn = this.glyphWidth[chr] & 15;
|
||||
final float startColumnF = (float) startColumn;
|
||||
final float endColumnF = (float) (endColumn + 1);
|
||||
final float chrWidth = endColumnF - startColumnF - 0.02F;
|
||||
return (chrWidth - 0.42f) / 256.0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getVSize(char chr) {
|
||||
return (16.0f - 0.42f) / 256.0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getShadowOffset() {
|
||||
return FontConfig.fontShadowOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getTexture(char chr) {
|
||||
final int uniPage = chr / 256;
|
||||
return getUnicodePageLocation(uniPage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getYScaleMultiplier() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package com.gtnewhorizons.angelica.client.font;
|
||||
|
||||
import com.google.common.collect.HashMultiset;
|
||||
import com.gtnewhorizons.angelica.config.FontConfig;
|
||||
import com.gtnewhorizons.angelica.mixins.interfaces.ResourceAccessor;
|
||||
import cpw.mods.fml.client.SplashProgress;
|
||||
import lombok.Getter;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.FontRenderer;
|
||||
import net.minecraft.client.resources.DefaultResourcePack;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.io.File;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class FontStrategist {
|
||||
|
||||
@Getter
|
||||
private static final Font[] availableFonts;
|
||||
public static final Logger LOGGER = LogManager.getLogger("Angelica");
|
||||
|
||||
static {
|
||||
if (GraphicsEnvironment.isHeadless()) {
|
||||
LOGGER.warn("GraphicsEnvironment.isHeadless() returned true! Custom fonts will be unavailable. This is likely a MacOS issue.");
|
||||
availableFonts = new Font[0];
|
||||
} else {
|
||||
// get available fonts without duplicates (250 copies of dialog.plain need not apply)
|
||||
Font[] availableFontsDirty = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
|
||||
HashMap<String, Font> fontSet = new HashMap<>();
|
||||
HashMultiset<String> duplicates = HashMultiset.create(); // for debugging
|
||||
|
||||
for (Font font : availableFontsDirty) {
|
||||
String fontName = font.getFontName();
|
||||
if (fontSet.containsKey(fontName)) {
|
||||
duplicates.add(fontName);
|
||||
} else {
|
||||
fontSet.put(fontName, font);
|
||||
}
|
||||
}
|
||||
|
||||
if (!duplicates.isEmpty()) {
|
||||
StringBuilder sb = new StringBuilder(duplicates.size() + " duplicate font(s) found in the list reported by Java: ");
|
||||
for (Iterator<String> iter = duplicates.stream().distinct().iterator(); iter.hasNext(); ) {
|
||||
String dupe = iter.next();
|
||||
sb.append(duplicates.count(dupe)).append("x ").append(dupe);
|
||||
if (iter.hasNext()) {
|
||||
sb.append(", ");
|
||||
}
|
||||
}
|
||||
sb.append(". Some fonts may be missing from the font selection menu.");
|
||||
LOGGER.warn(sb.toString());
|
||||
}
|
||||
availableFonts = fontSet.values().stream().sorted(Comparator.comparing(Font::getFontName)).toArray(Font[]::new);
|
||||
|
||||
LOGGER.info("Got {} fonts from GraphicsEnvironment ({} after deduplication)", availableFontsDirty.length, availableFonts.length);
|
||||
}
|
||||
|
||||
// create and add the resource pack that provides fonts
|
||||
HashMap<String, File> packMap = new HashMap<>();
|
||||
for (int i = 0; i < FontProviderCustom.ATLAS_COUNT; i++) {
|
||||
packMap.put(FontProviderCustom.getPrimary().getAtlasResourceName(i), new File(FontProviderCustom.getPrimary().getAtlasFullPath(i)));
|
||||
packMap.put(FontProviderCustom.getFallback().getAtlasResourceName(i), new File(FontProviderCustom.getFallback().getAtlasFullPath(i)));
|
||||
}
|
||||
|
||||
DefaultResourcePack fontResourcePack = new DefaultResourcePack(packMap);
|
||||
List defaultResourcePacks = ((ResourceAccessor) Minecraft.getMinecraft()).angelica$getDefaultResourcePacks();
|
||||
defaultResourcePacks.add(fontResourcePack);
|
||||
Minecraft.getMinecraft().refreshResources();
|
||||
}
|
||||
|
||||
/**
|
||||
Lets you get a FontProvider per char while respecting font priority and fallbacks, the unicode flag, whether or not
|
||||
SGA is on, if we're in a splash screen, if a font can even display a character in the first place, etc.
|
||||
*/
|
||||
public static FontProvider getFontProvider(BatchingFontRenderer me, char chr, boolean customFontEnabled, boolean forceUnicode) {
|
||||
if (me.isSGA && FontProviderMC.get(true).isGlyphAvailable(chr)) {
|
||||
return FontProviderMC.get(true);
|
||||
}
|
||||
if (customFontEnabled && !me.isSplash) {
|
||||
FontProvider fp;
|
||||
fp = FontProviderCustom.getPrimary();
|
||||
if (fp.isGlyphAvailable(chr)) { return fp; }
|
||||
fp = FontProviderCustom.getFallback();
|
||||
if (fp.isGlyphAvailable(chr)) { return fp; }
|
||||
return FontProviderUnicode.get();
|
||||
} else {
|
||||
if (!forceUnicode && FontProviderMC.get(false).isGlyphAvailable(chr)) {
|
||||
return FontProviderMC.get(false);
|
||||
} else {
|
||||
return FontProviderUnicode.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void reloadCustomFontProviders() {
|
||||
FontProviderCustom.getPrimary().setFont(null);
|
||||
FontProviderCustom.getFallback().setFont(null);
|
||||
for (int i = 0; i < availableFonts.length; i++) {
|
||||
if (Objects.equals(FontConfig.customFontNamePrimary, availableFonts[i].getFontName())) {
|
||||
FontProviderCustom.getPrimary().reloadFont(i);
|
||||
}
|
||||
if (Objects.equals(FontConfig.customFontNameFallback, availableFonts[i].getFontName())) {
|
||||
FontProviderCustom.getFallback().reloadFont(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isSplashFontRendererActive(FontRenderer fontRenderer) {
|
||||
// noinspection deprecation
|
||||
boolean active = fontRenderer instanceof SplashProgress.SplashFontRenderer;
|
||||
|
||||
try {
|
||||
Class<?> customSplashClass = Class.forName("gkappa.modernsplash.CustomSplash$SplashFontRenderer");
|
||||
active = active || customSplashClass.isInstance(fontRenderer);
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
}
|
||||
|
||||
return active;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package com.gtnewhorizons.angelica.client.gui;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.gtnewhorizons.angelica.dynamiclights.DynamicLights;
|
||||
import com.gtnewhorizons.angelica.dynamiclights.config.EntityLightConfig;
|
||||
import com.gtnewhorizons.angelica.dynamiclights.config.EntityLightConfigStorage;
|
||||
import com.gtnewhorizons.angelica.dynamiclights.config.EntityTypeEntry;
|
||||
import jss.notfine.core.Settings;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.Option;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.OptionGroup;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.OptionImpl;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.OptionImpact;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.OptionPage;
|
||||
import me.jellysquid.mods.sodium.client.gui.options.control.TickBoxControl;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class DynamicLightsOptionPages {
|
||||
|
||||
public static OptionPage dynamicLights() {
|
||||
if (!DynamicLights.configEnabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<OptionGroup> groups = new ArrayList<>();
|
||||
|
||||
groups.add(OptionGroup.createBuilder()
|
||||
.add(Settings.DYNAMIC_LIGHTS.option)
|
||||
.add(Settings.DYNAMIC_LIGHTS_SHADER_FORCE.option)
|
||||
.build());
|
||||
|
||||
groups.add(OptionGroup.createBuilder()
|
||||
.add(Settings.DYNAMIC_LIGHTS_FRUSTUM_CULLING.option)
|
||||
.add(Settings.DYNAMIC_LIGHTS_ADAPTIVE_TICKING.option)
|
||||
.add(Settings.DYNAMIC_LIGHTS_CULL_TIMEOUT.option)
|
||||
.build());
|
||||
|
||||
groups.add(OptionGroup.createBuilder()
|
||||
.add(Settings.DYNAMIC_LIGHTS_SLOW_DIST.option)
|
||||
.add(Settings.DYNAMIC_LIGHTS_SLOWER_DIST.option)
|
||||
.add(Settings.DYNAMIC_LIGHTS_BACKGROUND_DIST.option)
|
||||
.build());
|
||||
|
||||
// Entity type toggles - grouped by mod ID
|
||||
List<EntityTypeEntry> allEntities = EntityLightConfig.getAllEntityTypes();
|
||||
Map<String, List<EntityTypeEntry>> byMod = new LinkedHashMap<>();
|
||||
|
||||
for (EntityTypeEntry entry : allEntities) {
|
||||
byMod.computeIfAbsent(entry.getModId(), _ -> new ArrayList<>()).add(entry);
|
||||
}
|
||||
|
||||
// Create a group for each mod's entities
|
||||
for (Map.Entry<String, List<EntityTypeEntry>> modEntry : byMod.entrySet()) {
|
||||
String modId = modEntry.getKey();
|
||||
List<EntityTypeEntry> entities = modEntry.getValue();
|
||||
|
||||
OptionGroup.Builder groupBuilder = OptionGroup.createBuilder();
|
||||
|
||||
for (EntityTypeEntry entity : entities) {
|
||||
Option<Boolean> option = createEntityOption(entity);
|
||||
if (option != null) {
|
||||
groupBuilder.add(option);
|
||||
}
|
||||
}
|
||||
|
||||
// Only add group if it has options
|
||||
OptionGroup group = groupBuilder.build();
|
||||
if (!group.getOptions().isEmpty()) {
|
||||
groups.add(group);
|
||||
}
|
||||
}
|
||||
|
||||
return new OptionPage(I18n.format("options.dynamiclights.page"), ImmutableList.copyOf(groups));
|
||||
}
|
||||
|
||||
private static Option<Boolean> createEntityOption(EntityTypeEntry entry) {
|
||||
final String className = entry.getClassName();
|
||||
|
||||
// Resolve class once during option creation, not on every get/set
|
||||
Class<?> resolvedClass;
|
||||
try {
|
||||
resolvedClass = Class.forName(className);
|
||||
} catch (ClassNotFoundException e) {
|
||||
// Class not loaded, skip this option
|
||||
return null;
|
||||
}
|
||||
|
||||
final Class<?> entityClass = resolvedClass;
|
||||
|
||||
return OptionImpl.createBuilder(Boolean.class, EntityLightConfigStorage.INSTANCE)
|
||||
.setName(entry.getDisplayName() + " (" + entry.getModId() + ")")
|
||||
.setTooltip(I18n.format("options.dynamiclights.entity.tooltip", entry.getDisplayName()))
|
||||
.setControl(TickBoxControl::new)
|
||||
.setBinding(
|
||||
(_, value) -> EntityLightConfig.setEntityTypeEnabled(entityClass, value),
|
||||
storage -> EntityLightConfig.isEntityTypeEnabled(entityClass)
|
||||
)
|
||||
.setImpact(OptionImpact.LOW)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,561 @@
|
||||
package com.gtnewhorizons.angelica.client.gui;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.config.ConfigException;
|
||||
import com.gtnewhorizon.gtnhlib.config.ConfigurationManager;
|
||||
import com.gtnewhorizons.angelica.client.font.FontStrategist;
|
||||
import com.gtnewhorizons.angelica.config.FontConfig;
|
||||
import net.coderbot.iris.gui.element.widget.IrisButton;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import net.minecraft.client.gui.GuiSlot;
|
||||
import net.minecraft.client.gui.GuiTextField;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.util.MathHelper;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class FontConfigScreen extends GuiScreen {
|
||||
|
||||
private static final Font[] availableFonts = FontStrategist.getAvailableFonts();
|
||||
private final GuiScreen parent;
|
||||
private final String title;
|
||||
private final String searchPrompt;
|
||||
private final String testAreaPrompt;
|
||||
private List<String> testAreaInfo;
|
||||
private List<String> noFontsWarning;
|
||||
private String currentPrimaryFontName;
|
||||
private String currentFallbackFontName;
|
||||
private FontList fontList;
|
||||
private int selectedPrimaryFontListPos = -1;
|
||||
private int selectedFallbackFontListPos = -1;
|
||||
private ArrayList<Font> displayedFonts;
|
||||
private GuiTextField searchBox;
|
||||
private GuiTextField testArea;
|
||||
private int sliderPages = 0;
|
||||
private int displayedSliderPage = 0;
|
||||
private final int sliderWidth = 160;
|
||||
private final int sliderHeight = 20;
|
||||
|
||||
// need to save these separately
|
||||
private IrisButton fwdButton;
|
||||
private IrisButton backButton;
|
||||
|
||||
SliderClone.Option optFontQuality = new SliderClone.Option(6, 72, 6);
|
||||
SliderClone.Option optShadowOffset = new SliderClone.Option(0, 2, 0.05f);
|
||||
SliderClone.Option optShadowCopies = new SliderClone.Option(1, 8, 1);
|
||||
SliderClone.Option optBoldCopies = new SliderClone.Option(1, 8, 1);
|
||||
SliderClone.Option optGlyphAspect = new SliderClone.Option(-1, 1, 0.05f);
|
||||
SliderClone.Option optGlyphScale = new SliderClone.Option(0.1f, 3, 0.05f);
|
||||
SliderClone.Option optWhitespaceScale = new SliderClone.Option(0.1f, 3, 0.05f);
|
||||
SliderClone.Option optGlyphSpacing = new SliderClone.Option(-2f, 2f, 0.05f);
|
||||
SliderClone.Option optFontAAMode = new SliderClone.Option(0, 2, 1);
|
||||
SliderClone.Option optFontAAStrength = new SliderClone.Option(1, 24, 1);
|
||||
SliderClone.Option optCustomFontScale = new SliderClone.Option(0.1f, 3, 0.05f);
|
||||
|
||||
public FontConfigScreen(GuiScreen parent) {
|
||||
this.title = I18n.format("options.angelica.fontconfig.title");
|
||||
this.searchPrompt = I18n.format("options.angelica.fontconfig.searchprompt");
|
||||
this.testAreaPrompt = I18n.format("options.angelica.fontconfig.testareaprompt");
|
||||
this.parent = parent;
|
||||
this.currentPrimaryFontName = FontConfig.customFontNamePrimary;
|
||||
this.currentFallbackFontName = FontConfig.customFontNameFallback;
|
||||
this.displayedFonts = new ArrayList<>(Arrays.asList(availableFonts));
|
||||
for (int i = 0; i < availableFonts.length; i++) {
|
||||
if (Objects.equals(this.currentPrimaryFontName, availableFonts[i].getFontName())) {
|
||||
selectedPrimaryFontListPos = i;
|
||||
}
|
||||
if (Objects.equals(this.currentFallbackFontName, availableFonts[i].getFontName())) {
|
||||
selectedFallbackFontListPos = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void initGui() {
|
||||
Keyboard.enableRepeatEvents(true);
|
||||
searchBox = new GuiTextField(this.fontRendererObj, this.width / 2 - 120, 24, 240, 20);
|
||||
searchBox.setMaxStringLength(64);
|
||||
fontList = new FontList();
|
||||
testArea = new GuiTextField(this.fontRendererObj, this.width * 5 / 6 - this.width / 7, 63 - 10, this.width * 2 / 7, 20);
|
||||
testArea.setMaxStringLength(512);
|
||||
testArea.setText(I18n.format("options.angelica.fontconfig.testareaexample"));
|
||||
initButtons();
|
||||
}
|
||||
|
||||
private void initButtons() {
|
||||
final int halfWidth = this.width / 2;
|
||||
final int sliderSpacing = 4;
|
||||
|
||||
final int x1 = halfWidth - sliderWidth - sliderSpacing;
|
||||
final int x2 = halfWidth;
|
||||
final int x3 = halfWidth + sliderWidth + sliderSpacing;
|
||||
final int y3 = this.height - 65 + 2 * (sliderHeight + sliderSpacing);
|
||||
|
||||
this.buttonList.add(new IrisButton(x1 - sliderWidth / 2, y3 - sliderHeight / 2, sliderWidth, sliderHeight,
|
||||
FontConfig.enableCustomFont ? I18n.format("options.angelica.fontconfig.disable_custom_font") :
|
||||
I18n.format("options.angelica.fontconfig.enable_custom_font"), this::toggleCustomFont));
|
||||
this.buttonList.add(new IrisButton(x2 - sliderWidth / 2, y3 - sliderHeight / 2, sliderWidth, sliderHeight,
|
||||
I18n.format("options.angelica.fontconfig.reset_values"), this::resetValues));
|
||||
this.buttonList.add(new IrisButton(x3 - sliderWidth / 2, y3 - sliderHeight / 2, sliderWidth, sliderHeight,
|
||||
I18n.format("gui.done"), button -> this.onClose()));
|
||||
|
||||
backButton = new IrisButton(halfWidth - 20 - 224, this.height - 89 - 10, 40, 20,
|
||||
"<", button -> this.switchPage(-1));
|
||||
fwdButton = new IrisButton(halfWidth - 20 + 224, this.height - 89 - 10, 40, 20,
|
||||
">", button -> this.switchPage(1));
|
||||
this.buttonList.add(fwdButton);
|
||||
this.buttonList.add(backButton);
|
||||
|
||||
initSliders();
|
||||
}
|
||||
|
||||
private void initSliders() {
|
||||
ArrayList<SliderClone> sliders = new ArrayList<>();
|
||||
|
||||
sliders.add(new SliderClone.SliderCloneBuilder()
|
||||
.width(sliderWidth)
|
||||
.height(sliderHeight)
|
||||
.option(optFontQuality)
|
||||
.initialValue(FontConfig.customFontQuality)
|
||||
.setter(this::setFontQuality)
|
||||
.langKey("options.angelica.fontconfig.font_quality")
|
||||
.formatString("%2.0f")
|
||||
.build()
|
||||
);
|
||||
sliders.add(new SliderClone.SliderCloneBuilder()
|
||||
.width(sliderWidth)
|
||||
.height(sliderHeight)
|
||||
.option(optShadowOffset)
|
||||
.initialValue(FontConfig.fontShadowOffset)
|
||||
.setter(value -> FontConfig.fontShadowOffset = value)
|
||||
.langKey("options.angelica.fontconfig.shadow_offset")
|
||||
.formatString("x%3.2f")
|
||||
.build()
|
||||
);
|
||||
sliders.add(new SliderClone.SliderCloneBuilder()
|
||||
.width(sliderWidth)
|
||||
.height(sliderHeight)
|
||||
.option(optGlyphAspect)
|
||||
.initialValue(FontConfig.glyphAspect)
|
||||
.setter(value -> FontConfig.glyphAspect = value)
|
||||
.langKey("options.angelica.fontconfig.glyph_aspect")
|
||||
.build()
|
||||
);
|
||||
sliders.add(new SliderClone.SliderCloneBuilder()
|
||||
.width(sliderWidth)
|
||||
.height(sliderHeight)
|
||||
.option(optGlyphScale)
|
||||
.initialValue(FontConfig.glyphScale)
|
||||
.setter(value -> FontConfig.glyphScale = value)
|
||||
.langKey("options.angelica.fontconfig.glyph_scale")
|
||||
.formatString("x%3.2f")
|
||||
.build()
|
||||
);
|
||||
sliders.add(new SliderClone.SliderCloneBuilder()
|
||||
.width(sliderWidth)
|
||||
.height(sliderHeight)
|
||||
.option(optFontAAStrength)
|
||||
.initialValue(FontConfig.fontAAStrength)
|
||||
.setter(value -> FontConfig.fontAAStrength = value.intValue())
|
||||
.langKey("options.angelica.fontconfig.font_aa_strength")
|
||||
.formatString("%.0f")
|
||||
.build()
|
||||
);
|
||||
sliders.add(new SliderClone.SliderCloneBuilder()
|
||||
.width(sliderWidth)
|
||||
.height(sliderHeight)
|
||||
.option(optFontAAMode)
|
||||
.initialValue(FontConfig.fontAAMode)
|
||||
.setter(value -> FontConfig.fontAAMode = value.intValue())
|
||||
.formatter(this::fontAAModeFormat)
|
||||
.langKey("options.angelica.fontconfig.aamode")
|
||||
.build()
|
||||
);
|
||||
sliders.add(new SliderClone.SliderCloneBuilder()
|
||||
.width(sliderWidth)
|
||||
.height(sliderHeight)
|
||||
.option(optWhitespaceScale)
|
||||
.initialValue(FontConfig.whitespaceScale)
|
||||
.setter(value -> FontConfig.whitespaceScale = value)
|
||||
.langKey("options.angelica.fontconfig.whitespace_scale")
|
||||
.formatString("x%3.2f")
|
||||
.build()
|
||||
);
|
||||
sliders.add(new SliderClone.SliderCloneBuilder()
|
||||
.width(sliderWidth)
|
||||
.height(sliderHeight)
|
||||
.option(optGlyphSpacing)
|
||||
.initialValue(FontConfig.glyphSpacing)
|
||||
.setter(value -> FontConfig.glyphSpacing = value)
|
||||
.langKey("options.angelica.fontconfig.glyph_spacing")
|
||||
.build()
|
||||
);
|
||||
sliders.add(new SliderClone.SliderCloneBuilder()
|
||||
.width(sliderWidth)
|
||||
.height(sliderHeight)
|
||||
.option(optShadowCopies)
|
||||
.initialValue(FontConfig.shadowCopies)
|
||||
.setter(value -> FontConfig.shadowCopies = value.intValue())
|
||||
.langKey("options.angelica.fontconfig.shadow_copies")
|
||||
.formatString("%.0f")
|
||||
.build()
|
||||
);
|
||||
sliders.add(new SliderClone.SliderCloneBuilder()
|
||||
.width(sliderWidth)
|
||||
.height(sliderHeight)
|
||||
.option(optBoldCopies)
|
||||
.initialValue(FontConfig.boldCopies)
|
||||
.setter(value -> FontConfig.boldCopies = value.intValue())
|
||||
.langKey("options.angelica.fontconfig.bold_copies")
|
||||
.formatString("%.0f")
|
||||
.build()
|
||||
);
|
||||
sliders.add(new SliderClone.SliderCloneBuilder()
|
||||
.width(sliderWidth)
|
||||
.height(sliderHeight)
|
||||
.option(optCustomFontScale)
|
||||
.initialValue(FontConfig.customFontScale)
|
||||
.setter(value -> FontConfig.customFontScale = value)
|
||||
.langKey("options.angelica.fontconfig.custom_font_scale")
|
||||
.formatString("x%3.2f")
|
||||
.build()
|
||||
);
|
||||
|
||||
final int halfWidth = this.width / 2;
|
||||
final int sliderSpacing = 4;
|
||||
|
||||
final int x1 = halfWidth - sliderWidth - sliderSpacing;
|
||||
final int x2 = halfWidth;
|
||||
final int x3 = halfWidth + sliderWidth + sliderSpacing;
|
||||
final int y1 = this.height - 65;
|
||||
final int y2 = this.height - 65 + sliderHeight + sliderSpacing;
|
||||
|
||||
this.sliderPages = sliders.size() / 6;
|
||||
this.displayedSliderPage = Math.min(this.displayedSliderPage, this.sliderPages);
|
||||
|
||||
this.backButton.enabled = (this.displayedSliderPage != 0);
|
||||
this.fwdButton.enabled = (this.displayedSliderPage != this.sliderPages);
|
||||
|
||||
final int start = 6 * this.displayedSliderPage;
|
||||
final int end = Math.min(6 * (this.displayedSliderPage + 1), sliders.size());
|
||||
List<SliderClone> s = sliders.subList(start, end);
|
||||
try {
|
||||
s.get(0).setCenterPosition(x1, y1);
|
||||
s.get(1).setCenterPosition(x1, y2);
|
||||
s.get(2).setCenterPosition(x2, y1);
|
||||
s.get(3).setCenterPosition(x2, y2);
|
||||
s.get(4).setCenterPosition(x3, y1);
|
||||
s.get(5).setCenterPosition(x3, y2);
|
||||
} catch (IndexOutOfBoundsException ignored) {
|
||||
// we're on the last page and it has less than 6 sliders to display
|
||||
}
|
||||
this.buttonList.addAll(s);
|
||||
}
|
||||
|
||||
private void onClose() {
|
||||
applyChanges(true);
|
||||
this.mc.displayGuiScreen(parent);
|
||||
}
|
||||
|
||||
private void applyChanges(boolean finalApply) {
|
||||
int pos;
|
||||
pos = selectedPrimaryFontListPos;
|
||||
if (pos >= 0 && pos < displayedFonts.size()) {
|
||||
FontConfig.customFontNamePrimary = displayedFonts.get(pos).getFontName();
|
||||
}
|
||||
pos = selectedFallbackFontListPos;
|
||||
if (pos >= 0 && pos < displayedFonts.size()) {
|
||||
FontConfig.customFontNameFallback = displayedFonts.get(pos).getFontName();
|
||||
}
|
||||
|
||||
FontStrategist.reloadCustomFontProviders();
|
||||
|
||||
if (finalApply) {
|
||||
ConfigurationManager.save(FontConfig.class);
|
||||
}
|
||||
}
|
||||
|
||||
private void resetValues(IrisButton button) {
|
||||
try {
|
||||
ConfigurationManager.getConfigElements(FontConfig.class).forEach(elem -> elem.set(elem.getDefault()));
|
||||
} catch (ConfigException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
currentPrimaryFontName = null;
|
||||
currentFallbackFontName = null;
|
||||
selectedPrimaryFontListPos = -1;
|
||||
selectedFallbackFontListPos = -1;
|
||||
super.buttonList.clear();
|
||||
this.initButtons();
|
||||
}
|
||||
|
||||
private void toggleCustomFont(IrisButton button) {
|
||||
FontConfig.enableCustomFont = !FontConfig.enableCustomFont;
|
||||
applyChanges(false);
|
||||
button.displayString = FontConfig.enableCustomFont ?
|
||||
I18n.format("options.angelica.fontconfig.disable_custom_font") :
|
||||
I18n.format("options.angelica.fontconfig.enable_custom_font");
|
||||
}
|
||||
|
||||
private void switchPage(int offset) {
|
||||
this.displayedSliderPage = MathHelper.clamp_int(this.displayedSliderPage + offset, 0, this.sliderPages);
|
||||
this.buttonList.removeIf(guiButton -> guiButton instanceof SliderClone);
|
||||
this.initSliders();
|
||||
}
|
||||
|
||||
private int qualityLast = FontConfig.customFontQuality;
|
||||
|
||||
private void setFontQuality(float quality) {
|
||||
FontConfig.customFontQuality = (int) quality;
|
||||
if (qualityLast != (int) quality) {
|
||||
applyChanges(false);
|
||||
}
|
||||
qualityLast = (int) quality;
|
||||
}
|
||||
|
||||
private String fontAAModeFormat(float AAmode) {
|
||||
return switch ((int) AAmode) {
|
||||
case 2 -> I18n.format("options.angelica.fontconfig.aamode.aa_16x");
|
||||
case 1 -> I18n.format("options.angelica.fontconfig.aamode.aa_4x");
|
||||
default -> I18n.format("options.angelica.fontconfig.aamode.aa_none");
|
||||
};
|
||||
}
|
||||
|
||||
private float lastMouseX = 0;
|
||||
private float lastMouseY = 0;
|
||||
private long lastStillTime = 0;
|
||||
@Override
|
||||
public void drawScreen(int mouseX, int mouseY, float delta) {
|
||||
drawBackground(0);
|
||||
|
||||
this.fontList.drawScreen(mouseX, mouseY, delta);
|
||||
if (availableFonts.length == 0) {
|
||||
if (this.noFontsWarning == null) {
|
||||
this.noFontsWarning = this.fontRendererObj.listFormattedStringToWidth(
|
||||
I18n.format("options.angelica.fontconfig.no_fonts_warning"), this.width / 2
|
||||
);
|
||||
}
|
||||
int y = 80;
|
||||
for (String s : this.noFontsWarning) {
|
||||
drawCenteredString(this.fontRendererObj, s, this.width / 3, y, 0xFFFFFF);
|
||||
y += this.fontRendererObj.FONT_HEIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
this.searchBox.drawTextBox();
|
||||
if (!this.searchBox.isFocused() && this.searchBox.getText().isEmpty()) {
|
||||
this.drawCenteredString(this.fontRendererObj, this.searchPrompt,
|
||||
this.searchBox.xPosition + this.fontRendererObj.getStringWidth(this.searchPrompt) / 2 + 4,
|
||||
this.searchBox.yPosition + this.searchBox.height / 2 - 4, 0xFFFFFF);
|
||||
}
|
||||
drawCenteredString(this.fontRendererObj, this.title, (int) (this.width * 0.5), 8, 0xFFFFFF);
|
||||
drawCenteredString(this.fontRendererObj, I18n.format("options.angelica.fontconfig.currentfonts",
|
||||
FontConfig.customFontNamePrimary, FontConfig.customFontNameFallback), (int) (this.width * 0.5), this.height - 92, 0xFFFFFF);
|
||||
|
||||
if (this.testAreaInfo == null) {
|
||||
this.testAreaInfo = this.fontRendererObj.listFormattedStringToWidth(
|
||||
I18n.format("options.angelica.fontconfig.testareainfo"), this.width / 4
|
||||
);
|
||||
}
|
||||
int cumulativeY = 73;
|
||||
for (String s : this.testAreaInfo) {
|
||||
drawCenteredString(this.fontRendererObj, s, this.width * 5 / 6, cumulativeY, 0xFFFFFF);
|
||||
cumulativeY += this.fontRendererObj.FONT_HEIGHT;
|
||||
}
|
||||
cumulativeY += 4;
|
||||
this.testArea.yPosition = cumulativeY;
|
||||
this.testArea.drawTextBox();
|
||||
if (!this.testArea.isFocused() && this.testArea.getText().isEmpty()) {
|
||||
this.drawCenteredString(this.fontRendererObj, this.testAreaPrompt,
|
||||
this.testArea.xPosition + this.fontRendererObj.getStringWidth(this.testAreaPrompt) / 2 + 4,
|
||||
this.testArea.yPosition + this.testArea.height / 2 - 4, 0xFFFFFF);
|
||||
}
|
||||
List<String> testText = this.fontRendererObj.listFormattedStringToWidth(
|
||||
this.testArea.getText().replace('&', '§'), this.width / 4
|
||||
);
|
||||
cumulativeY += this.testArea.height + 4;
|
||||
for (String s : testText) {
|
||||
drawCenteredString(this.fontRendererObj, s, this.width * 5 / 6, cumulativeY, 0xFFFFFF);
|
||||
cumulativeY += this.fontRendererObj.FONT_HEIGHT;
|
||||
}
|
||||
|
||||
super.drawScreen(mouseX, mouseY, delta);
|
||||
|
||||
for (GuiButton guiButton : buttonList) {
|
||||
if (!(guiButton instanceof SliderClone slider)) { continue; }
|
||||
final int top = slider.yPosition;
|
||||
final int bot = slider.yPosition + slider.height;
|
||||
final int left = slider.xPosition;
|
||||
final int right = slider.xPosition + slider.width;
|
||||
if (mouseY < top || mouseY >= bot || mouseX < left || mouseX >= right) { continue; }
|
||||
if (mouseX == lastMouseX && mouseY == lastMouseY) {
|
||||
if (lastStillTime == 0) {
|
||||
lastStillTime = System.currentTimeMillis();
|
||||
}
|
||||
if (lastStillTime + 500L < System.currentTimeMillis()) {
|
||||
displayTooltip(mouseX, mouseY, slider.tooltipKey);
|
||||
}
|
||||
} else {
|
||||
lastStillTime = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
lastMouseX = mouseX;
|
||||
lastMouseY = mouseY;
|
||||
}
|
||||
|
||||
private void displayTooltip(int x, int y, String langKey) {
|
||||
List<String> lines = this.fontRendererObj.listFormattedStringToWidth(I18n.format(langKey), this.width / 2);
|
||||
this.drawHoveringText(lines, x, y, this.fontRendererObj);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void actionPerformed(GuiButton guiButton) {
|
||||
if (guiButton.enabled) {
|
||||
if (guiButton instanceof IrisButton irisButton) {
|
||||
irisButton.onPress();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void keyTyped(char typedChar, int keyCode) {
|
||||
if (this.searchBox.isFocused()) {
|
||||
if (keyCode == Keyboard.KEY_ESCAPE) {
|
||||
this.searchBox.setFocused(false);
|
||||
return;
|
||||
}
|
||||
this.searchBox.textboxKeyTyped(typedChar, keyCode);
|
||||
this.displayedFonts = filterFonts(this.searchBox.getText().toLowerCase());
|
||||
}
|
||||
if (this.testArea.isFocused()) {
|
||||
if (keyCode == Keyboard.KEY_ESCAPE) {
|
||||
this.testArea.setFocused(false);
|
||||
return;
|
||||
}
|
||||
this.testArea.textboxKeyTyped(typedChar, keyCode);
|
||||
}
|
||||
if (keyCode == Keyboard.KEY_ESCAPE) {
|
||||
this.onClose();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseClicked(int mouseX, int mouseY, int mouseButton) {
|
||||
super.mouseClicked(mouseX, mouseY, mouseButton);
|
||||
this.searchBox.mouseClicked(mouseX, mouseY, mouseButton);
|
||||
this.testArea.mouseClicked(mouseX, mouseY, mouseButton);
|
||||
this.fontList.mouseClicked(mouseX, mouseY, mouseButton);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateScreen() {
|
||||
this.searchBox.updateCursorCounter();
|
||||
this.testArea.updateCursorCounter();
|
||||
}
|
||||
|
||||
// this could be more efficient, but it's good enough as is
|
||||
private ArrayList<Font> filterFonts(String search) {
|
||||
ArrayList<Font> results;
|
||||
if (search == null || search.isEmpty()) {
|
||||
results = new ArrayList<>(Arrays.asList(availableFonts));
|
||||
} else {
|
||||
results = Arrays.stream(availableFonts).filter((font -> font.getFontName().toLowerCase().contains(search))).collect(Collectors.toCollection(ArrayList::new));
|
||||
}
|
||||
|
||||
selectedPrimaryFontListPos = -1;
|
||||
selectedFallbackFontListPos = -1;
|
||||
for (int i = 0; i < results.size(); i++) {
|
||||
if (Objects.equals(currentPrimaryFontName, results.get(i).getFontName())) {
|
||||
selectedPrimaryFontListPos = i;
|
||||
}
|
||||
if (Objects.equals(currentFallbackFontName, results.get(i).getFontName())) {
|
||||
selectedFallbackFontListPos = i;
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
class FontList extends GuiSlot {
|
||||
|
||||
public FontList() {
|
||||
super(FontConfigScreen.this.mc, FontConfigScreen.this.width * 2 / 3, FontConfigScreen.this.height, 52, FontConfigScreen.this.height - 102, 18);
|
||||
}
|
||||
|
||||
private void mouseClicked(int mouseX, int mouseY, int mouseButton) {
|
||||
if (mouseY < this.top || mouseY > this.bottom) { return; }
|
||||
|
||||
int listLeftBound = this.width / 2 - this.getListWidth() / 2;
|
||||
int listRightBound = this.width / 2 + this.getListWidth() / 2;
|
||||
if (mouseX < listLeftBound || mouseX > listRightBound) { return; }
|
||||
|
||||
int mousePosInList = mouseY - this.top - this.headerPadding + (int)this.amountScrolled - 4;
|
||||
int slotIndex = mousePosInList / this.slotHeight;
|
||||
if (slotIndex < 0 || slotIndex >= this.getSize()) { return; }
|
||||
|
||||
if (mouseButton == 0) {
|
||||
onElemClicked(slotIndex, false);
|
||||
} else if (mouseButton == 1) {
|
||||
onElemClicked(slotIndex, true);
|
||||
}
|
||||
}
|
||||
|
||||
protected void onElemClicked(int index, boolean rightClick) {
|
||||
if (!rightClick) {
|
||||
selectedPrimaryFontListPos = index;
|
||||
currentPrimaryFontName = displayedFonts.get(index).getFontName();
|
||||
} else {
|
||||
selectedFallbackFontListPos = index;
|
||||
currentFallbackFontName = displayedFonts.get(index).getFontName();
|
||||
}
|
||||
applyChanges(false);
|
||||
}
|
||||
|
||||
protected boolean isSelected(int index) {
|
||||
return (index == selectedPrimaryFontListPos || index == selectedFallbackFontListPos);
|
||||
}
|
||||
|
||||
protected int getSize() {
|
||||
return displayedFonts.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getContentHeight() {
|
||||
return this.getSize() * 18;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getScrollBarX() {
|
||||
return this.width * 15 / 16 - 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getListWidth() {
|
||||
return this.width * 2 / 3;
|
||||
}
|
||||
|
||||
// see onElemClicked for the proper version that supports right-clicking
|
||||
protected void elementClicked(int index, boolean doubleClicked, int mouseX, int mouseY) {}
|
||||
|
||||
protected void drawBackground() {
|
||||
// do nothing, the font list doesn't occupy the entire screen
|
||||
}
|
||||
|
||||
protected void drawSlot(int index, int x, int y, int p_148126_4_, Tessellator tessellator, int p_148126_6_, int p_148126_7_) {
|
||||
int color = 0xffffff;
|
||||
if (index == selectedPrimaryFontListPos) {
|
||||
color &= 0xffff55;
|
||||
}
|
||||
if (index == selectedFallbackFontListPos) {
|
||||
color &= 0x55ffff;
|
||||
}
|
||||
drawCenteredString(fontRendererObj, displayedFonts.get(index).getFontName(), this.width / 2, y + 1, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.gtnewhorizons.angelica.client.gui;
|
||||
|
||||
import com.gtnewhorizons.angelica.compat.mojang.Element;
|
||||
import net.minecraft.client.gui.GuiScreen;
|
||||
import org.lwjgl.input.Mouse;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class ScrollableGuiScreen extends GuiScreen {
|
||||
@Override
|
||||
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
|
||||
super.drawScreen(mouseX, mouseY, partialTicks);
|
||||
handleMouseScroll(mouseX, mouseY, partialTicks);
|
||||
}
|
||||
|
||||
public abstract List<? extends Element> children();
|
||||
|
||||
protected void handleMouseScroll(int mouseX, int mouseY, float partialTicks) {
|
||||
for (; !this.mc.gameSettings.touchscreen && Mouse.next(); this.mc.currentScreen.handleMouseInput()) {
|
||||
int dWheel = Mouse.getEventDWheel();
|
||||
|
||||
if (dWheel != 0) {
|
||||
for(Element child : children()) {
|
||||
child.mouseScrolled(mouseX, mouseY, dWheel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
package com.gtnewhorizons.angelica.client.gui;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class SliderClone extends GuiButton {
|
||||
|
||||
private final Function<Float, String> displayStringFormatter;
|
||||
private final Consumer<Float> valueSetter;
|
||||
private final Option option;
|
||||
private float sliderPercentage;
|
||||
public final String tooltipKey;
|
||||
public boolean mouseDragging;
|
||||
|
||||
@AllArgsConstructor
|
||||
public static class Option {
|
||||
float min;
|
||||
float max;
|
||||
float step;
|
||||
|
||||
float denormalize(float alpha) {
|
||||
float lerp = min * (1 - alpha) + max * alpha;
|
||||
return Math.round(lerp / step) * step;
|
||||
}
|
||||
float normalize(float value) {
|
||||
return (value - min) / (max - min);
|
||||
}
|
||||
}
|
||||
|
||||
public SliderClone(int x, int y, int width, int height, Option option, float initialValue,
|
||||
Consumer<Float> setter, Function<Float, String> formatter, String tooltipKey) {
|
||||
super(0, x, y, width, height, "");
|
||||
this.option = option;
|
||||
this.sliderPercentage = option.normalize(initialValue);
|
||||
this.displayString = formatter.apply(initialValue);
|
||||
this.valueSetter = setter;
|
||||
this.displayStringFormatter = formatter;
|
||||
this.tooltipKey = tooltipKey;
|
||||
}
|
||||
|
||||
public static SliderCloneBuilder builder() {
|
||||
return new SliderCloneBuilder();
|
||||
}
|
||||
|
||||
public void setCenterPosition(int x, int y) {
|
||||
this.xPosition = x - this.width / 2;
|
||||
this.yPosition = y - this.height / 2;
|
||||
}
|
||||
|
||||
@Accessors(fluent = true) @Setter
|
||||
public static class SliderCloneBuilder {
|
||||
private int x = 0, y = 0; // center position, not a corner
|
||||
private int width = 144, height = 20;
|
||||
private Option option;
|
||||
private float initialValue;
|
||||
private Consumer<Float> setter;
|
||||
private String formatString = "%3.2f";
|
||||
private String langKey;
|
||||
|
||||
// overrides: if null, these get set to default values
|
||||
private String tooltipKey;
|
||||
private Function<Float, String> formatter;
|
||||
|
||||
public SliderClone build() {
|
||||
if (this.formatter == null) {
|
||||
this.formatter = value -> I18n.format(this.langKey, String.format(this.formatString, value));
|
||||
}
|
||||
|
||||
if (this.tooltipKey == null) {
|
||||
this.tooltipKey = this.langKey + ".tooltip";
|
||||
}
|
||||
|
||||
return new SliderClone(
|
||||
this.x - this.width / 2,
|
||||
this.y - this.height / 2,
|
||||
this.width,
|
||||
this.height,
|
||||
this.option,
|
||||
this.initialValue,
|
||||
this.setter,
|
||||
this.formatter,
|
||||
this.tooltipKey
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns 0 if the button is disabled, 1 if the mouse is NOT hovering over this button and 2 if it IS hovering over
|
||||
* this button.
|
||||
*/
|
||||
public int getHoverState(boolean mouseOver) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when the mouse button is dragged. Equivalent of MouseListener.mouseDragged(MouseEvent e).
|
||||
*/
|
||||
protected void mouseDragged(Minecraft mc, int mouseX, int mouseY) {
|
||||
if (this.visible) {
|
||||
if (this.mouseDragging) {
|
||||
this.sliderPercentage = (float)(mouseX - (this.xPosition + 4)) / (float)(this.width - 8);
|
||||
|
||||
if (this.sliderPercentage < 0.0F) {
|
||||
this.sliderPercentage = 0.0F;
|
||||
}
|
||||
|
||||
if (this.sliderPercentage > 1.0F) {
|
||||
this.sliderPercentage = 1.0F;
|
||||
}
|
||||
|
||||
float f = this.option.denormalize(this.sliderPercentage);
|
||||
valueSetter.accept(f);
|
||||
this.sliderPercentage = this.option.normalize(f);
|
||||
this.displayString = displayStringFormatter.apply(f);
|
||||
}
|
||||
|
||||
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
this.drawTexturedModalRect(this.xPosition + (int)(this.sliderPercentage * (float)(this.width - 8)), this.yPosition, 0, 66, 4, 20);
|
||||
this.drawTexturedModalRect(this.xPosition + (int)(this.sliderPercentage * (float)(this.width - 8)) + 4, this.yPosition, 196, 66, 4, 20);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the mouse has been pressed on this control. Equivalent of MouseListener.mousePressed(MouseEvent e).
|
||||
*/
|
||||
public boolean mousePressed(Minecraft mc, int mouseX, int mouseY) {
|
||||
if (super.mousePressed(mc, mouseX, mouseY)) {
|
||||
this.sliderPercentage = (float)(mouseX - (this.xPosition + 4)) / (float)(this.width - 8);
|
||||
|
||||
if (this.sliderPercentage < 0.0F) {
|
||||
this.sliderPercentage = 0.0F;
|
||||
}
|
||||
|
||||
if (this.sliderPercentage > 1.0F) {
|
||||
this.sliderPercentage = 1.0F;
|
||||
}
|
||||
|
||||
float f = this.option.denormalize(this.sliderPercentage);
|
||||
valueSetter.accept(f);
|
||||
this.sliderPercentage = this.option.normalize(f);
|
||||
this.displayString = displayStringFormatter.apply(f);
|
||||
this.mouseDragging = true;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fired when the mouse button is released. Equivalent of MouseListener.mouseReleased(MouseEvent e).
|
||||
*/
|
||||
public void mouseReleased(int mouseX, int mouseY) {
|
||||
this.mouseDragging = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package com.gtnewhorizons.angelica.commands;
|
||||
|
||||
// Debug commands adapted from Beddium by Ven and FalsePattern
|
||||
|
||||
import com.gtnewhorizons.angelica.debug.ChunkDebugMinimap;
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.CeleritasDebugScreenHandler;
|
||||
import com.gtnewhorizons.angelica.rendering.celeritas.CeleritasWorldRenderer;
|
||||
import net.minecraft.command.CommandBase;
|
||||
import net.minecraft.command.ICommand;
|
||||
import net.minecraft.command.ICommandSender;
|
||||
import net.minecraft.util.ChatComponentText;
|
||||
import net.minecraft.util.EnumChatFormatting;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class AngelicaCommand extends CommandBase {
|
||||
|
||||
private static final List<String> SUBCOMMANDS = Arrays.asList("wireframe", "fog", "minimap", "help");
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return "angelica";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandUsage(ICommandSender sender) {
|
||||
return "/angelica <wireframe|fog|minimap|help>";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRequiredPermissionLevel() {
|
||||
return 0; // Available to all players (client-side only)
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> addTabCompletionOptions(ICommandSender sender, String[] args) {
|
||||
if (args.length == 1) {
|
||||
return getListOfStringsMatchingLastWord(args, SUBCOMMANDS.toArray(new String[0]));
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processCommand(ICommandSender sender, String[] args) {
|
||||
if (args.length == 0) {
|
||||
sendHelp(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (args[0].toLowerCase()) {
|
||||
case "wireframe" -> handleWireframe(sender);
|
||||
case "fog" -> handleFog(sender);
|
||||
case "minimap" -> handleMinimap(sender);
|
||||
default -> sendHelp(sender);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleWireframe(ICommandSender sender) {
|
||||
CeleritasWorldRenderer.DEBUG_WIREFRAME_MODE = !CeleritasWorldRenderer.DEBUG_WIREFRAME_MODE;
|
||||
final String state = CeleritasWorldRenderer.DEBUG_WIREFRAME_MODE ? "ON" : "OFF";
|
||||
sender.addChatMessage(new ChatComponentText(EnumChatFormatting.AQUA + "[Angelica] " + EnumChatFormatting.WHITE + "Wireframe mode: " + state));
|
||||
}
|
||||
|
||||
private void handleFog(ICommandSender sender) {
|
||||
CeleritasDebugScreenHandler.showFogDebug = !CeleritasDebugScreenHandler.showFogDebug;
|
||||
final String f3State = CeleritasDebugScreenHandler.showFogDebug ? "ON" : "OFF";
|
||||
|
||||
sender.addChatMessage(new ChatComponentText(EnumChatFormatting.AQUA + "[Angelica] " + EnumChatFormatting.WHITE + "Fog debug (F3): " + f3State));
|
||||
sender.addChatMessage(new ChatComponentText(EnumChatFormatting.GRAY + " " + CeleritasDebugScreenHandler.getFogDebugString()));
|
||||
}
|
||||
|
||||
private void handleMinimap(ICommandSender sender) {
|
||||
ChunkDebugMinimap.toggle();
|
||||
final String state = ChunkDebugMinimap.isEnabled() ? "ON" : "OFF";
|
||||
sender.addChatMessage(new ChatComponentText(EnumChatFormatting.AQUA + "[Angelica] " + EnumChatFormatting.WHITE + "Chunk debug minimap: " + state));
|
||||
}
|
||||
|
||||
private void sendHelp(ICommandSender sender) {
|
||||
sender.addChatMessage(new ChatComponentText(EnumChatFormatting.AQUA + "[Angelica] Debug Commands:"));
|
||||
sender.addChatMessage(new ChatComponentText(EnumChatFormatting.GRAY + " /angelica wireframe" + EnumChatFormatting.WHITE + " - Toggle wireframe rendering"));
|
||||
sender.addChatMessage(new ChatComponentText(EnumChatFormatting.GRAY + " /angelica fog" + EnumChatFormatting.WHITE + " - Toggle fog debug on F3"));
|
||||
sender.addChatMessage(new ChatComponentText(EnumChatFormatting.GRAY + " /angelica minimap" + EnumChatFormatting.WHITE + " - Toggle chunk debug overlay"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Object o) {
|
||||
if (o instanceof ICommand cmd) {
|
||||
return this.getCommandName().compareTo(cmd.getCommandName());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.gtnewhorizons.angelica.common;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraftforge.client.event.TextureStitchEvent;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
||||
|
||||
/**
|
||||
* This Block is not actually getting registered. A static instance is created in AngelicaMod.
|
||||
* Actually registering the block on the client but not the server can cause block IDs to
|
||||
* different between client/server, which is not good.
|
||||
|
||||
* We're essentially injecting the block's texture, so that we may use this block as if it were
|
||||
* any normal block for rendering purposes with RenderBlocks and such, but not have to actually
|
||||
* register it as a block.
|
||||
*/
|
||||
|
||||
public class BlockError extends Block {
|
||||
|
||||
public static final IIcon[] icons = new IIcon[2];
|
||||
|
||||
public BlockError() {
|
||||
super(Material.rock);
|
||||
|
||||
MinecraftForge.EVENT_BUS.register(new EventHandler());
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public IIcon getIcon(int side, int meta) {
|
||||
return meta >= 0 && meta < icons.length ? icons[meta] : null;
|
||||
}
|
||||
|
||||
public static class EventHandler{
|
||||
@SubscribeEvent
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void onTextureStitch(TextureStitchEvent.Pre event) {
|
||||
if (event.map.getTextureType() == 0) {
|
||||
for (int i = 0; i < icons.length; i++) {
|
||||
icons[i] = event.map.registerIcon("angelica:error_block_" + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.gtnewhorizons.angelica.common;
|
||||
|
||||
import static com.gtnewhorizon.gtnhlib.client.model.ModelISBRH.JSON_ISBRH_ID;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/// Unline {@link BlockError}, this *is* registered on both sides. It's intended to test functionality in a SP
|
||||
/// development environment.
|
||||
public class BlockTest extends Block {
|
||||
|
||||
public BlockTest() {
|
||||
super(Material.wood);
|
||||
setHardness(0.7f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpaqueCube() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a block is placed using its ItemBlock. Args: World, X, Y, Z, side, hitX, hitY, hitZ, block metadata
|
||||
*/
|
||||
@Override
|
||||
public int onBlockPlaced(@NotNull World worldIn, int x, int y, int z, int side, float subX, float subY, float subZ, int meta) {
|
||||
|
||||
// Face NORTH if placed up or down
|
||||
final var s = ForgeDirection.getOrientation(side);
|
||||
if (s == ForgeDirection.UP || s == ForgeDirection.DOWN)
|
||||
return 2;
|
||||
|
||||
// Face the placed side
|
||||
return side;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRenderType() {
|
||||
return JSON_ISBRH_ID;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.gtnewhorizons.angelica.compat;
|
||||
|
||||
import com.falsepattern.chunk.api.DataRegistry;
|
||||
import com.gtnewhorizons.neid.mixins.interfaces.IExtendedBlockStorageMixin;
|
||||
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.NibbleArray;
|
||||
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||
import ru.fewizz.idextender.Hooks;
|
||||
|
||||
public class ExtendedBlockStorageExt extends ExtendedBlockStorage {
|
||||
public boolean hasSky;
|
||||
|
||||
public ExtendedBlockStorageExt(int yBase, boolean hasSky) {
|
||||
super(yBase, hasSky);
|
||||
this.hasSky = hasSky;
|
||||
}
|
||||
|
||||
public ExtendedBlockStorageExt(Chunk chunk, ExtendedBlockStorage storage) {
|
||||
super(storage.yBase, storage.getSkylightArray() != null);
|
||||
|
||||
if (ModStatus.isChunkAPILoaded) {
|
||||
if (storage.getSkylightArray() != null) {
|
||||
hasSky = true;
|
||||
}
|
||||
DataRegistry.cloneSubChunk(chunk, storage, this);
|
||||
} else {
|
||||
int arrayLen;
|
||||
if (ModStatus.isNEIDLoaded){
|
||||
final short[] block16BArray = ((IExtendedBlockStorageMixin)(Object)this).getBlock16BArray();
|
||||
System.arraycopy(((IExtendedBlockStorageMixin)(Object)storage).getBlock16BArray(), 0, block16BArray, 0, block16BArray.length);
|
||||
if(storage.getBlockMSBArray() != null) {
|
||||
this.setBlockMSBArray(new NibbleArray(block16BArray.length, 4));
|
||||
copyNibbleArray(storage.getBlockMSBArray(), this.getBlockMSBArray());
|
||||
}
|
||||
arrayLen = block16BArray.length;
|
||||
if (ModStatus.isNEIDMetadataExtended) {
|
||||
final short[] block16BMetaArray = ((IExtendedBlockStorageMixin)(Object)this).getBlock16BMetaArray();
|
||||
System.arraycopy(((IExtendedBlockStorageMixin)(Object)storage).getBlock16BMetaArray(), 0, block16BMetaArray, 0, block16BMetaArray.length);
|
||||
}
|
||||
}
|
||||
else if (ModStatus.isOldNEIDLoaded){
|
||||
final short[] blockLSBArray = Hooks.get(this);
|
||||
System.arraycopy(Hooks.get(storage), 0, blockLSBArray, 0, blockLSBArray.length);
|
||||
// getBlockMSBArray is nuked in asm version
|
||||
arrayLen = blockLSBArray.length;
|
||||
}
|
||||
else {
|
||||
final byte[] blockLSBArray = this.getBlockLSBArray();
|
||||
System.arraycopy(storage.getBlockLSBArray(), 0, blockLSBArray, 0, blockLSBArray.length);
|
||||
if(storage.getBlockMSBArray() != null) {
|
||||
this.setBlockMSBArray(new NibbleArray(blockLSBArray.length, 4));
|
||||
copyNibbleArray(storage.getBlockMSBArray(), this.getBlockMSBArray());
|
||||
}
|
||||
arrayLen = blockLSBArray.length;
|
||||
}
|
||||
|
||||
|
||||
if (!ModStatus.isNEIDMetadataExtended) copyNibbleArray(storage.getMetadataArray(), this.getMetadataArray());
|
||||
copyNibbleArray(storage.getBlocklightArray(), this.getBlocklightArray());
|
||||
if(storage.getSkylightArray() != null) {
|
||||
hasSky = true;
|
||||
if(this.getSkylightArray() == null) {
|
||||
this.setSkylightArray(new NibbleArray(arrayLen, 4));
|
||||
}
|
||||
copyNibbleArray(storage.getSkylightArray(), this.getSkylightArray());
|
||||
}
|
||||
}
|
||||
this.blockRefCount = storage.blockRefCount;
|
||||
}
|
||||
|
||||
|
||||
private static void copyNibbleArray(NibbleArray srcArray, NibbleArray dstArray) {
|
||||
if (srcArray == null || dstArray == null) {
|
||||
throw new RuntimeException("NibbleArray is null src: " + (srcArray == null) + " dst: " + (dstArray == null));
|
||||
}
|
||||
final byte[] data = srcArray.data;
|
||||
System.arraycopy(data, 0, dstArray.data, 0, data.length);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.gtnewhorizons.angelica.compat;
|
||||
|
||||
import com.gtnewhorizons.angelica.compat.backhand.BackhandReflectionCompat;
|
||||
import com.gtnewhorizons.angelica.helpers.LoadControllerHelper;
|
||||
import cpw.mods.fml.common.Loader;
|
||||
import cpw.mods.fml.common.versioning.DefaultArtifactVersion;
|
||||
import mods.battlegear2.Battlegear;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public class ModStatus {
|
||||
public static final Logger LOGGER = LogManager.getLogger("ModCompat");
|
||||
|
||||
public static BackhandReflectionCompat backhandCompat;
|
||||
/**
|
||||
* Mixin Version
|
||||
*/
|
||||
public static boolean isNEIDLoaded;
|
||||
/**
|
||||
* ASM Version
|
||||
*/
|
||||
public static boolean isOldNEIDLoaded;
|
||||
public static boolean isBetterCrashesLoaded;
|
||||
public static boolean isNEIDMetadataExtended;
|
||||
public static boolean isLotrLoaded;
|
||||
public static boolean isChunkAPILoaded;
|
||||
public static boolean isEIDBiomeLoaded;
|
||||
public static boolean isXaerosMinimapLoaded;
|
||||
public static boolean isHoloInventoryLoaded;
|
||||
public static boolean isBattlegearLoaded;
|
||||
public static boolean isBackhandLoaded;
|
||||
public static boolean isThaumcraftLoaded;
|
||||
public static boolean isThaumicHorizonsLoaded;
|
||||
public static boolean isBaublesLoaded;
|
||||
public static boolean isFluidLoggedLoaded;
|
||||
|
||||
public static void preInit(){
|
||||
isBackhandLoaded = Loader.isModLoaded("backhand");
|
||||
if(isBackhandLoaded) {
|
||||
isBackhandLoaded = BackhandReflectionCompat.isBackhandLoaded();
|
||||
}
|
||||
|
||||
isBetterCrashesLoaded = Loader.isModLoaded("bettercrashes");
|
||||
isNEIDLoaded = Loader.isModLoaded("neid");
|
||||
isOldNEIDLoaded = Loader.isModLoaded("notenoughIDs");
|
||||
isLotrLoaded = Loader.isModLoaded("lotr");
|
||||
isChunkAPILoaded = Loader.isModLoaded("chunkapi");
|
||||
isEIDBiomeLoaded = Loader.isModLoaded("endlessids_biome");
|
||||
isXaerosMinimapLoaded = Loader.isModLoaded("XaeroMinimap");
|
||||
isHoloInventoryLoaded = Loader.isModLoaded("holoinventory");
|
||||
isBattlegearLoaded = Loader.isModLoaded("battlegear2");
|
||||
isThaumcraftLoaded = Loader.isModLoaded("Thaumcraft");
|
||||
isThaumicHorizonsLoaded = Loader.isModLoaded("ThaumicHorizons");
|
||||
isBaublesLoaded = Loader.isModLoaded("Baubles");
|
||||
isFluidLoggedLoaded = Loader.isModLoaded("fluidlogged");
|
||||
|
||||
isHoloInventoryLoaded = Loader.isModLoaded("holoinventory");
|
||||
|
||||
// remove compat with original release of BG2
|
||||
if (isBattlegearLoaded){
|
||||
isBattlegearLoaded = new DefaultArtifactVersion("1.2.0")
|
||||
.compareTo(
|
||||
LoadControllerHelper.getOwningMod(Battlegear.class).getProcessedVersion()
|
||||
) <= 0;
|
||||
}
|
||||
|
||||
isNEIDMetadataExtended = false;
|
||||
if (isNEIDLoaded) {
|
||||
final int majorVersion = Integer.parseInt(Loader.instance().getIndexedModList().get("neid").getVersion().split("\\.")[0]);
|
||||
if (majorVersion >= 2) {
|
||||
isNEIDMetadataExtended = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
package com.gtnewhorizons.angelica.compat.backhand;
|
||||
|
||||
import com.gtnewhorizons.angelica.helpers.LoadControllerHelper;
|
||||
import cpw.mods.fml.common.versioning.DefaultArtifactVersion;
|
||||
import cpw.mods.fml.relauncher.ReflectionHelper;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
|
||||
import static com.gtnewhorizons.angelica.compat.ModStatus.LOGGER;
|
||||
|
||||
public class BackhandReflectionCompat {
|
||||
private static final String BACKHAND_CLASS = "xonin.backhand.Backhand";
|
||||
private static final String ITEM_RENDERER_HOOKS_CLASS = "xonin.backhand.client.hooks.ItemRendererHooks";
|
||||
private static final String BACKHAND_UTILS_CLASS = "xonin.backhand.api.core.BackhandUtils";
|
||||
|
||||
private static boolean isLoaded;
|
||||
private static final MethodHandle renderOffhandReturn;
|
||||
private static final MethodHandle getOffhandItem;
|
||||
|
||||
static {
|
||||
MethodHandle renderOffhandReturnTemp = null;
|
||||
MethodHandle getOffhandItemTemp = null;
|
||||
|
||||
try {
|
||||
final Class<?> backhandClass = ReflectionHelper.getClass(BackhandReflectionCompat.class.getClassLoader(), BACKHAND_CLASS);
|
||||
final boolean versionCheck = new DefaultArtifactVersion("1.6.9").compareTo(LoadControllerHelper.getOwningMod(backhandClass).getProcessedVersion()) <= 0;
|
||||
|
||||
if (versionCheck) {
|
||||
final MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
final Class<?> itemRendererHooksClass = ReflectionHelper.getClass(BackhandReflectionCompat.class.getClassLoader(), ITEM_RENDERER_HOOKS_CLASS);
|
||||
final Class<?> backhandUtilsClass = ReflectionHelper.getClass(BackhandReflectionCompat.class.getClassLoader(), BACKHAND_UTILS_CLASS);
|
||||
|
||||
renderOffhandReturnTemp = lookup.findStatic(itemRendererHooksClass, "renderOffhandReturn", MethodType.methodType(void.class, float.class));
|
||||
getOffhandItemTemp = lookup.findStatic(backhandUtilsClass, "getOffhandItem", MethodType.methodType(ItemStack.class, EntityPlayer.class));
|
||||
isLoaded = true;
|
||||
LOGGER.info("Backhand compat loaded");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Failed to load Backhand compat", e);
|
||||
isLoaded = false;
|
||||
}
|
||||
|
||||
renderOffhandReturn = renderOffhandReturnTemp;
|
||||
getOffhandItem = getOffhandItemTemp;
|
||||
}
|
||||
|
||||
public static boolean isBackhandLoaded() {
|
||||
return isLoaded;
|
||||
}
|
||||
|
||||
public static void renderOffhand(float partialTicks) {
|
||||
if (isLoaded && renderOffhandReturn != null) {
|
||||
try {
|
||||
renderOffhandReturn.invokeExact(partialTicks);
|
||||
} catch (Error e) {
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
LOGGER.error("Failed to invoke HoloInventory renderEvent", t);
|
||||
isLoaded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static ItemStack getOffhandItem(EntityPlayer player) {
|
||||
if (isLoaded && getOffhandItem != null) {
|
||||
try {
|
||||
return (ItemStack) getOffhandItem.invokeExact(player);
|
||||
} catch (Error e) {
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
LOGGER.error("Failed to invoke HoloInventory renderEvent", t);
|
||||
isLoaded = false;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.gtnewhorizons.angelica.compat.battlegear2;
|
||||
|
||||
import mods.battlegear2.api.core.IInventoryPlayerBattle;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
/**
|
||||
* This class exists to isolate classes that exist in Battlegear 2 but not
|
||||
* in Battlegear 2 for Backhand in order to avoid class loading exceptions.
|
||||
*/
|
||||
public class Battlegear2Compat {
|
||||
public static ItemStack getBattlegear2Offhand(EntityPlayer player) {
|
||||
return ((IInventoryPlayerBattle) player.inventory).battlegear2$getCurrentOffhandWeapon();
|
||||
}
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package com.gtnewhorizons.angelica.compat.bettercrashes;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import com.gtnewhorizons.angelica.mixins.interfaces.IRenderGlobalExt;
|
||||
import cpw.mods.fml.common.Optional;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import vfyjxf.bettercrashes.utils.StateManager;
|
||||
|
||||
import static com.gtnewhorizons.angelica.loading.AngelicaTweaker.LOGGER;
|
||||
|
||||
@Optional.Interface(modid = "angelica", iface = "vfyjxf.bettercrashes.utils.StateManager.IResettable")
|
||||
public class BetterCrashesCompat implements StateManager.IResettable {
|
||||
private static BetterCrashesCompat INSTANCE;
|
||||
|
||||
public static void init() {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = new BetterCrashesCompat();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public BetterCrashesCompat() {
|
||||
LOGGER.info("BetterCrashesCompat initialized");
|
||||
this.register();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetState() {
|
||||
LOGGER.info("Reloading SodiumRenderer");
|
||||
((IRenderGlobalExt) Minecraft.getMinecraft().renderGlobal).angelica$reload();
|
||||
LOGGER.info("Resetting GLStateManager");
|
||||
GLStateManager.reset();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.gtnewhorizons.angelica.compat.endlessids;
|
||||
|
||||
import com.falsepattern.endlessids.mixin.helpers.ChunkBiomeHook;
|
||||
import lombok.val;
|
||||
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
|
||||
import static com.falsepattern.endlessids.constants.ExtendedConstants.biomeIDMask;
|
||||
import static com.falsepattern.endlessids.constants.ExtendedConstants.biomeIDNull;
|
||||
|
||||
public class EndlessIDsCompat {
|
||||
public static void sodium$populateBiomes(Chunk chunk) {
|
||||
if (!(chunk instanceof ChunkBiomeHook hook))
|
||||
return;
|
||||
|
||||
val biomes = hook.getBiomeShortArray();
|
||||
if (biomes == null)
|
||||
return;
|
||||
|
||||
val cX = chunk.xPosition << 4;
|
||||
val cZ = chunk.zPosition << 4;
|
||||
|
||||
val manager = chunk.worldObj.getWorldChunkManager();
|
||||
for(var z = 0; z < 16; z++) {
|
||||
for(var x = 0; x < 16; x++) {
|
||||
val idx = (z << 4) + x;
|
||||
val biome = biomes[idx] & biomeIDMask;
|
||||
if(biome == biomeIDNull) {
|
||||
val generated = manager.getBiomeGenAt(cX + x, cZ + z);
|
||||
if (generated == null)
|
||||
continue;
|
||||
biomes[idx] = (short)(generated.biomeID & biomeIDMask);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
package com.gtnewhorizons.angelica.compat.holoinventory;
|
||||
|
||||
import net.minecraftforge.client.event.RenderGameOverlayEvent;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import static com.gtnewhorizons.angelica.compat.ModStatus.LOGGER;
|
||||
|
||||
public class HoloInventoryReflectionCompat {
|
||||
private static final String RENDERER_CLASS = "net.dries007.holoInventory.client.Renderer";
|
||||
|
||||
private static boolean isLoaded;
|
||||
private static final MethodHandle renderEventPostMethod;
|
||||
private static final MethodHandle renderEventMethod;
|
||||
private static final MethodHandle angelicaOverrideSetter;
|
||||
|
||||
static {
|
||||
MethodHandle renderEventPostMethodTemp = null;
|
||||
MethodHandle renderEventMethodTemp = null;
|
||||
MethodHandle angelicaOverrideSetterTemp = null;
|
||||
final Object rendererInstance;
|
||||
final Class<?> rendererClass;
|
||||
|
||||
try {
|
||||
rendererClass = Class.forName(RENDERER_CLASS);
|
||||
|
||||
// Get and cache the Renderer.INSTANCE
|
||||
final Field instanceField = rendererClass.getDeclaredField("INSTANCE");
|
||||
instanceField.setAccessible(true);
|
||||
rendererInstance = instanceField.get(null);
|
||||
|
||||
final MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
try {
|
||||
renderEventPostMethodTemp = lookup.findVirtual(rendererClass, "renderEvent", MethodType.methodType(void.class, RenderGameOverlayEvent.Post.class));
|
||||
} catch (NoSuchMethodException e) {
|
||||
// Fallback for 2.5.0-GTNH and earlier
|
||||
renderEventMethodTemp = lookup.findVirtual(rendererClass, "renderEvent", MethodType.methodType(void.class, RenderGameOverlayEvent.class));
|
||||
}
|
||||
|
||||
final Field angelicaOverrideField = rendererClass.getDeclaredField("angelicaOverride");
|
||||
angelicaOverrideField.setAccessible(true);
|
||||
angelicaOverrideSetterTemp = lookup.unreflectSetter(angelicaOverrideField);
|
||||
|
||||
// Bind the method handles to the instance
|
||||
if (rendererInstance != null) {
|
||||
if (renderEventPostMethodTemp != null) {
|
||||
renderEventPostMethodTemp = renderEventPostMethodTemp.bindTo(rendererInstance);
|
||||
}
|
||||
if (renderEventMethodTemp != null) {
|
||||
renderEventMethodTemp = renderEventMethodTemp.bindTo(rendererInstance);
|
||||
}
|
||||
angelicaOverrideSetterTemp = angelicaOverrideSetterTemp.bindTo(rendererInstance);
|
||||
}
|
||||
|
||||
isLoaded = true;
|
||||
LOGGER.info("Successfully initialized HoloInventory compatibility layer");
|
||||
} catch (Exception e) {
|
||||
LOGGER.warn("Failed to initialize HoloInventory compatibility layer", e);
|
||||
isLoaded = false;
|
||||
}
|
||||
|
||||
renderEventPostMethod = renderEventPostMethodTemp;
|
||||
renderEventMethod = renderEventMethodTemp;
|
||||
angelicaOverrideSetter = angelicaOverrideSetterTemp;
|
||||
}
|
||||
|
||||
public static void renderEvent(RenderGameOverlayEvent event) {
|
||||
if (!isLoaded) return;
|
||||
try {
|
||||
if (event instanceof RenderGameOverlayEvent.Post && renderEventPostMethod != null) {
|
||||
renderEventPostMethod.invokeExact((RenderGameOverlayEvent.Post) event);
|
||||
} else {
|
||||
renderEventMethod.invokeExact(event);
|
||||
}
|
||||
} catch (Error e) {
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
LOGGER.error("Failed to invoke HoloInventory renderEvent", t);
|
||||
isLoaded = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void setAngelicaOverride(boolean value) {
|
||||
if (!isLoaded) return;
|
||||
try {
|
||||
angelicaOverrideSetter.invokeExact(value);
|
||||
} catch (Error e) {
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
LOGGER.error("Failed to invoke HoloInventory renderEvent", t);
|
||||
isLoaded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.gtnewhorizons.angelica.compat.iris;
|
||||
|
||||
/**
|
||||
* Interface implemented by BiomeGenBase via mixin to cache biome category.
|
||||
* This avoids recomputing the category every frame for shader uniforms.
|
||||
*/
|
||||
public interface BiomeCategoryCache {
|
||||
/**
|
||||
* Gets the cached biome category ordinal, or -1 if not yet computed.
|
||||
*/
|
||||
int iris$getCachedCategory();
|
||||
|
||||
/**
|
||||
* Sets the cached biome category ordinal.
|
||||
*/
|
||||
void iris$setCachedCategory(int category);
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package com.gtnewhorizons.angelica.compat.iris;
|
||||
|
||||
import net.coderbot.iris.parsing.BiomeCategories;
|
||||
import net.minecraft.world.biome.BiomeGenBase;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Detects and categorizes biomes from popular modded biome mods using cached class checks.
|
||||
* Currently supports: BiomesOPlenty (BOP), Realistic World Gen (RWG)
|
||||
*/
|
||||
public class ModdedBiomeDetector {
|
||||
private static boolean initialized = false;
|
||||
|
||||
// BiomesOPlenty (BOP) cache - dimension-specific base classes
|
||||
// BOP 1.7.10 hierarchy: BOPBiome -> BOPEndBiome/BOPNetherBiome/BOPOverworldBiome -> specific biomes
|
||||
private static Class<?> bopEndBiomeClass = null;
|
||||
private static Class<?> bopNetherBiomeClass = null;
|
||||
private static Class<?> bopOceanBiomeClass = null;
|
||||
|
||||
// Realistic World Gen (RWG) cache - base biome classes that extend BiomeGenBase
|
||||
// LinkedHashMap maintains insertion order for deterministic behavior
|
||||
private static final Map<Class<?>, BiomeCategories> rwgClassMap = new LinkedHashMap<>();
|
||||
|
||||
private static synchronized void initialize() {
|
||||
if (initialized) return;
|
||||
initialized = true;
|
||||
|
||||
initializeBOP();
|
||||
initializeRWG();
|
||||
}
|
||||
|
||||
private static void initializeBOP() {
|
||||
try {
|
||||
bopEndBiomeClass = Class.forName("biomesoplenty.common.biome.BOPEndBiome");
|
||||
bopNetherBiomeClass = Class.forName("biomesoplenty.common.biome.BOPNetherBiome");
|
||||
bopOceanBiomeClass = Class.forName("biomesoplenty.common.biome.BOPOceanBiome");
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
// BOP not installed
|
||||
}
|
||||
}
|
||||
|
||||
private static void initializeRWG() {
|
||||
// RWG adds actual BiomeGenBase subclasses in rwg.biomes.base package
|
||||
tryAddRWGClass("rwg.biomes.base.BaseBiomeOcean", BiomeCategories.OCEAN);
|
||||
tryAddRWGClass("rwg.biomes.base.BaseBiomeRiver", BiomeCategories.RIVER);
|
||||
tryAddRWGClass("rwg.biomes.base.BaseBiomePlains", BiomeCategories.PLAINS);
|
||||
tryAddRWGClass("rwg.biomes.base.BaseBiomeColdPlains", BiomeCategories.PLAINS);
|
||||
tryAddRWGClass("rwg.biomes.base.BaseBiomeHotPlains", BiomeCategories.PLAINS);
|
||||
tryAddRWGClass("rwg.biomes.base.BaseBiomeHotDesert", BiomeCategories.DESERT);
|
||||
tryAddRWGClass("rwg.biomes.base.BaseBiomeSnowDesert", BiomeCategories.DESERT); // Cold desert, but still desert
|
||||
tryAddRWGClass("rwg.biomes.base.BaseBiomeJungle", BiomeCategories.JUNGLE);
|
||||
tryAddRWGClass("rwg.biomes.base.BaseBiomeTropicalIsland", BiomeCategories.JUNGLE); // Tropical islands are jungle-like
|
||||
tryAddRWGClass("rwg.biomes.base.BaseBiomeRedwood", BiomeCategories.FOREST); // Redwood/Sequoia forests
|
||||
tryAddRWGClass("rwg.biomes.base.BaseBiomeTemperateForest", BiomeCategories.FOREST);
|
||||
tryAddRWGClass("rwg.biomes.base.BaseBiomeColdForest", BiomeCategories.TAIGA); // Cold forests are taiga-like
|
||||
tryAddRWGClass("rwg.biomes.base.BaseBiomeHotForest", BiomeCategories.FOREST);
|
||||
tryAddRWGClass("rwg.biomes.base.BaseBiomeSnowForest", BiomeCategories.TAIGA); // Snow forests are taiga
|
||||
}
|
||||
|
||||
private static void tryAddRWGClass(String className, BiomeCategories category) {
|
||||
try {
|
||||
final Class<?> clazz = Class.forName(className);
|
||||
rwgClassMap.put(clazz, category);
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
// Class not available, RWG not installed or different version
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to detect the biome category for modded biomes.
|
||||
* Returns null if no modded biome detection applies.
|
||||
*/
|
||||
public static BiomeCategories detectModdedBiome(BiomeGenBase biome) {
|
||||
if (!initialized) {
|
||||
initialize();
|
||||
}
|
||||
|
||||
// BiomesOPlenty detection - dimension-specific classes give us clear categories
|
||||
if (bopEndBiomeClass != null && bopEndBiomeClass.isInstance(biome)) {
|
||||
return BiomeCategories.THE_END;
|
||||
}
|
||||
if (bopNetherBiomeClass != null && bopNetherBiomeClass.isInstance(biome)) {
|
||||
return BiomeCategories.NETHER;
|
||||
}
|
||||
if (bopOceanBiomeClass != null && bopOceanBiomeClass.isInstance(biome)) {
|
||||
return BiomeCategories.OCEAN;
|
||||
}
|
||||
// For other BOP overworld biomes (e.g., Alps, Arctic, BambooForest),
|
||||
// fall through to name/property-based detection
|
||||
|
||||
// Realistic World Gen detection
|
||||
for (Map.Entry<Class<?>, BiomeCategories> entry : rwgClassMap.entrySet()) {
|
||||
if (entry.getKey().isInstance(biome)) {
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.gtnewhorizons.angelica.compat.mojang;
|
||||
|
||||
import com.gtnewhorizons.angelica.glsm.GLStateManager;
|
||||
import net.minecraft.client.renderer.texture.AbstractTexture;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
public abstract class AutoClosableAbstractTexture extends AbstractTexture implements AutoCloseable {
|
||||
@Override
|
||||
public void close() throws Exception {}
|
||||
|
||||
// TODO: Is this needed?
|
||||
public void bind() {
|
||||
GLStateManager.glBindTexture(GL11.GL_TEXTURE_2D, getGlTextureId());
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.gtnewhorizons.angelica.compat.mojang;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
|
||||
public class ByteBufferBackedInputStream extends InputStream {
|
||||
|
||||
ByteBuffer buf;
|
||||
|
||||
public ByteBufferBackedInputStream(ByteBuffer buf) {
|
||||
this.buf = buf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (!buf.hasRemaining()) {
|
||||
return -1;
|
||||
}
|
||||
return buf.get() & 0xFF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte @NotNull [] bytes, int off, int len) throws IOException {
|
||||
if (!buf.hasRemaining()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = Math.min(len, buf.remaining());
|
||||
buf.get(bytes, off, len);
|
||||
return len;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.gtnewhorizons.angelica.compat.mojang;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.blockpos.BlockPos;
|
||||
import com.gtnewhorizons.angelica.rendering.RenderingState;
|
||||
import lombok.Getter;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.util.MathHelper;
|
||||
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector3d;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
/**
|
||||
* Singleton camera instance that tracks the current camera position and orientation.
|
||||
*/
|
||||
@Getter
|
||||
public class Camera {
|
||||
public static final Camera INSTANCE = new Camera();
|
||||
|
||||
private final Vector3d pos = new Vector3d();
|
||||
private final BlockPos blockPos = new BlockPos();
|
||||
private final Vector3f offset = new Vector3f();
|
||||
private final Matrix4f inverseModelView = new Matrix4f();
|
||||
|
||||
private float pitch;
|
||||
private float yaw;
|
||||
private EntityLivingBase entity;
|
||||
private boolean thirdPerson;
|
||||
private float partialTicks;
|
||||
|
||||
private Camera() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the camera position and orientation based on the current entity and partial ticks.
|
||||
*
|
||||
* @param entity The entity to track (usually the render view entity)
|
||||
* @param partialTicks The partial tick time for interpolation
|
||||
*/
|
||||
public void update(EntityLivingBase entity, float partialTicks) {
|
||||
this.partialTicks = partialTicks;
|
||||
this.entity = entity;
|
||||
|
||||
// Entity position (interpolated, at feet level)
|
||||
final double entityX = entity.lastTickPosX + (entity.posX - entity.lastTickPosX) * partialTicks;
|
||||
final double entityY = entity.lastTickPosY + (entity.posY - entity.lastTickPosY) * partialTicks;
|
||||
final double entityZ = entity.lastTickPosZ + (entity.posZ - entity.lastTickPosZ) * partialTicks;
|
||||
final double eyeHeight = entity.getEyeHeight();
|
||||
|
||||
thirdPerson = Minecraft.getMinecraft().gameSettings.thirdPersonView > 0;
|
||||
|
||||
final double camX, camY, camZ;
|
||||
offset.set(0, 0, 0);
|
||||
|
||||
if (thirdPerson) {
|
||||
// Third person: use inverse modelview to find camera offset
|
||||
inverseModelView.set(RenderingState.INSTANCE.getModelViewMatrix()).invert();
|
||||
inverseModelView.transformPosition(offset);
|
||||
}
|
||||
camX = entityX + offset.x;
|
||||
camY = entityY + eyeHeight + offset.y;
|
||||
camZ = entityZ + offset.z;
|
||||
|
||||
pos.set(camX, camY, camZ);
|
||||
blockPos.set(MathHelper.floor_double(camX), MathHelper.floor_double(camY), MathHelper.floor_double(camZ));
|
||||
pitch = entity.cameraPitch;
|
||||
yaw = entity.rotationYaw;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.gtnewhorizons.angelica.compat.mojang;
|
||||
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
|
||||
import java.util.BitSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class ChunkOcclusionData {
|
||||
private static final int DIRECTION_COUNT = ForgeDirection.values().length;
|
||||
private final BitSet visibility;
|
||||
|
||||
public ChunkOcclusionData() {
|
||||
this.visibility = new BitSet(DIRECTION_COUNT * DIRECTION_COUNT);
|
||||
}
|
||||
|
||||
public void addOpenEdgeFaces(Set<ForgeDirection> faces) {
|
||||
for (ForgeDirection dirFrom : faces) {
|
||||
for (ForgeDirection dirTo : faces) {
|
||||
this.setVisibleThrough(dirFrom, dirTo, true);
|
||||
}
|
||||
}
|
||||
|
||||
for (ForgeDirection direction : faces) {
|
||||
this.visibility.set(direction.ordinal() * DIRECTION_COUNT + direction.ordinal());
|
||||
}
|
||||
}
|
||||
public void setVisibleThrough(ForgeDirection from, ForgeDirection to, boolean visible) {
|
||||
this.visibility.set(from.ordinal() + to.ordinal() * DIRECTION_COUNT, visible);
|
||||
this.visibility.set(to.ordinal() + from.ordinal() * DIRECTION_COUNT, visible);
|
||||
}
|
||||
|
||||
public boolean isVisibleThrough(ForgeDirection from, ForgeDirection to) {
|
||||
return this.visibility.get(from.ordinal() + to.ordinal() * DIRECTION_COUNT);
|
||||
}
|
||||
|
||||
public void fill(boolean visible) {
|
||||
this.visibility.set(0, this.visibility.size(), visible);
|
||||
}
|
||||
}
|
||||
+155
@@ -0,0 +1,155 @@
|
||||
package com.gtnewhorizons.angelica.compat.mojang;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.blockpos.BlockPos;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayFIFOQueue;
|
||||
import it.unimi.dsi.fastutil.ints.IntPriorityQueue;
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
|
||||
import java.util.BitSet;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* WARNING: Minecraft 1.16 code rip!!
|
||||
*/
|
||||
|
||||
public class ChunkOcclusionDataBuilder {
|
||||
private static final int STEP_X = (int)Math.pow(16.0, 0.0);
|
||||
private static final int STEP_Z = (int)Math.pow(16.0, 1.0);
|
||||
private static final int STEP_Y = (int)Math.pow(16.0, 2.0);
|
||||
private static final ForgeDirection[] DIRECTIONS = ForgeDirection.VALID_DIRECTIONS;
|
||||
private final BitSet closed = new BitSet(4096);
|
||||
private static final int[] EDGE_POINTS = new int[1352];
|
||||
|
||||
static {
|
||||
int k = 0;
|
||||
|
||||
for(int l = 0; l < 16; ++l) {
|
||||
for(int m = 0; m < 16; ++m) {
|
||||
for(int n = 0; n < 16; ++n) {
|
||||
if (l == 0 || l == 15 || m == 0 || m == 15 || n == 0 || n == 15) {
|
||||
EDGE_POINTS[k++] = pack(l, m, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private int openCount = 4096;
|
||||
|
||||
public void markClosed(BlockPos pos) {
|
||||
this.closed.set(pack(pos), true);
|
||||
--this.openCount;
|
||||
}
|
||||
|
||||
private static int pack(BlockPos pos) {
|
||||
return pack(pos.getX() & 15, pos.getY() & 15, pos.getZ() & 15);
|
||||
}
|
||||
|
||||
private static int pack(int x, int y, int z) {
|
||||
return x << 0 | y << 8 | z << 4;
|
||||
}
|
||||
|
||||
public ChunkOcclusionData build() {
|
||||
final ChunkOcclusionData lv = new ChunkOcclusionData();
|
||||
if (4096 - this.openCount < 256) {
|
||||
lv.fill(true);
|
||||
} else if (this.openCount == 0) {
|
||||
lv.fill(false);
|
||||
} else {
|
||||
for(int i : EDGE_POINTS) {
|
||||
if (!this.closed.get(i)) {
|
||||
lv.addOpenEdgeFaces(this.getOpenFaces(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return lv;
|
||||
}
|
||||
|
||||
private Set<ForgeDirection> getOpenFaces(int pos) {
|
||||
final Set<ForgeDirection> set = EnumSet.noneOf(ForgeDirection.class);
|
||||
final IntPriorityQueue intPriorityQueue = new IntArrayFIFOQueue();
|
||||
intPriorityQueue.enqueue(pos);
|
||||
this.closed.set(pos, true);
|
||||
|
||||
while(!intPriorityQueue.isEmpty()) {
|
||||
final int j = intPriorityQueue.dequeueInt();
|
||||
this.addEdgeFaces(j, set);
|
||||
|
||||
for(ForgeDirection lv : DIRECTIONS) {
|
||||
final int k = this.offset(j, lv);
|
||||
if (k >= 0 && !this.closed.get(k)) {
|
||||
this.closed.set(k, true);
|
||||
intPriorityQueue.enqueue(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
private void addEdgeFaces(int pos, Set<ForgeDirection> openFaces) {
|
||||
final int j = pos >> 0 & 15;
|
||||
if (j == 0) {
|
||||
openFaces.add(ForgeDirection.WEST);
|
||||
} else if (j == 15) {
|
||||
openFaces.add(ForgeDirection.EAST);
|
||||
}
|
||||
|
||||
final int k = pos >> 8 & 15;
|
||||
if (k == 0) {
|
||||
openFaces.add(ForgeDirection.DOWN);
|
||||
} else if (k == 15) {
|
||||
openFaces.add(ForgeDirection.UP);
|
||||
}
|
||||
|
||||
final int l = pos >> 4 & 15;
|
||||
if (l == 0) {
|
||||
openFaces.add(ForgeDirection.NORTH);
|
||||
} else if (l == 15) {
|
||||
openFaces.add(ForgeDirection.SOUTH);
|
||||
}
|
||||
}
|
||||
|
||||
private int offset(int pos, ForgeDirection arg) {
|
||||
return switch (arg) {
|
||||
case DOWN -> {
|
||||
if ((pos >> 8 & 15) == 0) {
|
||||
yield -1;
|
||||
}
|
||||
yield pos - STEP_Y;
|
||||
}
|
||||
case UP -> {
|
||||
if ((pos >> 8 & 15) == 15) {
|
||||
yield -1;
|
||||
}
|
||||
yield pos + STEP_Y;
|
||||
}
|
||||
case NORTH -> {
|
||||
if ((pos >> 4 & 15) == 0) {
|
||||
yield -1;
|
||||
}
|
||||
yield pos - STEP_Z;
|
||||
}
|
||||
case SOUTH -> {
|
||||
if ((pos >> 4 & 15) == 15) {
|
||||
yield -1;
|
||||
}
|
||||
yield pos + STEP_Z;
|
||||
}
|
||||
case WEST -> {
|
||||
if ((pos >> 0 & 15) == 0) {
|
||||
yield -1;
|
||||
}
|
||||
yield pos - STEP_X;
|
||||
}
|
||||
case EAST -> {
|
||||
if ((pos >> 0 & 15) == 15) {
|
||||
yield -1;
|
||||
}
|
||||
yield pos + STEP_X;
|
||||
}
|
||||
default -> -1;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.gtnewhorizons.angelica.compat.mojang;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.blockpos.BlockPos;
|
||||
|
||||
// See if we can merge/mixin/extend ChunkCoordIntPair?
|
||||
public class ChunkPos {
|
||||
public static long INT_MASK = (1L << Integer.SIZE) - 1;
|
||||
|
||||
public final int x;
|
||||
public final int z;
|
||||
|
||||
public ChunkPos(int x, int z) {
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public ChunkPos(BlockPos pos) {
|
||||
this.x = pos.getX() >> 4;
|
||||
this.z = pos.getZ() >> 4;
|
||||
}
|
||||
|
||||
public ChunkPos(long pos) {
|
||||
this.x = (int)pos;
|
||||
this.z = (int)(pos >> 32);
|
||||
}
|
||||
|
||||
public static int getPackedX(long pos) {
|
||||
return (int)(pos & INT_MASK);
|
||||
}
|
||||
|
||||
public static int getPackedZ(long pos) {
|
||||
return (int)(pos >>> 32 & INT_MASK);
|
||||
}
|
||||
|
||||
public long toLong() {
|
||||
return toLong(this.x, this.z);
|
||||
}
|
||||
|
||||
public static long toLong(int x, int z) {
|
||||
return (long)x & 4294967295L | ((long)z & 4294967295L) << 32;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
final int i = 1664525 * this.x + 1013904223;
|
||||
final int j = 1664525 * (this.z ^ -559038737) + 1013904223;
|
||||
return i ^ j;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if (this == object) {
|
||||
return true;
|
||||
}
|
||||
if (object instanceof ChunkPos lv) {
|
||||
return this.x == lv.x && this.z == lv.z;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.gtnewhorizons.angelica.compat.mojang;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.blockpos.BlockPos;
|
||||
import org.joml.Vector3i;
|
||||
|
||||
// See if we can merge/mixin/extend ChunkPosition maybe?
|
||||
public class ChunkSectionPos extends Vector3i {
|
||||
|
||||
public static int getSectionCoord(int coord) {
|
||||
return coord >> 4;
|
||||
}
|
||||
public static int getBlockCoord(int sectionCoord) {
|
||||
return sectionCoord << 4;
|
||||
}
|
||||
|
||||
private ChunkSectionPos(int x, int y, int z) {
|
||||
super(x, y, z);
|
||||
}
|
||||
public static ChunkSectionPos from(int x, int y, int z) {
|
||||
return new ChunkSectionPos(x, y, z);
|
||||
}
|
||||
|
||||
public static ChunkSectionPos from(BlockPos pos) {
|
||||
return new ChunkSectionPos(getSectionCoord(pos.getX()), getSectionCoord(pos.getY()), getSectionCoord(pos.getZ()));
|
||||
}
|
||||
|
||||
public static long asLong(int x, int y, int z) {
|
||||
long l = 0L;
|
||||
l |= ((long)x & 4194303L) << 42;
|
||||
l |= ((long)y & 1048575L) << 0;
|
||||
l |= ((long)z & 4194303L) << 20;
|
||||
return l;
|
||||
}
|
||||
|
||||
public static int getLocalCoord(int coord) {
|
||||
return coord & 15;
|
||||
}
|
||||
|
||||
public static short packLocal(int x, int y, int z) {
|
||||
final int i = getLocalCoord(x);
|
||||
final int j = getLocalCoord(y);
|
||||
final int k = getLocalCoord(z);
|
||||
return (short)(i << 8 | k << 4 | j << 0);
|
||||
}
|
||||
|
||||
public long asLong() {
|
||||
return asLong(this.x, this.y, this.z);
|
||||
}
|
||||
|
||||
public int getSectionX() {
|
||||
return this.x;
|
||||
}
|
||||
|
||||
public int getSectionY() {
|
||||
return this.y;
|
||||
}
|
||||
|
||||
public int getSectionZ() {
|
||||
return this.z;
|
||||
}
|
||||
|
||||
public int getMinX() {
|
||||
return this.x << 4;
|
||||
}
|
||||
|
||||
public int getMinY() {
|
||||
return this.y << 4;
|
||||
}
|
||||
|
||||
public int getMinZ() {
|
||||
return this.z << 4;
|
||||
}
|
||||
|
||||
public int getMaxX() {
|
||||
return (this.x << 4) + 15;
|
||||
}
|
||||
|
||||
public int getMaxY() {
|
||||
return (this.y << 4) + 15;
|
||||
}
|
||||
|
||||
public int getMaxZ() {
|
||||
return (this.z << 4) + 15;
|
||||
}
|
||||
|
||||
public ChunkPos toChunkPos() {
|
||||
return new ChunkPos(this.getSectionX(), this.getSectionZ());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.gtnewhorizons.angelica.compat.mojang;
|
||||
|
||||
public class CompatMathHelper {
|
||||
public static int smallestEncompassingPowerOfTwo(int value) {
|
||||
int j = value - 1;
|
||||
j |= j >> 1;
|
||||
j |= j >> 2;
|
||||
j |= j >> 4;
|
||||
j |= j >> 8;
|
||||
j |= j >> 16;
|
||||
return j + 1;
|
||||
}
|
||||
public static int roundUpToMultiple(int value, int divisor) {
|
||||
if (divisor == 0) {
|
||||
return 0;
|
||||
} else if (value == 0) {
|
||||
return divisor;
|
||||
} else {
|
||||
if (value < 0) {
|
||||
divisor *= -1;
|
||||
}
|
||||
|
||||
int k = value % divisor;
|
||||
return k == 0 ? value : value + divisor - k;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.gtnewhorizons.angelica.compat.mojang;
|
||||
|
||||
public class Constants {
|
||||
public static final float DEGREES_TO_RADIANS = (float)Math.PI / 180.0F;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.gtnewhorizons.angelica.compat.mojang;
|
||||
|
||||
public interface Drawable {
|
||||
default void render(int mouseX, int mouseY, float delta) {}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.gtnewhorizons.angelica.compat.mojang;
|
||||
|
||||
public interface Element {
|
||||
default boolean mouseClicked(double mouseX, double mouseY, int button) {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean mouseDragged(double mouseX, double mouseY, int button) {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean mouseReleased(double mouseX, double mouseY, int button) {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean mouseScrolled(double mouseX, double mouseY, double amount) {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean keyTyped(char typedChar, int keyCode) { return false; }
|
||||
|
||||
default boolean isMouseOver(double mouseX, double mouseY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean changeFocus(boolean lookForwards) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Loaded 100 of 1363 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user