Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab8faf358c | ||
|
|
243ce3c5dd | ||
|
|
d4762195f9 | ||
|
|
121e1615b6 | ||
|
|
350d33ae6f | ||
|
|
d4f7bced86 | ||
|
|
8037e659a8 | ||
|
|
28c7849252 | ||
|
|
cb277bf16a | ||
|
|
0612e1e188 | ||
|
|
7a9f83129e | ||
|
|
a17e5f13a7 | ||
|
|
02a565bf39 | ||
|
|
f1d7d5ac81 | ||
|
|
a1663f5a03 | ||
|
|
909492cfae | ||
|
|
a3b4cc21f5 | ||
|
|
402ebd729e | ||
|
|
349b5dc110 | ||
|
|
c778cc3368 | ||
|
|
26e5aab84e | ||
|
|
79da4e1bc4 | ||
|
|
51b550ca5e | ||
|
|
2877b74c42 | ||
|
|
c67d1a86c5 | ||
|
|
5cf9b34fd2 | ||
|
|
99acbe4960 | ||
|
|
2bf64b6107 | ||
|
|
4e86af8754 | ||
|
|
6bf639f18a | ||
|
|
9a7bb17459 | ||
|
|
6b84c683ee | ||
|
|
dc015dc457 | ||
|
|
fd7bc84cd5 | ||
|
|
9fd5b3b912 | ||
|
|
a2d259af58 | ||
|
|
6cc21a6d98 | ||
|
|
e105770dde | ||
|
|
68b7ee51dc | ||
|
|
a4a375f411 | ||
|
|
ae6b3d18a4 | ||
|
|
8763b0e77f | ||
|
|
2440b64981 | ||
|
|
ebe73587fe | ||
|
|
5b87ac4f61 | ||
|
|
d9a3f33199 | ||
|
|
9f44834514 | ||
|
|
314d4a2813 | ||
|
|
97fee0c898 | ||
|
|
bdc96a88cd | ||
|
|
af1691e6e5 | ||
|
|
e4058f7f15 | ||
|
|
7f0c922e10 | ||
|
|
453793eb60 | ||
|
|
015e7a4647 | ||
|
|
45c0c580f7 | ||
|
|
1c12a868c8 | ||
|
|
a3f22320d5 | ||
|
|
f4bb1dd8fc | ||
|
|
5203b3a376 | ||
|
|
fe66d743a9 | ||
|
|
1d1cf84c60 | ||
|
|
1c81aab994 | ||
|
|
52559f6fc8 | ||
|
|
06cc25bf23 | ||
|
|
86cf0d51ed | ||
|
|
5fbb052d6f | ||
|
|
b7021fcd1f | ||
|
|
64db7f13c6 | ||
|
|
20c9fdf634 | ||
|
|
a71035a157 | ||
|
|
b0002102e3 | ||
|
|
a3e65cfcbe | ||
|
|
edd9c5ce3d | ||
|
|
e918e6b10a | ||
|
|
f6c309fd18 | ||
|
|
322a99dbc4 | ||
|
|
6793dee0bc | ||
|
|
d33751dbb0 | ||
|
|
fa67de16a1 | ||
|
|
57fc21f411 | ||
|
|
9999ee3b4a | ||
|
|
4a90cadeb1 | ||
|
|
048903f33f | ||
|
|
3fa5eaf2a3 | ||
|
|
93bd6d5ac9 | ||
|
|
aa5535615c | ||
|
|
9ccd85178d | ||
|
|
14fd279c06 | ||
|
|
6df845324b | ||
|
|
c3f233ca61 | ||
|
|
ed4f018b34 | ||
|
|
ef4bc1c02e | ||
|
|
ca725b68a5 | ||
|
|
40f7463e93 | ||
|
|
7778768c30 | ||
|
|
6a6be44ab2 | ||
|
|
fe67c23ad4 | ||
|
|
c09348d4f7 | ||
|
|
e04cd2108f | ||
|
|
39f0dee9f1 | ||
|
|
9b9ae8d36c | ||
|
|
fc934195de | ||
|
|
6c4db8029b | ||
|
|
c4ce7b7a87 | ||
|
|
b751c63625 | ||
|
|
31ac149b42 | ||
|
|
2f45e9e469 | ||
|
|
7b152ff264 | ||
|
|
e9eb441a1c | ||
|
|
55c1093783 | ||
|
|
963ec4e978 | ||
|
|
26c30f46e7 | ||
|
|
c2cdafb17f | ||
|
|
22060a9889 | ||
|
|
e1a54099a4 | ||
|
|
3fa6a0f69a | ||
|
|
676cb6c3ce | ||
|
|
a3063f0bcb | ||
|
|
c1520401b6 | ||
|
|
d988d0c684 | ||
|
|
e2283d6f4e | ||
|
|
ea56cfde04 | ||
|
|
16733e587e | ||
|
|
b247807f0f | ||
|
|
679aea8181 | ||
|
|
f0d499a008 | ||
|
|
b5320f2ae7 | ||
|
|
0fd0821a93 | ||
|
|
c7c1b9da17 | ||
|
|
d67d307788 | ||
|
|
c057f18914 | ||
|
|
7a5b425dbb | ||
|
|
9b22739977 | ||
|
|
12e0869e0a | ||
|
|
0039ab8704 | ||
|
|
7da389db14 | ||
|
|
1f85797768 | ||
|
|
3c55703718 | ||
|
|
e3734c2d94 | ||
|
|
afc571e331 | ||
|
|
4549d07a6c | ||
|
|
acc220729b | ||
|
|
b27f64c3b1 | ||
|
|
1f7a09a561 | ||
|
|
f0b15c3f94 | ||
|
|
cc03d3029d | ||
|
|
ef2d24c5ff | ||
|
|
6a69d1bcb4 | ||
|
|
ea1e11d690 | ||
|
|
65b51fa6f5 | ||
|
|
dae31cedf6 | ||
|
|
6179f997c9 | ||
|
|
8cb083c29a | ||
|
|
7dd2434ea9 | ||
|
|
66ca952a1d | ||
|
|
d6fef1180f | ||
|
|
32451165ba | ||
|
|
2c806b2d4e | ||
|
|
a8dadfdfff | ||
|
|
4524b4289c | ||
|
|
67010e8f11 | ||
|
|
245ee7699a | ||
|
|
25dfb3c5b9 | ||
|
|
52709f279b | ||
|
|
13d6437638 | ||
|
|
7a3505070e | ||
|
|
7d79603d08 | ||
|
|
7890a8ae97 | ||
|
|
c73e149f43 | ||
|
|
2f72766aac | ||
|
|
43d915d09c | ||
|
|
3444b07f6a | ||
|
|
3cfb1c5b3e | ||
|
|
150736b170 | ||
|
|
1f325a36d6 | ||
|
|
bdc8f6ef82 | ||
|
|
d365e4b949 | ||
|
|
4f4a3ba87b | ||
|
|
7ceeaa5f3f | ||
|
|
6f968275c1 | ||
|
|
245b7a0d2a | ||
|
|
13b1007c1c | ||
|
|
c164908aac | ||
|
|
1dd28f124a | ||
|
|
149483ef21 | ||
|
|
0a689564ce | ||
|
|
facc6bc074 | ||
|
|
41224c9faf | ||
|
|
14548f5679 | ||
|
|
d31d0b2487 | ||
|
|
1366872acb | ||
|
|
40fcd23d87 | ||
|
|
ba7d09ee91 | ||
|
|
b0fa4eb3b7 | ||
|
|
a8bf163355 | ||
|
|
f81730c689 | ||
|
|
a830fe8b63 | ||
|
|
05c116271e | ||
|
|
a08f89813e | ||
|
|
87fa35dea0 | ||
|
|
4ed644313a | ||
|
|
9fdd1615bd | ||
|
|
4ab220f189 | ||
|
|
adef187685 | ||
|
|
0e5a443e9b | ||
|
|
4961ad6e8d | ||
|
|
e056f1ca0a | ||
|
|
9d43fd7a35 | ||
|
|
45bafb37fe | ||
|
|
3554f3c6ac | ||
|
|
10d4cf4a9d | ||
|
|
7a1621aa37 | ||
|
|
22a5e67c69 | ||
|
|
8737ba218a | ||
|
|
98e0a35f0c | ||
|
|
21500f3cab | ||
|
|
750d87937a | ||
|
|
f78ffc9a5c | ||
|
|
48b789d268 | ||
|
|
a765347cba | ||
|
|
21fe4c920d | ||
|
|
d35505b83a | ||
|
|
930d1370ce | ||
|
|
4f01b9b2d6 | ||
|
|
79ae548463 | ||
|
|
08120db4b4 | ||
|
|
11d2d979cc | ||
|
|
3822609afe | ||
|
|
dd057ca20f | ||
|
|
42403c9f51 | ||
|
|
9eb6b11fe0 | ||
|
|
8c02988330 | ||
|
|
fd7223a259 | ||
|
|
b22560852f | ||
|
|
3498720e8c | ||
|
|
457aed221b | ||
|
|
d6fb68d8e7 | ||
|
|
0e6c15eb8b | ||
|
|
485124bfef | ||
|
|
3517d1fd00 | ||
|
|
7d80f08e1c | ||
|
|
ff0af88299 | ||
|
|
ba08959d39 | ||
|
|
050aab96f7 | ||
|
|
afcdfae5a1 | ||
|
|
8908cce24f | ||
|
|
31447cb6cf | ||
|
|
884ab800f5 | ||
|
|
6e87103114 | ||
|
|
c3b8c213d3 | ||
|
|
33f50a0eb9 | ||
|
|
3f309bc92d | ||
|
|
8315b8d335 | ||
|
|
902c99aca2 | ||
|
|
f4fc20a1c8 | ||
|
|
0690c45558 | ||
|
|
699fd9ac02 | ||
|
|
b01db5ca2a | ||
|
|
4fdc9c67ad | ||
|
|
395ed0d58e | ||
|
|
bcad08260c | ||
|
|
06be6d52b2 | ||
|
|
7ec896b8b0 | ||
|
|
2717a94db5 | ||
|
|
2ea20e3d19 | ||
|
|
94d939ba67 | ||
|
|
620af0aec0 | ||
|
|
2299d82b92 | ||
|
|
25dbe61f64 | ||
|
|
ecd183156a | ||
|
|
3f0cb7e799 | ||
|
|
3400877958 | ||
|
|
7b209c9733 | ||
|
|
dfd490afc8 | ||
|
|
b5a2c0ac29 | ||
|
|
c43dd6425a | ||
|
|
8b643ae238 | ||
|
|
b07461340e | ||
|
|
4cec8fe549 | ||
|
|
55ea059640 | ||
|
|
5429e80f66 | ||
|
|
16c71fad14 | ||
|
|
d27a97c322 | ||
|
|
59ccfa89db | ||
|
|
b6f25939be | ||
|
|
d19406edf4 | ||
|
|
0702ff3716 | ||
|
|
4577c5a948 | ||
|
|
d073f716f9 | ||
|
|
5051c31bea | ||
|
|
eb2d91745a | ||
|
|
9d40bc506e | ||
|
|
0fa3be1ce2 | ||
|
|
acecdb57f4 | ||
|
|
33d3a72d4d | ||
|
|
2ce1fc1e79 | ||
|
|
63b9e27ebf | ||
|
|
8093481f08 | ||
|
|
629871fcb5 | ||
|
|
d2d9135c45 | ||
|
|
bf5c3e90b3 | ||
|
|
d100fd54de | ||
|
|
c8137956f1 | ||
|
|
e7739bac22 | ||
|
|
5c9cfcb25d | ||
|
|
4364d7a646 | ||
|
|
0ba826f578 | ||
|
|
92564a3a09 | ||
|
|
3e21b7d384 | ||
|
|
b934d7361d | ||
|
|
172cfceed7 | ||
|
|
4047bafc6a | ||
|
|
27de28476e | ||
|
|
e5dfb84a53 | ||
|
|
2b3c77b6b8 | ||
|
|
16294ccc63 | ||
|
|
9ae2cd0538 | ||
|
|
30492a7b1f | ||
|
|
ecce9d8c4e | ||
|
|
448f7be2ae | ||
|
|
4e3c45bc7e | ||
|
|
ccd3fd4b7b | ||
|
|
5003d578c7 | ||
|
|
881a66740f | ||
|
|
c9ae98814c | ||
|
|
ee2c562c9e | ||
|
|
cbd38ea581 | ||
|
|
983b27d071 | ||
|
|
b2a827e97b | ||
|
|
a709e5f746 | ||
|
|
c1f482dd35 | ||
|
|
269ca7ad43 | ||
|
|
594f8cdc6e | ||
|
|
187041bd47 | ||
|
|
68eb537b66 | ||
|
|
b18884a5b3 | ||
|
|
061d1c25e8 | ||
|
|
b1a881bfab | ||
|
|
e68dbe4155 | ||
|
|
60e33ef0a3 | ||
|
|
eac72687cb | ||
|
|
d205d83f61 | ||
|
|
61969bf9df | ||
|
|
ed9ff0c5da | ||
|
|
371ec62571 | ||
|
|
4eaf000dea | ||
|
|
97ca0007fc | ||
|
|
ece10d66c1 | ||
|
|
420a658b0a | ||
|
|
48fbb745e0 | ||
|
|
24d78ef500 | ||
|
|
a1123cdf67 | ||
|
|
cd3d3b17b1 | ||
|
|
1f2de8a566 | ||
|
|
74f4d65356 | ||
|
|
2be8692661 | ||
|
|
5021eebd55 | ||
|
|
124e59ba70 | ||
|
|
301adfb28f | ||
|
|
8d80725cf7 | ||
|
|
7aa429988b | ||
|
|
1cbd15e797 | ||
|
|
802c707902 | ||
|
|
17d5e3f711 | ||
|
|
7a342a8c21 | ||
|
|
a4e9a2cd06 | ||
|
|
4abc4a7403 | ||
|
|
2a364895cf | ||
|
|
ff56e81136 | ||
|
|
371fcff23a | ||
|
|
abe5b9f75a | ||
|
|
2c36b5ad9f | ||
|
|
0436b8cb6a | ||
|
|
2fb967ec04 | ||
|
|
aafc45d70d | ||
|
|
3e25fa641c | ||
|
|
3f3c6ba2e1 | ||
|
|
3175ef85c4 | ||
|
|
e876b1c95f | ||
|
|
be2094a21f | ||
|
|
95fdebfb08 | ||
|
|
5662c7ea9c | ||
|
|
b8587a2487 | ||
|
|
1411fd09b9 | ||
|
|
604a48e2dd | ||
|
|
f091ab69bc | ||
|
|
e22db21f72 | ||
|
|
24000fd837 | ||
|
|
87275458bb | ||
|
|
faac9cd83d | ||
|
|
887a9fa959 | ||
|
|
d716309e34 | ||
|
|
92603a382b | ||
|
|
88c788f654 | ||
|
|
bdb429a0b4 | ||
|
|
0c2e09bc7b | ||
|
|
131a66220f | ||
|
|
7e2c6726e0 | ||
|
|
882e7b57f9 | ||
|
|
990a19585f | ||
|
|
c2f7c92ed4 | ||
|
|
08b420ffb4 | ||
|
|
d9a821e44e | ||
|
|
2e39d61d53 | ||
|
|
bb9bd91970 | ||
|
|
a789d9ec83 | ||
|
|
524cf896c3 | ||
|
|
5190d71bc8 | ||
|
|
29dd1cdc03 | ||
|
|
cbe517e994 | ||
|
|
5175ed9733 | ||
|
|
26ddcfde2a | ||
|
|
e17eb7987f | ||
|
|
6cc2ac81df | ||
|
|
12d16144c0 | ||
|
|
f4fc034d51 | ||
|
|
42c6df480c | ||
|
|
c591335dd4 | ||
|
|
d93e01cca1 | ||
|
|
b666a1a62c | ||
|
|
fcdac76ba9 | ||
|
|
3e33d38518 | ||
|
|
46dd4be1d3 | ||
|
|
809517f04b | ||
|
|
f53e73ed9a | ||
|
|
a7e1852af4 | ||
|
|
95ac9d8633 | ||
|
|
8034de3ec3 | ||
|
|
ee6aac43d4 | ||
|
|
2fef51f3d4 | ||
|
|
f27ead56c7 | ||
|
|
317853fd8e | ||
|
|
db8a4184f8 | ||
|
|
95543c7033 | ||
|
|
306f1598e0 | ||
|
|
5a26451880 | ||
|
|
9384187f06 | ||
|
|
5e414bae58 | ||
|
|
990dfc279f | ||
|
|
27ec0876cb | ||
|
|
c3853614c5 | ||
|
|
67855eda8a | ||
|
|
e2ed78e81d | ||
|
|
80ae2de524 | ||
|
|
af3c440526 | ||
|
|
8bac60f2db | ||
|
|
6d0d1df82e | ||
|
|
44eba1fbdc | ||
|
|
7ca7eaa346 | ||
|
|
fb93dde220 | ||
|
|
4f9f58f76f | ||
|
|
4c2ee57f8d | ||
|
|
345db7d3f6 | ||
|
|
ab6df11274 | ||
|
|
71ed30e2a9 | ||
|
|
cbfccafce7 | ||
|
|
2888afa999 | ||
|
|
9c4d7cb933 | ||
|
|
baec4bdd00 | ||
|
|
a00ae8f52c | ||
|
|
b973820c59 | ||
|
|
5fbf597d20 | ||
|
|
cc8bb89ee5 | ||
|
|
1f0792f854 | ||
|
|
6b7ebc2162 | ||
|
|
596a961b05 | ||
|
|
9586d8da29 | ||
|
|
8391c11a7f | ||
|
|
51de60ab4f | ||
|
|
5d14703492 | ||
|
|
d3968b15db | ||
|
|
990cc38b67 | ||
|
|
df0d135a72 | ||
|
|
18ac4937b6 | ||
|
|
531cef241a | ||
|
|
e5353800e7 | ||
|
|
21dfaceb22 | ||
|
|
c13454a255 | ||
|
|
4f4f5f0578 | ||
|
|
02544cd0f5 | ||
|
|
3ed09a3834 | ||
|
|
28749faa44 | ||
|
|
2dbbdcc5d4 | ||
|
|
291266c4bd | ||
|
|
411693611a | ||
|
|
98c36ff39f | ||
|
|
1e69b33d4f | ||
|
|
ae2c6cdc4b | ||
|
|
3104885fb5 | ||
|
|
081868571b | ||
|
|
6a3b18aff9 | ||
|
|
c4caba57bd | ||
|
|
c9f3eb32aa | ||
|
|
1dad678f98 | ||
|
|
4f579f59c3 | ||
|
|
3352f25ede | ||
|
|
0378141ac4 | ||
|
|
9dbb877455 | ||
|
|
ee382176c5 | ||
|
|
b3d9c1f10f | ||
|
|
a51ce059e5 | ||
|
|
126bf406ce | ||
|
|
b476d51910 | ||
|
|
02e9f7f901 | ||
|
|
0cf411c4de | ||
|
|
37e2317a5f | ||
|
|
415550b354 | ||
|
|
3b5099f940 | ||
|
|
34605f3d72 | ||
|
|
8e5eab8bd1 | ||
|
|
8cde415712 | ||
|
|
c5189d2788 | ||
|
|
e550924b38 | ||
|
|
27d7495f65 | ||
|
|
7477483f15 | ||
|
|
7e064f453a | ||
|
|
f7e58de863 | ||
|
|
7a135fe0f5 | ||
|
|
8336f1c0ab | ||
|
|
2648f8538d | ||
|
|
6893216ed2 | ||
|
|
b6f944ad57 | ||
|
|
969f032607 | ||
|
|
daed712bf7 | ||
|
|
835952a7d2 | ||
|
|
d272f8d19e | ||
|
|
8cb8ad7388 | ||
|
|
6793fcb928 | ||
|
|
86ea24d3ee | ||
|
|
69f9c4f500 | ||
|
|
3d869f7dfc | ||
|
|
92d716d78e | ||
|
|
8a7f086fdf | ||
|
|
58f6a77287 | ||
|
|
04110da6f1 | ||
|
|
81e5a50b8a | ||
|
|
dfb6787322 | ||
|
|
6b03502307 | ||
|
|
499d2eea6c | ||
|
|
fdf1942553 | ||
|
|
9e9b9abb14 | ||
|
|
92397b2e4a | ||
|
|
154b789b48 | ||
|
|
0cee676a69 | ||
|
|
387f4661e8 | ||
|
|
c261e1d467 | ||
|
|
b43a76e682 | ||
|
|
6efb6f59b1 | ||
|
|
9f27a49358 | ||
|
|
5001b21e7a | ||
|
|
24446c61e0 | ||
|
|
d03ed48409 | ||
|
|
840153bc98 | ||
|
|
f3ee112a4e | ||
|
|
1634eed6e7 | ||
|
|
6e7dbf13e3 | ||
|
|
d60c661d3d | ||
|
|
cd0f1bb241 | ||
|
|
dd46140147 | ||
|
|
337d35f1d8 | ||
|
|
6ad2d61dd3 | ||
|
|
1d6e737611 | ||
|
|
01e161d37e | ||
|
|
bbb3e47a50 | ||
|
|
09ab2ff82b | ||
|
|
a59a8e116c | ||
|
|
9adfa831bf | ||
|
|
3a4daec265 | ||
|
|
de87ca203e | ||
|
|
9957cb3de9 | ||
|
|
2ac60d7055 | ||
|
|
87c2ca3c07 | ||
|
|
1f1b1aabd1 | ||
|
|
e2865ce4be | ||
|
|
f53f182090 | ||
|
|
2ec7771a8a | ||
|
|
75320ef583 |
No files matched your search
+1
-3
@@ -1,5 +1,3 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: retrooper
|
||||
custom: ['https://paypal.me/retrooperdev']
|
||||
github: [retrooper]
|
||||
@@ -8,16 +8,19 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
- name: Validate gradle wrapper
|
||||
uses: gradle/actions/wrapper-validation@v3
|
||||
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '17'
|
||||
java-version: '21'
|
||||
distribution: 'adopt'
|
||||
cache: 'gradle'
|
||||
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
|
||||
settings-path: ${{ github.workspace }} # location for the settings.xml file
|
||||
|
||||
@@ -25,37 +28,37 @@ jobs:
|
||||
run: chmod +x gradlew && ./gradlew build
|
||||
|
||||
- name: Upload build artifacts api
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: api-build
|
||||
path: api/build/libs
|
||||
|
||||
- name: Upload build artifacts spigot
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: spigot-build
|
||||
path: spigot/build/libs
|
||||
|
||||
- name: Upload build artifacts netty-common
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: netty-common-build
|
||||
path: netty-common/build/libs
|
||||
|
||||
- name: Upload build artifacts bungeecord
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bungeecord-build
|
||||
path: bungeecord/build/libs
|
||||
|
||||
- name: Upload build artifacts velocity
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: velocity-build
|
||||
path: velocity/build/libs
|
||||
|
||||
- name: Upload build artifacts fabric
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fabric-build
|
||||
path: fabric/build/libs
|
||||
path: fabric/build/libs
|
||||
@@ -1,33 +1,43 @@
|
||||
# packetevents
|
||||
<!--suppress HtmlDeprecatedAttribute -->
|
||||
<div align="center">
|
||||
<h2><i>packetevents</i></h2>
|
||||
<a href="https://github.com/retrooper/packetevents/actions"><img src="https://img.shields.io/github/actions/workflow/status/retrooper/packetevents/gradle-publish.yml?style=for-the-badge&logo=github"></a>
|
||||
<a href="https://discord.gg/DVHxPPxHZc"><img src="https://img.shields.io/discord/721686193061888071?color=5562e9&logo=discord&logoColor=white&style=for-the-badge"></a>
|
||||
<img src="https://img.shields.io/github/license/retrooper/packetevents?style=for-the-badge&logo=github">
|
||||
<a href="https://bstats.org/plugin/bukkit/packetevents/11327"><img src="https://img.shields.io/bstats/servers/11327?style=for-the-badge"></a>
|
||||
<a href="https://github.com/retrooper/packetevents/releases"><img src="https://img.shields.io/github/downloads/retrooper/packetevents/total.svg?style=for-the-badge&logo=github"></a>
|
||||
</div>
|
||||
PacketEvents is emerging as a strong contender in the realm of Minecraft packet processing libraries. Designed to simplify packet manipulation while delivering high performance, this powerful tool aims to demystify the complexities of projects utilizing packets. Imbued with versatility, PacketEvents supports various platforms such as Spigot, BungeeCord, Velocity, and Fabric.
|
||||
|
||||
[](https://github.com/retrooper/packetevents/blob/2.0/LICENSE) [](https://github.com/retrooper/packetevents/actions) [](https://discord.gg/prqzNg9tRU)
|
||||
<h3>Resources</h3>
|
||||
|
||||
PacketEvents is a fast and efficient multi-platform packet processing library. Our packet wrappers are easy to use with multi-version support. With our API you can write code that runs on Spigot, BungeeCord, Velocity, and Fabric! Switch to PacketEvents today by joining \
|
||||
our [Discord Server](https://discord.me/packetevents) for help.
|
||||
- [Read documentation](https://docs.packetevents.com/)
|
||||
- [Getting Started](https://docs.packetevents.com/getting-started)
|
||||
- [JavaDocs](javadocs.packetevents.com)
|
||||
- [Releases](https://github.com/retrooper/packetevents/releases/)
|
||||
- [GitHub](https://github.com/retrooper/packetevents/releases/)
|
||||
- [Modrinth](https://modrinth.com/plugin/packetevents)
|
||||
- [SpigotMC](https://www.spigotmc.org/resources/packetevents-api.80279/)
|
||||
- [Development Builds](https://ci.codemc.io/job/retrooper/job/packetevents)
|
||||
- [Statistics](https://bstats.org/plugin/bukkit/packetevents/11327)
|
||||
|
||||
### Links
|
||||
* [Find release builds on Modrinth](https://modrinth.com/plugin/packetevents)
|
||||
* [Find development builds on Jenkins](https://ci.codemc.io/job/retrooper/job/packetevents)
|
||||
* [View documentation on our JavaDocs Page](https://packetevents.github.io/javadocs)
|
||||
<h3>Sponsors</h3>
|
||||
|
||||
### Setup
|
||||
[How to Setup PacketEvents](https://github.com/retrooper/packetevents/wiki/Depending-on-pre%E2%80%90built-PacketEvents)
|
||||
<i>Thanks to the following sponsors for supporting this project:</i>
|
||||
|
||||
### Examples / How to use PacketEvents
|
||||
[Example repository](https://github.com/retrooper/packetevents-example)
|
||||
<a href="https://pebblehost.com"><img src="https://pebblehost.com/src/img/logos/main-old.png" width=150><br>
|
||||
|
||||
### Sponsorships
|
||||
[](https://www.ej-technologies.com/products/jprofiler/overview.html)
|
||||
<a href="https://www.ej-technologies.com"><img src="https://www.ej-technologies.com/images/product_banners/jprofiler_small.png"><br>
|
||||
|
||||
### Statistics
|
||||
PacketEvents optionally collects statistics using [bStats](https://bstats.org/)\
|
||||
Check out our [bStats page](https://bstats.org/plugin/bukkit/packetevents/11327)
|
||||
<a href="https://github.com/radstevee"><img src="https://github.com/radstevee.png" width="50px" alt="radstevee"/></a><br>
|
||||
|
||||
### Credit to these projects
|
||||
[wiki.vg/Protocol](https://wiki.vg/Protocol)\
|
||||
[netty](https://github.com/netty/netty)\
|
||||
[gson](https://github.com/google/gson)\
|
||||
[adventure](https://github.com/KyoriPowered/adventure)\
|
||||
<h3>Credits</h3>
|
||||
|
||||
<i>Here are some projects that we are heavily inspired by, thus we have integrated</i>\
|
||||
<i>small portions of their code into our work.</i>
|
||||
|
||||
[Protocol Documentation for the Minecraft Java Edition](https://wiki.vg/Protocol)\
|
||||
[ViaVersion](https://github.com/ViaVersion/ViaVersion)\
|
||||
[ProtocolSupport](https://github.com/ProtocolSupport/ProtocolSupport)\
|
||||
[adventure](https://github.com/KyoriPowered/adventure)\
|
||||
[MCProtocolLib](https://github.com/GeyserMC/MCProtocolLib/)
|
||||
@@ -1,60 +0,0 @@
|
||||
import com.github.retrooper.MappingCompressionTask
|
||||
|
||||
// papermc repo + disableAutoTargetJvm needed for mockbukkit
|
||||
repositories {
|
||||
maven { url 'https://repo.papermc.io/repository/maven-public/' }
|
||||
}
|
||||
|
||||
java {
|
||||
disableAutoTargetJvm()
|
||||
sourceSets {
|
||||
main {
|
||||
resources {
|
||||
srcDirs += ["$buildDir.canonicalPath/mappings/generated"]
|
||||
}
|
||||
}
|
||||
|
||||
test {
|
||||
resources {
|
||||
srcDirs += ["$buildDir.canonicalPath/mappings/generated"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(adventureDependencies)
|
||||
|
||||
testImplementation(adventureDependencies)
|
||||
testImplementation(project(":netty-common"))
|
||||
testImplementation("com.github.seeseemelk:MockBukkit-v1.20:3.9.0")
|
||||
testImplementation("org.slf4j:slf4j-simple:2.0.7")
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.0")
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.0")
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
task generateMapping(type: MappingCompressionTask) {
|
||||
mappingsDir = rootDir.toPath().resolve("mappings")
|
||||
outDir = project.buildDir.toPath().resolve("mappings/generated/assets/mappings")
|
||||
outputs.upToDateWhen {
|
||||
def gen_modified = project.buildDir.toPath().resolve("mappings/generated/assets/mappings").toFile().lastModified()
|
||||
def list = []
|
||||
project.rootProject.projectDir.toPath().resolve("mappings").toFile().eachFileRecurse(groovy.io.FileType.FILES) { file ->
|
||||
list << file
|
||||
}
|
||||
|
||||
for (File file : list) {
|
||||
if (file.lastModified() > gen_modified) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
tasks.processResources.dependsOn(generateMapping)
|
||||
@@ -0,0 +1,152 @@
|
||||
import com.github.retrooper.compression.strategy.JsonArrayCompressionStrategy
|
||||
import com.github.retrooper.compression.strategy.JsonObjectCompressionStrategy
|
||||
import com.github.retrooper.compression.strategy.JsonToNbtStrategy
|
||||
import com.github.retrooper.excludeAdventure
|
||||
|
||||
plugins {
|
||||
packetevents.`shadow-conventions`
|
||||
packetevents.`library-conventions`
|
||||
`mapping-compression`
|
||||
`pe-version`
|
||||
}
|
||||
|
||||
// papermc repo + disableAutoTargetJvm needed for mockbukkit
|
||||
repositories {
|
||||
maven("https://repo.papermc.io/repository/maven-public/")
|
||||
}
|
||||
|
||||
java {
|
||||
withJavadocJar()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnlyApi(libs.bundles.adventure)
|
||||
compileOnlyApi(libs.bundles.adventure.serializers)
|
||||
implementation(libs.adventure.api)
|
||||
api(project(":patch:adventure-text-serializer-gson", "shadow")) {
|
||||
excludeAdventure()
|
||||
}
|
||||
api(libs.adventure.text.serializer.legacy) {
|
||||
excludeAdventure()
|
||||
}
|
||||
compileOnly(libs.gson)
|
||||
|
||||
testImplementation(libs.bundles.adventure)
|
||||
testImplementation(project(":patch:adventure-text-serializer-gson"))
|
||||
testImplementation(libs.adventure.text.serializer.legacy)
|
||||
testImplementation(project(":netty-common"))
|
||||
testImplementation(testlibs.mockbukkit)
|
||||
testImplementation(testlibs.slf4j)
|
||||
testImplementation(testlibs.bundles.junit)
|
||||
}
|
||||
|
||||
mappingCompression {
|
||||
mappingDirectory = rootDir.resolve("mappings")
|
||||
outDirectory = project.layout.buildDirectory.dir("mappings/generated/assets/mappings")
|
||||
|
||||
with<JsonToNbtStrategy> {
|
||||
compress("block/legacy_block_mappings.json")
|
||||
compress("block/modern_block_mappings.json")
|
||||
|
||||
compress("enchantment/enchantment_type_data.json")
|
||||
|
||||
compress("stats/statistics.json")
|
||||
|
||||
compress("world/biome_data.json")
|
||||
}
|
||||
|
||||
with<JsonArrayCompressionStrategy> {
|
||||
compress("attribute/attribute_mappings.json")
|
||||
|
||||
compress("block/block_entity_type_mappings.json")
|
||||
compress("block/block_type_mappings.json")
|
||||
|
||||
compress("chat/chat_type_mappings.json")
|
||||
|
||||
compress("command/argument_parser_mappings.json")
|
||||
|
||||
compress("damage/damagetype_mappings.json")
|
||||
|
||||
compress("enchantment/effect_component_type.json")
|
||||
|
||||
compress("entity/entity_data_type_mappings.json")
|
||||
compress("entity/painting_mappings.json")
|
||||
compress("entity/wolf_variant_mappings.json")
|
||||
|
||||
compress("item/item_armor_material_mappings.json")
|
||||
compress("item/item_banner_pattern_mappings.json")
|
||||
compress("item/item_component_mappings.json")
|
||||
compress("item/item_instrument_mappings.json")
|
||||
compress("item/item_jukebox_song_mappings.json")
|
||||
compress("item/item_map_decoration_type_mappings.json")
|
||||
compress("item/item_potion_mappings.json")
|
||||
compress("item/item_trim_material_mappings.json")
|
||||
compress("item/item_trim_pattern_mappings.json")
|
||||
compress("item/recipe_serializer_mappings.json")
|
||||
|
||||
compress("particle/particle_type_mappings.json")
|
||||
|
||||
compress("sound/sound_mappings.json")
|
||||
|
||||
compress("world/biome_mappings.json")
|
||||
compress("world/world_position_source_mappings.json")
|
||||
}
|
||||
|
||||
with<JsonObjectCompressionStrategy> {
|
||||
compress("enchantment/enchantment_type_mappings.json")
|
||||
|
||||
compress("entity/entity_effect_mappings.json")
|
||||
compress("entity/entity_type_mappings.json")
|
||||
compress("entity/legacy_entity_type_mappings.json")
|
||||
|
||||
compress("item/item_type_mappings.json")
|
||||
|
||||
compress("world/dimension_type_mappings.json")
|
||||
}
|
||||
}
|
||||
|
||||
tasks {
|
||||
javadoc {
|
||||
setDestinationDir(file("${project.layout.buildDirectory.asFile.get()}/docs/javadoc"))
|
||||
options {
|
||||
(this as CoreJavadocOptions).addBooleanOption("Xdoclint:none", true)
|
||||
}
|
||||
mustRunAfter(generateVersionsFile)
|
||||
}
|
||||
|
||||
sourcesJar {
|
||||
mustRunAfter(generateVersionsFile)
|
||||
}
|
||||
|
||||
withType<JavaCompile> {
|
||||
dependsOn(generateVersionsFile)
|
||||
}
|
||||
|
||||
processResources {
|
||||
dependsOn(compressMappings)
|
||||
from(project.layout.buildDirectory.dir("mappings/generated").get())
|
||||
}
|
||||
|
||||
generateVersionsFile {
|
||||
packageName = "com.github.retrooper.packetevents.util"
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
exclude {
|
||||
val path = it.path
|
||||
path.startsWith("net/kyori") && !path.startsWith("net/kyori/adventure/text/serializer") && !path.startsWith("net/kyori/option")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
named<MavenPublication>("shadow") {
|
||||
artifact(tasks["javadocJar"])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,33 +27,34 @@ import com.github.retrooper.packetevents.netty.NettyManager;
|
||||
import com.github.retrooper.packetevents.settings.PacketEventsSettings;
|
||||
import com.github.retrooper.packetevents.util.LogManager;
|
||||
import com.github.retrooper.packetevents.util.PEVersion;
|
||||
//Note: The PEVersions class is generated. Refer to PEVersionTask.kt
|
||||
import com.github.retrooper.packetevents.util.PEVersions;
|
||||
import com.github.retrooper.packetevents.util.updatechecker.UpdateChecker;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public abstract class PacketEventsAPI<T> {
|
||||
private static final EventManager EVENT_MANAGER = new EventManager();
|
||||
private static final PacketEventsSettings SETTINGS = new PacketEventsSettings();
|
||||
private static final UpdateChecker UPDATE_CHECKER = new UpdateChecker();
|
||||
private final Logger LOGGER = Logger.getLogger(PacketEventsAPI.class.getName());
|
||||
private static final LogManager LOG_MANAGER = new LogManager();
|
||||
//TODO UPDATE
|
||||
private static final PEVersion VERSION = new PEVersion(2, 3, 0);
|
||||
|
||||
private final EventManager eventManager = new EventManager();
|
||||
private final PacketEventsSettings settings = new PacketEventsSettings();
|
||||
private final UpdateChecker updateChecker = new UpdateChecker();
|
||||
private final LogManager logManager = new LogManager();
|
||||
private static final Logger LOGGER = Logger.getLogger(PacketEventsAPI.class.getName());
|
||||
|
||||
public EventManager getEventManager() {
|
||||
return EVENT_MANAGER;
|
||||
return eventManager;
|
||||
}
|
||||
|
||||
public PacketEventsSettings getSettings() {
|
||||
return SETTINGS;
|
||||
return settings;
|
||||
}
|
||||
|
||||
public UpdateChecker getUpdateChecker() {
|
||||
return UPDATE_CHECKER;
|
||||
return updateChecker;
|
||||
}
|
||||
|
||||
public PEVersion getVersion() {
|
||||
return VERSION;
|
||||
//Note: The PEVersions class is generated by the auto-version task. Refer to PEVersionTask.kt
|
||||
return PEVersions.CURRENT;
|
||||
}
|
||||
|
||||
public Logger getLogger() {
|
||||
@@ -61,7 +62,7 @@ public abstract class PacketEventsAPI<T> {
|
||||
}
|
||||
|
||||
public LogManager getLogManager() {
|
||||
return LOG_MANAGER;
|
||||
return logManager;
|
||||
}
|
||||
|
||||
public abstract void load();
|
||||
@@ -74,6 +75,8 @@ public abstract class PacketEventsAPI<T> {
|
||||
|
||||
public abstract void terminate();
|
||||
|
||||
public abstract boolean isTerminated();
|
||||
|
||||
public abstract T getPlugin();
|
||||
|
||||
public abstract ServerManager getServerManager();
|
||||
|
||||
@@ -24,11 +24,35 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import java.util.logging.Level;
|
||||
|
||||
/**
|
||||
* Class for event managing. Implements both, internal and API methods.
|
||||
*
|
||||
* @apiNote It is highly recommended to register the event listeners at server start-up,
|
||||
* without frequent modifications during runtime, since this class needs to recalculate all of
|
||||
* its event listeners during any modifications. In other words, it assumes that reads (events fired)
|
||||
* greatly outnumber writes (listeners modifications). If your case requires frequent listener modifications,
|
||||
* open a pull request on GitHub and describe your case.
|
||||
*
|
||||
* @author retrooper
|
||||
* @author ShadowOfHeaven (optimization)
|
||||
*
|
||||
*/
|
||||
|
||||
public class EventManager {
|
||||
private final Map<PacketListenerPriority, Set<PacketListenerCommon>> listenersMap =
|
||||
Collections.synchronizedMap(new EnumMap<>(PacketListenerPriority.class));
|
||||
|
||||
//Using a ConcurrentHashMap is faster and more secure here, compared to Collections.synchronizedMap(new EnumMap<>(PacketListenerPriority.class))
|
||||
//This is mainly due to:
|
||||
//1. On each modification Collections.synchronizedMap synchronizes the whole Map object, while ConcurrentHashMap only it's internal, currently modified Node
|
||||
//2. ConcurrentHashMap won't fail in a multi-thread environment, while Collections.synchronizedMap is said to have a lot of potential problems,
|
||||
//being a generalized method for synchronization
|
||||
private final Map<PacketListenerPriority, Set<PacketListenerCommon>> listenersMap = new ConcurrentHashMap<>();
|
||||
//Since reads greatly outnumber writes, create an array for the best possible iteration time
|
||||
//Updated as a whole on writes, no index modifications are allowed
|
||||
private volatile PacketListenerCommon[] listeners = new PacketListenerCommon[0];
|
||||
|
||||
|
||||
/**
|
||||
* Call the PacketEvent.
|
||||
@@ -43,32 +67,43 @@ public class EventManager {
|
||||
callEvent(event, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Call the PacketEvent.
|
||||
* This method processes the event on all the registered dynamic packet event listeners.
|
||||
* The {@link PacketListenerPriority#LOWEST} prioritized listeners will be processing first,
|
||||
* the {@link PacketListenerPriority#MONITOR} will be processing last and can
|
||||
* be the final decider whether the event has been cancelled or not.
|
||||
*
|
||||
* @param event {@link PacketEvent}
|
||||
* @param postCallListenerAction The action to be ran after all the listeners have finished processing
|
||||
*/
|
||||
public void callEvent(PacketEvent event, @Nullable Runnable postCallListenerAction) {
|
||||
for (PacketListenerPriority priority : PacketListenerPriority.values()) {
|
||||
Set<PacketListenerCommon> listeners = listenersMap.get(priority);
|
||||
if (listeners != null) {
|
||||
for (PacketListenerCommon listener : listeners) {
|
||||
try {
|
||||
event.call(listener);
|
||||
} catch (Exception t) {
|
||||
// ignore handshake exceptions
|
||||
if (t.getClass() != InvalidHandshakeException.class) {
|
||||
PacketEvents.getAPI().getLogger().log(Level.WARNING, "PacketEvents caught an unhandled exception while calling your listener.", t);
|
||||
}
|
||||
}
|
||||
if (postCallListenerAction != null) {
|
||||
postCallListenerAction.run();
|
||||
}
|
||||
for (PacketListenerCommon listener : listeners) {
|
||||
try {
|
||||
event.call(listener);
|
||||
} catch (Exception t) {
|
||||
// ignore handshake exceptions
|
||||
if (t.getClass() != InvalidHandshakeException.class) {
|
||||
PacketEvents.getAPI().getLogger().log(Level.WARNING, "PacketEvents caught an unhandled exception while calling your listener.", t);
|
||||
}
|
||||
}
|
||||
if (postCallListenerAction != null) {
|
||||
postCallListenerAction.run();
|
||||
}
|
||||
}
|
||||
// For performance reasons, we don't want to re-encode the packet if it's not needed.
|
||||
if (event instanceof ProtocolPacketEvent && !((ProtocolPacketEvent<?>) event).needsReEncode()) {
|
||||
((ProtocolPacketEvent<?>) event).setLastUsedWrapper(null);
|
||||
if (event instanceof ProtocolPacketEvent && !((ProtocolPacketEvent) event).needsReEncode()) {
|
||||
((ProtocolPacketEvent) event).setLastUsedWrapper(null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the dynamic packet event listener.
|
||||
*
|
||||
* @param listener {@link PacketListenerCommon}
|
||||
* @param priority {@link PacketListenerPriority}
|
||||
*/
|
||||
public PacketListenerCommon registerListener(PacketListener listener, PacketListenerPriority priority) {
|
||||
PacketListenerCommon packetListenerAbstract = listener.asAbstract(priority);
|
||||
return registerListener(packetListenerAbstract);
|
||||
@@ -80,12 +115,8 @@ public class EventManager {
|
||||
* @param listener {@link PacketListenerCommon}
|
||||
*/
|
||||
public PacketListenerCommon registerListener(PacketListenerCommon listener) {
|
||||
Set<PacketListenerCommon> listenerSet = listenersMap.get(listener.getPriority());
|
||||
if (listenerSet == null) {
|
||||
listenerSet = ConcurrentHashMap.newKeySet();
|
||||
}
|
||||
listenerSet.add(listener);
|
||||
listenersMap.put(listener.getPriority(), listenerSet);
|
||||
this.registerListenerNoRecalculation(listener);
|
||||
this.recalculateListeners();
|
||||
return listener;
|
||||
}
|
||||
|
||||
@@ -96,21 +127,22 @@ public class EventManager {
|
||||
*/
|
||||
public PacketListenerCommon[] registerListeners(PacketListenerCommon... listeners) {
|
||||
for (PacketListenerCommon listener : listeners) {
|
||||
registerListener(listener);
|
||||
this.registerListenerNoRecalculation(listener);
|
||||
}
|
||||
this.recalculateListeners();
|
||||
return listeners;
|
||||
}
|
||||
|
||||
public void unregisterListener(PacketListenerCommon listener) {
|
||||
Set<PacketListenerCommon> listenerSet = listenersMap.get(listener.getPriority());
|
||||
if (listenerSet == null) return;
|
||||
listenerSet.remove(listener);
|
||||
if (this.unregisterListenerNoRecalculation(listener)) this.recalculateListeners();
|
||||
}
|
||||
|
||||
public void unregisterListeners(PacketListenerCommon... listeners) {
|
||||
boolean modified = false;
|
||||
for (PacketListenerCommon listener : listeners) {
|
||||
unregisterListener(listener);
|
||||
modified |= this.unregisterListenerNoRecalculation(listener);//OR - at least one of these needs to be true to return true, meaning the boolean will permanently stay true if once set so
|
||||
}
|
||||
if (modified) this.recalculateListeners();
|
||||
}
|
||||
|
||||
|
||||
@@ -118,6 +150,36 @@ public class EventManager {
|
||||
* Unregister all dynamic packet event listeners.
|
||||
*/
|
||||
public void unregisterAllListeners() {
|
||||
listenersMap.clear();
|
||||
this.listenersMap.clear();
|
||||
synchronized (this) {//like booky10 said, the synchronization is necessary here
|
||||
this.listeners = new PacketListenerCommon[0];
|
||||
}
|
||||
}
|
||||
|
||||
//Needs to be synchronized in order to avoid race conditions (for example where the 'listeners' variable
|
||||
//is overridden by its non-up-to-date value, simply because it finished a bit later than the most recent update)
|
||||
private void recalculateListeners() {
|
||||
synchronized (this) {
|
||||
List<PacketListenerCommon> list = new ArrayList<>();
|
||||
//adds from LOWEST to MONITOR, so in the correct order
|
||||
for (PacketListenerPriority priority : PacketListenerPriority.values()) {
|
||||
Set<PacketListenerCommon> set = this.listenersMap.get(priority);
|
||||
if (set != null) list.addAll(set);
|
||||
}
|
||||
this.listeners = list.toArray(new PacketListenerCommon[0]);
|
||||
}
|
||||
}
|
||||
|
||||
//Internal registration methods, specifically separated for lesser overhead when registering an array of Listeners
|
||||
|
||||
private void registerListenerNoRecalculation(PacketListenerCommon listener) {
|
||||
Set<PacketListenerCommon> listenerSet = this.listenersMap.computeIfAbsent(listener.getPriority(), p -> new CopyOnWriteArraySet<>());
|
||||
listenerSet.add(listener);
|
||||
}
|
||||
|
||||
//Returns true if the listener was removed, so a modification occurred
|
||||
private boolean unregisterListenerNoRecalculation(PacketListenerCommon listener) {
|
||||
Set<PacketListenerCommon> listenerSet = this.listenersMap.get(listener.getPriority());
|
||||
return listenerSet != null && listenerSet.remove(listener);
|
||||
}
|
||||
}
|
||||
+9
-7
@@ -30,8 +30,7 @@ package com.github.retrooper.packetevents.event;
|
||||
*/
|
||||
public enum PacketListenerPriority {
|
||||
/**
|
||||
* Listener is of very low importance.
|
||||
* This listener will be ran first.
|
||||
* This listener will be run first and has little say in the outcome of events.
|
||||
*/
|
||||
LOWEST,
|
||||
|
||||
@@ -41,8 +40,11 @@ public enum PacketListenerPriority {
|
||||
LOW,
|
||||
|
||||
/**
|
||||
* Default listener priority.
|
||||
* Listener is neither important nor unimportant and may run normally.
|
||||
* The normal listener priority.
|
||||
* If possible, always pick this.
|
||||
* It allows other projects to easily overturn your decisions.
|
||||
* Moreover, it is pretty bold to assume that your project should
|
||||
* always have the final say.
|
||||
*/
|
||||
NORMAL,
|
||||
|
||||
@@ -52,13 +54,13 @@ public enum PacketListenerPriority {
|
||||
HIGH,
|
||||
|
||||
/**
|
||||
* Listener is of critical importance and wants to decide the cancellation of an event.
|
||||
* Listener is of critical importance. Use this to decide the final state of packets.
|
||||
*/
|
||||
HIGHEST,
|
||||
|
||||
/**
|
||||
* Listener is purely trying to decide the cancellation of an event.
|
||||
* This listener should be ran last.
|
||||
* Only use this priority if you want to perform logic based on the outcome of an event.
|
||||
* Please do not modify packets in this stage.
|
||||
*/
|
||||
MONITOR;
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
package com.github.retrooper.packetevents.event;
|
||||
|
||||
import com.github.retrooper.packetevents.event.simple.*;
|
||||
import com.github.retrooper.packetevents.exception.PacketProcessException;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper;
|
||||
@@ -26,7 +25,7 @@ import com.github.retrooper.packetevents.protocol.PacketSide;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
|
||||
import com.github.retrooper.packetevents.protocol.player.User;
|
||||
|
||||
public class PacketReceiveEvent extends ProtocolPacketEvent<Object> {
|
||||
public class PacketReceiveEvent extends ProtocolPacketEvent {
|
||||
protected PacketReceiveEvent(Object channel, User user, Object player, Object rawByteBuf,
|
||||
boolean autoProtocolTranslation) throws PacketProcessException {
|
||||
super(PacketSide.CLIENT, channel, user, player, rawByteBuf, autoProtocolTranslation);
|
||||
|
||||
@@ -29,7 +29,7 @@ import com.github.retrooper.packetevents.protocol.player.User;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PacketSendEvent extends ProtocolPacketEvent<Object> {
|
||||
public class PacketSendEvent extends ProtocolPacketEvent {
|
||||
private List<Runnable> tasksAfterSend = null;
|
||||
|
||||
protected PacketSendEvent(Object channel, User user, Object player, Object rawByteBuf,
|
||||
|
||||
@@ -24,11 +24,11 @@ package com.github.retrooper.packetevents.event;
|
||||
* @author retrooper
|
||||
* @since 1.6.9
|
||||
*/
|
||||
public interface PlayerEvent<T> {
|
||||
public interface PlayerEvent {
|
||||
/**
|
||||
* Associated player.
|
||||
*
|
||||
* @return Player.
|
||||
*/
|
||||
T getPlayer();
|
||||
<T> T getPlayer();
|
||||
}
|
||||
@@ -39,11 +39,11 @@ import java.net.InetSocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class ProtocolPacketEvent<T> extends PacketEvent implements PlayerEvent<T>, CancellableEvent, UserEvent {
|
||||
public abstract class ProtocolPacketEvent extends PacketEvent implements PlayerEvent, CancellableEvent, UserEvent {
|
||||
private final Object channel;
|
||||
private final ConnectionState connectionState;
|
||||
private final User user;
|
||||
private final T player;
|
||||
private final Object player;
|
||||
private Object byteBuf;
|
||||
private final int packetID;
|
||||
private final PacketTypeCommon packetType;
|
||||
@@ -55,7 +55,7 @@ public abstract class ProtocolPacketEvent<T> extends PacketEvent implements Play
|
||||
private boolean needsReEncode = PacketEvents.getAPI().getSettings().reEncodeByDefault();
|
||||
|
||||
public ProtocolPacketEvent(PacketSide packetSide, Object channel,
|
||||
User user, T player, Object byteBuf,
|
||||
User user, Object player, Object byteBuf,
|
||||
boolean autoProtocolTranslation) throws PacketProcessException {
|
||||
this.channel = channel;
|
||||
this.user = user;
|
||||
@@ -92,7 +92,7 @@ public abstract class ProtocolPacketEvent<T> extends PacketEvent implements Play
|
||||
}
|
||||
|
||||
public ProtocolPacketEvent(int packetID, PacketTypeCommon packetType, ServerVersion serverVersion, Object channel,
|
||||
User user, T player, Object byteBuf) {
|
||||
User user, Object player, Object byteBuf) {
|
||||
this.channel = channel;
|
||||
this.user = user;
|
||||
this.player = player;
|
||||
@@ -133,8 +133,8 @@ public abstract class ProtocolPacketEvent<T> extends PacketEvent implements Play
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getPlayer() {
|
||||
return player;
|
||||
public <T> T getPlayer() {
|
||||
return (T) player;
|
||||
}
|
||||
|
||||
public ConnectionState getConnectionState() {
|
||||
@@ -213,7 +213,7 @@ public abstract class ProtocolPacketEvent<T> extends PacketEvent implements Play
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolPacketEvent<?> clone() {
|
||||
public ProtocolPacketEvent clone() {
|
||||
return this instanceof PacketReceiveEvent ? ((PacketReceiveEvent) this).clone()
|
||||
: ((PacketSendEvent) this).clone();
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ package com.github.retrooper.packetevents.event;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.player.User;
|
||||
|
||||
public class UserLoginEvent extends PacketEvent implements CallableEvent, UserEvent, PlayerEvent<Object> {
|
||||
public class UserLoginEvent extends PacketEvent implements CallableEvent, UserEvent, PlayerEvent {
|
||||
private final User user;
|
||||
private final Object player;
|
||||
|
||||
@@ -35,8 +35,8 @@ public class UserLoginEvent extends PacketEvent implements CallableEvent, UserEv
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPlayer() {
|
||||
return player;
|
||||
public <T> T getPlayer() {
|
||||
return (T) player;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+17
-60
@@ -26,31 +26,21 @@ import com.github.retrooper.packetevents.event.PacketSendEvent;
|
||||
import com.github.retrooper.packetevents.manager.protocol.ProtocolManager;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.ConnectionState;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTInt;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTList;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTType;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.User;
|
||||
import com.github.retrooper.packetevents.protocol.player.UserProfile;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.util.mappings.SynchronizedRegistriesHandler;
|
||||
import com.github.retrooper.packetevents.wrapper.configuration.server.WrapperConfigServerRegistryData;
|
||||
import com.github.retrooper.packetevents.wrapper.configuration.server.WrapperConfigServerRegistryData.RegistryElement;
|
||||
import com.github.retrooper.packetevents.wrapper.handshaking.client.WrapperHandshakingClientHandshake;
|
||||
import com.github.retrooper.packetevents.wrapper.login.server.WrapperLoginServerLoginSuccess;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerJoinGame;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerRespawn;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.List;
|
||||
|
||||
public class InternalPacketListener extends PacketListenerAbstract {
|
||||
|
||||
private static final ResourceLocation DIMENSION_TYPE_REGISTRY_KEY =
|
||||
ResourceLocation.minecraft("dimension_type");
|
||||
|
||||
public InternalPacketListener() {
|
||||
this(PacketListenerPriority.LOWEST);
|
||||
}
|
||||
@@ -92,70 +82,37 @@ public class InternalPacketListener extends PacketListenerAbstract {
|
||||
}
|
||||
}
|
||||
|
||||
// The server sends dimension information in configuration phase >= 1.20.2
|
||||
// The server sends dimension information in configuration phase, since 1.20.2
|
||||
else if (event.getPacketType() == PacketType.Configuration.Server.REGISTRY_DATA) {
|
||||
WrapperConfigServerRegistryData registryData = new WrapperConfigServerRegistryData(event);
|
||||
WrapperConfigServerRegistryData packet = new WrapperConfigServerRegistryData(event);
|
||||
|
||||
// Store world data
|
||||
NBTCompound registryDataTag = registryData.getRegistryData();
|
||||
NBTList<NBTCompound> list = null;
|
||||
if (registryDataTag != null) { // <1.20.5
|
||||
list = registryDataTag
|
||||
.getCompoundTagOrNull(DIMENSION_TYPE_REGISTRY_KEY.toString())
|
||||
.getCompoundListTagOrNull("value");
|
||||
} else if (DIMENSION_TYPE_REGISTRY_KEY.equals(registryData.getRegistryKey())) { // >=1.20.5
|
||||
// remap to legacy format
|
||||
list = new NBTList<>(NBTType.COMPOUND);
|
||||
List<RegistryElement> elements = registryData.getElements();
|
||||
if (elements != null) {
|
||||
int i = 0;
|
||||
for (RegistryElement element : elements) {
|
||||
NBTCompound tag = new NBTCompound();
|
||||
tag.setTag("name", new NBTString(element.getId().toString()));
|
||||
tag.setTag("id", new NBTInt(i++));
|
||||
if (element.getData() != null) { // may be null because of known packs not being sent
|
||||
tag.setTag("element", element.getData());
|
||||
}
|
||||
list.addTag(tag);
|
||||
}
|
||||
}
|
||||
if (packet.getElements() != null) { // 1.20.2 to 1.20.5
|
||||
SynchronizedRegistriesHandler.handleRegistry(user, packet.getServerVersion().toClientVersion(),
|
||||
packet.getRegistryKey(), packet.getElements());
|
||||
}
|
||||
if (list != null) {
|
||||
user.setWorldNBT(list);
|
||||
if (packet.getRegistryData() != null) { // since 1.20.5
|
||||
SynchronizedRegistriesHandler.handleLegacyRegistries(user, packet.getServerVersion()
|
||||
.toClientVersion(), packet.getRegistryData());
|
||||
}
|
||||
}
|
||||
|
||||
// The server sends dimension information in login packet for >= 1.17 and < 1.20.2
|
||||
// The server sends registry info in login packet for 1.16 to 1.20.1
|
||||
else if (event.getPacketType() == PacketType.Play.Server.JOIN_GAME) {
|
||||
WrapperPlayServerJoinGame joinGame = new WrapperPlayServerJoinGame(event);
|
||||
user.setEntityId(joinGame.getEntityId());
|
||||
user.setDimension(joinGame.getDimension());
|
||||
if (event.getServerVersion().isOlderThanOrEquals(ServerVersion.V_1_16_5)) {
|
||||
return; // Fixed world height, no tags are sent to the client
|
||||
|
||||
if (joinGame.getDimensionCodec() != null) { // 1.16 to 1.20.1
|
||||
SynchronizedRegistriesHandler.handleLegacyRegistries(user, joinGame.getServerVersion().toClientVersion(),
|
||||
joinGame.getDimensionCodec());
|
||||
}
|
||||
|
||||
// Store world data
|
||||
NBTCompound dimensionCodec = joinGame.getDimensionCodec();
|
||||
if (dimensionCodec != null) {
|
||||
NBTList<NBTCompound> list = dimensionCodec
|
||||
.getCompoundTagOrNull(DIMENSION_TYPE_REGISTRY_KEY.toString())
|
||||
.getCompoundListTagOrNull("value");
|
||||
user.setWorldNBT(list);
|
||||
}
|
||||
|
||||
// Update world height
|
||||
user.switchDimensionType(joinGame.getServerVersion(), joinGame.getDimension());
|
||||
user.setDimensionType(joinGame.getDimensionType());
|
||||
}
|
||||
|
||||
// Respawn is used to switch dimensions
|
||||
else if (event.getPacketType() == PacketType.Play.Server.RESPAWN) {
|
||||
WrapperPlayServerRespawn respawn = new WrapperPlayServerRespawn(event);
|
||||
user.setDimension(respawn.getDimension());
|
||||
if (event.getServerVersion().isOlderThanOrEquals(ServerVersion.V_1_16_5)) {
|
||||
return; // Fixed world height, no tags are sent to the client
|
||||
}
|
||||
|
||||
user.switchDimensionType(respawn.getServerVersion(), respawn.getDimension());
|
||||
WrapperPlayServerRespawn packet = new WrapperPlayServerRespawn(event);
|
||||
user.setDimensionType(packet.getDimensionType());
|
||||
} else if (event.getPacketType() == PacketType.Play.Server.CONFIGURATION_START) {
|
||||
user.setEncoderState(ConnectionState.CONFIGURATION);
|
||||
} else if (event.getPacketType() == PacketType.Configuration.Server.CONFIGURATION_END) {
|
||||
|
||||
+7
-4
@@ -104,10 +104,13 @@ public interface ProtocolManager {
|
||||
PacketWrapper<?>[] wrappers = PacketTransformationUtil.transform(wrapper);
|
||||
Object[] buffers = new Object[wrappers.length];
|
||||
for (int i = 0; i < wrappers.length; i++) {
|
||||
wrappers[i].prepareForSend(channel, outgoing);
|
||||
buffers[i] = wrappers[i].buffer;
|
||||
// Fix race condition when sending packets to multiple people (due to when the buffer is freed)
|
||||
wrappers[i].buffer = null;
|
||||
PacketWrapper<?> wrappper = wrappers[i];
|
||||
synchronized (wrappper.bufferLock) {
|
||||
wrappper.prepareForSend(channel, outgoing);
|
||||
buffers[i] = wrappper.buffer;
|
||||
// Fix race condition when sending packets to multiple people (due to when the buffer is freed)
|
||||
wrappper.buffer = null;
|
||||
}
|
||||
}
|
||||
return buffers;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,10 @@
|
||||
|
||||
package com.github.retrooper.packetevents.manager.server;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.User;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface ServerManager {
|
||||
/**
|
||||
* Get the server version.
|
||||
@@ -34,4 +38,20 @@ public interface ServerManager {
|
||||
default SystemOS getOS() {
|
||||
return SystemOS.getOS();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a platform-specific network-synchronized-registries cache key.
|
||||
* <p>
|
||||
* This tells packetevents, if a registry should be cached or read again. On
|
||||
* backend servers with global registries, this may be a constant value. On
|
||||
* proxy servers with per-server registries, this may be a value which depends
|
||||
* on the current server the {@link User} is on.
|
||||
*
|
||||
* @param user the {@link User} for which the registry gets read
|
||||
* @param version the version the packet is for
|
||||
* @return some value or null for no caching at all
|
||||
*/
|
||||
default @Nullable Object getRegistryCacheKey(User user, ClientVersion version) {
|
||||
return null; // no caching
|
||||
}
|
||||
}
|
||||
@@ -49,6 +49,8 @@ public enum ServerVersion {
|
||||
V_1_19(759), V_1_19_1(760), V_1_19_2(760), V_1_19_3(761), V_1_19_4(762),
|
||||
//1.20 and 1.20.1 have the same protocol version. 1.20.3 and 1.20.4 have the same protocol version. 1.20.5 and 1.20.6 have the same protocol version
|
||||
V_1_20(763), V_1_20_1(763), V_1_20_2(764), V_1_20_3(765), V_1_20_4(765), V_1_20_5(766), V_1_20_6(766),
|
||||
//1.21 and 1.21.1 have the same protocol version
|
||||
V_1_21(767), V_1_21_1(767),
|
||||
//TODO UPDATE Add server version constant
|
||||
ERROR(-1, true);
|
||||
|
||||
|
||||
+3
@@ -24,8 +24,11 @@ public interface ByteBufAllocationOperator {
|
||||
Object copiedBuffer(byte[] bytes);
|
||||
|
||||
Object buffer();
|
||||
Object buffer(int initialCapacity);
|
||||
|
||||
Object directBuffer();
|
||||
Object directBuffer(int initialCapacity);
|
||||
|
||||
Object compositeBuffer();
|
||||
Object compositeBuffer(int maxNumComponents);
|
||||
}
|
||||
@@ -103,6 +103,14 @@ public class ByteBufHelper {
|
||||
PacketEvents.getAPI().getNettyManager().getByteBufOperator().writeShort(buffer, value);
|
||||
}
|
||||
|
||||
public static int readMedium(Object buffer) {
|
||||
return PacketEvents.getAPI().getNettyManager().getByteBufOperator().readMedium(buffer);
|
||||
}
|
||||
|
||||
public static void writeMedium(Object buffer, int value) {
|
||||
PacketEvents.getAPI().getNettyManager().getByteBufOperator().writeMedium(buffer, value);
|
||||
}
|
||||
|
||||
public static int readInt(Object buffer) {
|
||||
return PacketEvents.getAPI().getNettyManager().getByteBufOperator().readInt(buffer);
|
||||
}
|
||||
|
||||
+6
-6
@@ -42,27 +42,27 @@ public class ByteBufInputStream extends InputStream implements DataInput {
|
||||
this(buffer, ByteBufHelper.readableBytes(buffer), releaseOnClose);
|
||||
}
|
||||
|
||||
public ByteBufInputStream(Object buffer, int length, boolean releaseOnClose) {
|
||||
public ByteBufInputStream(Object buffer, int maxLength, boolean releaseOnClose) {
|
||||
this.lineBuf = new StringBuilder();
|
||||
if (buffer == null) {
|
||||
throw new NullPointerException("buffer");
|
||||
} else if (length < 0) {
|
||||
} else if (maxLength < 0) {
|
||||
if (releaseOnClose) {
|
||||
ByteBufHelper.release(buffer);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("length: " + length);
|
||||
} else if (length > ByteBufHelper.readableBytes(buffer)) {
|
||||
throw new IllegalArgumentException("maxLength: " + maxLength);
|
||||
} else if (ByteBufHelper.readableBytes(buffer) > maxLength) {
|
||||
if (releaseOnClose) {
|
||||
ByteBufHelper.release(buffer);
|
||||
}
|
||||
|
||||
throw new IndexOutOfBoundsException("Too many bytes to be read - Needs " + length + ", maximum is " + ByteBufHelper.readableBytes(buffer));
|
||||
throw new IndexOutOfBoundsException("Too many bytes to be read - Found " + ByteBufHelper.readableBytes(buffer) + ", maximum is " + maxLength);
|
||||
} else {
|
||||
this.releaseOnClose = releaseOnClose;
|
||||
this.buffer = buffer;
|
||||
this.startIndex = ByteBufHelper.readerIndex(buffer);
|
||||
this.endIndex = this.startIndex + length;
|
||||
this.endIndex = this.startIndex + ByteBufHelper.readableBytes(buffer);
|
||||
ByteBufHelper.markReaderIndex(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,12 +35,14 @@ public interface ByteBufOperator {
|
||||
|
||||
byte readByte(Object buffer);
|
||||
short readShort(Object buffer);
|
||||
int readMedium(Object buffer);
|
||||
int readInt(Object buffer);
|
||||
long readUnsignedInt(Object buffer);
|
||||
long readLong(Object buffer);
|
||||
|
||||
void writeByte(Object buffer, int value);
|
||||
void writeShort(Object buffer, int value);
|
||||
void writeMedium(Object buffer, int value);
|
||||
void writeInt(Object buffer, int value);
|
||||
void writeLong(Object buffer, long value);
|
||||
|
||||
|
||||
+12
@@ -40,4 +40,16 @@ public class UnpooledByteBufAllocationHelper {
|
||||
public static Object compositeBuffer() {
|
||||
return PacketEvents.getAPI().getNettyManager().getByteBufAllocationOperator().compositeBuffer();
|
||||
}
|
||||
|
||||
public static Object buffer(int initialCapacity) {
|
||||
return PacketEvents.getAPI().getNettyManager().getByteBufAllocationOperator().buffer(initialCapacity);
|
||||
}
|
||||
|
||||
public static Object directBuffer(int initialCapacity) {
|
||||
return PacketEvents.getAPI().getNettyManager().getByteBufAllocationOperator().directBuffer(initialCapacity);
|
||||
}
|
||||
|
||||
public static Object compositeBuffer(int maxNumComponents) {
|
||||
return PacketEvents.getAPI().getNettyManager().getByteBufAllocationOperator().compositeBuffer(maxNumComponents);
|
||||
}
|
||||
}
|
||||
+12
-1
@@ -89,7 +89,7 @@ public class Attributes {
|
||||
// Added in 1.20.2
|
||||
public static final Attribute GENERIC_MAX_ABSORPTION = define("generic.max_absorption");
|
||||
|
||||
// added in 1.20.5
|
||||
// Added in 1.20.5
|
||||
public static final Attribute PLAYER_BLOCK_BREAK_SPEED = define("player.block_break_speed");
|
||||
public static final Attribute PLAYER_BLOCK_INTERACTION_RANGE = define("player.block_interaction_range");
|
||||
public static final Attribute PLAYER_ENTITY_INTERACTION_RANGE = define("player.entity_interaction_range");
|
||||
@@ -100,6 +100,17 @@ public class Attributes {
|
||||
public static final Attribute GENERIC_SCALE = define("generic.scale");
|
||||
public static final Attribute GENERIC_STEP_HEIGHT = define("generic.step_height");
|
||||
|
||||
// Added in 1.21
|
||||
public static final Attribute GENERIC_BURNING_TIME = define("generic.burning_time");
|
||||
public static final Attribute GENERIC_EXPLOSION_KNOCKBACK_RESISTANCE = define("generic.explosion_knockback_resistance");
|
||||
public static final Attribute PLAYER_MINING_EFFICIENCY = define("player.mining_efficiency");
|
||||
public static final Attribute GENERIC_MOVEMENT_EFFICIENCY = define("generic.movement_efficiency");
|
||||
public static final Attribute GENERIC_OXYGEN_BONUS = define("generic.oxygen_bonus");
|
||||
public static final Attribute PLAYER_SNEAKING_SPEED = define("player.sneaking_speed");
|
||||
public static final Attribute PLAYER_SUBMERGED_MINING_SPEED = define("player.submerged_mining_speed");
|
||||
public static final Attribute PLAYER_SWEEPING_DAMAGE_RATIO = define("player.sweeping_damage_ratio");
|
||||
public static final Attribute GENERIC_WATER_MOVEMENT_EFFICIENCY = define("generic.water_movement_efficiency");
|
||||
|
||||
static {
|
||||
TYPES_BUILDER.unloadFileMappings();
|
||||
}
|
||||
|
||||
@@ -18,8 +18,149 @@
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.chat;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.chat.message.ChatMessage_v1_19_1;
|
||||
import com.github.retrooper.packetevents.protocol.mapper.CopyableEntity;
|
||||
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.util.Index;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
|
||||
public interface ChatType extends MappedEntity {
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.github.retrooper.packetevents.util.adventure.AdventureIndexUtil.indexValueOrThrow;
|
||||
|
||||
public interface ChatType extends MappedEntity, CopyableEntity<ChatType> {
|
||||
|
||||
@UnknownNullability("only nullable for 1.19")
|
||||
ChatTypeDecoration getChatDecoration();
|
||||
|
||||
@ApiStatus.Obsolete(since = "1.19.1")
|
||||
@Nullable ChatTypeDecoration getOverlayDecoration();
|
||||
|
||||
@UnknownNullability("only nullable for 1.19")
|
||||
ChatTypeDecoration getNarrationDecoration();
|
||||
|
||||
@ApiStatus.Obsolete(since = "1.19.1")
|
||||
@Nullable NarrationPriority getNarrationPriority();
|
||||
|
||||
static ChatType readDirect(PacketWrapper<?> wrapper) {
|
||||
ChatTypeDecoration chatDecoration = ChatTypeDecoration.read(wrapper);
|
||||
ChatTypeDecoration narrationDecoration = ChatTypeDecoration.read(wrapper);
|
||||
return new StaticChatType(chatDecoration, narrationDecoration);
|
||||
}
|
||||
|
||||
static void writeDirect(PacketWrapper<?> wrapper, ChatType chatType) {
|
||||
ChatTypeDecoration.write(wrapper, chatType.getChatDecoration());
|
||||
ChatTypeDecoration.write(wrapper, chatType.getNarrationDecoration());
|
||||
}
|
||||
|
||||
static ChatType decode(NBT nbt, ClientVersion version, @Nullable TypesBuilderData data) {
|
||||
// everything is nullable in 1.19, even the chat format!
|
||||
NBTCompound compound = (NBTCompound) nbt;
|
||||
NBTCompound chatTag = compound.getCompoundTagOrNull("chat");
|
||||
NBTCompound narrationTag = compound.getCompoundTagOrNull("narration");
|
||||
|
||||
ChatTypeDecoration overlay = null;
|
||||
NarrationPriority narrationPriority = null;
|
||||
if (version.isOlderThan(ClientVersion.V_1_19_1)) {
|
||||
NBTCompound overlayTag = compound.getCompoundTagOrNull("overlay");
|
||||
if (overlayTag != null) {
|
||||
// why is this nullable? why is this wrapped? There is no reason to wrap this...
|
||||
overlayTag = overlayTag.getCompoundTagOrNull("description");
|
||||
if (overlayTag != null) {
|
||||
overlay = ChatTypeDecoration.decode(overlayTag, version);
|
||||
}
|
||||
}
|
||||
if (chatTag != null) {
|
||||
chatTag = chatTag.getCompoundTagOrNull("description");
|
||||
}
|
||||
if (narrationTag != null) {
|
||||
// the priority is the ONLY value which isn't nullable!
|
||||
narrationPriority = indexValueOrThrow(NarrationPriority.ID_INDEX,
|
||||
narrationTag.getStringTagValueOrThrow("priority"));
|
||||
narrationTag = narrationTag.getCompoundTagOrNull("description");
|
||||
}
|
||||
} else {
|
||||
// ensure this isn't null in everything but 1.19
|
||||
Objects.requireNonNull(chatTag, "NBT chat does not exist");
|
||||
Objects.requireNonNull(narrationTag, "NBT narration does not exist");
|
||||
}
|
||||
|
||||
ChatTypeDecoration chat = chatTag == null ? null : ChatTypeDecoration.decode(chatTag, version);
|
||||
ChatTypeDecoration narration = narrationTag == null ? null : ChatTypeDecoration.decode(narrationTag, version);
|
||||
return new StaticChatType(data, chat, overlay, narration, narrationPriority);
|
||||
}
|
||||
|
||||
static NBT encode(ChatType chatType, ClientVersion version) {
|
||||
NBTCompound compound = new NBTCompound();
|
||||
NBT chatTag = chatType.getChatDecoration() == null ? null :
|
||||
ChatTypeDecoration.encode(chatType.getChatDecoration(), version);
|
||||
NBT narrationTag = chatType.getNarrationDecoration() == null ? null :
|
||||
ChatTypeDecoration.encode(chatType.getNarrationDecoration(), version);
|
||||
|
||||
if (version.isOlderThan(ClientVersion.V_1_19_1)) {
|
||||
ChatTypeDecoration overlayDeco = chatType.getOverlayDecoration();
|
||||
if (overlayDeco != null) {
|
||||
NBTCompound overlayCompound = new NBTCompound();
|
||||
overlayCompound.setTag("description",
|
||||
ChatTypeDecoration.encode(overlayDeco, version));
|
||||
compound.setTag("overlay", overlayCompound);
|
||||
}
|
||||
if (narrationTag != null) {
|
||||
NBTCompound narrationCompound = new NBTCompound();
|
||||
narrationCompound.setTag("description", narrationTag);
|
||||
if (chatType.getNarrationPriority() != null) {
|
||||
narrationCompound.setTag("priority", new NBTString(chatType.getNarrationPriority().getId()));
|
||||
}
|
||||
narrationTag = narrationCompound;
|
||||
}
|
||||
if (chatTag != null) {
|
||||
NBTCompound chatCompound = new NBTCompound();
|
||||
chatCompound.setTag("description", chatTag);
|
||||
chatTag = chatCompound;
|
||||
}
|
||||
}
|
||||
|
||||
if (chatTag != null) {
|
||||
compound.setTag("chat", chatTag);
|
||||
}
|
||||
if (narrationTag != null) {
|
||||
compound.setTag("narration", narrationTag);
|
||||
}
|
||||
return compound;
|
||||
}
|
||||
|
||||
class Bound extends ChatMessage_v1_19_1.ChatTypeBoundNetwork {
|
||||
public Bound(ChatType type, Component name, @Nullable Component targetName) {
|
||||
super(type, name, targetName);
|
||||
}
|
||||
}
|
||||
|
||||
@ApiStatus.Obsolete(since = "1.19.1")
|
||||
enum NarrationPriority {
|
||||
|
||||
CHAT("chat"),
|
||||
SYSTEM("system");
|
||||
|
||||
public static final Index<String, NarrationPriority> ID_INDEX = Index.create(
|
||||
NarrationPriority.class, NarrationPriority::getId);
|
||||
|
||||
private final String id;
|
||||
|
||||
NarrationPriority(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return this.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2024 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.chat;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTList;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.util.adventure.AdventureSerializer;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.ComponentLike;
|
||||
import net.kyori.adventure.text.format.Style;
|
||||
import net.kyori.adventure.util.Index;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import static com.github.retrooper.packetevents.protocol.chat.ChatTypeDecoration.Parameter.CONTENT;
|
||||
import static com.github.retrooper.packetevents.protocol.chat.ChatTypeDecoration.Parameter.SENDER;
|
||||
import static com.github.retrooper.packetevents.protocol.chat.ChatTypeDecoration.Parameter.TARGET;
|
||||
import static com.github.retrooper.packetevents.util.adventure.AdventureIndexUtil.indexValueOrThrow;
|
||||
import static java.util.Arrays.asList;
|
||||
import static net.kyori.adventure.text.format.NamedTextColor.GRAY;
|
||||
import static net.kyori.adventure.text.format.Style.empty;
|
||||
import static net.kyori.adventure.text.format.Style.style;
|
||||
import static net.kyori.adventure.text.format.TextDecoration.ITALIC;
|
||||
|
||||
public class ChatTypeDecoration {
|
||||
|
||||
private final String translationKey;
|
||||
private final List<Parameter> parameters;
|
||||
private final Style style;
|
||||
|
||||
public ChatTypeDecoration(String translationKey, List<Parameter> parameters, Style style) {
|
||||
this.translationKey = translationKey;
|
||||
this.parameters = Collections.unmodifiableList(new ArrayList<>(parameters));
|
||||
this.style = style;
|
||||
}
|
||||
|
||||
public static ChatTypeDecoration read(PacketWrapper<?> wrapper) {
|
||||
String translationKey = wrapper.readString();
|
||||
List<Parameter> parameters = wrapper.readList(ew -> ew.readEnum(Parameter.values()));
|
||||
Style style = wrapper.readStyle();
|
||||
return new ChatTypeDecoration(translationKey, parameters, style);
|
||||
}
|
||||
|
||||
public static void write(PacketWrapper<?> wrapper, ChatTypeDecoration decoration) {
|
||||
wrapper.writeString(decoration.translationKey);
|
||||
wrapper.writeList(decoration.parameters, PacketWrapper::writeEnum);
|
||||
wrapper.writeStyle(decoration.style);
|
||||
}
|
||||
|
||||
public static ChatTypeDecoration decode(NBT nbt, ClientVersion version) {
|
||||
NBTCompound compound = (NBTCompound) nbt;
|
||||
String translationKey = compound.getStringTagValueOrThrow("translation_key");
|
||||
NBT paramsTag = compound.getTagOrThrow("parameters");
|
||||
List<Parameter> params;
|
||||
if (paramsTag instanceof NBTList<?>) {
|
||||
params = new ArrayList<>();
|
||||
NBTList<?> paramsTagList = (NBTList<?>) paramsTag;
|
||||
for (NBT paramTag : paramsTagList.getTags()) {
|
||||
String paramId = ((NBTString) paramTag).getValue();
|
||||
params.add(indexValueOrThrow(Parameter.ID_INDEX, paramId));
|
||||
}
|
||||
} else {
|
||||
String paramId = ((NBTString) paramsTag).getValue();
|
||||
params = Collections.singletonList(indexValueOrThrow(Parameter.ID_INDEX, paramId));
|
||||
}
|
||||
NBTCompound styleTag = compound.getCompoundTagOrNull("style");
|
||||
Style style = styleTag == null ? empty() :
|
||||
AdventureSerializer.getNBTSerializer().deserializeStyle(styleTag);
|
||||
return new ChatTypeDecoration(translationKey, params, style);
|
||||
}
|
||||
|
||||
public static NBT encode(ChatTypeDecoration decoration, ClientVersion version) {
|
||||
NBTList<NBTString> paramsTag = NBTList.createStringList();
|
||||
for (Parameter param : decoration.parameters) {
|
||||
paramsTag.addTag(new NBTString(param.getId()));
|
||||
}
|
||||
|
||||
NBTCompound compound = new NBTCompound();
|
||||
compound.setTag("translation_key", new NBTString(decoration.translationKey));
|
||||
compound.setTag("parameters", paramsTag);
|
||||
if (!decoration.style.isEmpty()) {
|
||||
compound.setTag("style", AdventureSerializer.getNBTSerializer()
|
||||
.serializeStyle(decoration.style));
|
||||
}
|
||||
return compound;
|
||||
}
|
||||
|
||||
public static ChatTypeDecoration withSender(String translationKey) {
|
||||
return new ChatTypeDecoration(translationKey, asList(SENDER, CONTENT), empty());
|
||||
}
|
||||
|
||||
public static ChatTypeDecoration incomingDirectMessage(String translationKey) {
|
||||
return new ChatTypeDecoration(translationKey, asList(SENDER, CONTENT),
|
||||
style(GRAY, ITALIC));
|
||||
}
|
||||
|
||||
public static ChatTypeDecoration outgoingDirectMessage(String translationKey) {
|
||||
return new ChatTypeDecoration(translationKey, asList(TARGET, CONTENT),
|
||||
style(GRAY, ITALIC));
|
||||
}
|
||||
|
||||
public static ChatTypeDecoration teamMessage(String translationKey) {
|
||||
return new ChatTypeDecoration(translationKey, asList(TARGET, SENDER, CONTENT), empty());
|
||||
}
|
||||
|
||||
public Component decorate(Component component, ChatType.Bound chatType) {
|
||||
ComponentLike[] components = new ComponentLike[this.parameters.size()];
|
||||
for (int i = 0; i < components.length; i++) {
|
||||
Parameter parameter = this.parameters.get(i);
|
||||
components[i] = parameter.selector.apply(component, chatType);
|
||||
}
|
||||
return Component.translatable(this.translationKey, null, this.style, components);
|
||||
}
|
||||
|
||||
public String getTranslationKey() {
|
||||
return this.translationKey;
|
||||
}
|
||||
|
||||
public List<Parameter> getParameters() {
|
||||
return this.parameters;
|
||||
}
|
||||
|
||||
public Style getStyle() {
|
||||
return this.style;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof ChatTypeDecoration)) return false;
|
||||
ChatTypeDecoration that = (ChatTypeDecoration) obj;
|
||||
if (!this.translationKey.equals(that.translationKey)) return false;
|
||||
if (!this.parameters.equals(that.parameters)) return false;
|
||||
return this.style.equals(that.style);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.translationKey, this.parameters, this.style);
|
||||
}
|
||||
|
||||
public enum Parameter {
|
||||
|
||||
SENDER("sender", (component, type) -> type.getName()),
|
||||
TARGET("target", (component, type) -> type.getTargetName() != null
|
||||
? type.getTargetName() : Component.empty()),
|
||||
CONTENT("content", (component, type) -> component);
|
||||
|
||||
public static final Index<String, Parameter> ID_INDEX = Index.create(
|
||||
Parameter.class, Parameter::getId);
|
||||
|
||||
private final String id;
|
||||
private final BiFunction<Component, ChatType.Bound, Component> selector;
|
||||
|
||||
Parameter(String id, BiFunction<Component, ChatType.Bound, Component> selector) {
|
||||
this.id = id;
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static @Nullable Parameter valueByName(String id) {
|
||||
return ID_INDEX.value(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,54 +19,68 @@
|
||||
package com.github.retrooper.packetevents.protocol.chat;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.util.mappings.MappingHelper;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilder;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
|
||||
public class ChatTypes {
|
||||
private static final Map<String, ChatType> CHAT_TYPE_MAP = new HashMap<>();
|
||||
//Key - mappings version, value - map with chat type ids and chat types
|
||||
private static final Map<Byte, Map<Integer, ChatType>> CHAT_TYPE_ID_MAP = new HashMap<>();
|
||||
private static final TypesBuilder TYPES_BUILDER = new TypesBuilder("chat/chat_type_mappings");
|
||||
import static com.github.retrooper.packetevents.protocol.chat.ChatTypeDecoration.incomingDirectMessage;
|
||||
import static com.github.retrooper.packetevents.protocol.chat.ChatTypeDecoration.outgoingDirectMessage;
|
||||
import static com.github.retrooper.packetevents.protocol.chat.ChatTypeDecoration.teamMessage;
|
||||
import static com.github.retrooper.packetevents.protocol.chat.ChatTypeDecoration.withSender;
|
||||
|
||||
public static ChatType define(String key) {
|
||||
TypesBuilderData data = TYPES_BUILDER.define(key);
|
||||
ChatType chatType = new ChatType() {
|
||||
@Override
|
||||
public ResourceLocation getName() {
|
||||
return data.getName();
|
||||
}
|
||||
public final class ChatTypes {
|
||||
|
||||
@Override
|
||||
public int getId(ClientVersion version) {
|
||||
return MappingHelper.getId(version, TYPES_BUILDER, data);
|
||||
}
|
||||
};
|
||||
MappingHelper.registerMapping(TYPES_BUILDER, CHAT_TYPE_MAP, CHAT_TYPE_ID_MAP, chatType);
|
||||
return chatType;
|
||||
private static final VersionedRegistry<ChatType> REGISTRY = new VersionedRegistry<>(
|
||||
"chat_type", "chat/chat_type_mappings");
|
||||
|
||||
private ChatTypes() {
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static ChatType define(String key) {
|
||||
return define(key, withSender("chat.type.text"));
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static ChatType define(String key, ChatTypeDecoration chatDeco) {
|
||||
return define(key, chatDeco, withSender("chat.type.text.narrate"));
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static ChatType define(String key, ChatTypeDecoration chatDeco, ChatTypeDecoration narrationDeco) {
|
||||
return REGISTRY.define(key, data ->
|
||||
new StaticChatType(data, chatDeco, narrationDeco));
|
||||
}
|
||||
|
||||
public static VersionedRegistry<ChatType> getRegistry() {
|
||||
return REGISTRY;
|
||||
}
|
||||
|
||||
//with minecraft:key
|
||||
public static ChatType getByName(String name) {
|
||||
return CHAT_TYPE_MAP.get(name);
|
||||
return REGISTRY.getByName(name);
|
||||
}
|
||||
|
||||
public static ChatType getById(ClientVersion version, int id) {
|
||||
int index = TYPES_BUILDER.getDataIndex(version);
|
||||
return CHAT_TYPE_ID_MAP.get((byte) index).get(id);
|
||||
return REGISTRY.getById(version, id);
|
||||
}
|
||||
|
||||
public static final ChatType CHAT = define("chat");
|
||||
public static final ChatType SAY_COMMAND = define("say_command");
|
||||
public static final ChatType MSG_COMMAND_INCOMING = define("msg_command_incoming");
|
||||
public static final ChatType MSG_COMMAND_OUTGOING = define("msg_command_outgoing");
|
||||
public static final ChatType TEAM_MSG_COMMAND_INCOMING = define("team_msg_command_incoming");
|
||||
public static final ChatType TEAM_MSG_COMMAND_OUTGOING = define("team_msg_command_outgoing");
|
||||
public static final ChatType EMOTE_COMMAND = define("emote_command");
|
||||
public static final ChatType SAY_COMMAND = define("say_command",
|
||||
withSender("chat.type.announcement"));
|
||||
public static final ChatType MSG_COMMAND_INCOMING = define("msg_command_incoming",
|
||||
incomingDirectMessage("commands.message.display.incoming"));
|
||||
public static final ChatType MSG_COMMAND_OUTGOING = define("msg_command_outgoing",
|
||||
outgoingDirectMessage("commands.message.display.outgoing"));
|
||||
public static final ChatType TEAM_MSG_COMMAND_INCOMING = define("team_msg_command_incoming",
|
||||
teamMessage("chat.type.team.text"));
|
||||
public static final ChatType TEAM_MSG_COMMAND_OUTGOING = define("team_msg_command_outgoing",
|
||||
teamMessage("chat.type.team.sent"));
|
||||
public static final ChatType EMOTE_COMMAND = define("emote_command",
|
||||
withSender("chat.type.emote"),
|
||||
withSender("chat.type.emote"));
|
||||
|
||||
// added by CraftBukkit for a few versions
|
||||
public static final ChatType RAW = define("raw");
|
||||
|
||||
@Deprecated
|
||||
@@ -78,7 +92,16 @@ public class ChatTypes {
|
||||
@Deprecated
|
||||
public static final ChatType TEAM_MSG_COMMAND = define("team_msg_command");
|
||||
|
||||
/**
|
||||
* Returns an immutable view of the chat types.
|
||||
*
|
||||
* @return Chat Types
|
||||
*/
|
||||
public static Collection<ChatType> values() {
|
||||
return REGISTRY.getEntries();
|
||||
}
|
||||
|
||||
static {
|
||||
TYPES_BUILDER.unloadFileMappings();
|
||||
REGISTRY.unloadMappings();
|
||||
}
|
||||
}
|
||||
@@ -16,9 +16,10 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.chat;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.protocol.chat.Parsers.Parser;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -26,20 +27,33 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class Node {
|
||||
|
||||
private byte flags;
|
||||
private List<Integer> children;
|
||||
private int redirectNodeIndex;
|
||||
private Optional<String> name;
|
||||
private Optional<Integer> parserID;
|
||||
private Optional<Parser> parser;
|
||||
private Optional<List<Object>> properties;
|
||||
private Optional<ResourceLocation> suggestionsType;
|
||||
|
||||
public Node(byte flags, List<Integer> children, int redirectNodeIndex, @Nullable String name, @Nullable Integer parserID, @Nullable List<Object> properties, @Nullable ResourceLocation suggestionsType) {
|
||||
public Node(
|
||||
byte flags, List<Integer> children, int redirectNodeIndex, @Nullable String name,
|
||||
@Nullable Integer parserID, @Nullable List<Object> properties, @Nullable ResourceLocation suggestionsType
|
||||
) {
|
||||
this(flags, children, redirectNodeIndex, name, parserID == null ? null : Parsers.getById(
|
||||
PacketEvents.getAPI().getServerManager().getVersion().toClientVersion(), parserID),
|
||||
properties, suggestionsType);
|
||||
}
|
||||
|
||||
public Node(
|
||||
byte flags, List<Integer> children, int redirectNodeIndex, @Nullable String name, @Nullable Parser parser,
|
||||
@Nullable List<Object> properties, @Nullable ResourceLocation suggestionsType
|
||||
) {
|
||||
this.flags = flags;
|
||||
this.children = children;
|
||||
this.redirectNodeIndex = redirectNodeIndex;
|
||||
this.name = Optional.ofNullable(name);
|
||||
this.parserID = Optional.ofNullable(parserID);
|
||||
this.parser = Optional.ofNullable(parser);
|
||||
this.properties = Optional.ofNullable(properties);
|
||||
this.suggestionsType = Optional.ofNullable(suggestionsType);
|
||||
}
|
||||
@@ -76,12 +90,22 @@ public class Node {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Optional<Parser> getParser() {
|
||||
return this.parser;
|
||||
}
|
||||
|
||||
public void setParser(Optional<Parser> parser) {
|
||||
this.parser = parser;
|
||||
}
|
||||
|
||||
public Optional<Integer> getParserID() {
|
||||
return parserID;
|
||||
return this.parser.map(parser -> parser.getId(PacketEvents.getAPI()
|
||||
.getServerManager().getVersion().toClientVersion()));
|
||||
}
|
||||
|
||||
public void setParserID(Optional<Integer> parserID) {
|
||||
this.parserID = parserID;
|
||||
this.parser = parserID.map(id -> Parsers.getById(PacketEvents.getAPI()
|
||||
.getServerManager().getVersion().toClientVersion(), id));
|
||||
}
|
||||
|
||||
public Optional<List<Object>> getProperties() {
|
||||
|
||||
@@ -151,7 +151,9 @@ public class Parsers {
|
||||
public static final Parser COMPONENT = define("component", null, null);
|
||||
public static final Parser STYLE = define("style", null, null);
|
||||
public static final Parser MESSAGE = define("message", null, null);
|
||||
public static final Parser NBT = define("nbt", null, null);
|
||||
public static final Parser NBT_COMPOUND_TAG = define("nbt_compound_tag", null, null);
|
||||
@Deprecated
|
||||
public static final Parser NBT = NBT_COMPOUND_TAG;
|
||||
public static final Parser NBT_TAG = define("nbt_tag", null, null);
|
||||
public static final Parser NBT_PATH = define("nbt_path", null, null);
|
||||
public static final Parser OBJECTIVE = define("objective", null, null);
|
||||
@@ -170,10 +172,13 @@ public class Parsers {
|
||||
public static final Parser ITEM_SLOT = define("item_slot", null, null);
|
||||
public static final Parser ITEM_SLOTS = define("item_slots", null, null);
|
||||
public static final Parser RESOURCE_LOCATION = define("resource_location", null, null);
|
||||
public static final Parser MOB_EFFECT = define("mob_effect", null, null);
|
||||
public static final Parser FUNCTION = define("function", null, null);
|
||||
public static final Parser ENTITY_ANCHOR = define("entity_anchor", null, null);
|
||||
public static final Parser INT_RANGE = define("int_range", null, null);
|
||||
public static final Parser FLOAT_RANGE = define("float_range", null, null);
|
||||
public static final Parser ITEM_ENCHANTMENT = define("item_enchantment", null, null);
|
||||
public static final Parser ENTITY_SUMMON = define("entity_summon", null, null);
|
||||
public static final Parser DIMENSION = define("dimension", null, null);
|
||||
public static final Parser GAMEMODE = define("gamemode", null, null);
|
||||
public static final Parser TIME = define("time",
|
||||
|
||||
+4
-4
@@ -2,9 +2,9 @@ package com.github.retrooper.packetevents.protocol.chat;
|
||||
|
||||
public class SignedCommandArgument {
|
||||
private String argument;
|
||||
private byte[] signature;
|
||||
private MessageSignature signature;
|
||||
|
||||
public SignedCommandArgument(String argument, byte[] signature) {
|
||||
public SignedCommandArgument(String argument, MessageSignature signature) {
|
||||
this.argument = argument;
|
||||
this.signature = signature;
|
||||
}
|
||||
@@ -17,11 +17,11 @@ public class SignedCommandArgument {
|
||||
this.argument = argument;
|
||||
}
|
||||
|
||||
public byte[] getSignature() {
|
||||
public MessageSignature getSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
public void setSignature(byte[] signature) {
|
||||
public void setSignature(MessageSignature signature) {
|
||||
this.signature = signature;
|
||||
}
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2024 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.chat;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.mapper.AbstractMappedEntity;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class StaticChatType extends AbstractMappedEntity implements ChatType {
|
||||
|
||||
private final @UnknownNullability("only nullable for 1.19") ChatTypeDecoration chatDecoration;
|
||||
private final @Nullable ChatTypeDecoration overlayDecoration;
|
||||
private final @UnknownNullability("only nullable for 1.19") ChatTypeDecoration narrationDecoration;
|
||||
private final @Nullable NarrationPriority narrationPriority;
|
||||
|
||||
public StaticChatType(
|
||||
ChatTypeDecoration chatDecoration,
|
||||
ChatTypeDecoration narrationDecoration
|
||||
) {
|
||||
this(null, chatDecoration, null, narrationDecoration, null);
|
||||
}
|
||||
|
||||
public StaticChatType(
|
||||
@Nullable TypesBuilderData data,
|
||||
ChatTypeDecoration chatDecoration,
|
||||
ChatTypeDecoration narrationDecoration
|
||||
) {
|
||||
this(data, chatDecoration, null, narrationDecoration, null);
|
||||
}
|
||||
|
||||
public StaticChatType(
|
||||
@UnknownNullability("only nullable for 1.19") ChatTypeDecoration chatDecoration,
|
||||
@Nullable ChatTypeDecoration overlayDecoration,
|
||||
@UnknownNullability("only nullable for 1.19") ChatTypeDecoration narrationDecoration,
|
||||
@Nullable NarrationPriority narrationPriority
|
||||
) {
|
||||
this(null, chatDecoration, overlayDecoration, narrationDecoration, narrationPriority);
|
||||
}
|
||||
|
||||
public StaticChatType(
|
||||
@Nullable TypesBuilderData data,
|
||||
@UnknownNullability("only nullable for 1.19") ChatTypeDecoration chatDecoration,
|
||||
@Nullable ChatTypeDecoration overlayDecoration,
|
||||
@UnknownNullability("only nullable for 1.19") ChatTypeDecoration narrationDecoration,
|
||||
@Nullable NarrationPriority narrationPriority
|
||||
) {
|
||||
super(data);
|
||||
this.chatDecoration = chatDecoration;
|
||||
this.overlayDecoration = overlayDecoration;
|
||||
this.narrationDecoration = narrationDecoration;
|
||||
this.narrationPriority = narrationPriority;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChatType copy(@Nullable TypesBuilderData newData) {
|
||||
return new StaticChatType(newData, this.chatDecoration,
|
||||
this.overlayDecoration, this.narrationDecoration, this.narrationPriority);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @UnknownNullability("only nullable for 1.19") ChatTypeDecoration getChatDecoration() {
|
||||
return this.chatDecoration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ChatTypeDecoration getOverlayDecoration() {
|
||||
return this.overlayDecoration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @UnknownNullability("only nullable for 1.19") ChatTypeDecoration getNarrationDecoration() {
|
||||
return this.narrationDecoration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable NarrationPriority getNarrationPriority() {
|
||||
return this.narrationPriority;
|
||||
}
|
||||
|
||||
public boolean deepEquals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof StaticChatType)) return false;
|
||||
if (!super.equals(obj)) return false;
|
||||
StaticChatType that = (StaticChatType) obj;
|
||||
if (!Objects.equals(this.chatDecoration, that.chatDecoration)) return false;
|
||||
if (!Objects.equals(this.overlayDecoration, that.overlayDecoration)) return false;
|
||||
if (!Objects.equals(this.narrationDecoration, that.narrationDecoration)) return false;
|
||||
return this.narrationPriority == that.narrationPriority;
|
||||
}
|
||||
|
||||
public int deepHashCode() {
|
||||
return Objects.hash(super.hashCode(), this.chatDecoration, this.overlayDecoration, this.narrationDecoration, this.narrationPriority);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StaticChatType{chatDecoration=" + this.chatDecoration + ", overlayDecoration=" + this.overlayDecoration + ", narrationDecoration=" + this.narrationDecoration + ", narrationPriority=" + this.narrationPriority + '}';
|
||||
}
|
||||
}
|
||||
+32
-10
@@ -30,7 +30,7 @@ import java.util.UUID;
|
||||
public class ChatMessage_v1_19_1 extends ChatMessage_v1_16 {
|
||||
private String plainContent;
|
||||
private @Nullable Component unsignedChatContent;
|
||||
private ChatTypeBoundNetwork chatType;
|
||||
private ChatType.Bound chatFormatting;
|
||||
private byte @Nullable [] previousSignature;
|
||||
private byte[] signature;
|
||||
private Instant timestamp;
|
||||
@@ -40,15 +40,15 @@ public class ChatMessage_v1_19_1 extends ChatMessage_v1_16 {
|
||||
|
||||
public ChatMessage_v1_19_1(String plainContent, Component decoratedChatContent,
|
||||
@Nullable Component unsignedChatContent,
|
||||
UUID senderUUID, ChatTypeBoundNetwork chatType,
|
||||
UUID senderUUID, ChatType.Bound chatFormatting,
|
||||
byte @Nullable [] previousSignature, byte[] signature,
|
||||
Instant timestamp, long salt,
|
||||
LastSeenMessages lastSeenMessages,
|
||||
FilterMask filterMask) {
|
||||
super(decoratedChatContent, chatType.getType(), senderUUID);
|
||||
super(decoratedChatContent, chatFormatting.getType(), senderUUID);
|
||||
this.plainContent = plainContent;
|
||||
this.unsignedChatContent = unsignedChatContent;
|
||||
this.chatType = chatType;
|
||||
this.chatFormatting = chatFormatting;
|
||||
this.previousSignature = previousSignature;
|
||||
this.signature = signature;
|
||||
this.timestamp = timestamp;
|
||||
@@ -79,20 +79,38 @@ public class ChatMessage_v1_19_1 extends ChatMessage_v1_16 {
|
||||
|
||||
@Override
|
||||
public ChatType getType() {
|
||||
return chatType.getType();
|
||||
return chatFormatting.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setType(ChatType type) {
|
||||
chatType.setType(type);
|
||||
chatFormatting.setType(type);
|
||||
}
|
||||
|
||||
public ChatTypeBoundNetwork getChatType() {
|
||||
return chatType;
|
||||
public ChatType.Bound getChatFormatting() {
|
||||
return chatFormatting;
|
||||
}
|
||||
|
||||
public void setChatType(ChatTypeBoundNetwork type) {
|
||||
this.chatType = type;
|
||||
public void setChatFormatting(ChatType.Bound chatFormatting) {
|
||||
this.chatFormatting = chatFormatting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the chat formatting. Please refer to {@link ChatMessage_v1_19_1#getChatFormatting}
|
||||
* @return chat formatting which contains the actual chat type.
|
||||
*/
|
||||
@Deprecated
|
||||
public ChatType.Bound getChatType() {
|
||||
return chatFormatting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the chat formatting. Please refer to {@link ChatMessage_v1_19_1#setChatFormatting}
|
||||
* @param chatFormatting formatting which contains the actual chat type.
|
||||
*/
|
||||
@Deprecated
|
||||
public void setChatType(ChatType.Bound chatFormatting) {
|
||||
this.chatFormatting = chatFormatting;
|
||||
}
|
||||
|
||||
public byte @Nullable [] getPreviousSignature() {
|
||||
@@ -143,6 +161,10 @@ public class ChatMessage_v1_19_1 extends ChatMessage_v1_16 {
|
||||
this.filterMask = filterMask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Please refer to {@link com.github.retrooper.packetevents.protocol.chat.ChatType.Bound}
|
||||
*/
|
||||
@Deprecated
|
||||
public static class ChatTypeBoundNetwork {
|
||||
private ChatType type;
|
||||
private Component name;
|
||||
|
||||
+28
-8
@@ -1,5 +1,6 @@
|
||||
package com.github.retrooper.packetevents.protocol.chat.message;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.chat.ChatType;
|
||||
import com.github.retrooper.packetevents.protocol.chat.LastSeenMessages;
|
||||
import com.github.retrooper.packetevents.protocol.chat.filter.FilterMask;
|
||||
import com.github.retrooper.packetevents.util.adventure.AdventureSerializer;
|
||||
@@ -19,10 +20,10 @@ public class ChatMessage_v1_19_3 extends ChatMessage_v1_16 {
|
||||
LastSeenMessages.Packed lastSeenMessagesPacked;
|
||||
@Nullable Component unsignedChatContent;
|
||||
FilterMask filterMask;
|
||||
ChatMessage_v1_19_1.ChatTypeBoundNetwork chatType;
|
||||
ChatType.Bound chatFormatting;
|
||||
|
||||
public ChatMessage_v1_19_3(UUID senderUUID, int index, byte[] signature, String plainContent, Instant timestamp, long salt, LastSeenMessages.Packed lastSeenMessagesPacked, @Nullable Component unsignedChatContent, FilterMask filterMask, ChatMessage_v1_19_1.ChatTypeBoundNetwork chatType) {
|
||||
super(Component.text(plainContent), chatType.getType(), senderUUID);
|
||||
public ChatMessage_v1_19_3(UUID senderUUID, int index, byte[] signature, String plainContent, Instant timestamp, long salt, LastSeenMessages.Packed lastSeenMessagesPacked, @Nullable Component unsignedChatContent, FilterMask filterMask, ChatType.Bound chatFormatting) {
|
||||
super(Component.text(plainContent), chatFormatting.getType(), senderUUID);
|
||||
this.index = index;
|
||||
this.signature = signature;
|
||||
this.plainContent = plainContent;
|
||||
@@ -31,7 +32,7 @@ public class ChatMessage_v1_19_3 extends ChatMessage_v1_16 {
|
||||
this.lastSeenMessagesPacked = lastSeenMessagesPacked;
|
||||
this.unsignedChatContent = unsignedChatContent;
|
||||
this.filterMask = filterMask;
|
||||
this.chatType = chatType;
|
||||
this.chatFormatting = chatFormatting;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
@@ -109,11 +110,30 @@ public class ChatMessage_v1_19_3 extends ChatMessage_v1_16 {
|
||||
this.filterMask = filterMask;
|
||||
}
|
||||
|
||||
public ChatMessage_v1_19_1.ChatTypeBoundNetwork getChatType() {
|
||||
return chatType;
|
||||
|
||||
public ChatType.Bound getChatFormatting() {
|
||||
return chatFormatting;
|
||||
}
|
||||
|
||||
public void setChatType(ChatMessage_v1_19_1.ChatTypeBoundNetwork chatType) {
|
||||
this.chatType = chatType;
|
||||
public void setChatFormatting(ChatType.Bound chatFormatting) {
|
||||
this.chatFormatting = chatFormatting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the chat formatting. Please refer to {@link ChatMessage_v1_19_3#getChatFormatting}
|
||||
* @return chat formatting which contains the actual chat type.
|
||||
*/
|
||||
@Deprecated
|
||||
public ChatType.Bound getChatType() {
|
||||
return chatFormatting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the chat formatting. Please refer to {@link ChatMessage_v1_19_3#setChatFormatting}
|
||||
* @param chatFormatting formatting which contains the actual chat type.
|
||||
*/
|
||||
@Deprecated
|
||||
public void setChatType(ChatType.Bound chatFormatting) {
|
||||
this.chatFormatting = chatFormatting;
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -31,14 +31,13 @@ public class ChatMessageProcessorLegacy implements ChatMessageProcessor {
|
||||
@Override
|
||||
public ChatMessage readChatMessage(@NotNull PacketWrapper<?> wrapper) {
|
||||
Component chatContent = wrapper.readComponent();
|
||||
int id = wrapper.readByte();
|
||||
ChatType type = ChatTypes.getById(wrapper.getServerVersion().toClientVersion(), id);
|
||||
ChatType type = wrapper.readMappedEntity(ChatTypes.getRegistry());
|
||||
return new ChatMessageLegacy(chatContent, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeChatMessage(@NotNull PacketWrapper<?> wrapper, @NotNull ChatMessage data) {
|
||||
wrapper.writeComponent(data.getChatContent());
|
||||
wrapper.writeByte(data.getType().getId(wrapper.getServerVersion().toClientVersion()));
|
||||
wrapper.writeMappedEntity(data.getType());
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -33,8 +33,7 @@ public class ChatMessageProcessor_v1_16 implements ChatMessageProcessor {
|
||||
@Override
|
||||
public ChatMessage readChatMessage(@NotNull PacketWrapper<?> wrapper) {
|
||||
Component chatContent = wrapper.readComponent();
|
||||
int id = wrapper.readByte();
|
||||
ChatType type = ChatTypes.getById(wrapper.getServerVersion().toClientVersion(), id);
|
||||
ChatType type = wrapper.readMappedEntity(ChatTypes.getRegistry());
|
||||
UUID senderUUID = wrapper.readUUID();
|
||||
return new ChatMessage_v1_16(chatContent, type, senderUUID);
|
||||
}
|
||||
@@ -42,7 +41,7 @@ public class ChatMessageProcessor_v1_16 implements ChatMessageProcessor {
|
||||
@Override
|
||||
public void writeChatMessage(@NotNull PacketWrapper<?> wrapper, @NotNull ChatMessage data) {
|
||||
wrapper.writeComponent(data.getChatContent());
|
||||
wrapper.writeByte(data.getType().getId(wrapper.getServerVersion().toClientVersion()));
|
||||
wrapper.writeMappedEntity(data.getType());
|
||||
wrapper.writeUUID(((ChatMessage_v1_16) data).getSenderUUID());
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -36,8 +36,7 @@ public class ChatMessageProcessor_v1_19 implements ChatMessageProcessor {
|
||||
public ChatMessage readChatMessage(@NotNull PacketWrapper<?> wrapper) {
|
||||
Component chatContent = wrapper.readComponent();
|
||||
Component unsignedChatContent = wrapper.readOptional(PacketWrapper::readComponent);
|
||||
int id = wrapper.readVarInt();
|
||||
ChatType type = ChatTypes.getById(wrapper.getServerVersion().toClientVersion(), id);
|
||||
ChatType type = wrapper.readMappedEntity(ChatTypes.getRegistry());
|
||||
UUID senderUUID = wrapper.readUUID();
|
||||
Component senderDisplayName = wrapper.readComponent();
|
||||
@Nullable Component teamName = wrapper.readOptional(PacketWrapper::readComponent);
|
||||
@@ -53,7 +52,7 @@ public class ChatMessageProcessor_v1_19 implements ChatMessageProcessor {
|
||||
ChatMessage_v1_19 newData = (ChatMessage_v1_19) data;
|
||||
wrapper.writeComponent(newData.getChatContent());
|
||||
wrapper.writeOptional(newData.getUnsignedChatContent(), PacketWrapper::writeComponent);
|
||||
wrapper.writeVarInt(newData.getType().getId(wrapper.getServerVersion().toClientVersion()));
|
||||
wrapper.writeMappedEntity(newData.getType());
|
||||
wrapper.writeUUID(newData.getSenderUUID());
|
||||
wrapper.writeComponent(newData.getSenderDisplayName());
|
||||
wrapper.writeOptional(newData.getTeamName(), PacketWrapper::writeComponent);
|
||||
|
||||
+3
-3
@@ -50,8 +50,8 @@ public class ChatMessageProcessor_v1_19_1 implements ChatMessageProcessor {
|
||||
LastSeenMessages lastSeenMessages = wrapper.readLastSeenMessages();
|
||||
Component unsignedChatContent = wrapper.readOptional(PacketWrapper::readComponent);
|
||||
FilterMask filterMask = wrapper.readFilterMask();
|
||||
ChatMessage_v1_19_1.ChatTypeBoundNetwork chatType = wrapper.readChatTypeBoundNetwork();
|
||||
return new ChatMessage_v1_19_1(plainContent, chatContent, unsignedChatContent, senderUUID, chatType,
|
||||
ChatType.Bound chatFormatting = wrapper.readChatTypeBoundNetwork();
|
||||
return new ChatMessage_v1_19_1(plainContent, chatContent, unsignedChatContent, senderUUID, chatFormatting,
|
||||
previousSignature, signature, timestamp, salt, lastSeenMessages, filterMask);
|
||||
}
|
||||
|
||||
@@ -68,6 +68,6 @@ public class ChatMessageProcessor_v1_19_1 implements ChatMessageProcessor {
|
||||
wrapper.writeLastSeenMessages(newData.getLastSeenMessages());
|
||||
wrapper.writeOptional(newData.getUnsignedChatContent(), PacketWrapper::writeComponent);
|
||||
wrapper.writeFilterMask(newData.getFilterMask());
|
||||
wrapper.writeChatTypeBoundNetwork(newData.getChatType());
|
||||
wrapper.writeChatTypeBoundNetwork(newData.getChatFormatting());
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -1,5 +1,6 @@
|
||||
package com.github.retrooper.packetevents.protocol.chat.message.reader.impl;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.chat.ChatType;
|
||||
import com.github.retrooper.packetevents.protocol.chat.LastSeenMessages;
|
||||
import com.github.retrooper.packetevents.protocol.chat.filter.FilterMask;
|
||||
import com.github.retrooper.packetevents.protocol.chat.message.ChatMessage;
|
||||
@@ -25,7 +26,7 @@ public class ChatMessageProcessor_v1_19_3 implements ChatMessageProcessor {
|
||||
LastSeenMessages.Packed lastSeenMessagesPacked = wrapper.readLastSeenMessagesPacked();
|
||||
Component unsignedChatContent = wrapper.readOptional(PacketWrapper::readComponent);
|
||||
FilterMask filterMask = wrapper.readFilterMask();
|
||||
ChatMessage_v1_19_1.ChatTypeBoundNetwork chatType = wrapper.readChatTypeBoundNetwork();
|
||||
ChatType.Bound chatType = wrapper.readChatTypeBoundNetwork();
|
||||
|
||||
return new ChatMessage_v1_19_3(senderUUID, index, signature, plainContent, timestamp, salt, lastSeenMessagesPacked, unsignedChatContent, filterMask, chatType);
|
||||
}
|
||||
@@ -42,6 +43,6 @@ public class ChatMessageProcessor_v1_19_3 implements ChatMessageProcessor {
|
||||
wrapper.writeLastSeenMessagesPacked(newData.getLastSeenMessagesPacked());
|
||||
wrapper.writeOptional(newData.getUnsignedChatContent().orElse(null), PacketWrapper::writeComponent);
|
||||
wrapper.writeFilterMask(newData.getFilterMask());
|
||||
wrapper.writeChatTypeBoundNetwork(newData.getChatType());
|
||||
wrapper.writeChatTypeBoundNetwork(newData.getChatFormatting());
|
||||
}
|
||||
}
|
||||
+19
@@ -23,6 +23,7 @@ import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@@ -88,4 +89,22 @@ public class ComponentPredicate implements Predicate<IComponentMap> {
|
||||
public void setRequiredComponents(List<ComponentValue<?>> requiredComponents) {
|
||||
this.requiredComponents = requiredComponents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof ComponentPredicate)) return false;
|
||||
ComponentPredicate that = (ComponentPredicate) obj;
|
||||
return this.requiredComponents.equals(that.requiredComponents);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(this.requiredComponents);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ComponentPredicate{requiredComponents=" + this.requiredComponents + '}';
|
||||
}
|
||||
}
|
||||
+16
@@ -19,6 +19,8 @@
|
||||
package com.github.retrooper.packetevents.protocol.component;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
|
||||
public interface ComponentType<T> extends MappedEntity {
|
||||
@@ -26,4 +28,18 @@ public interface ComponentType<T> extends MappedEntity {
|
||||
T read(PacketWrapper<?> wrapper);
|
||||
|
||||
void write(PacketWrapper<?> wrapper, T content);
|
||||
|
||||
T decode(NBT nbt, ClientVersion version);
|
||||
|
||||
NBT encode(T value, ClientVersion version);
|
||||
|
||||
interface Decoder<T> {
|
||||
|
||||
T decode(NBT nbt, ClientVersion version);
|
||||
}
|
||||
|
||||
interface Encoder<T> {
|
||||
|
||||
NBT encode(T value, ClientVersion version);
|
||||
}
|
||||
}
|
||||
+44
-65
@@ -23,6 +23,7 @@ import com.github.retrooper.packetevents.protocol.component.builtin.item.ArmorTr
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.BannerLayers;
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.BundleContents;
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.ChargedProjectiles;
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.CustomData;
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.DebugStickState;
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.FireworkExplosion;
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.FoodProperties;
|
||||
@@ -35,6 +36,7 @@ import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemCon
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemDyeColor;
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemEnchantments;
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemFireworks;
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemJukeboxPlayable;
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemLock;
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemLore;
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemMapDecorations;
|
||||
@@ -54,85 +56,55 @@ import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.util.Dummy;
|
||||
import com.github.retrooper.packetevents.util.mappings.MappingHelper;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilder;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper.Reader;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper.Writer;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.Collection;
|
||||
|
||||
public class ComponentTypes {
|
||||
/**
|
||||
* Contains all item data component types.
|
||||
*
|
||||
* @see EnchantEffectComponentTypes
|
||||
*/
|
||||
public final class ComponentTypes {
|
||||
|
||||
private static final Map<String, ComponentType<?>> COMPONENT_TYPE_MAP = new HashMap<>();
|
||||
private static final Map<Byte, Map<Integer, ComponentType<?>>> COMPONENT_TYPE_ID_MAP = new HashMap<>();
|
||||
private static final TypesBuilder TYPES_BUILDER = new TypesBuilder("item/item_component_mappings");
|
||||
private static final VersionedRegistry<ComponentType<?>> REGISTRY = new VersionedRegistry<>(
|
||||
"data_component_type", "item/item_component_mappings");
|
||||
|
||||
private ComponentTypes() {
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static <T> ComponentType<T> define(String key) {
|
||||
return define(key, null, null);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static <T> ComponentType<T> define(String key, @Nullable Reader<T> reader, @Nullable Writer<T> writer) {
|
||||
TypesBuilderData data = TYPES_BUILDER.define(key);
|
||||
ComponentType<T> type = new ComponentType<T>() {
|
||||
@Override
|
||||
public T read(PacketWrapper<?> wrapper) {
|
||||
return reader == null ? null : reader.apply(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(PacketWrapper<?> wrapper, T content) {
|
||||
if (writer != null) {
|
||||
writer.accept(wrapper, content);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getName() {
|
||||
return data.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId(ClientVersion version) {
|
||||
return MappingHelper.getId(version, TYPES_BUILDER, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof ComponentType<?>) {
|
||||
return this.getName().equals(((ComponentType<?>) obj).getName());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Component[" + this.getName() + "]";
|
||||
}
|
||||
};
|
||||
|
||||
MappingHelper.registerMapping(TYPES_BUILDER, COMPONENT_TYPE_MAP, COMPONENT_TYPE_ID_MAP, type);
|
||||
return type;
|
||||
return REGISTRY.define(key, data -> new StaticComponentType<>(data, reader, writer));
|
||||
}
|
||||
|
||||
public static VersionedRegistry<ComponentType<?>> getRegistry() {
|
||||
return REGISTRY;
|
||||
}
|
||||
|
||||
// with key
|
||||
public static ComponentType<?> getByName(String name) {
|
||||
return COMPONENT_TYPE_MAP.get(name);
|
||||
return REGISTRY.getByName(name);
|
||||
}
|
||||
|
||||
public static ComponentType<?> getById(ClientVersion version, int id) {
|
||||
int index = TYPES_BUILDER.getDataIndex(version);
|
||||
Map<Integer, ComponentType<?>> idMap = COMPONENT_TYPE_ID_MAP.get((byte) index);
|
||||
return idMap.get(id);
|
||||
return REGISTRY.getById(version, id);
|
||||
}
|
||||
|
||||
// item component types
|
||||
public static final ComponentType<NBTCompound> CUSTOM_DATA = define("custom_data",
|
||||
PacketWrapper::readNBT, PacketWrapper::writeNBT);
|
||||
// mojang wraps their "persistent" codec as a stream codec just here,
|
||||
// so packetevents has to handle nbt strings
|
||||
CustomData::read, CustomData::write);
|
||||
public static final ComponentType<Integer> MAX_STACK_SIZE = define("max_stack_size",
|
||||
PacketWrapper::readVarInt, PacketWrapper::writeVarInt);
|
||||
public static final ComponentType<Integer> MAX_DAMAGE = define("max_damage",
|
||||
@@ -244,13 +216,20 @@ public class ComponentTypes {
|
||||
public static final ComponentType<ItemContainerLoot> CONTAINER_LOOT = define("container_loot",
|
||||
ItemContainerLoot::read, ItemContainerLoot::write);
|
||||
|
||||
static {
|
||||
TYPES_BUILDER.unloadFileMappings();
|
||||
// added in 1.21
|
||||
public static final ComponentType<ItemJukeboxPlayable> JUKEBOX_PLAYABLE = define("jukebox_playable",
|
||||
ItemJukeboxPlayable::read, ItemJukeboxPlayable::write);
|
||||
|
||||
/**
|
||||
* Returns an immutable view of the component types.
|
||||
*
|
||||
* @return Component Types
|
||||
*/
|
||||
public static Collection<ComponentType<?>> values() {
|
||||
return REGISTRY.getEntries();
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Reader<T> extends Function<PacketWrapper<?>, T> {}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Writer<T> extends BiConsumer<PacketWrapper<?>, T> {}
|
||||
static {
|
||||
REGISTRY.unloadMappings();
|
||||
}
|
||||
}
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2024 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.component;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.component.ComponentType.Decoder;
|
||||
import com.github.retrooper.packetevents.protocol.component.ComponentType.Encoder;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Contains all enchantment effect component types.
|
||||
*
|
||||
* @see ComponentTypes
|
||||
*/
|
||||
public final class EnchantEffectComponentTypes {
|
||||
|
||||
private static final VersionedRegistry<ComponentType<?>> REGISTRY = new VersionedRegistry<>(
|
||||
"enchantment_effect_component_type", "enchantment/effect_component_type");
|
||||
|
||||
private EnchantEffectComponentTypes() {
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static <T> ComponentType<T> define(String key) {
|
||||
return define(key, null, null);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static <T> ComponentType<T> define(String key, @Nullable Decoder<T> reader, @Nullable Encoder<T> writer) {
|
||||
return REGISTRY.define(key, data -> new StaticComponentType<>(data, reader, writer));
|
||||
}
|
||||
|
||||
public static VersionedRegistry<ComponentType<?>> getRegistry() {
|
||||
return REGISTRY;
|
||||
}
|
||||
|
||||
// just pass everything through for now
|
||||
public static ComponentType<NBT> DAMAGE_PROTECTION = define("damage_protection",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
public static ComponentType<NBT> DAMAGE_IMMUNITY = define("damage_immunity",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
public static ComponentType<NBT> DAMAGE = define("damage",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
public static ComponentType<NBT> SMASH_DAMAGE_PER_FALLEN_BLOCK = define("smash_damage_per_fallen_block",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
public static ComponentType<NBT> KNOCKBACK = define("knockback",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
public static ComponentType<NBT> ARMOR_EFFECTIVENESS = define("armor_effectiveness",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
public static ComponentType<NBT> POST_ATTACK = define("post_attack",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
public static ComponentType<NBT> HIT_BLOCK = define("hit_block",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
public static ComponentType<NBT> ITEM_DAMAGE = define("item_damage",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
public static ComponentType<NBT> ATTRIBUTES = define("attributes",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
public static ComponentType<NBT> EQUIPMENT_DROPS = define("equipment_drops",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
public static ComponentType<NBT> LOCATION_CHANGED = define("location_changed",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
public static ComponentType<NBT> TICK = define("tick",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
public static ComponentType<NBT> AMMO_USE = define("ammo_use",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
public static ComponentType<NBT> PROJECTILE_PIERCING = define("projectile_piercing",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
public static ComponentType<NBT> PROJECTILE_SPAWNED = define("projectile_spawned",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
public static ComponentType<NBT> PROJECTILE_SPREAD = define("projectile_spread",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
public static ComponentType<NBT> PROJECTILE_COUNT = define("projectile_count",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
public static ComponentType<NBT> TRIDENT_RETURN_ACCELERATION = define("trident_return_acceleration",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
public static ComponentType<NBT> FISHING_TIME_REDUCTION = define("fishing_time_reduction",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
public static ComponentType<NBT> FISHING_LUCK_BONUS = define("fishing_luck_bonus",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
public static ComponentType<NBT> BLOCK_EXPERIENCE = define("block_experience",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
public static ComponentType<NBT> MOB_EXPERIENCE = define("mob_experience",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
public static ComponentType<NBT> REPAIR_WITH_XP = define("repair_with_xp",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
public static ComponentType<NBT> CROSSBOW_CHARGE_TIME = define("crossbow_charge_time",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
public static ComponentType<NBT> CROSSBOW_CHARGING_SOUNDS = define("crossbow_charging_sounds",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
public static ComponentType<NBT> TRIDENT_SOUND = define("trident_sound",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
public static ComponentType<NBT> PREVENT_EQUIPMENT_DROP = define("prevent_equipment_drop",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
public static ComponentType<NBT> PREVENT_ARMOR_CHANGE = define("prevent_armor_change",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
public static ComponentType<NBT> TRIDENT_SPIN_ATTACK_STRENGTH = define("trident_spin_attack_strength",
|
||||
(nbt, version) -> nbt, (val, version) -> val);
|
||||
|
||||
static {
|
||||
REGISTRY.unloadMappings();
|
||||
}
|
||||
}
|
||||
+31
@@ -18,13 +18,44 @@
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.component;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.util.mappings.IRegistry;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface IComponentMap {
|
||||
|
||||
@SuppressWarnings("unchecked") // safe in this case
|
||||
static StaticComponentMap decode(NBT nbt, ClientVersion version, IRegistry<? extends ComponentType<?>> registry) {
|
||||
NBTCompound compound = (NBTCompound) nbt;
|
||||
StaticComponentMap.Builder components = StaticComponentMap.builder();
|
||||
for (Map.Entry<String, NBT> entry : compound.getTags().entrySet()) {
|
||||
ComponentType<?> type = registry.getByName(entry.getKey());
|
||||
if (type == null) {
|
||||
throw new IllegalStateException("Unknown component type named " + entry.getKey() + " encountered");
|
||||
}
|
||||
Object value = type.decode(entry.getValue(), version);
|
||||
components.set((ComponentType<? super Object>) type, value);
|
||||
}
|
||||
return components.build();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // safe in this case
|
||||
static NBT encode(StaticComponentMap components, ClientVersion version) {
|
||||
NBTCompound compound = new NBTCompound();
|
||||
for (Map.Entry<ComponentType<?>, ?> entry : components.getDelegate().entrySet()) {
|
||||
String key = entry.getKey().getName().toString();
|
||||
NBT value = ((ComponentType<? super Object>) entry.getKey()).encode(entry.getValue(), version);
|
||||
compound.setTag(key, value);
|
||||
}
|
||||
return compound;
|
||||
}
|
||||
|
||||
default <T> Optional<T> getOptional(ComponentType<T> type) {
|
||||
return Optional.ofNullable(this.get(type));
|
||||
}
|
||||
|
||||
+14
@@ -96,6 +96,20 @@ public class PatchableComponentMap implements IComponentMap {
|
||||
return this.patches;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof PatchableComponentMap)) return false;
|
||||
PatchableComponentMap that = (PatchableComponentMap) obj;
|
||||
if (!this.base.equals(that.base)) return false;
|
||||
return this.patches.equals(that.patches);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.base, this.patches);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PatchableComponentMap{base=" + this.base + ", patches=" + this.patches + '}';
|
||||
|
||||
+19
@@ -27,6 +27,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
public class StaticComponentMap implements IComponentMap {
|
||||
@@ -82,6 +83,24 @@ public class StaticComponentMap implements IComponentMap {
|
||||
return this.empty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof StaticComponentMap)) return false;
|
||||
StaticComponentMap that = (StaticComponentMap) obj;
|
||||
return this.delegate.equals(that.delegate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(this.delegate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StaticComponentMap{empty=" + this.empty + ", delegate=" + this.delegate + '}';
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private final Map<ComponentType<?>, Object> map = new HashMap<>();
|
||||
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2024 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.component;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.mapper.AbstractMappedEntity;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper.Reader;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper.Writer;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class StaticComponentType<T> extends AbstractMappedEntity implements ComponentType<T> {
|
||||
|
||||
private final @Nullable Reader<T> reader;
|
||||
private final @Nullable Writer<T> writer;
|
||||
private final @Nullable Decoder<T> decoder;
|
||||
private final @Nullable Encoder<T> encoder;
|
||||
|
||||
public StaticComponentType(
|
||||
@Nullable TypesBuilderData data,
|
||||
@Nullable Reader<T> reader,
|
||||
@Nullable Writer<T> writer
|
||||
) {
|
||||
this(data, reader, writer, null, null);
|
||||
}
|
||||
|
||||
public StaticComponentType(
|
||||
@Nullable TypesBuilderData data,
|
||||
@Nullable Decoder<T> decoder,
|
||||
@Nullable Encoder<T> encoder
|
||||
) {
|
||||
this(data, null, null, decoder, encoder);
|
||||
}
|
||||
|
||||
public StaticComponentType(
|
||||
@Nullable TypesBuilderData data,
|
||||
@Nullable Reader<T> reader,
|
||||
@Nullable Writer<T> writer,
|
||||
@Nullable Decoder<T> decoder,
|
||||
@Nullable Encoder<T> encoder
|
||||
) {
|
||||
super(data);
|
||||
this.reader = reader;
|
||||
this.writer = writer;
|
||||
this.decoder = decoder;
|
||||
this.encoder = encoder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T read(PacketWrapper<?> wrapper) {
|
||||
return this.reader != null ? this.reader.apply(wrapper) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(PacketWrapper<?> wrapper, T content) {
|
||||
if (this.writer != null) {
|
||||
this.writer.accept(wrapper, content);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public T decode(NBT nbt, ClientVersion version) {
|
||||
if (this.decoder != null) {
|
||||
return this.decoder.decode(nbt, version);
|
||||
}
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBT encode(T value, ClientVersion version) {
|
||||
if (this.encoder != null) {
|
||||
return this.encoder.encode(value, version);
|
||||
}
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
+5
@@ -87,4 +87,9 @@ public class ArmorTrim {
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.material, this.pattern, this.showInTooltip);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ArmorTrim{material=" + this.material + ", pattern=" + this.pattern + ", showInTooltip=" + this.showInTooltip + '}';
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -80,7 +80,7 @@ public class BannerLayers {
|
||||
|
||||
public static Layer read(PacketWrapper<?> wrapper) {
|
||||
BannerPattern pattern = wrapper.readMappedEntityOrDirect(
|
||||
BannerPatterns::getById, BannerPattern::readDirect);
|
||||
BannerPatterns.getRegistry(), BannerPattern::readDirect);
|
||||
DyeColor color = wrapper.readEnum(DyeColor.values());
|
||||
return new Layer(pattern, color);
|
||||
}
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2024 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.component.builtin.item;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
|
||||
public class CustomData {
|
||||
|
||||
private CustomData() {
|
||||
}
|
||||
|
||||
public static NBTCompound read(PacketWrapper<?> wrapper) {
|
||||
NBT nbt = wrapper.readNBTRaw();
|
||||
if (nbt instanceof NBTCompound) {
|
||||
return (NBTCompound) nbt;
|
||||
}
|
||||
if (nbt instanceof NBTString) {
|
||||
// TODO: parse nbt string
|
||||
}
|
||||
throw new UnsupportedOperationException("Unsupported custom data nbt type: " + nbt.getType());
|
||||
}
|
||||
|
||||
public static void write(PacketWrapper<?> wrapper, NBTCompound compound) {
|
||||
wrapper.writeNBT(compound);
|
||||
}
|
||||
}
|
||||
+33
-4
@@ -18,8 +18,11 @@
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.component.builtin.item;
|
||||
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.item.ItemStack;
|
||||
import com.github.retrooper.packetevents.protocol.potion.PotionEffect;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@@ -31,13 +34,25 @@ public class FoodProperties {
|
||||
private boolean canAlwaysEat;
|
||||
private float eatSeconds;
|
||||
private List<PossibleEffect> effects;
|
||||
private @Nullable ItemStack usingConvertsTo;
|
||||
|
||||
public FoodProperties(int nutrition, float saturation, boolean canAlwaysEat, float eatSeconds, List<PossibleEffect> effects) {
|
||||
public FoodProperties(
|
||||
int nutrition, float saturation, boolean canAlwaysEat,
|
||||
float eatSeconds, List<PossibleEffect> effects
|
||||
) {
|
||||
this(nutrition, saturation, canAlwaysEat, eatSeconds, effects, null);
|
||||
}
|
||||
|
||||
public FoodProperties(
|
||||
int nutrition, float saturation, boolean canAlwaysEat, float eatSeconds,
|
||||
List<PossibleEffect> effects, @Nullable ItemStack usingConvertsTo
|
||||
) {
|
||||
this.nutrition = nutrition;
|
||||
this.saturation = saturation;
|
||||
this.canAlwaysEat = canAlwaysEat;
|
||||
this.eatSeconds = eatSeconds;
|
||||
this.effects = effects;
|
||||
this.usingConvertsTo = usingConvertsTo;
|
||||
}
|
||||
|
||||
public static FoodProperties read(PacketWrapper<?> wrapper) {
|
||||
@@ -46,7 +61,9 @@ public class FoodProperties {
|
||||
boolean canAlwaysEat = wrapper.readBoolean();
|
||||
float eatSeconds = wrapper.readFloat();
|
||||
List<PossibleEffect> effects = wrapper.readList(PossibleEffect::read);
|
||||
return new FoodProperties(nutrition, saturation, canAlwaysEat, eatSeconds, effects);
|
||||
ItemStack usingConvertsTo = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21)
|
||||
? wrapper.readOptional(PacketWrapper::readItemStack) : null;
|
||||
return new FoodProperties(nutrition, saturation, canAlwaysEat, eatSeconds, effects, usingConvertsTo);
|
||||
}
|
||||
|
||||
public static void write(PacketWrapper<?> wrapper, FoodProperties props) {
|
||||
@@ -55,6 +72,9 @@ public class FoodProperties {
|
||||
wrapper.writeBoolean(props.canAlwaysEat);
|
||||
wrapper.writeFloat(props.eatSeconds);
|
||||
wrapper.writeList(props.effects, PossibleEffect::write);
|
||||
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21)) {
|
||||
wrapper.writeOptional(props.usingConvertsTo, PacketWrapper::writeItemStack);
|
||||
}
|
||||
}
|
||||
|
||||
public int getNutrition() {
|
||||
@@ -101,6 +121,14 @@ public class FoodProperties {
|
||||
this.effects = effects;
|
||||
}
|
||||
|
||||
public @Nullable ItemStack getUsingConvertsTo() {
|
||||
return this.usingConvertsTo;
|
||||
}
|
||||
|
||||
public void setUsingConvertsTo(@Nullable ItemStack usingConvertsTo) {
|
||||
this.usingConvertsTo = usingConvertsTo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
@@ -110,12 +138,13 @@ public class FoodProperties {
|
||||
if (Float.compare(that.saturation, this.saturation) != 0) return false;
|
||||
if (this.canAlwaysEat != that.canAlwaysEat) return false;
|
||||
if (Float.compare(that.eatSeconds, this.eatSeconds) != 0) return false;
|
||||
return this.effects.equals(that.effects);
|
||||
if (!this.effects.equals(that.effects)) return false;
|
||||
return Objects.equals(this.usingConvertsTo, that.usingConvertsTo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.nutrition, this.saturation, this.canAlwaysEat, this.eatSeconds, this.effects);
|
||||
return Objects.hash(this.nutrition, this.saturation, this.canAlwaysEat, this.eatSeconds, this.effects, this.usingConvertsTo);
|
||||
}
|
||||
|
||||
public static class PossibleEffect {
|
||||
|
||||
+3
-2
@@ -104,8 +104,9 @@ public class ItemAdventurePredicate {
|
||||
public static BlockPredicate read(PacketWrapper<?> wrapper) {
|
||||
MappedEntitySet<StateType.Mapped> blocks = wrapper.readOptional(
|
||||
ew -> MappedEntitySet.read(ew, StateTypes::getMappedById));
|
||||
List<PropertyMatcher> properties = wrapper.readList(PropertyMatcher::read);
|
||||
NBTCompound nbt = wrapper.readNBT();
|
||||
List<PropertyMatcher> properties = wrapper.readOptional(
|
||||
ew -> wrapper.readList(PropertyMatcher::read));
|
||||
NBTCompound nbt = wrapper.readOptional(PacketWrapper::readNBT);
|
||||
return new BlockPredicate(blocks, properties, nbt);
|
||||
}
|
||||
|
||||
|
||||
+64
-16
@@ -18,10 +18,15 @@
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.component.builtin.item;
|
||||
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.attribute.Attribute;
|
||||
import com.github.retrooper.packetevents.protocol.attribute.AttributeOperation;
|
||||
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerUpdateAttributes.PropertyModifier;
|
||||
import net.kyori.adventure.util.Index;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -168,11 +173,16 @@ public class ItemAttributeModifiers {
|
||||
|
||||
public static class Modifier {
|
||||
|
||||
private UUID id;
|
||||
private String name;
|
||||
private UUID id; // removed in 1.21
|
||||
private String name; // ResourceLocation since 1.21
|
||||
private double value;
|
||||
private AttributeOperation operation;
|
||||
|
||||
public Modifier(ResourceLocation name, double value, AttributeOperation operation) {
|
||||
this(PropertyModifier.generateSemiUniqueId(name), name.toString(), value, operation);
|
||||
}
|
||||
|
||||
@ApiStatus.Obsolete
|
||||
public Modifier(UUID id, String name, double value, AttributeOperation operation) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
@@ -181,32 +191,56 @@ public class ItemAttributeModifiers {
|
||||
}
|
||||
|
||||
public static Modifier read(PacketWrapper<?> wrapper) {
|
||||
UUID id = wrapper.readUUID();
|
||||
String name = wrapper.readString();
|
||||
UUID id;
|
||||
String name;
|
||||
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21)) {
|
||||
ResourceLocation nameKey = wrapper.readIdentifier();
|
||||
name = nameKey.toString();
|
||||
id = PropertyModifier.generateSemiUniqueId(nameKey);
|
||||
} else {
|
||||
id = wrapper.readUUID();
|
||||
name = wrapper.readString();
|
||||
}
|
||||
double value = wrapper.readDouble();
|
||||
AttributeOperation operation = wrapper.readEnum(AttributeOperation.values());
|
||||
return new Modifier(id, name, value, operation);
|
||||
}
|
||||
|
||||
public static void write(PacketWrapper<?> wrapper, Modifier modifier) {
|
||||
wrapper.writeUUID(modifier.id);
|
||||
wrapper.writeString(modifier.name);
|
||||
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_21)) {
|
||||
wrapper.writeIdentifier(new ResourceLocation(modifier.name));
|
||||
} else {
|
||||
wrapper.writeUUID(modifier.id);
|
||||
wrapper.writeString(modifier.name);
|
||||
}
|
||||
wrapper.writeDouble(modifier.value);
|
||||
wrapper.writeEnum(modifier.operation);
|
||||
}
|
||||
|
||||
public ResourceLocation getNameKey() {
|
||||
return new ResourceLocation(this.name);
|
||||
}
|
||||
|
||||
public void setNameKey(ResourceLocation nameKey) {
|
||||
this.name = nameKey.toString();
|
||||
}
|
||||
|
||||
@ApiStatus.Obsolete
|
||||
public UUID getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@ApiStatus.Obsolete
|
||||
public void setId(UUID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@ApiStatus.Obsolete
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@ApiStatus.Obsolete
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
@@ -250,15 +284,29 @@ public class ItemAttributeModifiers {
|
||||
}
|
||||
|
||||
public enum EquipmentSlotGroup {
|
||||
ANY,
|
||||
MAINHAND,
|
||||
OFFHAND,
|
||||
HAND,
|
||||
FEET,
|
||||
LEGS,
|
||||
CHEST,
|
||||
HEAD,
|
||||
ARMOR,
|
||||
BODY,
|
||||
|
||||
ANY("any"),
|
||||
MAINHAND("mainhand"),
|
||||
OFFHAND("offhand"),
|
||||
HAND("hand"),
|
||||
FEET("feet"),
|
||||
LEGS("legs"),
|
||||
CHEST("chest"),
|
||||
HEAD("head"),
|
||||
ARMOR("armor"),
|
||||
BODY("body");
|
||||
|
||||
public static final Index<String, EquipmentSlotGroup> ID_INDEX = Index.create(
|
||||
EquipmentSlotGroup.class, EquipmentSlotGroup::getId);
|
||||
|
||||
private final String id;
|
||||
|
||||
EquipmentSlotGroup(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return this.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -47,9 +47,8 @@ public class ItemEnchantments implements Iterable<Map.Entry<EnchantmentType, Int
|
||||
}
|
||||
|
||||
public static ItemEnchantments read(PacketWrapper<?> wrapper) {
|
||||
ClientVersion version = wrapper.getServerVersion().toClientVersion();
|
||||
Map<EnchantmentType, Integer> enchantments = wrapper.readMap(
|
||||
ew -> EnchantmentTypes.getById(version, ew.readVarInt()),
|
||||
ew -> wrapper.readMappedEntity(EnchantmentTypes.getRegistry()),
|
||||
PacketWrapper::readVarInt
|
||||
);
|
||||
boolean showInTooltip = wrapper.readBoolean();
|
||||
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2024 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.component.builtin.item;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.item.jukebox.IJukeboxSong;
|
||||
import com.github.retrooper.packetevents.protocol.item.jukebox.JukeboxSong;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class ItemJukeboxPlayable {
|
||||
|
||||
private @Nullable IJukeboxSong song;
|
||||
private @Nullable ResourceLocation songKey;
|
||||
private boolean showInTooltip;
|
||||
|
||||
public ItemJukeboxPlayable(
|
||||
@Nullable JukeboxSong song,
|
||||
@Nullable ResourceLocation songKey,
|
||||
boolean showInTooltip
|
||||
) {
|
||||
this((IJukeboxSong) song, songKey, showInTooltip);
|
||||
}
|
||||
|
||||
public ItemJukeboxPlayable(
|
||||
@Nullable IJukeboxSong song,
|
||||
@Nullable ResourceLocation songKey,
|
||||
boolean showInTooltip
|
||||
) {
|
||||
if ((song == null) == (songKey == null)) {
|
||||
throw new IllegalStateException("Illegal state of both song and "
|
||||
+ "song key combined: " + song + " / " + songKey);
|
||||
}
|
||||
|
||||
this.song = song;
|
||||
this.songKey = songKey;
|
||||
this.showInTooltip = showInTooltip;
|
||||
}
|
||||
|
||||
public static ItemJukeboxPlayable read(PacketWrapper<?> wrapper) {
|
||||
IJukeboxSong song;
|
||||
ResourceLocation songKey;
|
||||
if (wrapper.readBoolean()) {
|
||||
song = IJukeboxSong.read(wrapper);
|
||||
songKey = null;
|
||||
} else {
|
||||
song = null;
|
||||
songKey = wrapper.readIdentifier();
|
||||
}
|
||||
boolean showInTooltip = wrapper.readBoolean();
|
||||
return new ItemJukeboxPlayable(song, songKey, showInTooltip);
|
||||
}
|
||||
|
||||
public static void write(PacketWrapper<?> wrapper, ItemJukeboxPlayable jukeboxPlayable) {
|
||||
if (jukeboxPlayable.song != null) {
|
||||
wrapper.writeBoolean(true);
|
||||
IJukeboxSong.write(wrapper, jukeboxPlayable.song);
|
||||
} else {
|
||||
assert jukeboxPlayable.songKey != null;
|
||||
wrapper.writeBoolean(false);
|
||||
wrapper.writeIdentifier(jukeboxPlayable.songKey);
|
||||
}
|
||||
wrapper.writeBoolean(jukeboxPlayable.showInTooltip);
|
||||
}
|
||||
|
||||
public @Nullable IJukeboxSong getJukeboxSong() {
|
||||
return this.song;
|
||||
}
|
||||
|
||||
public void setJukeboxSong(@Nullable JukeboxSong song) {
|
||||
this.song = song;
|
||||
this.songKey = null;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public @Nullable JukeboxSong getSong() {
|
||||
if (this.song == null) {
|
||||
return null;
|
||||
} else if (this.song instanceof JukeboxSong) {
|
||||
return (JukeboxSong) this.song;
|
||||
}
|
||||
return (JukeboxSong) this.song.copy(null);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setSong(JukeboxSong song) {
|
||||
this.song = song;
|
||||
this.songKey = null;
|
||||
}
|
||||
|
||||
public @Nullable ResourceLocation getSongKey() {
|
||||
return this.songKey;
|
||||
}
|
||||
|
||||
public void setSongKey(ResourceLocation songKey) {
|
||||
this.song = null;
|
||||
this.songKey = songKey;
|
||||
}
|
||||
|
||||
public boolean isShowInTooltip() {
|
||||
return this.showInTooltip;
|
||||
}
|
||||
|
||||
public void setShowInTooltip(boolean showInTooltip) {
|
||||
this.showInTooltip = showInTooltip;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof ItemJukeboxPlayable)) return false;
|
||||
ItemJukeboxPlayable that = (ItemJukeboxPlayable) obj;
|
||||
if (this.showInTooltip != that.showInTooltip) return false;
|
||||
if (!Objects.equals(this.song, that.song)) return false;
|
||||
return Objects.equals(this.songKey, that.songKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.song, this.songKey, this.showInTooltip);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -122,7 +122,7 @@ public class ItemMapDecorations {
|
||||
compound.setTag("type", new NBTString(decoration.type.getName().toString()));
|
||||
compound.setTag("x", new NBTDouble(decoration.x));
|
||||
compound.setTag("z", new NBTDouble(decoration.z));
|
||||
compound.setTag("float", new NBTFloat(decoration.rotation));
|
||||
compound.setTag("rotation", new NBTFloat(decoration.rotation));
|
||||
}
|
||||
|
||||
public MapDecorationType getType() {
|
||||
|
||||
+21
-10
@@ -27,6 +27,7 @@ import java.util.ArrayDeque;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Queue;
|
||||
|
||||
public class PotDecorations {
|
||||
@@ -36,8 +37,13 @@ public class PotDecorations {
|
||||
private @Nullable ItemType right;
|
||||
private @Nullable ItemType front;
|
||||
|
||||
private PotDecorations(Queue<ItemType> items) {
|
||||
this(items.poll(), items.poll(), items.poll(), items.poll());
|
||||
private PotDecorations(Queue<Optional<ItemType>> items) {
|
||||
this(
|
||||
items.isEmpty() ? null : items.remove().orElse(null),
|
||||
items.isEmpty() ? null : items.remove().orElse(null),
|
||||
items.isEmpty() ? null : items.remove().orElse(null),
|
||||
items.isEmpty() ? null : items.remove().orElse(null)
|
||||
);
|
||||
}
|
||||
|
||||
public PotDecorations(
|
||||
@@ -52,23 +58,28 @@ public class PotDecorations {
|
||||
this.front = front;
|
||||
}
|
||||
|
||||
private List<ItemType> asList() {
|
||||
return Arrays.asList(this.back, this.left, this.right, this.front);
|
||||
private List<Optional<ItemType>> asList() {
|
||||
return Arrays.asList(
|
||||
Optional.ofNullable(this.back),
|
||||
Optional.ofNullable(this.left),
|
||||
Optional.ofNullable(this.right),
|
||||
Optional.ofNullable(this.front)
|
||||
);
|
||||
}
|
||||
|
||||
private static @Nullable ItemType readItem(PacketWrapper<?> wrapper) {
|
||||
private static Optional<ItemType> readItem(PacketWrapper<?> wrapper) {
|
||||
ItemType type = wrapper.readMappedEntity(ItemTypes::getById);
|
||||
return type == ItemTypes.BRICK ? null : type;
|
||||
return type == ItemTypes.BRICK ? Optional.empty() : Optional.of(type);
|
||||
}
|
||||
|
||||
public static PotDecorations read(PacketWrapper<?> wrapper) {
|
||||
Queue<ItemType> items = wrapper.<ItemType, Queue<ItemType>>readCollection(
|
||||
ArrayDeque::new, PotDecorations::readItem);
|
||||
Queue<Optional<ItemType>> items = wrapper.<Optional<ItemType>, Queue<Optional<ItemType>>>
|
||||
readCollection(ArrayDeque::new, PotDecorations::readItem);
|
||||
return new PotDecorations(items);
|
||||
}
|
||||
|
||||
private static void writeItem(PacketWrapper<?> wrapper, @Nullable ItemType type) {
|
||||
wrapper.writeMappedEntity(type == null ? ItemTypes.BRICK : type);
|
||||
private static void writeItem(PacketWrapper<?> wrapper, Optional<ItemType> type) {
|
||||
wrapper.writeMappedEntity(type.orElse(ItemTypes.BRICK));
|
||||
}
|
||||
|
||||
public static void write(PacketWrapper<?> wrapper, PotDecorations decorations) {
|
||||
|
||||
+9
-5
@@ -39,11 +39,7 @@ import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
@@ -210,6 +206,14 @@ public class EntityDataTypes {
|
||||
public static final EntityDataType<Integer> WOLF_VARIANT =
|
||||
define("wolf_variant_type", readIntDeserializer(), writeIntSerializer());
|
||||
|
||||
/**
|
||||
* Returns an immutable view of the entity-data types.
|
||||
* @return Entity-Data Types
|
||||
*/
|
||||
public static Collection<EntityDataType<?>> values() {
|
||||
return Collections.unmodifiableCollection(ENTITY_DATA_TYPE_MAP.values());
|
||||
}
|
||||
|
||||
public static EntityDataType<?> getById(ClientVersion version, int id) {
|
||||
int index = TYPES_BUILDER.getDataIndex(version);
|
||||
Map<Integer, EntityDataType<?>> typeIdMap = ENTITY_DATA_TYPE_ID_MAP.get((byte) index);
|
||||
|
||||
+9
-3
@@ -24,9 +24,7 @@ import com.github.retrooper.packetevents.util.mappings.TypesBuilder;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.*;
|
||||
|
||||
public class EntityTypes {
|
||||
private static final Map<String, EntityType> ENTITY_TYPE_MAP = new HashMap<>();
|
||||
@@ -297,6 +295,14 @@ public class EntityTypes {
|
||||
public static final EntityType BREEZE_WIND_CHARGE = define("breeze_wind_charge", ABSTRACT_WIND_CHARGE);
|
||||
public static final EntityType OMINOUS_ITEM_SPAWNER = define("ominous_item_spawner", ENTITY);
|
||||
|
||||
/**
|
||||
* Returns an immutable view of the entity types.
|
||||
* @return Entity Types
|
||||
*/
|
||||
public static Collection<EntityType> values() {
|
||||
return Collections.unmodifiableCollection(ENTITY_TYPE_MAP.values());
|
||||
}
|
||||
|
||||
static {
|
||||
TYPES_BUILDER.unloadFileMappings();
|
||||
LEGACY_TYPES_BUILDER.unloadFileMappings();
|
||||
|
||||
+10
@@ -20,6 +20,8 @@ package com.github.retrooper.packetevents.protocol.entity.villager.type;
|
||||
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -62,4 +64,12 @@ public class VillagerTypes {
|
||||
public static final VillagerType SNOW = define(4, "minecraft:snow");
|
||||
public static final VillagerType SWAMP = define(5, "minecraft:swamp");
|
||||
public static final VillagerType TAIGA = define(6, "minecraft:taiga");
|
||||
|
||||
/**
|
||||
* Returns an immutable view of the villager types.
|
||||
* @return Villager Types
|
||||
*/
|
||||
public static Collection<VillagerType> values() {
|
||||
return Collections.unmodifiableCollection(VILLAGER_TYPE_MAP.values());
|
||||
}
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2024 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.entity.wolfvariant;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.mapper.AbstractMappedEntity;
|
||||
import com.github.retrooper.packetevents.protocol.mapper.MappedEntitySet;
|
||||
import com.github.retrooper.packetevents.protocol.world.biome.Biome;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class StaticWolfVariant extends AbstractMappedEntity implements WolfVariant {
|
||||
|
||||
private final ResourceLocation wildTexture;
|
||||
private final ResourceLocation tameTexture;
|
||||
private final ResourceLocation angryTexture;
|
||||
private final MappedEntitySet<Biome> biomes;
|
||||
|
||||
public StaticWolfVariant(
|
||||
ResourceLocation wildTexture,
|
||||
ResourceLocation tameTexture,
|
||||
ResourceLocation angryTexture,
|
||||
MappedEntitySet<Biome> biomes
|
||||
) {
|
||||
this(null, wildTexture, tameTexture, angryTexture, biomes);
|
||||
}
|
||||
|
||||
public StaticWolfVariant(
|
||||
@Nullable TypesBuilderData data,
|
||||
ResourceLocation wildTexture,
|
||||
ResourceLocation tameTexture,
|
||||
ResourceLocation angryTexture,
|
||||
MappedEntitySet<Biome> biomes
|
||||
) {
|
||||
super(data);
|
||||
this.wildTexture = wildTexture;
|
||||
this.tameTexture = tameTexture;
|
||||
this.angryTexture = angryTexture;
|
||||
this.biomes = biomes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WolfVariant copy(@Nullable TypesBuilderData newData) {
|
||||
return new StaticWolfVariant(newData, this.wildTexture, this.tameTexture, this.angryTexture, this.biomes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getWildTexture() {
|
||||
return this.wildTexture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getTameTexture() {
|
||||
return this.tameTexture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getAngryTexture() {
|
||||
return this.angryTexture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappedEntitySet<Biome> getBiomes() {
|
||||
return this.biomes;
|
||||
}
|
||||
|
||||
public boolean deepEquals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof StaticWolfVariant)) return false;
|
||||
if (!super.equals(obj)) return false;
|
||||
StaticWolfVariant that = (StaticWolfVariant) obj;
|
||||
if (!this.wildTexture.equals(that.wildTexture)) return false;
|
||||
if (!this.tameTexture.equals(that.tameTexture)) return false;
|
||||
if (!this.angryTexture.equals(that.angryTexture)) return false;
|
||||
return this.biomes.equals(that.biomes);
|
||||
}
|
||||
|
||||
public int deepHashCode() {
|
||||
return Objects.hash(super.hashCode(), this.wildTexture, this.tameTexture, this.angryTexture, this.biomes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StaticWolfVariant{wildTexture=" + this.wildTexture + ", tameTexture=" + this.tameTexture + ", angryTexture=" + this.angryTexture + ", biomes=" + this.biomes + '}';
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2024 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.entity.wolfvariant;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.mapper.CopyableEntity;
|
||||
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
|
||||
import com.github.retrooper.packetevents.protocol.mapper.MappedEntitySet;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.world.biome.Biome;
|
||||
import com.github.retrooper.packetevents.protocol.world.biome.Biomes;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface WolfVariant extends MappedEntity, CopyableEntity<WolfVariant> {
|
||||
|
||||
ResourceLocation getWildTexture();
|
||||
|
||||
ResourceLocation getTameTexture();
|
||||
|
||||
ResourceLocation getAngryTexture();
|
||||
|
||||
MappedEntitySet<Biome> getBiomes();
|
||||
|
||||
static WolfVariant decode(NBT nbt, ClientVersion version, @Nullable TypesBuilderData data) {
|
||||
NBTCompound compound = (NBTCompound) nbt;
|
||||
ResourceLocation wildTexture = new ResourceLocation(compound.getStringTagValueOrThrow("wild_texture"));
|
||||
ResourceLocation tameTexture = new ResourceLocation(compound.getStringTagValueOrThrow("tame_texture"));
|
||||
ResourceLocation angryTexture = new ResourceLocation(compound.getStringTagValueOrThrow("angry_texture"));
|
||||
MappedEntitySet<Biome> biomes = MappedEntitySet.decode(
|
||||
compound.getTagOrThrow("biomes"), version, Biomes.getRegistry());
|
||||
return new StaticWolfVariant(data, wildTexture, tameTexture, angryTexture, biomes);
|
||||
}
|
||||
|
||||
static NBT encode(WolfVariant variant, ClientVersion version) {
|
||||
NBTCompound compound = new NBTCompound();
|
||||
compound.setTag("wild_texture", new NBTString(variant.getWildTexture().toString()));
|
||||
compound.setTag("tame_texture", new NBTString(variant.getTameTexture().toString()));
|
||||
compound.setTag("angry_texture", new NBTString(variant.getAngryTexture().toString()));
|
||||
compound.setTag("biomes", MappedEntitySet.encode(variant.getBiomes(), version));
|
||||
return compound;
|
||||
}
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2024 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.entity.wolfvariant;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.mapper.MappedEntitySet;
|
||||
import com.github.retrooper.packetevents.protocol.world.biome.Biome;
|
||||
import com.github.retrooper.packetevents.protocol.world.biome.Biomes;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public final class WolfVariants {
|
||||
|
||||
private static final VersionedRegistry<WolfVariant> REGISTRY = new VersionedRegistry<>(
|
||||
"wolf_variant", "entity/wolf_variant_mappings");
|
||||
|
||||
private WolfVariants() {
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static WolfVariant define(String key, MappedEntitySet<Biome> biomes) {
|
||||
return define(key, "wolf_" + key, biomes);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static WolfVariant define(String key, String assetId, MappedEntitySet<Biome> biomes) {
|
||||
return define(key, ResourceLocation.minecraft("entity/wolf/" + assetId),
|
||||
ResourceLocation.minecraft("entity/wolf/" + assetId + "_tame"),
|
||||
ResourceLocation.minecraft("entity/wolf/" + assetId + "_angry"), biomes);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static WolfVariant define(
|
||||
String key,
|
||||
ResourceLocation wildTexture,
|
||||
ResourceLocation tameTexture,
|
||||
ResourceLocation angryTexture,
|
||||
MappedEntitySet<Biome> biomes
|
||||
) {
|
||||
return REGISTRY.define(key, data -> new StaticWolfVariant(
|
||||
data, wildTexture, tameTexture, angryTexture, biomes));
|
||||
}
|
||||
|
||||
public static VersionedRegistry<WolfVariant> getRegistry() {
|
||||
return REGISTRY;
|
||||
}
|
||||
|
||||
public static final WolfVariant PALE = define("pale", "wolf",
|
||||
new MappedEntitySet<>(Arrays.asList(Biomes.TAIGA)));
|
||||
public static final WolfVariant SPOTTED = define("spotted",
|
||||
new MappedEntitySet<>(ResourceLocation.minecraft("is_savanna")));
|
||||
public static final WolfVariant SNOWY = define("snowy",
|
||||
new MappedEntitySet<>(Arrays.asList(Biomes.GROVE)));
|
||||
public static final WolfVariant BLACK = define("black",
|
||||
new MappedEntitySet<>(Arrays.asList(Biomes.OLD_GROWTH_PINE_TAIGA)));
|
||||
public static final WolfVariant ASHEN = define("ashen",
|
||||
new MappedEntitySet<>(Arrays.asList(Biomes.SNOWY_TAIGA)));
|
||||
public static final WolfVariant RUSTY = define("rusty",
|
||||
new MappedEntitySet<>(ResourceLocation.minecraft("is_jungle")));
|
||||
public static final WolfVariant WOODS = define("woods",
|
||||
new MappedEntitySet<>(Arrays.asList(Biomes.FOREST)));
|
||||
public static final WolfVariant CHESTNUT = define("chestnut",
|
||||
new MappedEntitySet<>(Arrays.asList(Biomes.OLD_GROWTH_SPRUCE_TAIGA)));
|
||||
public static final WolfVariant STRIPED = define("striped",
|
||||
new MappedEntitySet<>(ResourceLocation.minecraft("is_badlands")));
|
||||
|
||||
static {
|
||||
REGISTRY.unloadMappings();
|
||||
}
|
||||
}
|
||||
@@ -21,19 +21,23 @@ package com.github.retrooper.packetevents.protocol.item;
|
||||
import com.github.retrooper.packetevents.protocol.component.ComponentType;
|
||||
import com.github.retrooper.packetevents.protocol.component.ComponentTypes;
|
||||
import com.github.retrooper.packetevents.protocol.component.PatchableComponentMap;
|
||||
import com.github.retrooper.packetevents.protocol.component.StaticComponentMap;
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemEnchantments;
|
||||
import com.github.retrooper.packetevents.protocol.item.enchantment.Enchantment;
|
||||
import com.github.retrooper.packetevents.protocol.item.enchantment.type.EnchantmentType;
|
||||
import com.github.retrooper.packetevents.protocol.item.enchantment.type.EnchantmentTypes;
|
||||
import com.github.retrooper.packetevents.protocol.item.type.ItemType;
|
||||
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTInt;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTList;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTNumber;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTShort;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -80,6 +84,54 @@ public class ItemStack {
|
||||
updateCachedEmptyStatus();
|
||||
}
|
||||
|
||||
public static ItemStack decode(NBT nbt, ClientVersion version) {
|
||||
if (nbt instanceof NBTString) {
|
||||
ResourceLocation itemName = new ResourceLocation(((NBTString) nbt).getValue());
|
||||
return ItemStack.builder().type(ItemTypes.getByName(itemName.toString())).build();
|
||||
}
|
||||
NBTCompound compound = (NBTCompound) nbt;
|
||||
ItemStack.Builder builder = ItemStack.builder();
|
||||
|
||||
ResourceLocation itemName = Optional.ofNullable(compound.getStringTagValueOrNull("id")).map(Optional::of)
|
||||
.orElseGet(() -> Optional.ofNullable(compound.getStringTagValueOrNull("item")))
|
||||
.map(ResourceLocation::new).orElseThrow(() -> new IllegalArgumentException(
|
||||
"No item type specified: " + compound.getTags().keySet()));
|
||||
builder.type(ItemTypes.getByName(itemName.toString()));
|
||||
builder.nbt(compound.getCompoundTagOrNull("tag"));
|
||||
|
||||
Optional.ofNullable(compound.getNumberTagOrNull("Count")).map(Optional::of)
|
||||
.orElseGet(() -> Optional.ofNullable(compound.getNumberTagOrNull("count")))
|
||||
.map(NBTNumber::getAsInt).ifPresent(builder::amount);
|
||||
|
||||
// TODO components
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public static NBT encodeForParticle(ItemStack itemStack, ClientVersion version) {
|
||||
if (version.isNewerThanOrEquals(ClientVersion.V_1_20_5)) {
|
||||
boolean simple = itemStack.isEmpty()
|
||||
|| itemStack.components == null
|
||||
|| itemStack.components.getPatches().isEmpty();
|
||||
if (simple) {
|
||||
return new NBTString(itemStack.type.getName().toString());
|
||||
}
|
||||
}
|
||||
|
||||
NBTCompound compound = new NBTCompound();
|
||||
compound.setTag("id", new NBTString(itemStack.type.getName().toString()));
|
||||
if (version.isOlderThan(ClientVersion.V_1_20_5)) {
|
||||
compound.setTag("Count", new NBTInt(itemStack.amount));
|
||||
if (itemStack.nbt != null) {
|
||||
compound.setTag("tag", itemStack.nbt);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO components
|
||||
|
||||
return compound;
|
||||
}
|
||||
|
||||
public int getMaxStackSize() {
|
||||
return this.getComponentOr(MAX_STACK_SIZE,
|
||||
// fallback to legacy specified max stack size
|
||||
@@ -273,17 +325,15 @@ public class ItemStack {
|
||||
}
|
||||
|
||||
// check for components
|
||||
Optional<ItemEnchantments> optEnchantments = this.getComponent(ENCHANTMENTS);
|
||||
Optional<ItemEnchantments> optStoredEnchantments = this.getComponent(STORED_ENCHANTMENTS);
|
||||
if (optEnchantments.isPresent() || optStoredEnchantments.isPresent()) {
|
||||
ItemEnchantments enchantments = optEnchantments.orElse(ItemEnchantments.EMPTY);
|
||||
ItemEnchantments storedEnchantments = optStoredEnchantments.orElse(ItemEnchantments.EMPTY);
|
||||
ItemEnchantments enchantmentsComp = this.getComponentOr(ENCHANTMENTS, ItemEnchantments.EMPTY);
|
||||
ItemEnchantments storedEnchantmentsComp = this.getComponentOr(STORED_ENCHANTMENTS, ItemEnchantments.EMPTY);
|
||||
if (!enchantmentsComp.isEmpty() || !storedEnchantmentsComp.isEmpty()) {
|
||||
List<Enchantment> enchantmentsList = new ArrayList<>(
|
||||
enchantments.getEnchantmentCount() + storedEnchantments.getEnchantmentCount());
|
||||
for (Map.Entry<EnchantmentType, Integer> enchantment : enchantments) {
|
||||
enchantmentsComp.getEnchantmentCount() + storedEnchantmentsComp.getEnchantmentCount());
|
||||
for (Map.Entry<EnchantmentType, Integer> enchantment : enchantmentsComp) {
|
||||
enchantmentsList.add(new Enchantment(enchantment.getKey(), enchantment.getValue()));
|
||||
}
|
||||
for (Map.Entry<EnchantmentType, Integer> enchantment : storedEnchantments) {
|
||||
for (Map.Entry<EnchantmentType, Integer> enchantment : storedEnchantmentsComp) {
|
||||
enchantmentsList.add(new Enchantment(enchantment.getKey(), enchantment.getValue()));
|
||||
}
|
||||
return enchantmentsList;
|
||||
@@ -320,16 +370,16 @@ public class ItemStack {
|
||||
}
|
||||
|
||||
// check for components
|
||||
Optional<ItemEnchantments> optEnchantments = this.getComponent(ENCHANTMENTS);
|
||||
if (optEnchantments.isPresent()) {
|
||||
int level = optEnchantments.get().getEnchantmentLevel(enchantment);
|
||||
ItemEnchantments enchantmentsComp = this.getComponentOr(ENCHANTMENTS, ItemEnchantments.EMPTY);
|
||||
if (!enchantmentsComp.isEmpty()) {
|
||||
int level = enchantmentsComp.getEnchantmentLevel(enchantment);
|
||||
if (level > 0) {
|
||||
return level;
|
||||
}
|
||||
}
|
||||
Optional<ItemEnchantments> optStoredEnchantments = this.getComponent(STORED_ENCHANTMENTS);
|
||||
if (optStoredEnchantments.isPresent()) {
|
||||
int level = optStoredEnchantments.get().getEnchantmentLevel(enchantment);
|
||||
ItemEnchantments storedEnchantmentsComp = this.getComponentOr(STORED_ENCHANTMENTS, ItemEnchantments.EMPTY);
|
||||
if (!storedEnchantmentsComp.isEmpty()) {
|
||||
int level = storedEnchantmentsComp.getEnchantmentLevel(enchantment);
|
||||
if (level > 0) {
|
||||
return level;
|
||||
}
|
||||
@@ -496,11 +546,28 @@ public class ItemStack {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder nbt(String key, NBT tag) {
|
||||
if (this.nbt == null) {
|
||||
this.nbt = new NBTCompound();
|
||||
}
|
||||
this.nbt.setTag(key, tag);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder components(@Nullable PatchableComponentMap components) {
|
||||
this.components = components;
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> Builder component(ComponentType<T> type, @Nullable T value) {
|
||||
if (this.components == null) {
|
||||
this.components = new PatchableComponentMap(this.type == null
|
||||
? StaticComponentMap.SHARED_ITEM_COMPONENTS : this.type.getComponents());
|
||||
}
|
||||
this.components.set(type, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder legacyData(int legacyData) {
|
||||
this.legacyData = legacyData;
|
||||
return this;
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ public class ArmorMaterials {
|
||||
|
||||
@Override
|
||||
public int getId(ClientVersion version) {
|
||||
return TYPES_BUILDER.getDataIndex(version);
|
||||
return MappingHelper.getId(version, TYPES_BUILDER, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+22
-1
@@ -18,11 +18,18 @@
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.item.banner;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.mapper.CopyableEntity;
|
||||
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface BannerPattern extends MappedEntity {
|
||||
public interface BannerPattern extends MappedEntity, CopyableEntity<BannerPattern> {
|
||||
|
||||
ResourceLocation getAssetId();
|
||||
|
||||
@@ -38,4 +45,18 @@ public interface BannerPattern extends MappedEntity {
|
||||
wrapper.writeIdentifier(pattern.getAssetId());
|
||||
wrapper.writeString(pattern.getTranslationKey());
|
||||
}
|
||||
|
||||
static BannerPattern decode(NBT nbt, ClientVersion version, @Nullable TypesBuilderData data) {
|
||||
NBTCompound compound = (NBTCompound) nbt;
|
||||
ResourceLocation assetId = new ResourceLocation(compound.getStringTagValueOrThrow("asset_id"));
|
||||
String translationKey = compound.getStringTagValueOrThrow("translation_key");
|
||||
return new StaticBannerPattern(data, assetId, translationKey);
|
||||
}
|
||||
|
||||
static NBT encode(BannerPattern bannerPattern, ClientVersion version) {
|
||||
NBTCompound compound = new NBTCompound();
|
||||
compound.setTag("asset_id", new NBTString(bannerPattern.getAssetId().toString()));
|
||||
compound.setTag("translation_key", new NBTString(bannerPattern.getTranslationKey()));
|
||||
return compound;
|
||||
}
|
||||
}
|
||||
+33
-47
@@ -20,69 +20,42 @@ package com.github.retrooper.packetevents.protocol.item.banner;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.util.mappings.MappingHelper;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilder;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
|
||||
public class BannerPatterns {
|
||||
public final class BannerPatterns {
|
||||
|
||||
private static final Map<String, BannerPattern> PATTERN_TYPE_MAP = new HashMap<>();
|
||||
private static final Map<Byte, Map<Integer, BannerPattern>> PATTERN_TYPE_ID_MAP = new HashMap<>();
|
||||
private static final TypesBuilder TYPES_BUILDER = new TypesBuilder("item/item_banner_pattern_mappings");
|
||||
private static final VersionedRegistry<BannerPattern> REGISTRY = new VersionedRegistry<>(
|
||||
"banner_pattern", "item/item_banner_pattern_mappings");
|
||||
|
||||
private BannerPatterns() {
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static BannerPattern define(String key) {
|
||||
ResourceLocation assetId = ResourceLocation.minecraft(key);
|
||||
String translationKey = "block.minecraft.banner." + key;
|
||||
return define(key, assetId, translationKey);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static BannerPattern define(String key, ResourceLocation assetId, String translationKey) {
|
||||
TypesBuilderData data = TYPES_BUILDER.define(key);
|
||||
BannerPattern pattern = new BannerPattern() {
|
||||
@Override
|
||||
public ResourceLocation getAssetId() {
|
||||
return assetId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTranslationKey() {
|
||||
return translationKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getName() {
|
||||
return data.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId(ClientVersion version) {
|
||||
return TYPES_BUILDER.getDataIndex(version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof BannerPattern) {
|
||||
return getName().equals(((BannerPattern) obj).getName());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
MappingHelper.registerMapping(TYPES_BUILDER, PATTERN_TYPE_MAP, PATTERN_TYPE_ID_MAP, pattern);
|
||||
return pattern;
|
||||
return REGISTRY.define(key, data ->
|
||||
new StaticBannerPattern(data, assetId, translationKey));
|
||||
}
|
||||
|
||||
public static VersionedRegistry<BannerPattern> getRegistry() {
|
||||
return REGISTRY;
|
||||
}
|
||||
|
||||
// with key
|
||||
public static BannerPattern getByName(String name) {
|
||||
return PATTERN_TYPE_MAP.get(name);
|
||||
return REGISTRY.getByName(name);
|
||||
}
|
||||
|
||||
public static BannerPattern getById(ClientVersion version, int id) {
|
||||
int index = TYPES_BUILDER.getDataIndex(version);
|
||||
Map<Integer, BannerPattern> idMap = PATTERN_TYPE_ID_MAP.get((byte) index);
|
||||
return idMap.get(id);
|
||||
return REGISTRY.getById(version, id);
|
||||
}
|
||||
|
||||
public static final BannerPattern SQUARE_BOTTOM_LEFT = define("square_bottom_left");
|
||||
@@ -127,7 +100,20 @@ public class BannerPatterns {
|
||||
public static final BannerPattern PIGLIN = define("piglin");
|
||||
public static final BannerPattern DIAGONAL_LEFT = define("diagonal_left");
|
||||
|
||||
// Added with 1.21
|
||||
public static final BannerPattern FLOW = define("flow");
|
||||
public static final BannerPattern GUSTER = define("guster");
|
||||
|
||||
/**
|
||||
* Returns an immutable view of the banner patterns.
|
||||
*
|
||||
* @return Banner Patterns
|
||||
*/
|
||||
public static Collection<BannerPattern> values() {
|
||||
return REGISTRY.getEntries();
|
||||
}
|
||||
|
||||
static {
|
||||
TYPES_BUILDER.unloadFileMappings();
|
||||
REGISTRY.unloadMappings();
|
||||
}
|
||||
}
|
||||
+22
-21
@@ -18,21 +18,33 @@
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.item.banner;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.mapper.AbstractMappedEntity;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class StaticBannerPattern implements BannerPattern {
|
||||
public class StaticBannerPattern extends AbstractMappedEntity implements BannerPattern {
|
||||
|
||||
private final ResourceLocation assetId;
|
||||
private final String translationKey;
|
||||
|
||||
public StaticBannerPattern(ResourceLocation assetId, String translationKey) {
|
||||
this(null, assetId, translationKey);
|
||||
}
|
||||
|
||||
public StaticBannerPattern(@Nullable TypesBuilderData data, ResourceLocation assetId, String translationKey) {
|
||||
super(data);
|
||||
this.assetId = assetId;
|
||||
this.translationKey = translationKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BannerPattern copy(@Nullable TypesBuilderData newData) {
|
||||
return new StaticBannerPattern(newData, this.assetId, this.translationKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getAssetId() {
|
||||
return this.assetId;
|
||||
@@ -43,32 +55,21 @@ public class StaticBannerPattern implements BannerPattern {
|
||||
return this.translationKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getName() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId(ClientVersion version) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRegistered() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean deepEquals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof StaticBannerPattern)) return false;
|
||||
if (!super.equals(obj)) return false;
|
||||
StaticBannerPattern that = (StaticBannerPattern) obj;
|
||||
if (!this.assetId.equals(that.assetId)) return false;
|
||||
return this.translationKey.equals(that.translationKey);
|
||||
}
|
||||
|
||||
public int deepHashCode() {
|
||||
return Objects.hash(super.hashCode(), this.assetId, this.translationKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.assetId, this.translationKey);
|
||||
public String toString() {
|
||||
return "StaticBannerPattern{assetId=" + this.assetId + ", translationKey='" + this.translationKey + '\'' + '}';
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2024 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.item.enchantment;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTInt;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public final class EnchantmentCost {
|
||||
|
||||
private final int base;
|
||||
private final int perLevelAboveFirst;
|
||||
|
||||
public EnchantmentCost(int base, int perLevelAboveFirst) {
|
||||
this.base = base;
|
||||
this.perLevelAboveFirst = perLevelAboveFirst;
|
||||
}
|
||||
|
||||
public static EnchantmentCost decode(NBT nbt, ClientVersion version) {
|
||||
NBTCompound compound = (NBTCompound) nbt;
|
||||
int base = compound.getNumberTagOrThrow("base").getAsInt();
|
||||
int perLevelAboveFirst = compound.getNumberTagOrThrow("per_level_above_first").getAsInt();
|
||||
return new EnchantmentCost(base, perLevelAboveFirst);
|
||||
}
|
||||
|
||||
public static NBT encode(EnchantmentCost cost, ClientVersion version) {
|
||||
NBTCompound compound = new NBTCompound();
|
||||
compound.setTag("base", new NBTInt(cost.base));
|
||||
compound.setTag("per_level_above_first", new NBTInt(cost.perLevelAboveFirst));
|
||||
return compound;
|
||||
}
|
||||
|
||||
public int getBase() {
|
||||
return this.base;
|
||||
}
|
||||
|
||||
public int getPerLevelAboveFirst() {
|
||||
return this.perLevelAboveFirst;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof EnchantmentCost)) return false;
|
||||
EnchantmentCost that = (EnchantmentCost) obj;
|
||||
if (this.base != that.base) return false;
|
||||
return this.perLevelAboveFirst == that.perLevelAboveFirst;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.base, this.perLevelAboveFirst);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "EnchantmentCost{base=" + this.base + ", perLevelAboveFirst=" + this.perLevelAboveFirst + '}';
|
||||
}
|
||||
}
|
||||
+175
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2024 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.item.enchantment;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.component.builtin.item.ItemAttributeModifiers.EquipmentSlotGroup;
|
||||
import com.github.retrooper.packetevents.protocol.item.type.ItemType;
|
||||
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
|
||||
import com.github.retrooper.packetevents.protocol.mapper.MappedEntitySet;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTInt;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTList;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import static com.github.retrooper.packetevents.util.adventure.AdventureIndexUtil.indexValueOrThrow;
|
||||
|
||||
public final class EnchantmentDefinition {
|
||||
|
||||
private final MappedEntitySet<ItemType> supportedItems;
|
||||
private final Optional<MappedEntitySet<ItemType>> primaryItems;
|
||||
private final int weight;
|
||||
private final int maxLevel;
|
||||
private final EnchantmentCost minCost;
|
||||
private final EnchantmentCost maxCost;
|
||||
private final int anvilCost;
|
||||
private final List<EquipmentSlotGroup> slots;
|
||||
|
||||
public EnchantmentDefinition(
|
||||
MappedEntitySet<ItemType> supportedItems,
|
||||
Optional<MappedEntitySet<ItemType>> primaryItems,
|
||||
int weight, int maxLevel,
|
||||
EnchantmentCost minCost, EnchantmentCost maxCost,
|
||||
int anvilCost, List<EquipmentSlotGroup> slots
|
||||
) {
|
||||
this.supportedItems = supportedItems;
|
||||
this.primaryItems = primaryItems;
|
||||
this.weight = weight;
|
||||
this.maxLevel = maxLevel;
|
||||
this.minCost = minCost;
|
||||
this.maxCost = maxCost;
|
||||
this.anvilCost = anvilCost;
|
||||
this.slots = slots;
|
||||
}
|
||||
|
||||
public static EnchantmentDefinition decode(NBT nbt, ClientVersion version) {
|
||||
NBTCompound compound = (NBTCompound) nbt;
|
||||
MappedEntitySet<ItemType> supportedItems = MappedEntitySet.decode(
|
||||
compound.getTagOrThrow("supported_items"), version, ItemTypes.getRegistry());
|
||||
Optional<MappedEntitySet<ItemType>> primaryItems = Optional.ofNullable(compound.getTagOrNull("primary_items"))
|
||||
.map(items -> MappedEntitySet.decode(items, version, ItemTypes.getRegistry()));
|
||||
int weight = compound.getNumberTagOrThrow("weight").getAsInt();
|
||||
int maxLevel = compound.getNumberTagOrThrow("max_level").getAsInt();
|
||||
EnchantmentCost minCost = EnchantmentCost.decode(compound.getTagOrThrow("min_cost"), version);
|
||||
EnchantmentCost maxCost = EnchantmentCost.decode(compound.getTagOrThrow("max_cost"), version);
|
||||
int anvilCost = compound.getNumberTagOrThrow("anvil_cost").getAsInt();
|
||||
|
||||
NBT slotsTag = compound.getTagOrThrow("slots");
|
||||
List<EquipmentSlotGroup> slots;
|
||||
if (slotsTag instanceof NBTList<?>) {
|
||||
NBTList<?> slotsTagList = (NBTList<?>) slotsTag;
|
||||
slots = new ArrayList<>(slotsTagList.size());
|
||||
for (NBT tag : slotsTagList.getTags()) {
|
||||
String slotGroupId = ((NBTString) tag).getValue();
|
||||
slots.add(indexValueOrThrow(EquipmentSlotGroup.ID_INDEX, slotGroupId));
|
||||
}
|
||||
} else {
|
||||
String slotGroupId = ((NBTString) slotsTag).getValue();
|
||||
EquipmentSlotGroup slotGroup = indexValueOrThrow(EquipmentSlotGroup.ID_INDEX, slotGroupId);
|
||||
slots = Collections.singletonList(slotGroup);
|
||||
}
|
||||
|
||||
return new EnchantmentDefinition(supportedItems, primaryItems, weight,
|
||||
maxLevel, minCost, maxCost, anvilCost, slots);
|
||||
}
|
||||
|
||||
public static NBT encode(EnchantmentDefinition definition, ClientVersion version) {
|
||||
NBTList<NBTString> slotsTag = NBTList.createStringList();
|
||||
for (EquipmentSlotGroup slot : definition.slots) {
|
||||
slotsTag.addTag(new NBTString(slot.getId()));
|
||||
}
|
||||
|
||||
NBTCompound compound = new NBTCompound();
|
||||
compound.setTag("supported_items", MappedEntitySet.encode(
|
||||
definition.supportedItems, version));
|
||||
definition.primaryItems.ifPresent(set -> compound.setTag(
|
||||
"primary_items", MappedEntitySet.encode(set, version)));
|
||||
compound.setTag("weight", new NBTInt(definition.weight));
|
||||
compound.setTag("max_level", new NBTInt(definition.maxLevel));
|
||||
compound.setTag("min_cost", EnchantmentCost.encode(definition.minCost, version));
|
||||
compound.setTag("max_cost", EnchantmentCost.encode(definition.maxCost, version));
|
||||
compound.setTag("anvil_cost", new NBTInt(definition.anvilCost));
|
||||
compound.setTag("slots", slotsTag);
|
||||
return compound;
|
||||
}
|
||||
|
||||
public MappedEntitySet<ItemType> getSupportedItems() {
|
||||
return this.supportedItems;
|
||||
}
|
||||
|
||||
public Optional<MappedEntitySet<ItemType>> getPrimaryItems() {
|
||||
return this.primaryItems;
|
||||
}
|
||||
|
||||
public int getWeight() {
|
||||
return this.weight;
|
||||
}
|
||||
|
||||
public int getMaxLevel() {
|
||||
return this.maxLevel;
|
||||
}
|
||||
|
||||
public EnchantmentCost getMinCost() {
|
||||
return this.minCost;
|
||||
}
|
||||
|
||||
public EnchantmentCost getMaxCost() {
|
||||
return this.maxCost;
|
||||
}
|
||||
|
||||
public int getAnvilCost() {
|
||||
return this.anvilCost;
|
||||
}
|
||||
|
||||
public List<EquipmentSlotGroup> getSlots() {
|
||||
return this.slots;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof EnchantmentDefinition)) return false;
|
||||
EnchantmentDefinition that = (EnchantmentDefinition) obj;
|
||||
if (this.weight != that.weight) return false;
|
||||
if (this.maxLevel != that.maxLevel) return false;
|
||||
if (this.anvilCost != that.anvilCost) return false;
|
||||
if (!this.supportedItems.equals(that.supportedItems)) return false;
|
||||
if (!this.primaryItems.equals(that.primaryItems)) return false;
|
||||
if (!this.minCost.equals(that.minCost)) return false;
|
||||
if (!this.maxCost.equals(that.maxCost)) return false;
|
||||
return this.slots.equals(that.slots);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.supportedItems, this.primaryItems, this.weight, this.maxLevel, this.minCost, this.maxCost, this.anvilCost, this.slots);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "EnchantmentDefinition{supportedItems=" + this.supportedItems + ", primaryItems=" + this.primaryItems + ", weight=" + this.weight + ", maxLevel=" + this.maxLevel + ", minCost=" + this.minCost + ", maxCost=" + this.maxCost + ", anvilCost=" + this.anvilCost + ", slots=" + this.slots + '}';
|
||||
}
|
||||
}
|
||||
+50
-1
@@ -18,7 +18,56 @@
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.item.enchantment.type;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.component.EnchantEffectComponentTypes;
|
||||
import com.github.retrooper.packetevents.protocol.component.IComponentMap;
|
||||
import com.github.retrooper.packetevents.protocol.component.StaticComponentMap;
|
||||
import com.github.retrooper.packetevents.protocol.item.enchantment.EnchantmentDefinition;
|
||||
import com.github.retrooper.packetevents.protocol.mapper.CopyableEntity;
|
||||
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
|
||||
import com.github.retrooper.packetevents.protocol.mapper.MappedEntitySet;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.util.adventure.AdventureSerializer;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface EnchantmentType extends MappedEntity {
|
||||
import java.util.Optional;
|
||||
|
||||
public interface EnchantmentType extends MappedEntity, CopyableEntity<EnchantmentType> {
|
||||
|
||||
Component getDescription();
|
||||
|
||||
EnchantmentDefinition getDefinition();
|
||||
|
||||
MappedEntitySet<EnchantmentType> getExclusiveSet();
|
||||
|
||||
StaticComponentMap getEffects();
|
||||
|
||||
static EnchantmentType decode(NBT nbt, ClientVersion version, @Nullable TypesBuilderData data) {
|
||||
NBTCompound compound = (NBTCompound) nbt;
|
||||
Component description = AdventureSerializer.fromNbt(compound.getTagOrThrow("description"));
|
||||
EnchantmentDefinition definition = EnchantmentDefinition.decode(compound, version);
|
||||
MappedEntitySet<EnchantmentType> exclusiveSet = Optional.ofNullable(compound.getTagOrNull("exclusive_set"))
|
||||
.map(tag -> MappedEntitySet.decode(tag, version, EnchantmentTypes.getRegistry()))
|
||||
.orElseGet(MappedEntitySet::createEmpty);
|
||||
StaticComponentMap effects = Optional.ofNullable(compound.getTagOrNull("effects"))
|
||||
.map(tag -> IComponentMap.decode(tag, version,
|
||||
EnchantEffectComponentTypes.getRegistry()))
|
||||
.orElse(StaticComponentMap.EMPTY);
|
||||
return new StaticEnchantmentType(data, description, definition, exclusiveSet, effects);
|
||||
}
|
||||
|
||||
static NBT encode(EnchantmentType type, ClientVersion version) {
|
||||
NBTCompound compound = (NBTCompound) EnchantmentDefinition.encode(type.getDefinition(), version);
|
||||
compound.setTag("description", AdventureSerializer.toNbt(type.getDescription()));
|
||||
if (!type.getExclusiveSet().isEmpty()) {
|
||||
compound.setTag("exclusive_set", MappedEntitySet.encode(type.getExclusiveSet(), version));
|
||||
}
|
||||
if (!type.getEffects().isEmpty()) {
|
||||
compound.setTag("effects", IComponentMap.encode(type.getEffects(), version));
|
||||
}
|
||||
return compound;
|
||||
}
|
||||
}
|
||||
+45
-37
@@ -18,17 +18,21 @@
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.item.enchantment.type;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.serializer.SequentialNBTReader;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.util.mappings.MappingHelper;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilder;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class EnchantmentTypes {
|
||||
public final class EnchantmentTypes {
|
||||
|
||||
private static final Map<String, String> STRING_UPDATER = new HashMap<>();
|
||||
|
||||
@@ -37,47 +41,50 @@ public class EnchantmentTypes {
|
||||
STRING_UPDATER.put("minecraft:sweeping", "minecraft:sweeping_edge");
|
||||
}
|
||||
|
||||
private static final Map<String, EnchantmentType> ENCHANTMENT_TYPE_MAPPINGS = new HashMap<>();
|
||||
private static final Map<Byte, Map<Integer, EnchantmentType>> ENCHANTMENT_TYPE_ID_MAPPINGS = new HashMap<>();
|
||||
private static final TypesBuilder TYPES_BUILDER = new TypesBuilder("enchantment/enchantment_type_mappings");
|
||||
// load data from file, enchantment types are too complex to define in code here
|
||||
private static final Map<ResourceLocation, NBTCompound> ENCHANTMENT_DATA;
|
||||
|
||||
public static EnchantmentType define(String key) {
|
||||
TypesBuilderData data = TYPES_BUILDER.define(key);
|
||||
EnchantmentType enchantmentType = new EnchantmentType() {
|
||||
@Override
|
||||
public ResourceLocation getName() {
|
||||
return data.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId(ClientVersion version) {
|
||||
return MappingHelper.getId(version, TYPES_BUILDER, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof EnchantmentType) {
|
||||
return getName() == ((EnchantmentType) obj).getName();
|
||||
static {
|
||||
ENCHANTMENT_DATA = new HashMap<>();
|
||||
try (SequentialNBTReader.Compound dataTag = MappingHelper.decompress("mappings/enchantment/enchantment_type_data")) {
|
||||
while (dataTag.hasNext()) {
|
||||
Map.Entry<String, NBT> entry = dataTag.next();
|
||||
if (entry.getKey().equals("version")) {
|
||||
continue; // skip version field
|
||||
}
|
||||
return false;
|
||||
ResourceLocation enchantKey = new ResourceLocation(entry.getKey());
|
||||
ENCHANTMENT_DATA.put(enchantKey, ((SequentialNBTReader.Compound) entry.getValue()).readFully());
|
||||
}
|
||||
};
|
||||
|
||||
MappingHelper.registerMapping(TYPES_BUILDER, ENCHANTMENT_TYPE_MAPPINGS, ENCHANTMENT_TYPE_ID_MAPPINGS, enchantmentType);
|
||||
return enchantmentType;
|
||||
} catch (IOException exception) {
|
||||
throw new RuntimeException("Error while reading enchantment type data", exception);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static EnchantmentType getByName(String name) {
|
||||
private static final VersionedRegistry<EnchantmentType> REGISTRY = new VersionedRegistry<>(
|
||||
"enchantment", "enchantment/enchantment_type_mappings");
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static EnchantmentType define(String key) {
|
||||
return REGISTRY.define(key, data -> {
|
||||
NBTCompound dataTag = ENCHANTMENT_DATA.get(data.getName());
|
||||
if (dataTag == null) {
|
||||
throw new IllegalArgumentException("Can't define enchantment " + data.getName() + ", no data found");
|
||||
}
|
||||
return EnchantmentType.decode(dataTag, ClientVersion.getLatest(), data);
|
||||
});
|
||||
}
|
||||
|
||||
public static VersionedRegistry<EnchantmentType> getRegistry() {
|
||||
return REGISTRY;
|
||||
}
|
||||
|
||||
public static @Nullable EnchantmentType getByName(String name) {
|
||||
String fixedName = STRING_UPDATER.getOrDefault(name, name);
|
||||
return ENCHANTMENT_TYPE_MAPPINGS.get(fixedName);
|
||||
return REGISTRY.getByName(fixedName);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static EnchantmentType getById(ClientVersion version, int id) {
|
||||
int index = TYPES_BUILDER.getDataIndex(version);
|
||||
Map<Integer, EnchantmentType> typeIdMap = ENCHANTMENT_TYPE_ID_MAPPINGS.get((byte) index);
|
||||
return typeIdMap.get(id);
|
||||
public static @Nullable EnchantmentType getById(ClientVersion version, int id) {
|
||||
return REGISTRY.getById(version, id);
|
||||
}
|
||||
|
||||
public static final EnchantmentType ALL_DAMAGE_PROTECTION = define("protection");
|
||||
@@ -126,6 +133,7 @@ public class EnchantmentTypes {
|
||||
public static final EnchantmentType WIND_BURST = define("wind_burst");
|
||||
|
||||
static {
|
||||
TYPES_BUILDER.unloadFileMappings();
|
||||
ENCHANTMENT_DATA.clear();
|
||||
REGISTRY.unloadMappings();
|
||||
}
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2024 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.item.enchantment.type;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.component.StaticComponentMap;
|
||||
import com.github.retrooper.packetevents.protocol.item.enchantment.EnchantmentDefinition;
|
||||
import com.github.retrooper.packetevents.protocol.mapper.AbstractMappedEntity;
|
||||
import com.github.retrooper.packetevents.protocol.mapper.MappedEntitySet;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class StaticEnchantmentType extends AbstractMappedEntity implements EnchantmentType {
|
||||
|
||||
private final Component description;
|
||||
private final EnchantmentDefinition definition;
|
||||
private final MappedEntitySet<EnchantmentType> exclusiveSet;
|
||||
private final StaticComponentMap effects;
|
||||
|
||||
public StaticEnchantmentType(
|
||||
Component description,
|
||||
EnchantmentDefinition definition,
|
||||
MappedEntitySet<EnchantmentType> exclusiveSet,
|
||||
StaticComponentMap effects
|
||||
) {
|
||||
this(null, description, definition, exclusiveSet, effects);
|
||||
}
|
||||
|
||||
public StaticEnchantmentType(
|
||||
@Nullable TypesBuilderData data,
|
||||
Component description,
|
||||
EnchantmentDefinition definition,
|
||||
MappedEntitySet<EnchantmentType> exclusiveSet,
|
||||
StaticComponentMap effects
|
||||
) {
|
||||
super(data);
|
||||
this.description = description;
|
||||
this.definition = definition;
|
||||
this.exclusiveSet = exclusiveSet;
|
||||
this.effects = effects;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnchantmentType copy(@Nullable TypesBuilderData newData) {
|
||||
return new StaticEnchantmentType(newData, this.description,
|
||||
this.definition, this.exclusiveSet, this.effects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getDescription() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnchantmentDefinition getDefinition() {
|
||||
return this.definition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappedEntitySet<EnchantmentType> getExclusiveSet() {
|
||||
return this.exclusiveSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StaticComponentMap getEffects() {
|
||||
return this.effects;
|
||||
}
|
||||
|
||||
public boolean deepEquals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof StaticEnchantmentType)) return false;
|
||||
if (!super.equals(obj)) return false;
|
||||
StaticEnchantmentType that = (StaticEnchantmentType) obj;
|
||||
if (!this.description.equals(that.description)) return false;
|
||||
if (!this.definition.equals(that.definition)) return false;
|
||||
if (!this.exclusiveSet.equals(that.exclusiveSet)) return false;
|
||||
return this.effects.equals(that.effects);
|
||||
}
|
||||
|
||||
public int deepHashCode() {
|
||||
return Objects.hash(super.hashCode(), this.description, this.definition, this.exclusiveSet, this.effects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "StaticEnchantmentType{description=" + this.description + ", definition=" + this.definition + ", exclusiveSet=" + this.exclusiveSet + ", effects=" + this.effects + "}";
|
||||
}
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2024 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.item.jukebox;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.mapper.CopyableEntity;
|
||||
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTFloat;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTInt;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.sound.Sound;
|
||||
import com.github.retrooper.packetevents.util.adventure.AdventureSerializer;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface IJukeboxSong extends MappedEntity, CopyableEntity<IJukeboxSong> {
|
||||
Sound getSound();
|
||||
|
||||
Component getDescription();
|
||||
|
||||
float getLengthInSeconds();
|
||||
|
||||
int getComparatorOutput();
|
||||
|
||||
static IJukeboxSong decode(NBT nbt, ClientVersion version, @Nullable TypesBuilderData data) {
|
||||
NBTCompound compound = (NBTCompound) nbt;
|
||||
Sound sound = Sound.decode(compound.getTagOrThrow("sound_event"), version);
|
||||
Component description = AdventureSerializer.fromNbt(compound.getTagOrThrow("description"));
|
||||
float length = compound.getNumberTagOrThrow("length_in_seconds").getAsFloat();
|
||||
int comparator_output = compound.getNumberTagOrThrow("comparator_output").getAsInt();
|
||||
return new JukeboxSong(data, sound, description, length, comparator_output);
|
||||
}
|
||||
|
||||
static NBT encode(IJukeboxSong jukeboxSong, ClientVersion version) {
|
||||
NBTCompound compound = new NBTCompound();
|
||||
|
||||
compound.setTag("sound_event", Sound.encode(jukeboxSong.getSound(), version));
|
||||
compound.setTag("description", AdventureSerializer.toNbt(jukeboxSong.getDescription()));
|
||||
compound.setTag("length_in_seconds", new NBTFloat(jukeboxSong.getLengthInSeconds()));
|
||||
compound.setTag("comparator_output", new NBTInt(jukeboxSong.getComparatorOutput()));
|
||||
|
||||
return compound;
|
||||
}
|
||||
|
||||
static IJukeboxSong read(PacketWrapper<?> wrapper) {
|
||||
Sound sound = Sound.read(wrapper);
|
||||
Component description = wrapper.readComponent();
|
||||
float lengthInSeconds = wrapper.readFloat();
|
||||
int comparatorOutput = wrapper.readVarInt();
|
||||
|
||||
return new JukeboxSong(null, sound, description, lengthInSeconds, comparatorOutput);
|
||||
}
|
||||
|
||||
static void write(PacketWrapper<?> wrapper, IJukeboxSong song) {
|
||||
Sound.write(wrapper, song.getSound());
|
||||
wrapper.writeComponent(song.getDescription());
|
||||
wrapper.writeFloat(song.getLengthInSeconds());
|
||||
wrapper.writeVarInt(song.getComparatorOutput());
|
||||
}
|
||||
}
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2024 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.item.jukebox;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.mapper.AbstractMappedEntity;
|
||||
import com.github.retrooper.packetevents.protocol.sound.Sound;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class JukeboxSong extends AbstractMappedEntity implements IJukeboxSong {
|
||||
private Sound sound;
|
||||
private Component description;
|
||||
private float lengthInSeconds;
|
||||
private int comparatorOutput;
|
||||
|
||||
public JukeboxSong(Sound sound, Component description, float lengthInSeconds, int comparatorOutput) {
|
||||
this(null, sound, description, lengthInSeconds, comparatorOutput);
|
||||
}
|
||||
|
||||
public JukeboxSong(@Nullable TypesBuilderData data, Sound sound, Component description, float lengthInSeconds,
|
||||
int comparatorOutput) {
|
||||
super(data);
|
||||
this.sound = sound;
|
||||
this.description = description;
|
||||
this.lengthInSeconds = lengthInSeconds;
|
||||
this.comparatorOutput = comparatorOutput;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static JukeboxSong read(PacketWrapper<?> wrapper) {
|
||||
return (JukeboxSong) IJukeboxSong.read(wrapper);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static void write(PacketWrapper<?> wrapper, JukeboxSong song) {
|
||||
IJukeboxSong.write(wrapper, song);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IJukeboxSong copy(@Nullable TypesBuilderData newData) {
|
||||
return new JukeboxSong(newData, sound, description, lengthInSeconds, comparatorOutput);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sound getSound() {
|
||||
return this.sound;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setSound(Sound sound) {
|
||||
this.sound = sound;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getDescription() {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setDescription(Component description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getLengthInSeconds() {
|
||||
return this.lengthInSeconds;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setLengthInSeconds(float lengthInSeconds) {
|
||||
this.lengthInSeconds = lengthInSeconds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getComparatorOutput() {
|
||||
return this.comparatorOutput;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setComparatorOutput(int comparatorOutput) {
|
||||
this.comparatorOutput = comparatorOutput;
|
||||
}
|
||||
|
||||
public boolean deepEquals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof JukeboxSong)) return false;
|
||||
if (!super.equals(obj)) return false;
|
||||
JukeboxSong that = (JukeboxSong) obj;
|
||||
if (Float.compare(that.lengthInSeconds, this.lengthInSeconds) != 0) return false;
|
||||
if (this.comparatorOutput != that.comparatorOutput) return false;
|
||||
if (!this.sound.equals(that.sound)) return false;
|
||||
return this.description.equals(that.description);
|
||||
}
|
||||
|
||||
public int deepHashCode() {
|
||||
return Objects.hash(super.hashCode(), this.sound, this.description, this.lengthInSeconds, this.comparatorOutput);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "JukeboxSong{sound=" + this.sound + ", description=" + this.description + ", lengthInSeconds=" + this.lengthInSeconds + ", comparatorOutput=" + this.comparatorOutput + '}';
|
||||
}
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2024 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.item.jukebox;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.sound.Sound;
|
||||
import com.github.retrooper.packetevents.protocol.sound.Sounds;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class JukeboxSongs {
|
||||
private static final VersionedRegistry<IJukeboxSong> REGISTRY = new VersionedRegistry<>("jukebox_song",
|
||||
"item/item_jukebox_song_mappings");
|
||||
|
||||
private JukeboxSongs() {
|
||||
}
|
||||
|
||||
private static String makeDescriptionId(String var0, @Nullable ResourceLocation var1) {
|
||||
return var1 == null ? var0 + ".unregistered_sadface" :
|
||||
var0 + "." + var1.getNamespace() + "." + var1.getKey().replace('/', '.');
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static IJukeboxSong define(String key, Sound sound, float lengthInSeconds, int comparatorOutput) {
|
||||
return REGISTRY.define(key, data -> new JukeboxSong(data, sound,
|
||||
Component.translatable(makeDescriptionId("jukebox_song", data.getName())), lengthInSeconds,
|
||||
comparatorOutput));
|
||||
}
|
||||
|
||||
public static VersionedRegistry<IJukeboxSong> getRegistry() {
|
||||
return REGISTRY;
|
||||
}
|
||||
|
||||
public static IJukeboxSong getByName(String name) {
|
||||
return REGISTRY.getByName(name);
|
||||
}
|
||||
|
||||
public static IJukeboxSong getById(ClientVersion version, int id) {
|
||||
return REGISTRY.getById(version, id);
|
||||
}
|
||||
|
||||
public static final IJukeboxSong THIRTEEN = define("13", Sounds.MUSIC_DISC_13, 178, 1);
|
||||
public static final IJukeboxSong CAT = define("cat", Sounds.MUSIC_DISC_CAT, 185, 2);
|
||||
public static final IJukeboxSong BLOCKS = define("blocks", Sounds.MUSIC_DISC_BLOCKS, 345, 3);
|
||||
public static final IJukeboxSong CHIRP = define("chirp", Sounds.MUSIC_DISC_CHIRP, 185, 4);
|
||||
public static final IJukeboxSong FAR = define("far", Sounds.MUSIC_DISC_FAR, 174, 5);
|
||||
public static final IJukeboxSong MALL = define("mall", Sounds.MUSIC_DISC_MALL, 197, 6);
|
||||
public static final IJukeboxSong MELLOHI = define("mellohi", Sounds.MUSIC_DISC_MELLOHI, 96, 7);
|
||||
public static final IJukeboxSong STAL = define("stal", Sounds.MUSIC_DISC_STAL, 150, 8);
|
||||
public static final IJukeboxSong STRAD = define("strad", Sounds.MUSIC_DISC_STRAD, 188, 9);
|
||||
public static final IJukeboxSong WARD = define("ward", Sounds.MUSIC_DISC_WARD, 251, 10);
|
||||
public static final IJukeboxSong ELEVEN = define("11", Sounds.MUSIC_DISC_11, 71, 11);
|
||||
public static final IJukeboxSong WAIT = define("wait", Sounds.MUSIC_DISC_WAIT, 238, 12);
|
||||
public static final IJukeboxSong PIGSTEP = define("pigstep", Sounds.MUSIC_DISC_PIGSTEP, 149, 13);
|
||||
public static final IJukeboxSong OTHERSIDE = define("otherside", Sounds.MUSIC_DISC_OTHERSIDE, 195, 14);
|
||||
public static final IJukeboxSong FIVE = define("5", Sounds.MUSIC_DISC_5, 178, 15);
|
||||
public static final IJukeboxSong RELIC = define("relic", Sounds.MUSIC_DISC_RELIC, 218, 14);
|
||||
public static final IJukeboxSong PRECIPICE = define("precipice", Sounds.MUSIC_DISC_PRECIPICE, 299, 13);
|
||||
public static final IJukeboxSong CREATOR = define("creator", Sounds.MUSIC_DISC_CREATOR, 176, 12);
|
||||
public static final IJukeboxSong CREATOR_MUSIC_BOX = define("creator_music_box", Sounds.MUSIC_DISC_CREATOR_MUSIC_BOX,
|
||||
73, 11);
|
||||
|
||||
/**
|
||||
* Returns an immutable view of the jukebox songs.
|
||||
*
|
||||
* @return Jukebox Songs
|
||||
*/
|
||||
public static Collection<IJukeboxSong> values() {
|
||||
return REGISTRY.getEntries();
|
||||
}
|
||||
|
||||
static {
|
||||
REGISTRY.unloadMappings();
|
||||
}
|
||||
}
|
||||
+14
@@ -25,6 +25,8 @@ import com.github.retrooper.packetevents.util.mappings.TypesBuilder;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -117,6 +119,10 @@ public class MapDecorationTypes {
|
||||
}
|
||||
|
||||
public static @Nullable MapDecorationType getById(int id, ClientVersion version) {
|
||||
return getById(version, id);
|
||||
}
|
||||
|
||||
public static @Nullable MapDecorationType getById(ClientVersion version, int id) {
|
||||
int index = TYPES_BUILDER.getDataIndex(version);
|
||||
Map<Integer, MapDecorationType> idMap = DECORATION_TYPE_ID_MAP.get((byte) index);
|
||||
return idMap.get(id);
|
||||
@@ -201,6 +207,14 @@ public class MapDecorationTypes {
|
||||
public static final MapDecorationType TRIAL_CHAMBERS = define("trial_chambers",
|
||||
true, COPPER_COLOR, true, false);
|
||||
|
||||
/**
|
||||
* Returns an immutable view of the map decoration types.
|
||||
* @return Map Decoration Types
|
||||
*/
|
||||
public static Collection<MapDecorationType> values() {
|
||||
return Collections.unmodifiableCollection(DECORATION_TYPE_MAP.values());
|
||||
}
|
||||
|
||||
static {
|
||||
TYPES_BUILDER.unloadFileMappings();
|
||||
}
|
||||
|
||||
+29
-25
@@ -20,15 +20,15 @@ package com.github.retrooper.packetevents.protocol.item.trimmaterial;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.item.armormaterial.ArmorMaterial;
|
||||
import com.github.retrooper.packetevents.protocol.item.type.ItemType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.protocol.mapper.AbstractMappedEntity;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class StaticTrimMaterial implements TrimMaterial {
|
||||
public class StaticTrimMaterial extends AbstractMappedEntity implements TrimMaterial {
|
||||
|
||||
private final String assetName;
|
||||
private final ItemType ingredient;
|
||||
@@ -40,6 +40,15 @@ public class StaticTrimMaterial implements TrimMaterial {
|
||||
String assetName, ItemType ingredient, float itemModelIndex,
|
||||
Map<ArmorMaterial, String> overrideArmorMaterials, Component description
|
||||
) {
|
||||
this(null, assetName, ingredient, itemModelIndex, overrideArmorMaterials, description);
|
||||
}
|
||||
|
||||
public StaticTrimMaterial(
|
||||
@Nullable TypesBuilderData data,
|
||||
String assetName, ItemType ingredient, float itemModelIndex,
|
||||
Map<ArmorMaterial, String> overrideArmorMaterials, Component description
|
||||
) {
|
||||
super(data);
|
||||
this.assetName = assetName;
|
||||
this.ingredient = ingredient;
|
||||
this.itemModelIndex = itemModelIndex;
|
||||
@@ -48,18 +57,9 @@ public class StaticTrimMaterial implements TrimMaterial {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getName() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId(ClientVersion version) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRegistered() {
|
||||
return false;
|
||||
public TrimMaterial copy(@Nullable TypesBuilderData newData) {
|
||||
return new StaticTrimMaterial(newData, this.assetName, this.ingredient, this.itemModelIndex,
|
||||
this.overrideArmorMaterials, this.description);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -87,20 +87,24 @@ public class StaticTrimMaterial implements TrimMaterial {
|
||||
return this.description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean deepEquals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof StaticTrimMaterial)) return false;
|
||||
StaticTrimMaterial material = (StaticTrimMaterial) obj;
|
||||
if (Float.compare(material.itemModelIndex, this.itemModelIndex) != 0) return false;
|
||||
if (!this.assetName.equals(material.assetName)) return false;
|
||||
if (!this.ingredient.equals(material.ingredient)) return false;
|
||||
if (!this.overrideArmorMaterials.equals(material.overrideArmorMaterials)) return false;
|
||||
return this.description.equals(material.description);
|
||||
if (!super.equals(obj)) return false;
|
||||
StaticTrimMaterial that = (StaticTrimMaterial) obj;
|
||||
if (Float.compare(that.itemModelIndex, this.itemModelIndex) != 0) return false;
|
||||
if (!this.assetName.equals(that.assetName)) return false;
|
||||
if (!this.ingredient.equals(that.ingredient)) return false;
|
||||
if (!this.overrideArmorMaterials.equals(that.overrideArmorMaterials)) return false;
|
||||
return this.description.equals(that.description);
|
||||
}
|
||||
|
||||
public int deepHashCode() {
|
||||
return Objects.hash(super.hashCode(), this.assetName, this.ingredient, this.itemModelIndex, this.overrideArmorMaterials, this.description);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.assetName, this.ingredient, this.itemModelIndex, this.overrideArmorMaterials, this.description);
|
||||
public String toString() {
|
||||
return "StaticTrimMaterial{assetName='" + this.assetName + '\'' + ", ingredient=" + this.ingredient + ", itemModelIndex=" + this.itemModelIndex + ", overrideArmorMaterials=" + this.overrideArmorMaterials + ", description=" + this.description + '}';
|
||||
}
|
||||
}
|
||||
+57
-2
@@ -22,14 +22,24 @@ import com.github.retrooper.packetevents.protocol.item.armormaterial.ArmorMateri
|
||||
import com.github.retrooper.packetevents.protocol.item.armormaterial.ArmorMaterials;
|
||||
import com.github.retrooper.packetevents.protocol.item.type.ItemType;
|
||||
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
|
||||
import com.github.retrooper.packetevents.protocol.mapper.CopyableEntity;
|
||||
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTFloat;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.util.adventure.AdventureSerializer;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public interface TrimMaterial extends MappedEntity {
|
||||
public interface TrimMaterial extends MappedEntity, CopyableEntity<TrimMaterial> {
|
||||
|
||||
String getAssetName();
|
||||
|
||||
@@ -46,7 +56,7 @@ public interface TrimMaterial extends MappedEntity {
|
||||
Component getDescription();
|
||||
|
||||
static TrimMaterial read(PacketWrapper<?> wrapper) {
|
||||
return wrapper.readMappedEntityOrDirect(TrimMaterials::getById, TrimMaterial::readDirect);
|
||||
return wrapper.readMappedEntityOrDirect(TrimMaterials.getRegistry(), TrimMaterial::readDirect);
|
||||
}
|
||||
|
||||
static TrimMaterial readDirect(PacketWrapper<?> wrapper) {
|
||||
@@ -72,4 +82,49 @@ public interface TrimMaterial extends MappedEntity {
|
||||
PacketWrapper::writeMappedEntity, PacketWrapper::writeString);
|
||||
wrapper.writeComponent(material.getDescription());
|
||||
}
|
||||
|
||||
static TrimMaterial decode(NBT nbt, ClientVersion version, @Nullable TypesBuilderData data) {
|
||||
NBTCompound compound = (NBTCompound) nbt;
|
||||
String assetName = compound.getStringTagValueOrThrow("asset_name");
|
||||
ItemType ingredient = ItemTypes.getByName(compound.getStringTagValueOrThrow("ingredient"));
|
||||
float itemModelIndex = compound.getNumberTagOrThrow("item_model_index").getAsFloat();
|
||||
NBTCompound overrideArmorMaterialsTag = compound.getCompoundTagOrNull("override_armor_materials");
|
||||
Map<ArmorMaterial, String> overrideArmorMaterials;
|
||||
if (overrideArmorMaterialsTag != null) {
|
||||
overrideArmorMaterials = new HashMap<>();
|
||||
for (Map.Entry<String, NBT> entry : overrideArmorMaterialsTag.getTags().entrySet()) {
|
||||
ArmorMaterial material = ArmorMaterials.getByName(entry.getKey());
|
||||
String override = ((NBTString) entry.getValue()).getValue();
|
||||
overrideArmorMaterials.put(material, override);
|
||||
}
|
||||
} else {
|
||||
overrideArmorMaterials = Collections.emptyMap();
|
||||
}
|
||||
Component description = AdventureSerializer.fromNbt(((NBTCompound) nbt).getTagOrThrow("description"));
|
||||
return new StaticTrimMaterial(data, assetName, ingredient, itemModelIndex, overrideArmorMaterials, description);
|
||||
}
|
||||
|
||||
static NBT encode(TrimMaterial material, ClientVersion version) {
|
||||
NBTCompound overrideArmorMaterialsTag;
|
||||
if (!material.getOverrideArmorMaterials().isEmpty()) {
|
||||
overrideArmorMaterialsTag = new NBTCompound();
|
||||
for (Map.Entry<ArmorMaterial, String> entry : material.getOverrideArmorMaterials().entrySet()) {
|
||||
String materialName = entry.getKey().getName().toString();
|
||||
NBTString overrideTag = new NBTString(entry.getValue());
|
||||
overrideArmorMaterialsTag.setTag(materialName, overrideTag);
|
||||
}
|
||||
} else {
|
||||
overrideArmorMaterialsTag = null;
|
||||
}
|
||||
|
||||
NBTCompound compound = new NBTCompound();
|
||||
compound.setTag("asset_name", new NBTString(material.getAssetName()));
|
||||
compound.setTag("ingredient", new NBTString(material.getIngredient().getName().toString()));
|
||||
compound.setTag("item_model_index", new NBTFloat(material.getItemModelIndex()));
|
||||
if (overrideArmorMaterialsTag != null) {
|
||||
compound.setTag("override_armor_materials", overrideArmorMaterialsTag);
|
||||
}
|
||||
compound.setTag("description", AdventureSerializer.toNbt(material.getDescription()));
|
||||
return compound;
|
||||
}
|
||||
}
|
||||
+29
-60
@@ -24,23 +24,26 @@ import com.github.retrooper.packetevents.protocol.item.type.ItemType;
|
||||
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.util.mappings.MappingHelper;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilder;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static net.kyori.adventure.text.Component.translatable;
|
||||
import static net.kyori.adventure.text.format.TextColor.color;
|
||||
|
||||
public class TrimMaterials {
|
||||
public final class TrimMaterials {
|
||||
|
||||
private static final Map<String, TrimMaterial> PATTERN_TYPE_MAP = new HashMap<>();
|
||||
private static final Map<Byte, Map<Integer, TrimMaterial>> PATTERN_TYPE_ID_MAP = new HashMap<>();
|
||||
private static final TypesBuilder TYPES_BUILDER = new TypesBuilder("item/item_trim_material_mappings");
|
||||
private static final VersionedRegistry<TrimMaterial> REGISTRY = new VersionedRegistry<>(
|
||||
"trim_material", "item/item_trim_material_mappings");
|
||||
|
||||
private TrimMaterials() {
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static TrimMaterial define(String key, ItemType ingredient, float itemModelIndex, int color) {
|
||||
// darken own armor material - if present
|
||||
Map<ArmorMaterial, String> overrideArmorMaterials = new HashMap<>(2);
|
||||
@@ -54,68 +57,25 @@ public class TrimMaterials {
|
||||
return define(key, key, ingredient, itemModelIndex, overrideArmorMaterials, description);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static TrimMaterial define(
|
||||
String key, String assetName, ItemType ingredient, float itemModelIndex,
|
||||
Map<ArmorMaterial, String> overrideArmorMaterials, Component description
|
||||
) {
|
||||
TypesBuilderData data = TYPES_BUILDER.define(key);
|
||||
TrimMaterial pattern = new TrimMaterial() {
|
||||
@Override
|
||||
public String getAssetName() {
|
||||
return assetName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getIngredient() {
|
||||
return ingredient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getItemModelIndex() {
|
||||
return itemModelIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<ArmorMaterial, String> getOverrideArmorMaterials() {
|
||||
return overrideArmorMaterials;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getName() {
|
||||
return data.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId(ClientVersion version) {
|
||||
return TYPES_BUILDER.getDataIndex(version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof TrimMaterial) {
|
||||
return this.getName().equals(((TrimMaterial) obj).getName());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
MappingHelper.registerMapping(TYPES_BUILDER, PATTERN_TYPE_MAP, PATTERN_TYPE_ID_MAP, pattern);
|
||||
return pattern;
|
||||
return REGISTRY.define(key, data ->
|
||||
new StaticTrimMaterial(data, assetName, ingredient, itemModelIndex, overrideArmorMaterials, description));
|
||||
}
|
||||
|
||||
public static VersionedRegistry<TrimMaterial> getRegistry() {
|
||||
return REGISTRY;
|
||||
}
|
||||
|
||||
// with key
|
||||
public static TrimMaterial getByName(String name) {
|
||||
return PATTERN_TYPE_MAP.get(name);
|
||||
return REGISTRY.getByName(name);
|
||||
}
|
||||
|
||||
public static TrimMaterial getById(ClientVersion version, int id) {
|
||||
int index = TYPES_BUILDER.getDataIndex(version);
|
||||
Map<Integer, TrimMaterial> idMap = PATTERN_TYPE_ID_MAP.get((byte) index);
|
||||
return idMap.get(id);
|
||||
return REGISTRY.getById(version, id);
|
||||
}
|
||||
|
||||
// Added in 1.19.4
|
||||
@@ -130,7 +90,16 @@ public class TrimMaterials {
|
||||
public static final TrimMaterial QUARTZ = define("quartz", ItemTypes.QUARTZ, 0.1f, 0xE3D4C4);
|
||||
public static final TrimMaterial REDSTONE = define("redstone", ItemTypes.REDSTONE, 0.4f, 0x971607);
|
||||
|
||||
/**
|
||||
* Returns an immutable view of the trim materials.
|
||||
*
|
||||
* @return Trim Materials
|
||||
*/
|
||||
public static Collection<TrimMaterial> values() {
|
||||
return REGISTRY.getEntries();
|
||||
}
|
||||
|
||||
static {
|
||||
TYPES_BUILDER.unloadFileMappings();
|
||||
REGISTRY.unloadMappings();
|
||||
}
|
||||
}
|
||||
+29
-23
@@ -19,13 +19,15 @@
|
||||
package com.github.retrooper.packetevents.protocol.item.trimpattern;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.item.type.ItemType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.mapper.AbstractMappedEntity;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class StaticTrimPattern implements TrimPattern {
|
||||
public class StaticTrimPattern extends AbstractMappedEntity implements TrimPattern {
|
||||
|
||||
private final ResourceLocation assetId;
|
||||
private final ItemType templateItem;
|
||||
@@ -36,6 +38,15 @@ public class StaticTrimPattern implements TrimPattern {
|
||||
ResourceLocation assetId, ItemType templateItem,
|
||||
Component description, boolean decal
|
||||
) {
|
||||
this(null, assetId, templateItem, description, decal);
|
||||
}
|
||||
|
||||
public StaticTrimPattern(
|
||||
@Nullable TypesBuilderData data,
|
||||
ResourceLocation assetId, ItemType templateItem,
|
||||
Component description, boolean decal
|
||||
) {
|
||||
super(data);
|
||||
this.assetId = assetId;
|
||||
this.templateItem = templateItem;
|
||||
this.description = description;
|
||||
@@ -43,18 +54,9 @@ public class StaticTrimPattern implements TrimPattern {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getName() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId(ClientVersion version) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRegistered() {
|
||||
return false;
|
||||
public TrimPattern copy(@Nullable TypesBuilderData newData) {
|
||||
return new StaticTrimPattern(newData, this.assetId,
|
||||
this.templateItem, this.description, this.decal);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -77,19 +79,23 @@ public class StaticTrimPattern implements TrimPattern {
|
||||
return this.decal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean deepEquals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof StaticTrimPattern)) return false;
|
||||
StaticTrimPattern pattern = (StaticTrimPattern) obj;
|
||||
if (this.decal != pattern.decal) return false;
|
||||
if (!this.assetId.equals(pattern.assetId)) return false;
|
||||
if (!this.templateItem.equals(pattern.templateItem)) return false;
|
||||
return this.description.equals(pattern.description);
|
||||
if (!super.equals(obj)) return false;
|
||||
StaticTrimPattern that = (StaticTrimPattern) obj;
|
||||
if (this.decal != that.decal) return false;
|
||||
if (!this.assetId.equals(that.assetId)) return false;
|
||||
if (!this.templateItem.equals(that.templateItem)) return false;
|
||||
return this.description.equals(that.description);
|
||||
}
|
||||
|
||||
public int deepHashCode() {
|
||||
return Objects.hash(super.hashCode(), this.assetId, this.templateItem, this.description, this.decal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.assetId, this.templateItem, this.description, this.decal);
|
||||
public String toString() {
|
||||
return "StaticTrimPattern{assetId=" + this.assetId + ", templateItem=" + this.templateItem + ", description=" + this.description + ", decal=" + this.decal + '}';
|
||||
}
|
||||
}
|
||||
+31
-2
@@ -20,12 +20,21 @@ package com.github.retrooper.packetevents.protocol.item.trimpattern;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.item.type.ItemType;
|
||||
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
|
||||
import com.github.retrooper.packetevents.protocol.mapper.CopyableEntity;
|
||||
import com.github.retrooper.packetevents.protocol.mapper.MappedEntity;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTByte;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.util.adventure.AdventureSerializer;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface TrimPattern extends MappedEntity {
|
||||
public interface TrimPattern extends MappedEntity, CopyableEntity<TrimPattern> {
|
||||
|
||||
ResourceLocation getAssetId();
|
||||
|
||||
@@ -36,7 +45,7 @@ public interface TrimPattern extends MappedEntity {
|
||||
boolean isDecal();
|
||||
|
||||
static TrimPattern read(PacketWrapper<?> wrapper) {
|
||||
return wrapper.readMappedEntityOrDirect(TrimPatterns::getById, TrimPattern::readDirect);
|
||||
return wrapper.readMappedEntityOrDirect(TrimPatterns.getRegistry(), TrimPattern::readDirect);
|
||||
}
|
||||
|
||||
static TrimPattern readDirect(PacketWrapper<?> wrapper) {
|
||||
@@ -57,4 +66,24 @@ public interface TrimPattern extends MappedEntity {
|
||||
wrapper.writeComponent(pattern.getDescription());
|
||||
wrapper.writeBoolean(pattern.isDecal());
|
||||
}
|
||||
|
||||
static TrimPattern decode(NBT nbt, ClientVersion version, @Nullable TypesBuilderData data) {
|
||||
NBTCompound compound = (NBTCompound) nbt;
|
||||
ResourceLocation assetId = new ResourceLocation(compound.getStringTagValueOrThrow("asset_id"));
|
||||
ItemType templateItem = ItemTypes.getByName(compound.getStringTagValueOrThrow("template_item"));
|
||||
Component description = AdventureSerializer.fromNbt(compound.getTagOrThrow("description"));
|
||||
boolean decal = version.isNewerThanOrEquals(ClientVersion.V_1_20_2) && compound.getBoolean("decal");
|
||||
return new StaticTrimPattern(data, assetId, templateItem, description, decal);
|
||||
}
|
||||
|
||||
static NBT encode(TrimPattern pattern, ClientVersion version) {
|
||||
NBTCompound compound = new NBTCompound();
|
||||
compound.setTag("asset_id", new NBTString(pattern.getAssetId().toString()));
|
||||
compound.setTag("template_item", new NBTString(pattern.getTemplateItem().getName().toString()));
|
||||
compound.setTag("description", AdventureSerializer.toNbt(pattern.getDescription()));
|
||||
if (version.isNewerThanOrEquals(ClientVersion.V_1_20_2)) {
|
||||
compound.setTag("decal", new NBTByte(pattern.isDecal()));
|
||||
}
|
||||
return compound;
|
||||
}
|
||||
}
|
||||
+18
-57
@@ -22,20 +22,19 @@ import com.github.retrooper.packetevents.protocol.item.type.ItemType;
|
||||
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.util.mappings.MappingHelper;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilder;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
public final class TrimPatterns {
|
||||
|
||||
public class TrimPatterns {
|
||||
private static final VersionedRegistry<TrimPattern> REGISTRY = new VersionedRegistry<>(
|
||||
"trim_pattern", "item/item_trim_pattern_mappings");
|
||||
|
||||
private static final Map<String, TrimPattern> PATTERN_TYPE_MAP = new HashMap<>();
|
||||
private static final Map<Byte, Map<Integer, TrimPattern>> PATTERN_TYPE_ID_MAP = new HashMap<>();
|
||||
private static final TypesBuilder TYPES_BUILDER = new TypesBuilder("item/item_trim_pattern_mappings");
|
||||
private TrimPatterns() {
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static TrimPattern define(String key) {
|
||||
ResourceLocation assetId = ResourceLocation.minecraft(key);
|
||||
ItemType templateItem = ItemTypes.getByName(assetId + "_armor_trim_smithing_template");
|
||||
@@ -44,63 +43,25 @@ public class TrimPatterns {
|
||||
return define(key, assetId, templateItem, description, decal);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static TrimPattern define(
|
||||
String key, ResourceLocation assetId, ItemType templateItem,
|
||||
Component description, boolean decal
|
||||
) {
|
||||
TypesBuilderData data = TYPES_BUILDER.define(key);
|
||||
TrimPattern pattern = new TrimPattern() {
|
||||
@Override
|
||||
public ResourceLocation getAssetId() {
|
||||
return assetId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemType getTemplateItem() {
|
||||
return templateItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDecal() {
|
||||
return decal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getName() {
|
||||
return data.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId(ClientVersion version) {
|
||||
return TYPES_BUILDER.getDataIndex(version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof TrimPattern) {
|
||||
return this.getName().equals(((TrimPattern) obj).getName());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
MappingHelper.registerMapping(TYPES_BUILDER, PATTERN_TYPE_MAP, PATTERN_TYPE_ID_MAP, pattern);
|
||||
return pattern;
|
||||
return REGISTRY.define(key, data ->
|
||||
new StaticTrimPattern(data, assetId, templateItem, description, decal));
|
||||
}
|
||||
|
||||
public static VersionedRegistry<TrimPattern> getRegistry() {
|
||||
return REGISTRY;
|
||||
}
|
||||
|
||||
// with key
|
||||
public static TrimPattern getByName(String name) {
|
||||
return PATTERN_TYPE_MAP.get(name);
|
||||
return REGISTRY.getByName(name);
|
||||
}
|
||||
|
||||
public static TrimPattern getById(ClientVersion version, int id) {
|
||||
int index = TYPES_BUILDER.getDataIndex(version);
|
||||
Map<Integer, TrimPattern> idMap = PATTERN_TYPE_ID_MAP.get((byte) index);
|
||||
return idMap.get(id);
|
||||
return REGISTRY.getById(version, id);
|
||||
}
|
||||
|
||||
// Added in 1.19.4
|
||||
@@ -128,6 +89,6 @@ public class TrimPatterns {
|
||||
public static final TrimPattern FLOW = define("flow");
|
||||
|
||||
static {
|
||||
TYPES_BUILDER.unloadFileMappings();
|
||||
REGISTRY.unloadMappings();
|
||||
}
|
||||
}
|
||||
+35
-34
@@ -45,9 +45,7 @@ import com.github.retrooper.packetevents.protocol.potion.PotionTypes;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.util.mappings.MappingHelper;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilder;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import com.github.retrooper.packetevents.util.mappings.VersionedRegistry;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -87,14 +85,15 @@ import static com.github.retrooper.packetevents.protocol.component.ComponentType
|
||||
import static com.github.retrooper.packetevents.protocol.component.ComponentTypes.WRITABLE_BOOK_CONTENT;
|
||||
|
||||
public class ItemTypes {
|
||||
private static final Map<String, ItemType> ITEM_TYPE_MAP = new HashMap<>();
|
||||
private static final Map<Byte, Map<Integer, ItemType>> ITEM_TYPE_ID_MAP = new HashMap<>();
|
||||
|
||||
private static final VersionedRegistry<ItemType> REGISTRY = new VersionedRegistry<>(
|
||||
"item", "item/item_type_mappings");
|
||||
private static final Map<StateType, ItemType> HELD_TO_PLACED_MAP = new HashMap<>();
|
||||
private static final TypesBuilder TYPES_BUILDER = new TypesBuilder("item/item_type_mappings");
|
||||
|
||||
private static final UUID TOOL_MODIFIER_ATTACK_DAMAGE_UUID = UUID.fromString("cb3f55d3-645c-4f38-a497-9c13a33db5cf");
|
||||
private static final UUID TOOL_MODIFIER_ATTACK_SPEED_UUID = UUID.fromString("fa233e1c-4180-4865-b01b-bcce9785aca3");
|
||||
|
||||
// <editor-fold desc="item type definitions" defaultstate="collapsed">
|
||||
public static final ItemType GILDED_BLACKSTONE = builder("gilded_blackstone").setMaxAmount(64).setPlacedType(StateTypes.GILDED_BLACKSTONE).build();
|
||||
public static final ItemType NETHER_BRICK_SLAB = builder("nether_brick_slab").setMaxAmount(64).setPlacedType(StateTypes.NETHER_BRICK_SLAB).build();
|
||||
public static final ItemType ANDESITE_SLAB = builder("andesite_slab").setMaxAmount(64).setPlacedType(StateTypes.ANDESITE_SLAB).build();
|
||||
@@ -1385,14 +1384,14 @@ public class ItemTypes {
|
||||
public static final ItemType WAXED_EXPOSED_CHISELED_COPPER = builder("waxed_exposed_chiseled_copper").setMaxAmount(64).setPlacedType(StateTypes.WAXED_EXPOSED_CHISELED_COPPER).build();
|
||||
public static final ItemType WAXED_WEATHERED_CHISELED_COPPER = builder("waxed_weathered_chiseled_copper").setMaxAmount(64).setPlacedType(StateTypes.WAXED_WEATHERED_CHISELED_COPPER).build();
|
||||
public static final ItemType WAXED_OXIDIZED_CHISELED_COPPER = builder("waxed_oxidized_chiseled_copper").setMaxAmount(64).setPlacedType(StateTypes.WAXED_OXIDIZED_CHISELED_COPPER).build();
|
||||
public static final ItemType COPPER_DOOR = builder("copper_door").setMaxAmount(64).setPlacedType(StateTypes.COPPER_DOOR).build();
|
||||
public static final ItemType EXPOSED_COPPER_DOOR = builder("exposed_copper_door").setMaxAmount(64).setPlacedType(StateTypes.EXPOSED_COPPER_DOOR).build();
|
||||
public static final ItemType WEATHERED_COPPER_DOOR = builder("weathered_copper_door").setMaxAmount(64).setPlacedType(StateTypes.WEATHERED_COPPER_DOOR).build();
|
||||
public static final ItemType OXIDIZED_COPPER_DOOR = builder("oxidized_copper_door").setMaxAmount(64).setPlacedType(StateTypes.OXIDIZED_COPPER_DOOR).build();
|
||||
public static final ItemType WAXED_COPPER_DOOR = builder("waxed_copper_door").setMaxAmount(64).setPlacedType(StateTypes.WAXED_COPPER_DOOR).build();
|
||||
public static final ItemType WAXED_EXPOSED_COPPER_DOOR = builder("waxed_exposed_copper_door").setMaxAmount(64).setPlacedType(StateTypes.WAXED_EXPOSED_COPPER_DOOR).build();
|
||||
public static final ItemType WAXED_WEATHERED_COPPER_DOOR = builder("waxed_weathered_copper_door").setMaxAmount(64).setPlacedType(StateTypes.WAXED_WEATHERED_COPPER_DOOR).build();
|
||||
public static final ItemType WAXED_OXIDIZED_COPPER_DOOR = builder("waxed_oxidized_copper_door").setMaxAmount(64).setPlacedType(StateTypes.WAXED_OXIDIZED_COPPER_DOOR).build();
|
||||
public static final ItemType COPPER_DOOR = builder("copper_door").setMaxAmount(64).setPlacedType(StateTypes.COPPER_DOOR).setAttributes(ItemAttribute.FUEL).build();
|
||||
public static final ItemType EXPOSED_COPPER_DOOR = builder("exposed_copper_door").setMaxAmount(64).setPlacedType(StateTypes.EXPOSED_COPPER_DOOR).setAttributes(ItemAttribute.FUEL).build();
|
||||
public static final ItemType WEATHERED_COPPER_DOOR = builder("weathered_copper_door").setMaxAmount(64).setPlacedType(StateTypes.WEATHERED_COPPER_DOOR).setAttributes(ItemAttribute.FUEL).build();
|
||||
public static final ItemType OXIDIZED_COPPER_DOOR = builder("oxidized_copper_door").setMaxAmount(64).setPlacedType(StateTypes.OXIDIZED_COPPER_DOOR).setAttributes(ItemAttribute.FUEL).build();
|
||||
public static final ItemType WAXED_COPPER_DOOR = builder("waxed_copper_door").setMaxAmount(64).setPlacedType(StateTypes.WAXED_COPPER_DOOR).setAttributes(ItemAttribute.FUEL).build();
|
||||
public static final ItemType WAXED_EXPOSED_COPPER_DOOR = builder("waxed_exposed_copper_door").setMaxAmount(64).setPlacedType(StateTypes.WAXED_EXPOSED_COPPER_DOOR).setAttributes(ItemAttribute.FUEL).build();
|
||||
public static final ItemType WAXED_WEATHERED_COPPER_DOOR = builder("waxed_weathered_copper_door").setMaxAmount(64).setPlacedType(StateTypes.WAXED_WEATHERED_COPPER_DOOR).setAttributes(ItemAttribute.FUEL).build();
|
||||
public static final ItemType WAXED_OXIDIZED_COPPER_DOOR = builder("waxed_oxidized_copper_door").setMaxAmount(64).setPlacedType(StateTypes.WAXED_OXIDIZED_COPPER_DOOR).setAttributes(ItemAttribute.FUEL).build();
|
||||
public static final ItemType COPPER_TRAPDOOR = builder("copper_trapdoor").setMaxAmount(64).setPlacedType(StateTypes.COPPER_TRAPDOOR).build();
|
||||
public static final ItemType EXPOSED_COPPER_TRAPDOOR = builder("exposed_copper_trapdoor").setMaxAmount(64).setPlacedType(StateTypes.EXPOSED_COPPER_TRAPDOOR).build();
|
||||
public static final ItemType WEATHERED_COPPER_TRAPDOOR = builder("weathered_copper_trapdoor").setMaxAmount(64).setPlacedType(StateTypes.WEATHERED_COPPER_TRAPDOOR).build();
|
||||
@@ -1429,7 +1428,7 @@ public class ItemTypes {
|
||||
public static final ItemType HEAVY_CORE = builder("heavy_core").setMaxAmount(64).setPlacedType(StateTypes.HEAVY_CORE).build();
|
||||
public static final ItemType BOGGED_SPAWN_EGG = builder("bogged_spawn_egg").setMaxAmount(64).build();
|
||||
public static final ItemType WIND_CHARGE = builder("wind_charge").setMaxAmount(64).build();
|
||||
public static final ItemType MACE = builder("mace").setMaxAmount(1).setMaxDurability(250).setComponent(DAMAGE, 0).setComponent(ATTRIBUTE_MODIFIERS, new ItemAttributeModifiers(Arrays.asList(new ItemAttributeModifiers.ModifierEntry(Attributes.GENERIC_ATTACK_DAMAGE, new ItemAttributeModifiers.Modifier(TOOL_MODIFIER_ATTACK_DAMAGE_UUID, "Weapon modifier", 6.0d, AttributeOperation.ADDITION), ItemAttributeModifiers.EquipmentSlotGroup.MAINHAND), new ItemAttributeModifiers.ModifierEntry(Attributes.GENERIC_ATTACK_SPEED, new ItemAttributeModifiers.Modifier(TOOL_MODIFIER_ATTACK_SPEED_UUID, "Weapon modifier", -2.4d, AttributeOperation.ADDITION), ItemAttributeModifiers.EquipmentSlotGroup.MAINHAND)), true)).setComponent(TOOL, new ItemTool(Collections.emptyList(), 1.0f, 2)).build();
|
||||
public static final ItemType MACE = builder("mace").setMaxAmount(1).setMaxDurability(500).setComponent(DAMAGE, 0).setComponent(ATTRIBUTE_MODIFIERS, new ItemAttributeModifiers(Arrays.asList(new ItemAttributeModifiers.ModifierEntry(Attributes.GENERIC_ATTACK_DAMAGE, new ItemAttributeModifiers.Modifier(TOOL_MODIFIER_ATTACK_DAMAGE_UUID, "Weapon modifier", 5.0d, AttributeOperation.ADDITION), ItemAttributeModifiers.EquipmentSlotGroup.MAINHAND), new ItemAttributeModifiers.ModifierEntry(Attributes.GENERIC_ATTACK_SPEED, new ItemAttributeModifiers.Modifier(TOOL_MODIFIER_ATTACK_SPEED_UUID, "Weapon modifier", -3.5d, AttributeOperation.ADDITION), ItemAttributeModifiers.EquipmentSlotGroup.MAINHAND)), true)).setComponent(TOOL, new ItemTool(Collections.emptyList(), 1.0f, 2)).build();
|
||||
public static final ItemType FLOW_BANNER_PATTERN = builder("flow_banner_pattern").setMaxAmount(1).build();
|
||||
public static final ItemType GUSTER_BANNER_PATTERN = builder("guster_banner_pattern").setMaxAmount(1).build();
|
||||
public static final ItemType FLOW_ARMOR_TRIM_SMITHING_TEMPLATE = builder("flow_armor_trim_smithing_template").setMaxAmount(64).build();
|
||||
@@ -1442,6 +1441,11 @@ public class ItemTypes {
|
||||
public static final ItemType OMINOUS_BOTTLE = builder("ominous_bottle").setMaxAmount(64).setAttributes(ItemAttribute.EDIBLE).setComponent(FOOD, new FoodProperties(1, 0.2f, false, 1.6f, Collections.emptyList())).setComponent(OMINOUS_BOTTLE_AMPLIFIER, 0).build();
|
||||
public static final ItemType BREEZE_ROD = builder("breeze_rod").setMaxAmount(64).build();
|
||||
|
||||
// 1.21 items
|
||||
public static final ItemType MUSIC_DISC_CREATOR = builder("music_disc_creator").setMaxAmount(1).setAttributes(ItemAttribute.MUSIC_DISC).setComponent(RARITY, ItemRarity.RARE).build();
|
||||
public static final ItemType MUSIC_DISC_CREATOR_MUSIC_BOX = builder("music_disc_creator_music_box").setMaxAmount(1).setAttributes(ItemAttribute.MUSIC_DISC).setComponent(RARITY, ItemRarity.RARE).build();
|
||||
public static final ItemType MUSIC_DISC_PRECIPICE = builder("music_disc_precipice").setMaxAmount(1).setAttributes(ItemAttribute.MUSIC_DISC).setComponent(RARITY, ItemRarity.RARE).build();
|
||||
|
||||
/**
|
||||
* @deprecated Burning furnace shows up as a missing texture, removed in 1.9
|
||||
*/
|
||||
@@ -1483,8 +1487,15 @@ public class ItemTypes {
|
||||
@Deprecated
|
||||
public static final ItemType POTTERY_SHARD_SKULL = builder("POTTERY_SHARD_SKULL").setMaxAmount(64).build();
|
||||
|
||||
// </editor-fold>
|
||||
|
||||
|
||||
public static VersionedRegistry<ItemType> getRegistry() {
|
||||
return REGISTRY;
|
||||
}
|
||||
|
||||
public static Collection<ItemType> values() {
|
||||
return ITEM_TYPE_MAP.values();
|
||||
return REGISTRY.getEntries();
|
||||
}
|
||||
|
||||
public static Builder builder(String key) {
|
||||
@@ -1511,10 +1522,7 @@ public class ItemTypes {
|
||||
}
|
||||
StaticComponentMap components = mapBuilder.build();
|
||||
|
||||
TypesBuilderData data = TYPES_BUILDER.define(key);
|
||||
ItemType type = new ItemType() {
|
||||
private final int[] ids = data.getData();
|
||||
|
||||
return REGISTRY.define(key, data -> new ItemType() {
|
||||
@Override
|
||||
public int getMaxAmount() {
|
||||
return maxAmount;
|
||||
@@ -1532,8 +1540,7 @@ public class ItemTypes {
|
||||
|
||||
@Override
|
||||
public int getId(ClientVersion version) {
|
||||
int index = TYPES_BUILDER.getDataIndex(version);
|
||||
return ids[index];
|
||||
return data.getId(version);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1574,21 +1581,15 @@ public class ItemTypes {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
MappingHelper.registerMapping(TYPES_BUILDER, ITEM_TYPE_MAP, ITEM_TYPE_ID_MAP, type);
|
||||
return type;
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ItemType getByName(String name) {
|
||||
return ITEM_TYPE_MAP.get(name);
|
||||
public static @Nullable ItemType getByName(String name) {
|
||||
return REGISTRY.getByName(name);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ItemType getById(ClientVersion version, int id) {
|
||||
int index = TYPES_BUILDER.getDataIndex(version);
|
||||
Map<Integer, ItemType> typeIdMap = ITEM_TYPE_ID_MAP.get((byte) index);
|
||||
return typeIdMap.getOrDefault(id, ItemTypes.AIR);
|
||||
public static @Nullable ItemType getById(ClientVersion version, int id) {
|
||||
return REGISTRY.getById(version, id);
|
||||
}
|
||||
|
||||
public static ItemType getTypePlacingState(StateType type) {
|
||||
@@ -1657,6 +1658,6 @@ public class ItemTypes {
|
||||
}
|
||||
|
||||
static {
|
||||
TYPES_BUILDER.unloadFileMappings();
|
||||
REGISTRY.unloadMappings();
|
||||
}
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2024 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.mapper;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public abstract class AbstractMappedEntity implements MappedEntity {
|
||||
|
||||
protected final @Nullable TypesBuilderData data;
|
||||
|
||||
protected AbstractMappedEntity(@Nullable TypesBuilderData data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public @Nullable TypesBuilderData getRegistryData() {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getName() {
|
||||
if (this.data != null) {
|
||||
return this.data.getName();
|
||||
}
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId(ClientVersion version) {
|
||||
if (this.data != null) {
|
||||
return this.data.getId(version);
|
||||
}
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRegistered() {
|
||||
return this.data != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof AbstractMappedEntity)) return false;
|
||||
AbstractMappedEntity that = (AbstractMappedEntity) obj;
|
||||
if (this.data != null && that.data != null) {
|
||||
return this.data.getName().equals(that.data.getName());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
if (this.data != null) {
|
||||
return Objects.hashCode(this.data.getName());
|
||||
}
|
||||
return super.hashCode();
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2024 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.mapper;
|
||||
|
||||
import com.github.retrooper.packetevents.util.mappings.TypesBuilderData;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface CopyableEntity<T extends MappedEntity> {
|
||||
|
||||
T copy(@Nullable TypesBuilderData newData);
|
||||
}
|
||||
+69
@@ -18,13 +18,18 @@
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.mapper;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTList;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.util.mappings.IRegistry;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
/**
|
||||
@@ -54,6 +59,10 @@ public class MappedEntitySet<T> {
|
||||
this.entities = entities;
|
||||
}
|
||||
|
||||
public static <Z extends MappedEntity> MappedEntitySet<Z> createEmpty() {
|
||||
return new MappedEntitySet<>(new ArrayList<>(0));
|
||||
}
|
||||
|
||||
public static <Z extends MappedEntity> MappedEntitySet<Z> read(
|
||||
PacketWrapper<?> wrapper, BiFunction<ClientVersion, Integer, Z> getter) {
|
||||
int count = wrapper.readVarInt() - 1;
|
||||
@@ -80,4 +89,64 @@ public class MappedEntitySet<T> {
|
||||
wrapper.writeMappedEntity(entity);
|
||||
}
|
||||
}
|
||||
|
||||
public static <Z extends MappedEntity> MappedEntitySet<Z> decode(
|
||||
NBT nbt, ClientVersion version, IRegistry<Z> registry) {
|
||||
if (nbt instanceof NBTString) {
|
||||
String tagName = ((NBTString) nbt).getValue();
|
||||
ResourceLocation tagKey = new ResourceLocation(tagName);
|
||||
return new MappedEntitySet<>(tagKey);
|
||||
}
|
||||
NBTList<?> listTag = (NBTList<?>) nbt;
|
||||
List<Z> list = new ArrayList<>(listTag.size());
|
||||
for (NBT tag : listTag.getTags()) {
|
||||
ResourceLocation tagKey = new ResourceLocation(((NBTString) tag).getValue());
|
||||
list.add(registry.getByName(tagKey));
|
||||
}
|
||||
return new MappedEntitySet<>(list);
|
||||
}
|
||||
|
||||
public static <Z extends MappedEntity> NBT encode(MappedEntitySet<Z> set, ClientVersion version) {
|
||||
if (set.tagKey != null) {
|
||||
return new NBTString(set.tagKey.toString());
|
||||
}
|
||||
|
||||
assert set.entities != null; // can't be null, verified in ctor
|
||||
NBTList<NBTString> listTag = NBTList.createStringList();
|
||||
for (Z entity : set.entities) {
|
||||
listTag.addTag(new NBTString(entity.getName().toString()));
|
||||
}
|
||||
return listTag;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return this.entities != null && this.entities.isEmpty();
|
||||
}
|
||||
|
||||
public @Nullable ResourceLocation getTagKey() {
|
||||
return this.tagKey;
|
||||
}
|
||||
|
||||
public @Nullable List<T> getEntities() {
|
||||
return this.entities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof MappedEntitySet)) return false;
|
||||
MappedEntitySet<?> that = (MappedEntitySet<?>) obj;
|
||||
if (!Objects.equals(this.tagKey, that.tagKey)) return false;
|
||||
return Objects.equals(this.entities, that.entities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.tagKey, this.entities);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MappedEntitySet{tagKey=" + this.tagKey + ", entities=" + this.entities + '}';
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,10 @@ public class NBTByte extends NBTNumber {
|
||||
this((byte) (value ? 1 : 0));
|
||||
}
|
||||
|
||||
public boolean getAsBool() {
|
||||
return this.value != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTType<NBTByte> getType() {
|
||||
return NBTType.BYTE;
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2024 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.github.retrooper.packetevents.protocol.nbt;
|
||||
|
||||
import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface NBTLimiter {
|
||||
|
||||
int DEFAULT_MAX_SIZE = 2097152;
|
||||
|
||||
static NBTLimiter noop() {
|
||||
return new NBTLimiter() {
|
||||
@Override
|
||||
public void increment(int amount) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkReadability(int length) {
|
||||
// no-op
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static NBTLimiter forBuffer(final @NotNull Object byteBuf) {
|
||||
return forBuffer(byteBuf, DEFAULT_MAX_SIZE);
|
||||
}
|
||||
|
||||
static NBTLimiter forBuffer(final @NotNull Object byteBuf, final int max) {
|
||||
return new NBTLimiter() {
|
||||
private int bytes;
|
||||
|
||||
@Override
|
||||
public void increment(int amount) {
|
||||
bytes += amount;
|
||||
|
||||
if (bytes > max) throw new IllegalArgumentException("NBT size limit reached (" + bytes + "/" + max + ")");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkReadability(int length) {
|
||||
if (length > ByteBufHelper.readableBytes(byteBuf)) throw new IllegalArgumentException("Length is too large: " + length + ", readable: " + ByteBufHelper.readableBytes(byteBuf));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void increment(int amount);
|
||||
|
||||
void checkReadability(int length);
|
||||
|
||||
}
|
||||
@@ -27,14 +27,21 @@ import java.util.Objects;
|
||||
public class NBTList<T extends NBT> extends NBT {
|
||||
|
||||
protected final NBTType<T> type;
|
||||
protected final List<T> tags = new ArrayList<>();
|
||||
protected final List<T> tags;
|
||||
|
||||
public NBTList(NBTType<T> type) {
|
||||
this.type = type;
|
||||
this.tags = new ArrayList<>();
|
||||
}
|
||||
|
||||
public NBTList(NBTType<T> type, int size) {
|
||||
this.type = type;
|
||||
this.tags = new ArrayList<>(size);
|
||||
}
|
||||
|
||||
public NBTList(NBTType<T> type, List<T> tags) {
|
||||
this.type = type;
|
||||
this.tags = new ArrayList<>();
|
||||
this.tags.addAll(tags);
|
||||
}
|
||||
|
||||
|
||||
+8
-2
@@ -37,6 +37,7 @@ import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
public class NBTCodec {
|
||||
|
||||
//PacketEvents start: JSON -> NBT conversion method
|
||||
@Deprecated
|
||||
public static NBT jsonToNBT(JsonElement element) {
|
||||
@@ -149,11 +150,16 @@ public class NBTCodec {
|
||||
//PacketEvents end
|
||||
|
||||
public static NBT readNBTFromBuffer(Object byteBuf, ServerVersion serverVersion) {
|
||||
NBTLimiter limiter = NBTLimiter.forBuffer(byteBuf);
|
||||
return readNBTFromBuffer(byteBuf, serverVersion, limiter);
|
||||
}
|
||||
|
||||
public static NBT readNBTFromBuffer(Object byteBuf, ServerVersion serverVersion, NBTLimiter limiter) {
|
||||
if (serverVersion.isNewerThanOrEquals(ServerVersion.V_1_8)) {
|
||||
try {
|
||||
final boolean named = serverVersion.isOlderThan(ServerVersion.V_1_20_2);
|
||||
return DefaultNBTSerializer.INSTANCE.deserializeTag(
|
||||
new ByteBufInputStream(byteBuf), named);
|
||||
limiter, new ByteBufInputStream(byteBuf), named);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -167,7 +173,7 @@ public class NBTCodec {
|
||||
Object slicedBuffer = ByteBufHelper.readSlice(byteBuf, length);
|
||||
try (DataInputStream stream = new DataInputStream(
|
||||
new GZIPInputStream(new ByteBufInputStream(slicedBuffer)))) {
|
||||
return DefaultNBTSerializer.INSTANCE.deserializeTag(stream);
|
||||
return DefaultNBTSerializer.INSTANCE.deserializeTag(limiter, stream);
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
|
||||
+131
-57
@@ -31,20 +31,61 @@ public class DefaultNBTSerializer extends NBTSerializer<DataInput, DataOutput> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public DefaultNBTSerializer() {
|
||||
super(DataInput::readByte, DataOutput::writeByte, DataInput::readUTF, DataOutput::writeUTF);
|
||||
registerType(NBTType.END, 0, stream -> NBTEnd.INSTANCE, (stream, tag) -> {
|
||||
super(
|
||||
(limiter, dataInput) -> {
|
||||
limiter.increment(1);
|
||||
return dataInput.readByte();
|
||||
},
|
||||
DataOutput::writeByte,
|
||||
(limiter, dataInput) -> {
|
||||
String name = dataInput.readUTF();
|
||||
limiter.increment(name.length() * 2 + 28);
|
||||
return name;
|
||||
},
|
||||
DataOutput::writeUTF
|
||||
);
|
||||
registerType(NBTType.END, 0, (limiter, stream) -> {
|
||||
limiter.increment(8);
|
||||
return NBTEnd.INSTANCE;
|
||||
}, (stream, tag) -> {
|
||||
});
|
||||
registerType(NBTType.BYTE, 1, stream -> new NBTByte(stream.readByte()), (stream, tag) -> stream.writeByte(tag.getAsByte()));
|
||||
registerType(NBTType.SHORT, 2, stream -> new NBTShort(stream.readShort()), (stream, tag) -> stream.writeShort(tag.getAsShort()));
|
||||
registerType(NBTType.INT, 3, stream -> new NBTInt(stream.readInt()), (stream, tag) -> stream.writeInt(tag.getAsInt()));
|
||||
registerType(NBTType.LONG, 4, stream -> new NBTLong(stream.readLong()), (stream, tag) -> stream.writeLong(tag.getAsLong()));
|
||||
registerType(NBTType.FLOAT, 5, stream -> new NBTFloat(stream.readFloat()), (stream, tag) -> stream.writeFloat(tag.getAsFloat()));
|
||||
registerType(NBTType.DOUBLE, 6, stream -> new NBTDouble(stream.readDouble()), (stream, tag) -> stream.writeDouble(tag.getAsDouble()));
|
||||
registerType(NBTType.STRING, 8, stream -> new NBTString(stream.readUTF()), (stream, tag) -> stream.writeUTF(tag.getValue()));
|
||||
registerType(NBTType.BYTE, 1, (limiter, stream) -> {
|
||||
limiter.increment(9);
|
||||
return new NBTByte(stream.readByte());
|
||||
}, (stream, tag) -> stream.writeByte(tag.getAsByte()));
|
||||
registerType(NBTType.SHORT, 2, (limiter, stream) -> {
|
||||
limiter.increment(10);
|
||||
return new NBTShort(stream.readShort());
|
||||
}, (stream, tag) -> stream.writeShort(tag.getAsShort()));
|
||||
registerType(NBTType.INT, 3, (limiter, stream) -> {
|
||||
limiter.increment(12);
|
||||
return new NBTInt(stream.readInt());
|
||||
}, (stream, tag) -> stream.writeInt(tag.getAsInt()));
|
||||
registerType(NBTType.LONG, 4, (limiter, stream) -> {
|
||||
limiter.increment(16);
|
||||
return new NBTLong(stream.readLong());
|
||||
}, (stream, tag) -> stream.writeLong(tag.getAsLong()));
|
||||
registerType(NBTType.FLOAT, 5, (limiter, stream) -> {
|
||||
limiter.increment(12);
|
||||
return new NBTFloat(stream.readFloat());
|
||||
}, (stream, tag) -> stream.writeFloat(tag.getAsFloat()));
|
||||
registerType(NBTType.DOUBLE, 6, (limiter, stream) -> {
|
||||
limiter.increment(16);
|
||||
return new NBTDouble(stream.readDouble());
|
||||
}, (stream, tag) -> stream.writeDouble(tag.getAsDouble()));
|
||||
registerType(
|
||||
NBTType.BYTE_ARRAY, 7,
|
||||
stream -> {
|
||||
byte[] array = new byte[stream.readInt()];
|
||||
(limiter, stream) -> {
|
||||
limiter.increment(24);
|
||||
int length = stream.readInt();
|
||||
|
||||
if (length >= 1 << 24)
|
||||
throw new IllegalArgumentException("Byte array length is too large: " + length);
|
||||
|
||||
limiter.checkReadability(length);
|
||||
limiter.increment(length);
|
||||
|
||||
byte[] array = new byte[length];
|
||||
stream.readFully(array);
|
||||
return new NBTByteArray(array);
|
||||
},
|
||||
@@ -54,10 +95,76 @@ public class DefaultNBTSerializer extends NBTSerializer<DataInput, DataOutput> {
|
||||
stream.write(array);
|
||||
}
|
||||
);
|
||||
registerType(NBTType.STRING, 8, (limiter, stream) -> {
|
||||
limiter.increment(36);
|
||||
String string = stream.readUTF();
|
||||
limiter.increment(string.length() * 2);
|
||||
return new NBTString(string);
|
||||
}, (stream, tag) -> stream.writeUTF(tag.getValue()));
|
||||
registerType(
|
||||
NBTType.LIST, 9,
|
||||
(limiter, stream) -> {
|
||||
limiter.increment(37);
|
||||
|
||||
NBTType<? extends NBT> valueType = readTagType(limiter, stream);
|
||||
int size = stream.readInt();
|
||||
|
||||
if ((valueType == NBTType.END) && (size > 0)) {
|
||||
throw new IllegalStateException("Missing nbt list values tag type");
|
||||
}
|
||||
limiter.increment(4 * size);
|
||||
NBTList<NBT> list = new NBTList<>((NBTType<NBT>) valueType, size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
list.addTag(readTag(limiter, stream, valueType));
|
||||
}
|
||||
return list;
|
||||
},
|
||||
(stream, tag) -> {
|
||||
writeTagType(stream, tag.getTagsType());
|
||||
stream.writeInt(tag.size());
|
||||
for (NBT value : ((List<NBT>) tag.getTags())) {
|
||||
writeTag(stream, value);
|
||||
}
|
||||
}
|
||||
);
|
||||
registerType(
|
||||
NBTType.COMPOUND, 10,
|
||||
(limiter, stream) -> {
|
||||
limiter.increment(48);
|
||||
|
||||
NBTCompound compound = new NBTCompound();
|
||||
NBTType<?> valueType;
|
||||
while ((valueType = readTagType(limiter, stream)) != NBTType.END) {
|
||||
String name = readTagName(limiter, stream);
|
||||
NBT nbt = readTag(limiter, stream, valueType);
|
||||
if(!compound.getTags().containsKey(name)) limiter.increment(36);
|
||||
compound.setTag(name, nbt);
|
||||
}
|
||||
return compound;
|
||||
},
|
||||
(stream, tag) -> {
|
||||
for (Entry<String, NBT> entry : tag.getTags().entrySet()) {
|
||||
NBT value = entry.getValue();
|
||||
writeTagType(stream, value.getType());
|
||||
writeTagName(stream, entry.getKey());
|
||||
writeTag(stream, value);
|
||||
}
|
||||
writeTagType(stream, NBTType.END);
|
||||
}
|
||||
);
|
||||
registerType(
|
||||
NBTType.INT_ARRAY, 11,
|
||||
stream -> {
|
||||
int[] array = new int[stream.readInt()];
|
||||
(limiter, stream) -> {
|
||||
limiter.increment(24);
|
||||
int length = stream.readInt();
|
||||
|
||||
if (length >= 1 << 24)
|
||||
throw new IllegalArgumentException("Int array length is too large: " + length);
|
||||
|
||||
limiter.checkReadability(length * 4);
|
||||
limiter.increment(length * 4);
|
||||
|
||||
int[] array = new int[length];
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
array[i] = stream.readInt();
|
||||
}
|
||||
@@ -73,8 +180,17 @@ public class DefaultNBTSerializer extends NBTSerializer<DataInput, DataOutput> {
|
||||
);
|
||||
registerType(
|
||||
NBTType.LONG_ARRAY, 12,
|
||||
stream -> {
|
||||
long[] array = new long[stream.readInt()];
|
||||
(limiter, stream) -> {
|
||||
limiter.increment(24);
|
||||
int length = stream.readInt();
|
||||
|
||||
if (length >= 1 << 24)
|
||||
throw new IllegalArgumentException("Long array length is too large: " + length);
|
||||
|
||||
limiter.checkReadability(length * 8);
|
||||
limiter.increment(length * 8);
|
||||
|
||||
long[] array = new long[length];
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
array[i] = stream.readLong();
|
||||
}
|
||||
@@ -88,48 +204,6 @@ public class DefaultNBTSerializer extends NBTSerializer<DataInput, DataOutput> {
|
||||
}
|
||||
}
|
||||
);
|
||||
registerType(
|
||||
NBTType.COMPOUND, 10,
|
||||
stream -> {
|
||||
NBTCompound compound = new NBTCompound();
|
||||
NBTType<?> valueType = null;
|
||||
while ((valueType = readTagType(stream)) != NBTType.END) {
|
||||
compound.setTag(readTagName(stream), readTag(stream, valueType));
|
||||
}
|
||||
return compound;
|
||||
},
|
||||
(stream, tag) -> {
|
||||
for (Entry<String, NBT> entry : tag.getTags().entrySet()) {
|
||||
NBT value = entry.getValue();
|
||||
writeTagType(stream, value.getType());
|
||||
writeTagName(stream, entry.getKey());
|
||||
writeTag(stream, value);
|
||||
}
|
||||
writeTagType(stream, NBTType.END);
|
||||
}
|
||||
);
|
||||
registerType(
|
||||
NBTType.LIST, 9,
|
||||
stream -> {
|
||||
NBTType<? extends NBT> valueType = readTagType(stream);
|
||||
int size = stream.readInt();
|
||||
if ((valueType == NBTType.END) && (size > 0)) {
|
||||
throw new IllegalStateException("Missing nbt list values tag type");
|
||||
}
|
||||
NBTList<NBT> list = new NBTList<>((NBTType<NBT>) valueType);
|
||||
for (int i = 0; i < size; i++) {
|
||||
list.addTag(readTag(stream, valueType));
|
||||
}
|
||||
return list;
|
||||
},
|
||||
(stream, tag) -> {
|
||||
writeTagType(stream, tag.getTagsType());
|
||||
stream.writeInt(tag.size());
|
||||
for (NBT value : ((List<NBT>) tag.getTags())) {
|
||||
writeTag(stream, value);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2024 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.github.retrooper.packetevents.protocol.nbt.serializer;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTLimiter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface NBTReader<T extends NBT, IN> {
|
||||
|
||||
default T deserializeTag(NBTLimiter limiter, IN from) throws IOException {
|
||||
return deserializeTag(limiter, from, true);
|
||||
}
|
||||
|
||||
T deserializeTag(NBTLimiter limiter, IN from, boolean named) throws IOException;
|
||||
|
||||
}
|
||||
+20
-25
@@ -19,6 +19,7 @@
|
||||
package com.github.retrooper.packetevents.protocol.nbt.serializer;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTLimiter;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTType;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -26,7 +27,7 @@ import java.text.MessageFormat;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class NBTSerializer<IN, OUT> {
|
||||
public class NBTSerializer<IN, OUT> implements NBTReader<NBT, IN>, NBTWriter<NBT, OUT> {
|
||||
|
||||
protected final IdReader<IN> idReader;
|
||||
protected final IdWriter<OUT> idWriter;
|
||||
@@ -46,25 +47,19 @@ public class NBTSerializer<IN, OUT> {
|
||||
this.nameWriter = nameWriter;
|
||||
}
|
||||
|
||||
public NBT deserializeTag(IN from) throws IOException {
|
||||
return deserializeTag(from, true);
|
||||
}
|
||||
|
||||
public NBT deserializeTag(IN from, boolean named) throws IOException {
|
||||
NBTType<?> type = readTagType(from);
|
||||
@Override
|
||||
public NBT deserializeTag(NBTLimiter limiter, IN from, boolean named) throws IOException {
|
||||
NBTType<?> type = readTagType(limiter, from);
|
||||
if (type == NBTType.END) {
|
||||
return null;
|
||||
}
|
||||
if (named) {
|
||||
readTagName(from);
|
||||
readTagName(limiter, from);
|
||||
}
|
||||
return readTag(from, type);
|
||||
}
|
||||
|
||||
public void serializeTag(OUT to, NBT tag) throws IOException {
|
||||
serializeTag(to, tag, true);
|
||||
return readTag(limiter, from, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeTag(OUT to, NBT tag, boolean named) throws IOException {
|
||||
NBTType<?> type = tag.getType();
|
||||
writeTagType(to, type);
|
||||
@@ -94,8 +89,8 @@ public class NBTSerializer<IN, OUT> {
|
||||
typeWriters.put(type, typeWriter);
|
||||
}
|
||||
|
||||
protected NBTType<?> readTagType(IN from) throws IOException {
|
||||
int id = idReader.readId(from);
|
||||
NBTType<?> readTagType(NBTLimiter limiter, IN from) throws IOException {
|
||||
int id = idReader.readId(limiter, from);
|
||||
NBTType<?> type = idToType.get(id);
|
||||
if (type == null) {
|
||||
throw new IOException(MessageFormat.format("Unknown nbt type id {0}", id));
|
||||
@@ -103,19 +98,19 @@ public class NBTSerializer<IN, OUT> {
|
||||
return type;
|
||||
}
|
||||
|
||||
protected String readTagName(IN from) throws IOException {
|
||||
return nameReader.readName(from);
|
||||
String readTagName(NBTLimiter limiter, IN from) throws IOException {
|
||||
return nameReader.readName(limiter, from);
|
||||
}
|
||||
|
||||
protected NBT readTag(IN from, NBTType<?> type) throws IOException {
|
||||
NBT readTag(NBTLimiter limiter, IN from, NBTType<?> type) throws IOException {
|
||||
TagReader<IN, ? extends NBT> f = typeReaders.get(type);
|
||||
if (f == null) {
|
||||
throw new IOException(MessageFormat.format("No reader registered for nbt type {0}", type));
|
||||
}
|
||||
return f.readTag(from);
|
||||
return f.readTag(limiter, from);
|
||||
}
|
||||
|
||||
protected void writeTagType(OUT stream, NBTType<?> type) throws IOException {
|
||||
void writeTagType(OUT stream, NBTType<?> type) throws IOException {
|
||||
int id = typeToId.getOrDefault(type, -1);
|
||||
if (id == -1) {
|
||||
throw new IOException(MessageFormat.format("Unknown nbt type {0}", type));
|
||||
@@ -123,12 +118,12 @@ public class NBTSerializer<IN, OUT> {
|
||||
idWriter.writeId(stream, id);
|
||||
}
|
||||
|
||||
protected void writeTagName(OUT stream, String name) throws IOException {
|
||||
void writeTagName(OUT stream, String name) throws IOException {
|
||||
nameWriter.writeName(stream, name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void writeTag(OUT stream, NBT tag) throws IOException {
|
||||
void writeTag(OUT stream, NBT tag) throws IOException {
|
||||
TagWriter<OUT, NBT> f = (TagWriter<OUT, NBT>) typeWriters.get(tag.getType());
|
||||
if (f == null) {
|
||||
throw new IOException(MessageFormat.format("No writer registered for nbt type {0}", tag.getType()));
|
||||
@@ -138,7 +133,7 @@ public class NBTSerializer<IN, OUT> {
|
||||
|
||||
@FunctionalInterface
|
||||
protected interface IdReader<T> {
|
||||
int readId(T from) throws IOException;
|
||||
int readId(NBTLimiter limiter, T from) throws IOException;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
@@ -148,7 +143,7 @@ public class NBTSerializer<IN, OUT> {
|
||||
|
||||
@FunctionalInterface
|
||||
protected interface NameReader<T> {
|
||||
String readName(T from) throws IOException;
|
||||
String readName(NBTLimiter limiter, T from) throws IOException;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
@@ -158,7 +153,7 @@ public class NBTSerializer<IN, OUT> {
|
||||
|
||||
@FunctionalInterface
|
||||
protected interface TagReader<IN, T extends NBT> {
|
||||
T readTag(IN from) throws IOException;
|
||||
T readTag(NBTLimiter limiter, IN from) throws IOException;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2024 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.github.retrooper.packetevents.protocol.nbt.serializer;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public interface NBTWriter<T extends NBT, OUT> {
|
||||
|
||||
default void serializeTag(OUT to, T tag) throws IOException {
|
||||
serializeTag(to, tag, true);
|
||||
}
|
||||
|
||||
void serializeTag(OUT to, NBT tag, boolean named) throws IOException;
|
||||
|
||||
}
|
||||
+698
@@ -0,0 +1,698 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2024 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.github.retrooper.packetevents.protocol.nbt.serializer;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.nbt.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
public final class SequentialNBTReader implements NBTReader<NBT, DataInputStream> {
|
||||
|
||||
public static final SequentialNBTReader INSTANCE = new SequentialNBTReader();
|
||||
|
||||
private static final Map<NBTType<?>, TagSkip> TAG_SKIPS = new HashMap<>(16);
|
||||
private static final Map<NBTType<?>, TagBinaryReader> TAG_BINARY_READERS = new HashMap<>(16);
|
||||
|
||||
@Override
|
||||
public NBT deserializeTag(NBTLimiter limiter, DataInputStream from, boolean named) throws IOException {
|
||||
NBTType<?> type = DefaultNBTSerializer.INSTANCE.readTagType(limiter, from);
|
||||
|
||||
if (named) {
|
||||
// skip name
|
||||
int len = from.readUnsignedShort();
|
||||
from.skipBytes(len);
|
||||
}
|
||||
|
||||
NBT nbt;
|
||||
if (type == NBTType.COMPOUND) {
|
||||
nbt = new Compound(from, limiter, () -> {});
|
||||
} else if (type == NBTType.LIST) {
|
||||
nbt = new List(from, limiter, () -> {});
|
||||
} else {
|
||||
nbt = DefaultNBTSerializer.INSTANCE.readTag(limiter, from, type);
|
||||
}
|
||||
|
||||
return nbt;
|
||||
}
|
||||
|
||||
private static void checkReadable(NBT lastRead) {
|
||||
if (lastRead == null) return;
|
||||
if (lastRead instanceof Iterator && ((Iterator<NBT>) lastRead).hasNext()) {
|
||||
throw new IllegalStateException("Previous nbt has not been read completely");
|
||||
}
|
||||
}
|
||||
|
||||
public static class Compound extends NBT implements Iterator<Map.Entry<String, NBT>>, Iterable<Map.Entry<String, NBT>>, Skippable, Closeable {
|
||||
|
||||
private final DataInputStream stream;
|
||||
private final NBTLimiter limiter;
|
||||
private final Runnable onComplete;
|
||||
private NBTType<?> nextType;
|
||||
private NBT lastRead;
|
||||
private boolean hasReadType;
|
||||
|
||||
private Compound(DataInputStream stream, NBTLimiter limiter, Runnable onComplete) {
|
||||
this.stream = stream;
|
||||
this.limiter = limiter;
|
||||
this.onComplete = onComplete;
|
||||
limiter.increment(48);
|
||||
runCompleted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTType<?> getType() {
|
||||
return NBTType.COMPOUND;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return this == other;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBT copy() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
checkReadable(lastRead);
|
||||
if (!hasReadType) {
|
||||
try {
|
||||
nextType = DefaultNBTSerializer.INSTANCE.readTagType(limiter, stream);
|
||||
hasReadType = true;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
return nextType != NBTType.END;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map.Entry<String, NBT> next() {
|
||||
if (!hasNext()) {
|
||||
throw new IllegalStateException("No more elements in compound");
|
||||
}
|
||||
|
||||
try {
|
||||
hasReadType = false;
|
||||
|
||||
String name = DefaultNBTSerializer.INSTANCE.readTagName(limiter, stream);
|
||||
|
||||
if (nextType == NBTType.COMPOUND) {
|
||||
lastRead = new Compound(stream, limiter, this::runCompleted);
|
||||
} else if (nextType == NBTType.LIST) {
|
||||
lastRead = new List(stream, limiter, this::runCompleted);
|
||||
} else {
|
||||
lastRead = DefaultNBTSerializer.INSTANCE.readTag(limiter, stream, nextType);
|
||||
runCompleted();
|
||||
}
|
||||
limiter.increment(36);
|
||||
|
||||
return new AbstractMap.SimpleEntry<>(name, lastRead);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void runCompleted() {
|
||||
if (!hasNext()) {
|
||||
onComplete.run();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<Map.Entry<String, NBT>> iterator() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void skip() {
|
||||
if (lastRead instanceof Skippable) {
|
||||
((Skippable) lastRead).skip();
|
||||
}
|
||||
|
||||
if (!hasNext()) return;
|
||||
|
||||
try {
|
||||
int len = stream.readUnsignedShort();
|
||||
stream.skipBytes(len);
|
||||
|
||||
TAG_SKIPS.get(nextType).skip(limiter, stream);
|
||||
limiter.increment(36);
|
||||
|
||||
TAG_SKIPS.get(NBTType.COMPOUND).skip(limiter, stream);
|
||||
|
||||
hasReadType = true;
|
||||
nextType = NBTType.END;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
runCompleted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void skipOne() {
|
||||
checkReadable(lastRead);
|
||||
|
||||
if (!hasNext()) return;
|
||||
|
||||
try {
|
||||
int len = stream.readUnsignedShort();
|
||||
stream.skipBytes(len);
|
||||
|
||||
TAG_SKIPS.get(nextType).skip(limiter, stream);
|
||||
limiter.increment(36);
|
||||
hasReadType = false;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
runCompleted();
|
||||
}
|
||||
|
||||
public NBTCompound readFully() {
|
||||
try {
|
||||
// skip last read
|
||||
if (lastRead instanceof Skippable) {
|
||||
((Skippable) lastRead).skip();
|
||||
}
|
||||
|
||||
if (!hasNext()) return new NBTCompound();
|
||||
|
||||
NBTCompound compound = new NBTCompound();
|
||||
|
||||
// we have read a tag type, so we can start reading the tag
|
||||
do {
|
||||
String name = DefaultNBTSerializer.INSTANCE.readTagName(limiter, stream);
|
||||
NBT nbt = DefaultNBTSerializer.INSTANCE.readTag(limiter, stream, nextType);
|
||||
limiter.increment(36);
|
||||
compound.setTag(name, nbt);
|
||||
} while ((nextType = DefaultNBTSerializer.INSTANCE.readTagType(limiter, stream)) != NBTType.END);
|
||||
|
||||
hasReadType = true;
|
||||
runCompleted();
|
||||
return compound;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] readFullyAsBytes() {
|
||||
try {
|
||||
// skip last read
|
||||
if (lastRead instanceof Skippable) {
|
||||
((Skippable) lastRead).skip();
|
||||
}
|
||||
|
||||
if (!hasNext()) return new byte[] { 10, 0 }; // empty compound
|
||||
|
||||
try (ByteArrayOutputStream bytes = new ByteArrayOutputStream(); DataOutputStream out = new DataOutputStream(bytes)) {
|
||||
out.write(10); // compound type
|
||||
|
||||
do {
|
||||
out.write(DefaultNBTSerializer.INSTANCE.typeToId.get(nextType));
|
||||
|
||||
// name
|
||||
byte[] name = TAG_BINARY_READERS.get(NBTType.STRING).read(NBTLimiter.noop(), stream);
|
||||
limiter.increment(name.length * 2 + 28);
|
||||
out.write(name);
|
||||
|
||||
// nbt
|
||||
byte[] nbt = TAG_BINARY_READERS.get(nextType).read(limiter, stream);
|
||||
limiter.increment(36);
|
||||
|
||||
out.write(nbt);
|
||||
} while ((nextType = DefaultNBTSerializer.INSTANCE.readTagType(limiter, stream)) != NBTType.END);
|
||||
|
||||
out.write(0);
|
||||
hasReadType = true;
|
||||
runCompleted();
|
||||
return bytes.toByteArray();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
|
||||
public static class List extends NBT implements Iterator<NBT>, Iterable<NBT>, Skippable, Closeable {
|
||||
|
||||
private final DataInputStream stream;
|
||||
private final NBTLimiter limiter;
|
||||
private final Runnable onComplete;
|
||||
private final NBTType<?> listType;
|
||||
private NBT lastRead;
|
||||
public int remaining;
|
||||
|
||||
private List(DataInputStream stream, NBTLimiter limiter, Runnable onComplete) {
|
||||
this.stream = stream;
|
||||
this.limiter = limiter;
|
||||
this.onComplete = onComplete;
|
||||
limiter.increment(37);
|
||||
try {
|
||||
this.listType = DefaultNBTSerializer.INSTANCE.readTagType(limiter, stream);
|
||||
this.remaining = stream.readInt();
|
||||
limiter.increment(remaining * 4);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
runCompleted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTType<?> getType() {
|
||||
return NBTType.LIST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return this == other;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBT copy() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return remaining > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBT next() {
|
||||
checkReadable(lastRead);
|
||||
if (!hasNext()) {
|
||||
throw new IllegalStateException("No more elements in list");
|
||||
}
|
||||
|
||||
try {
|
||||
remaining--;
|
||||
if (listType == NBTType.COMPOUND) {
|
||||
lastRead = new Compound(stream, limiter, this::runCompleted);
|
||||
} else if (listType == NBTType.LIST) {
|
||||
lastRead = new List(stream, limiter, this::runCompleted);
|
||||
} else {
|
||||
lastRead = DefaultNBTSerializer.INSTANCE.readTag(limiter, stream, listType);
|
||||
runCompleted();
|
||||
}
|
||||
|
||||
return lastRead;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void runCompleted() {
|
||||
if (!hasNext()) {
|
||||
onComplete.run();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<NBT> iterator() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void skip() {
|
||||
if (lastRead instanceof Skippable) {
|
||||
((Skippable) lastRead).skip();
|
||||
}
|
||||
|
||||
if (!hasNext()) return;
|
||||
|
||||
try {
|
||||
TagSkip typeSkip = TAG_SKIPS.get(listType);
|
||||
for (int i = 0; i < remaining; i++) {
|
||||
typeSkip.skip(limiter, stream);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
remaining = 0;
|
||||
runCompleted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void skipOne() {
|
||||
checkReadable(lastRead);
|
||||
|
||||
if (!hasNext()) return;
|
||||
|
||||
try {
|
||||
TAG_SKIPS.get(listType).skip(limiter, stream);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
remaining--;
|
||||
runCompleted();
|
||||
}
|
||||
|
||||
public NBTList<NBT> readFully() {
|
||||
try {
|
||||
// skip last read
|
||||
if (lastRead instanceof Skippable) {
|
||||
((Skippable) lastRead).skip();
|
||||
}
|
||||
|
||||
if (!hasNext()) return new NBTList<>((NBTType<NBT>) listType, 0);
|
||||
|
||||
NBTList<NBT> list = new NBTList<>((NBTType<NBT>) listType, remaining);
|
||||
for (int i = 0; i < remaining; i++) {
|
||||
list.addTag(DefaultNBTSerializer.INSTANCE.readTag(limiter, stream, listType));
|
||||
}
|
||||
|
||||
remaining = 0;
|
||||
runCompleted();
|
||||
return list;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] readFullyAsBinary() {
|
||||
try {
|
||||
// skip last read
|
||||
if (lastRead instanceof Skippable) {
|
||||
((Skippable) lastRead).skip();
|
||||
}
|
||||
|
||||
if (!hasNext()) return new byte[] { 9 };
|
||||
|
||||
byte[] array = null;
|
||||
for (int i = 0; i < remaining; i++) {
|
||||
byte[] element = TAG_BINARY_READERS.get(listType).read(limiter, stream);
|
||||
|
||||
if (array == null) {
|
||||
array = new byte[2 + Integer.BYTES + remaining * element.length]; // all the remaining child tags will be of same size
|
||||
array[0] = 9; // list tag
|
||||
array[1] = DefaultNBTSerializer.INSTANCE.typeToId.get(listType).byteValue();
|
||||
|
||||
// write length
|
||||
array[2] = (byte) (remaining >>> 24);
|
||||
array[3] = (byte) (remaining >>> 16);
|
||||
array[4] = (byte) (remaining >>> 8);
|
||||
array[5] = (byte) remaining;
|
||||
}
|
||||
|
||||
System.arraycopy(element, 0, array, 1 + Integer.BYTES + i * element.length, element.length);
|
||||
}
|
||||
|
||||
remaining = 0;
|
||||
runCompleted();
|
||||
return array;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
|
||||
interface Skippable {
|
||||
void skip();
|
||||
|
||||
void skipOne();
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private interface TagSkip {
|
||||
void skip(NBTLimiter limiter, DataInput in) throws IOException;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private interface TagBinaryReader {
|
||||
byte[] read(NBTLimiter limiter, DataInput in) throws IOException;
|
||||
}
|
||||
|
||||
static {
|
||||
TAG_SKIPS.put(NBTType.BYTE, (limiter, in) -> {
|
||||
limiter.increment(9);
|
||||
in.skipBytes(Byte.BYTES);
|
||||
});
|
||||
TAG_SKIPS.put(NBTType.SHORT, (limiter, in) -> {
|
||||
limiter.increment(10);
|
||||
in.skipBytes(Short.BYTES);
|
||||
});
|
||||
TAG_SKIPS.put(NBTType.INT, (limiter, in) -> {
|
||||
limiter.increment(12);
|
||||
in.skipBytes(Integer.BYTES);
|
||||
});
|
||||
TAG_SKIPS.put(NBTType.LONG, (limiter, in) -> {
|
||||
limiter.increment(16);
|
||||
in.skipBytes(Long.BYTES);
|
||||
});
|
||||
TAG_SKIPS.put(NBTType.FLOAT, (limiter, in) -> {
|
||||
limiter.increment(12);
|
||||
in.skipBytes(Float.BYTES);
|
||||
});
|
||||
TAG_SKIPS.put(NBTType.DOUBLE, (limiter, in) -> {
|
||||
limiter.increment(16);
|
||||
in.skipBytes(Double.BYTES);
|
||||
});
|
||||
TAG_SKIPS.put(NBTType.BYTE_ARRAY, (limiter, in) -> {
|
||||
limiter.increment(24);
|
||||
int length = in.readInt();
|
||||
|
||||
limiter.checkReadability(length);
|
||||
limiter.increment(length);
|
||||
|
||||
in.skipBytes(length);
|
||||
});
|
||||
TAG_SKIPS.put(NBTType.STRING, (limiter, in) -> {
|
||||
limiter.increment(36);
|
||||
int length = in.readUnsignedShort();
|
||||
limiter.increment(length * 2);
|
||||
in.skipBytes(length);
|
||||
});
|
||||
TAG_SKIPS.put(NBTType.LIST, (limiter, in) -> {
|
||||
limiter.increment(37);
|
||||
NBTType<?> listType = DefaultNBTSerializer.INSTANCE.readTagType(limiter, in);
|
||||
int length = in.readInt();
|
||||
limiter.increment(length * 4);
|
||||
for (int i = 0; i < length; i++) {
|
||||
TAG_SKIPS.get(listType).skip(limiter, in);
|
||||
}
|
||||
});
|
||||
TAG_SKIPS.put(NBTType.COMPOUND, (limiter, in) -> {
|
||||
limiter.increment(48);
|
||||
NBTType<?> valueType;
|
||||
while ((valueType = DefaultNBTSerializer.INSTANCE.readTagType(limiter, in)) != NBTType.END) {
|
||||
int utfLen = in.readUnsignedShort();
|
||||
in.skipBytes(utfLen);
|
||||
limiter.increment(36);
|
||||
TAG_SKIPS.get(valueType).skip(limiter, in);
|
||||
}
|
||||
});
|
||||
TAG_SKIPS.put(NBTType.INT_ARRAY, (limiter, in) -> {
|
||||
limiter.increment(24);
|
||||
int length = in.readInt();
|
||||
|
||||
limiter.checkReadability(length * 4);
|
||||
limiter.increment(length * 4);
|
||||
|
||||
in.skipBytes(length * Integer.BYTES);
|
||||
});
|
||||
TAG_SKIPS.put(NBTType.LONG_ARRAY, (limiter, in) -> {
|
||||
limiter.increment(24);
|
||||
int length = in.readInt();
|
||||
|
||||
limiter.checkReadability(length * 8);
|
||||
limiter.increment(length * 8);
|
||||
|
||||
in.skipBytes(length * Long.BYTES);
|
||||
});
|
||||
|
||||
TAG_BINARY_READERS.put(NBTType.BYTE, (limiter, in) -> {
|
||||
limiter.increment(9);
|
||||
return new byte[] { in.readByte() };
|
||||
});
|
||||
TAG_BINARY_READERS.put(NBTType.SHORT, (limiter, in) -> {
|
||||
limiter.increment(10);
|
||||
return new byte[] { in.readByte(), in.readByte() };
|
||||
});
|
||||
TAG_BINARY_READERS.put(NBTType.INT, (limiter, in) -> {
|
||||
limiter.increment(12);
|
||||
byte[] bytes = new byte[Integer.BYTES];
|
||||
in.readFully(bytes);
|
||||
return bytes;
|
||||
});
|
||||
TAG_BINARY_READERS.put(NBTType.LONG, (limiter, in) -> {
|
||||
limiter.increment(16);
|
||||
byte[] bytes = new byte[Long.BYTES];
|
||||
in.readFully(bytes);
|
||||
return bytes;
|
||||
});
|
||||
TAG_BINARY_READERS.put(NBTType.FLOAT, (limiter, in) -> {
|
||||
limiter.increment(12);
|
||||
byte[] bytes = new byte[Float.BYTES];
|
||||
in.readFully(bytes);
|
||||
return bytes;
|
||||
});
|
||||
TAG_BINARY_READERS.put(NBTType.DOUBLE, (limiter, in) -> {
|
||||
limiter.increment(16);
|
||||
byte[] bytes = new byte[Double.BYTES];
|
||||
in.readFully(bytes);
|
||||
return bytes;
|
||||
});
|
||||
TAG_BINARY_READERS.put(NBTType.BYTE_ARRAY, (limiter, in) -> {
|
||||
limiter.increment(24);
|
||||
byte[] length = new byte[Integer.BYTES];
|
||||
in.readFully(length);
|
||||
int len = bytesToInt(length);
|
||||
|
||||
if (len >= 1 << 24)
|
||||
throw new IllegalArgumentException("Byte array length is too large: " + len);
|
||||
|
||||
limiter.checkReadability(len);
|
||||
limiter.increment(len);
|
||||
|
||||
byte[] array = new byte[Integer.BYTES + len];
|
||||
System.arraycopy(length, 0, array, 0, Integer.BYTES);
|
||||
in.readFully(array, Integer.BYTES, len);
|
||||
return array;
|
||||
});
|
||||
TAG_BINARY_READERS.put(NBTType.STRING, (limiter, in) -> {
|
||||
limiter.increment(36);
|
||||
byte[] length = new byte[Short.BYTES];
|
||||
in.readFully(length);
|
||||
// read len
|
||||
short signedVal = (short) ((length[0] & 0xFF) << 8 | (length[1] & 0xFF));
|
||||
int len = signedVal >= 0 ? signedVal : 0x10000 + signedVal;
|
||||
|
||||
limiter.increment(len * 2);
|
||||
|
||||
byte[] array = new byte[Short.BYTES + len];
|
||||
System.arraycopy(length, 0, array, 0, Short.BYTES);
|
||||
in.readFully(array, Short.BYTES, len);
|
||||
return array;
|
||||
});
|
||||
TAG_BINARY_READERS.put(NBTType.LIST, (limiter, in) -> {
|
||||
limiter.increment(37);
|
||||
byte type = in.readByte();
|
||||
NBTType<? extends NBT> nbtType = DefaultNBTSerializer.INSTANCE.idToType.get((int) type);
|
||||
|
||||
byte[] length = new byte[Integer.BYTES];
|
||||
in.readFully(length);
|
||||
int len = bytesToInt(length);
|
||||
|
||||
limiter.increment(len * 4);
|
||||
|
||||
byte[] array = null;
|
||||
for (int i = 0; i < len; i++) {
|
||||
byte[] element = TAG_BINARY_READERS.get(nbtType).read(limiter, in);
|
||||
|
||||
if (array == null) {
|
||||
array = new byte[1 + Integer.BYTES + len * element.length]; // all the remaining child tags will be of same size
|
||||
array[0] = type;
|
||||
System.arraycopy(length, 0, array, 1, Integer.BYTES);
|
||||
}
|
||||
|
||||
System.arraycopy(element, 0, array, 1 + Integer.BYTES + i * element.length, element.length);
|
||||
}
|
||||
return array;
|
||||
});
|
||||
TAG_BINARY_READERS.put(NBTType.COMPOUND, (limiter, in) -> {
|
||||
limiter.increment(48);
|
||||
try (ByteArrayOutputStream bytes = new ByteArrayOutputStream(); DataOutputStream out = new DataOutputStream(bytes)) {
|
||||
byte type;
|
||||
while ((type = in.readByte()) != 0) {
|
||||
out.writeByte(type);
|
||||
|
||||
// name
|
||||
byte[] name = TAG_BINARY_READERS.get(NBTType.STRING).read(NBTLimiter.noop(), in);
|
||||
limiter.increment(name.length * 2 + 28);
|
||||
out.write(name);
|
||||
|
||||
// nbt
|
||||
byte[] nbt = TAG_BINARY_READERS.get(DefaultNBTSerializer.INSTANCE.idToType.get((int) type)).read(limiter, in);
|
||||
limiter.increment(36);
|
||||
|
||||
out.write(nbt);
|
||||
}
|
||||
|
||||
out.write(0); // end
|
||||
return bytes.toByteArray();
|
||||
}
|
||||
});
|
||||
TAG_BINARY_READERS.put(NBTType.INT_ARRAY, (limiter, in) -> {
|
||||
limiter.increment(24);
|
||||
byte[] length = new byte[Integer.BYTES];
|
||||
in.readFully(length);
|
||||
int len = bytesToInt(length);
|
||||
|
||||
limiter.checkReadability(len * 4);
|
||||
limiter.increment(len * 4);
|
||||
|
||||
byte[] array = new byte[Integer.BYTES + len * Integer.BYTES];
|
||||
System.arraycopy(length, 0, array, 0, Integer.BYTES);
|
||||
in.readFully(array, Integer.BYTES, len * Integer.BYTES);
|
||||
return array;
|
||||
});
|
||||
TAG_BINARY_READERS.put(NBTType.LONG_ARRAY, (limiter, in) -> {
|
||||
limiter.increment(24);
|
||||
byte[] length = new byte[Integer.BYTES];
|
||||
in.readFully(length);
|
||||
int len = bytesToInt(length);
|
||||
|
||||
limiter.checkReadability(len * 8);
|
||||
limiter.increment(len * 8);
|
||||
|
||||
byte[] array = new byte[Integer.BYTES + len * Long.BYTES];
|
||||
System.arraycopy(length, 0, array, 0, Integer.BYTES);
|
||||
in.readFully(array, Integer.BYTES, len * Long.BYTES);
|
||||
return array;
|
||||
});
|
||||
}
|
||||
|
||||
private static int bytesToInt(byte[] bytes) {
|
||||
return ((bytes[0] & 0xFF) << 24) |
|
||||
((bytes[1] & 0xFF) << 16) |
|
||||
((bytes[2] & 0xFF) << 8 ) |
|
||||
((bytes[3] & 0xFF));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -120,6 +120,7 @@ public class NPC {
|
||||
WrapperPlayServerDestroyEntities destroyEntities = new WrapperPlayServerDestroyEntities(getId());
|
||||
PacketEvents.getAPI().getProtocolManager().sendPacket(channel, destroyEntities);
|
||||
}
|
||||
channels.clear();
|
||||
}
|
||||
|
||||
public void teleport(Location to) {
|
||||
@@ -255,9 +256,16 @@ public class NPC {
|
||||
}
|
||||
PacketEvents.getAPI().getProtocolManager().sendPacket(channel, playerInfoAdd);
|
||||
|
||||
WrapperPlayServerSpawnPlayer spawnPlayer =
|
||||
new WrapperPlayServerSpawnPlayer(getId(), getProfile().getUUID(), getLocation());
|
||||
PacketEvents.getAPI().getProtocolManager().sendPacket(channel, spawnPlayer);
|
||||
PacketWrapper<?> spawnPacket;
|
||||
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_20_2)) {
|
||||
spawnPacket = new WrapperPlayServerSpawnEntity(getId(), getProfile().getUUID(), EntityTypes.PLAYER, getLocation(), getLocation().getYaw(), 0, null);
|
||||
}
|
||||
else {
|
||||
spawnPacket = new WrapperPlayServerSpawnPlayer(getId(),
|
||||
getProfile().getUUID(),
|
||||
getLocation());
|
||||
}
|
||||
PacketEvents.getAPI().getProtocolManager().sendPacket(channel, spawnPacket);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+18
-4
@@ -38,6 +38,7 @@ import com.github.retrooper.packetevents.protocol.packettype.clientbound.Clientb
|
||||
import com.github.retrooper.packetevents.protocol.packettype.clientbound.ClientboundPacketType_1_20_2;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.clientbound.ClientboundPacketType_1_20_3;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.clientbound.ClientboundPacketType_1_20_5;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.clientbound.ClientboundPacketType_1_21;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.clientbound.ClientboundPacketType_1_7_10;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.clientbound.ClientboundPacketType_1_8;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.clientbound.ClientboundPacketType_1_9;
|
||||
@@ -45,6 +46,7 @@ import com.github.retrooper.packetevents.protocol.packettype.clientbound.Clientb
|
||||
import com.github.retrooper.packetevents.protocol.packettype.config.clientbound.ClientboundConfigPacketType_1_20_2;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.config.clientbound.ClientboundConfigPacketType_1_20_3;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.config.clientbound.ClientboundConfigPacketType_1_20_5;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.config.clientbound.ClientboundConfigPacketType_1_21;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.config.serverbound.ServerboundConfigPacketType_1_20_2;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.config.serverbound.ServerboundConfigPacketType_1_20_5;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.serverbound.ServerboundPacketType_1_12;
|
||||
@@ -100,7 +102,8 @@ public final class PacketType {
|
||||
ClientVersion.V_1_19_4,
|
||||
ClientVersion.V_1_20_2,
|
||||
ClientVersion.V_1_20_3,
|
||||
ClientVersion.V_1_20_5);
|
||||
ClientVersion.V_1_20_5,
|
||||
ClientVersion.V_1_21);
|
||||
|
||||
//TODO UPDATE Update packet type mappings (serverbound pt. 1)
|
||||
private static final VersionMapper SERVERBOUND_PLAY_VERSION_MAPPER = new VersionMapper(
|
||||
@@ -127,7 +130,8 @@ public final class PacketType {
|
||||
private static final VersionMapper CLIENTBOUND_CONFIG_VERSION_MAPPER = new VersionMapper(
|
||||
ClientVersion.V_1_20_2,
|
||||
ClientVersion.V_1_20_3,
|
||||
ClientVersion.V_1_20_5);
|
||||
ClientVersion.V_1_20_5,
|
||||
ClientVersion.V_1_21);
|
||||
// TODO UPDATE Update packet type mappings (config serverbound pt. 1)
|
||||
private static final VersionMapper SERVERBOUND_CONFIG_VERSION_MAPPER = new VersionMapper(
|
||||
ClientVersion.V_1_20_2,
|
||||
@@ -512,7 +516,11 @@ public final class PacketType {
|
||||
RESET_CHAT,
|
||||
STORE_COOKIE,
|
||||
TRANSFER,
|
||||
SELECT_KNOWN_PACKS;
|
||||
SELECT_KNOWN_PACKS,
|
||||
|
||||
// added in 1.21
|
||||
CUSTOM_REPORT_DETAILS,
|
||||
SERVER_LINKS;
|
||||
|
||||
private static int INDEX = 0;
|
||||
private static final Map<Byte, Map<Integer, PacketTypeCommon>> PACKET_TYPE_ID_MAP = new HashMap<>();
|
||||
@@ -528,6 +536,7 @@ public final class PacketType {
|
||||
loadPacketIds(ClientboundConfigPacketType_1_20_2.values());
|
||||
loadPacketIds(ClientboundConfigPacketType_1_20_3.values());
|
||||
loadPacketIds(ClientboundConfigPacketType_1_20_5.values());
|
||||
loadPacketIds(ClientboundConfigPacketType_1_21.values());
|
||||
// TODO UPDATE Update packet type mappings (config clientbound pt. 2)
|
||||
}
|
||||
|
||||
@@ -888,7 +897,11 @@ public final class PacketType {
|
||||
DEBUG_SAMPLE,
|
||||
STORE_COOKIE,
|
||||
TRANSFER,
|
||||
PROJECTILE_POWER;
|
||||
PROJECTILE_POWER,
|
||||
|
||||
// added in 1.21
|
||||
CUSTOM_REPORT_DETAILS,
|
||||
SERVER_LINKS;
|
||||
|
||||
private static int INDEX = 0;
|
||||
private static final Map<Byte, Map<Integer, PacketTypeCommon>> PACKET_TYPE_ID_MAP = new HashMap<>();
|
||||
@@ -958,6 +971,7 @@ public final class PacketType {
|
||||
loadPacketIds(ClientboundPacketType_1_20_2.values());
|
||||
loadPacketIds(ClientboundPacketType_1_20_3.values());
|
||||
loadPacketIds(ClientboundPacketType_1_20_5.values());
|
||||
loadPacketIds(ClientboundPacketType_1_21.values());
|
||||
//TODO UPDATE Update packet type mappings (clientbound pt. 2)
|
||||
}
|
||||
}
|
||||
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2024 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.packettype.clientbound;
|
||||
|
||||
public enum ClientboundPacketType_1_21 {
|
||||
|
||||
BUNDLE,
|
||||
SPAWN_ENTITY,
|
||||
SPAWN_EXPERIENCE_ORB,
|
||||
ENTITY_ANIMATION,
|
||||
STATISTICS,
|
||||
ACKNOWLEDGE_BLOCK_CHANGES,
|
||||
BLOCK_BREAK_ANIMATION,
|
||||
BLOCK_ENTITY_DATA,
|
||||
BLOCK_ACTION,
|
||||
BLOCK_CHANGE,
|
||||
BOSS_BAR,
|
||||
SERVER_DIFFICULTY,
|
||||
CHUNK_BATCH_END,
|
||||
CHUNK_BATCH_BEGIN,
|
||||
CHUNK_BIOMES,
|
||||
CLEAR_TITLES,
|
||||
TAB_COMPLETE,
|
||||
DECLARE_COMMANDS,
|
||||
CLOSE_WINDOW,
|
||||
WINDOW_ITEMS,
|
||||
WINDOW_PROPERTY,
|
||||
SET_SLOT,
|
||||
COOKIE_REQUEST,
|
||||
SET_COOLDOWN,
|
||||
CUSTOM_CHAT_COMPLETIONS,
|
||||
PLUGIN_MESSAGE,
|
||||
DAMAGE_EVENT,
|
||||
DEBUG_SAMPLE,
|
||||
DELETE_CHAT,
|
||||
DISCONNECT,
|
||||
DISGUISED_CHAT,
|
||||
ENTITY_STATUS,
|
||||
EXPLOSION,
|
||||
UNLOAD_CHUNK,
|
||||
CHANGE_GAME_STATE,
|
||||
OPEN_HORSE_WINDOW,
|
||||
HURT_ANIMATION,
|
||||
INITIALIZE_WORLD_BORDER,
|
||||
KEEP_ALIVE,
|
||||
CHUNK_DATA,
|
||||
EFFECT,
|
||||
PARTICLE,
|
||||
UPDATE_LIGHT,
|
||||
JOIN_GAME,
|
||||
MAP_DATA,
|
||||
MERCHANT_OFFERS,
|
||||
ENTITY_RELATIVE_MOVE,
|
||||
ENTITY_RELATIVE_MOVE_AND_ROTATION,
|
||||
ENTITY_ROTATION,
|
||||
VEHICLE_MOVE,
|
||||
OPEN_BOOK,
|
||||
OPEN_WINDOW,
|
||||
OPEN_SIGN_EDITOR,
|
||||
PING,
|
||||
DEBUG_PONG,
|
||||
CRAFT_RECIPE_RESPONSE,
|
||||
PLAYER_ABILITIES,
|
||||
CHAT_MESSAGE,
|
||||
END_COMBAT_EVENT,
|
||||
ENTER_COMBAT_EVENT,
|
||||
DEATH_COMBAT_EVENT,
|
||||
PLAYER_INFO_REMOVE,
|
||||
PLAYER_INFO_UPDATE,
|
||||
FACE_PLAYER,
|
||||
PLAYER_POSITION_AND_LOOK,
|
||||
UNLOCK_RECIPES,
|
||||
DESTROY_ENTITIES,
|
||||
REMOVE_ENTITY_EFFECT,
|
||||
RESET_SCORE,
|
||||
RESOURCE_PACK_REMOVE,
|
||||
RESOURCE_PACK_SEND,
|
||||
RESPAWN,
|
||||
ENTITY_HEAD_LOOK,
|
||||
MULTI_BLOCK_CHANGE,
|
||||
SELECT_ADVANCEMENTS_TAB,
|
||||
SERVER_DATA,
|
||||
ACTION_BAR,
|
||||
WORLD_BORDER_CENTER,
|
||||
WORLD_BORDER_LERP_SIZE,
|
||||
WORLD_BORDER_SIZE,
|
||||
WORLD_BORDER_WARNING_DELAY,
|
||||
WORLD_BORDER_WARNING_REACH,
|
||||
CAMERA,
|
||||
HELD_ITEM_CHANGE,
|
||||
UPDATE_VIEW_POSITION,
|
||||
UPDATE_VIEW_DISTANCE,
|
||||
SPAWN_POSITION,
|
||||
DISPLAY_SCOREBOARD,
|
||||
ENTITY_METADATA,
|
||||
ATTACH_ENTITY,
|
||||
ENTITY_VELOCITY,
|
||||
ENTITY_EQUIPMENT,
|
||||
SET_EXPERIENCE,
|
||||
UPDATE_HEALTH,
|
||||
SCOREBOARD_OBJECTIVE,
|
||||
SET_PASSENGERS,
|
||||
TEAMS,
|
||||
UPDATE_SCORE,
|
||||
UPDATE_SIMULATION_DISTANCE,
|
||||
SET_TITLE_SUBTITLE,
|
||||
TIME_UPDATE,
|
||||
SET_TITLE_TEXT,
|
||||
SET_TITLE_TIMES,
|
||||
ENTITY_SOUND_EFFECT,
|
||||
SOUND_EFFECT,
|
||||
CONFIGURATION_START,
|
||||
STOP_SOUND,
|
||||
STORE_COOKIE,
|
||||
SYSTEM_CHAT_MESSAGE,
|
||||
PLAYER_LIST_HEADER_AND_FOOTER,
|
||||
NBT_QUERY_RESPONSE,
|
||||
COLLECT_ITEM,
|
||||
ENTITY_TELEPORT,
|
||||
TICKING_STATE,
|
||||
TICKING_STEP,
|
||||
TRANSFER,
|
||||
UPDATE_ADVANCEMENTS,
|
||||
UPDATE_ATTRIBUTES,
|
||||
ENTITY_EFFECT,
|
||||
DECLARE_RECIPES,
|
||||
TAGS,
|
||||
PROJECTILE_POWER,
|
||||
CUSTOM_REPORT_DETAILS, // new packet
|
||||
SERVER_LINKS, // new packet
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2024 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.packettype.config.clientbound;
|
||||
|
||||
public enum ClientboundConfigPacketType_1_21 {
|
||||
|
||||
COOKIE_REQUEST,
|
||||
PLUGIN_MESSAGE,
|
||||
DISCONNECT,
|
||||
CONFIGURATION_END,
|
||||
KEEP_ALIVE,
|
||||
PING,
|
||||
RESET_CHAT,
|
||||
REGISTRY_DATA,
|
||||
RESOURCE_PACK_REMOVE,
|
||||
RESOURCE_PACK_SEND,
|
||||
STORE_COOKIE,
|
||||
TRANSFER,
|
||||
UPDATE_ENABLED_FEATURES,
|
||||
UPDATE_TAGS,
|
||||
SELECT_KNOWN_PACKS,
|
||||
CUSTOM_REPORT_DETAILS, // new packet
|
||||
SERVER_LINKS, // new packet
|
||||
}
|
||||
@@ -18,9 +18,14 @@
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.particle;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTNumber;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
|
||||
import com.github.retrooper.packetevents.protocol.particle.data.ParticleData;
|
||||
import com.github.retrooper.packetevents.protocol.particle.type.ParticleType;
|
||||
import com.github.retrooper.packetevents.protocol.particle.type.ParticleTypes;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
|
||||
public class Particle<T extends ParticleData> {
|
||||
@@ -48,6 +53,24 @@ public class Particle<T extends ParticleData> {
|
||||
particle.getType().writeData(wrapper, particle.data);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Particle<?> decode(NBT nbt, ClientVersion version) {
|
||||
NBTCompound compound = (NBTCompound) nbt;
|
||||
NBT typeTag = compound.getTagOrThrow("type");
|
||||
ParticleType<?> type = typeTag instanceof NBTNumber
|
||||
? ParticleTypes.getById(version, ((NBTNumber) typeTag).getAsInt())
|
||||
: ParticleTypes.getByName(((NBTString) typeTag).getValue());
|
||||
ParticleData data = type.decodeData(compound, version);
|
||||
return new Particle<>((ParticleType<? super ParticleData>) type, data);
|
||||
}
|
||||
|
||||
public static <T extends ParticleData> NBT encode(Particle<T> particle, ClientVersion version) {
|
||||
NBTCompound compound = new NBTCompound();
|
||||
compound.setTag("type", new NBTString(particle.type.getName().toString()));
|
||||
particle.type.encodeData(particle.getData(), version, compound);
|
||||
return compound;
|
||||
}
|
||||
|
||||
public ParticleType<T> getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
+16
-6
@@ -19,11 +19,13 @@
|
||||
package com.github.retrooper.packetevents.protocol.particle.data;
|
||||
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
|
||||
public class ParticleBlockStateData extends ParticleData implements LegacyConvertible {
|
||||
|
||||
private WrappedBlockState blockState;
|
||||
|
||||
public ParticleBlockStateData(WrappedBlockState blockState) {
|
||||
@@ -42,11 +44,9 @@ public class ParticleBlockStateData extends ParticleData implements LegacyConver
|
||||
int blockID;
|
||||
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_9)) {
|
||||
blockID = wrapper.readVarInt();
|
||||
}
|
||||
else if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_13)) {
|
||||
} else if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_13)) {
|
||||
blockID = wrapper.readInt();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
blockID = wrapper.readVarInt();
|
||||
}
|
||||
return new ParticleBlockStateData(WrappedBlockState.getByGlobalId(wrapper.getServerVersion()
|
||||
@@ -56,12 +56,22 @@ public class ParticleBlockStateData extends ParticleData implements LegacyConver
|
||||
public static void write(PacketWrapper<?> wrapper, ParticleBlockStateData data) {
|
||||
if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_9)) {
|
||||
wrapper.writeVarInt(data.getBlockState().getGlobalId());
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
wrapper.writeInt(data.getBlockState().getGlobalId());
|
||||
}
|
||||
}
|
||||
|
||||
public static ParticleBlockStateData decode(NBTCompound compound, ClientVersion version) {
|
||||
String key = version.isNewerThanOrEquals(ClientVersion.V_1_20_5) ? "block_state" : "value";
|
||||
WrappedBlockState state = WrappedBlockState.decode(compound.getTagOrThrow(key), version);
|
||||
return new ParticleBlockStateData(state);
|
||||
}
|
||||
|
||||
public static void encode(ParticleBlockStateData data, ClientVersion version, NBTCompound compound) {
|
||||
String key = version.isNewerThanOrEquals(ClientVersion.V_1_20_5) ? "block_state" : "value";
|
||||
compound.setTag(key, WrappedBlockState.encode(data.blockState, version));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
|
||||
Loaded 100 of 368 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user