Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6060954f87 | ||
|
|
ff8a27d92a | ||
|
|
617abe2d8c | ||
|
|
93c84b1912 | ||
|
|
0b17b81b63 | ||
|
|
6a7a92a97b | ||
|
|
31f7bde35f | ||
|
|
da77c32a0d | ||
|
|
421453d25e | ||
|
|
fa4d44b929 | ||
|
|
7c8b56b3cb | ||
|
|
f6fec5b93b | ||
|
|
ea0f91136e | ||
|
|
cf7d49aec5 | ||
|
|
03733d274a | ||
|
|
2dd688fa0e | ||
|
|
8165e55514 | ||
|
|
e5464c8e4b | ||
|
|
f70b9a8322 | ||
|
|
c31f728a37 | ||
|
|
0a519379a1 | ||
|
|
2b50f6c713 | ||
|
|
be2ba2b1b9 | ||
|
|
5051e7ea48 | ||
|
|
a42aa4b202 | ||
|
|
3d22258321 | ||
|
|
8fe1648d6b | ||
|
|
49211240a3 | ||
|
|
89c503dd92 | ||
|
|
c326bb7b51 | ||
|
|
50024b0602 | ||
|
|
5503a338fa | ||
|
|
076c5e5265 | ||
|
|
01d534391d | ||
|
|
48f8412440 | ||
|
|
2c9ce50312 | ||
|
|
601a6eb808 | ||
|
|
647230a996 | ||
|
|
5047aaff0c | ||
|
|
a981adf7a3 | ||
|
|
a16a085f75 | ||
|
|
37f5948b0a | ||
|
|
7fa80e1759 | ||
|
|
e1464044a7 | ||
|
|
42167394e0 | ||
|
|
3ef1912267 | ||
|
|
3c20b79573 | ||
|
|
7171802b78 | ||
|
|
58e7455cd9 | ||
|
|
a613edcb42 | ||
|
|
5ce1e850c8 | ||
|
|
4f392ba361 | ||
|
|
61fb1c249c | ||
|
|
dae83d0e36 | ||
|
|
67c5e78e7b | ||
|
|
1ec2551fcc | ||
|
|
d4a299501a | ||
|
|
3fbeb3e902 | ||
|
|
7f2023176f | ||
|
|
3ddd289b49 | ||
|
|
f16ff65933 | ||
|
|
96485c444e | ||
|
|
b99b79f44a | ||
|
|
3ba2191829 | ||
|
|
26de3fe573 | ||
|
|
d59749fb03 | ||
|
|
a0195c59cc | ||
|
|
26b90b6d71 | ||
|
|
ed0db721dd | ||
|
|
b203db3ce5 | ||
|
|
e386f7cf45 | ||
|
|
c1c542cc5a | ||
|
|
642d427783 | ||
|
|
b2514a9e50 | ||
|
|
a942d3aad5 | ||
|
|
7a25645ed5 | ||
|
|
3c23bd41dd | ||
|
|
e5ba76e006 | ||
|
|
7a03feeccc | ||
|
|
67ef4700c7 | ||
|
|
790a9d0058 | ||
|
|
002ad95cad | ||
|
|
7ff42400c0 | ||
|
|
3df7f760a6 | ||
|
|
3a48e54e52 | ||
|
|
73eef1727a | ||
|
|
1ab0cd07af | ||
|
|
9df545483c | ||
|
|
3f93bb051d | ||
|
|
8bd982a412 | ||
|
|
7b200ad264 | ||
|
|
5d2a4e2ef3 | ||
|
|
d414106d5a | ||
|
|
d86ac64ac9 | ||
|
|
6761489ebf | ||
|
|
dd0ec0033a | ||
|
|
f91ddb2521 | ||
|
|
3ee94415a9 | ||
|
|
1a7ce908b8 | ||
|
|
d3fb7cd91b | ||
|
|
8b61d168f7 | ||
|
|
50cb30b4fc | ||
|
|
5b807a9f17 | ||
|
|
f671a4fa5c | ||
|
|
0b1c210f77 | ||
|
|
9220c5ae40 | ||
|
|
f391cc6185 | ||
|
|
b0fe7d9c6d | ||
|
|
3d39f0d304 | ||
|
|
42029770a2 | ||
|
|
cf00b9ee7c | ||
|
|
b0816b1ce6 | ||
|
|
67cce53b72 | ||
|
|
0c097d7467 | ||
|
|
70e142e4c4 | ||
|
|
9f104866b2 | ||
|
|
7ec9eb08d9 | ||
|
|
2ea3d60307 | ||
|
|
7595ca0c40 | ||
|
|
5a15d34d9e | ||
|
|
cc500e4681 | ||
|
|
4c7cf56655 | ||
|
|
f570e77325 | ||
|
|
9785878d87 | ||
|
|
6cd6c87127 | ||
|
|
8d7c7743b8 | ||
|
|
b9889d2c45 | ||
|
|
a58257bc38 | ||
|
|
7924dfeab2 | ||
|
|
989c0bf55f | ||
|
|
064c7a3cd0 | ||
|
|
e1b2702231 | ||
|
|
029f399a14 | ||
|
|
7588609c56 | ||
|
|
6513df10e7 | ||
|
|
d14a74f29e | ||
|
|
2f9c66eafb | ||
|
|
ad1707f0ee | ||
|
|
aa59ed112a | ||
|
|
7be8c9d8aa | ||
|
|
f408a5d4c6 | ||
|
|
5d8084986f | ||
|
|
5bd1ef882e | ||
|
|
6167c3b526 | ||
|
|
8188ae09f5 | ||
|
|
9c81ba368f | ||
|
|
39cb8fd554 | ||
|
|
623cdaf881 | ||
|
|
1ad559212e | ||
|
|
30e10bb645 | ||
|
|
df495f8131 | ||
|
|
529da10615 | ||
|
|
f2d6691af7 | ||
|
|
a8a1e9448e | ||
|
|
d58959fcca | ||
|
|
5fca206b8d | ||
|
|
67993364b4 | ||
|
|
25652eab15 | ||
|
|
f117239184 | ||
|
|
cc3dae127b | ||
|
|
137050be16 | ||
|
|
baf1b851c4 | ||
|
|
545ab2de79 | ||
|
|
38f845bb7e | ||
|
|
9f80553749 | ||
|
|
d7d4e58106 | ||
|
|
5293417900 | ||
|
|
9a59c40ce1 | ||
|
|
8a00e260f6 | ||
|
|
1285a0c6bf | ||
|
|
eb9d913cb6 | ||
|
|
a60340f330 | ||
|
|
796a42c981 | ||
|
|
63a81b939d | ||
|
|
a9e2544188 | ||
|
|
bea01bc794 | ||
|
|
3db74c79ab | ||
|
|
799c933d95 | ||
|
|
6b9e67f96b | ||
|
|
062d846c37 | ||
|
|
af3023562d | ||
|
|
92f4e3dd81 | ||
|
|
f7eb445d61 | ||
|
|
98b77278cd | ||
|
|
60461b9cff | ||
|
|
1394c70981 | ||
|
|
595b8c3b56 | ||
|
|
27cbd844f0 | ||
|
|
5c5c1ed402 | ||
|
|
245c7e8219 | ||
|
|
3079663ba9 | ||
|
|
25d54ae229 | ||
|
|
045c35243f | ||
|
|
5009ffbb5a | ||
|
|
47b43402f5 | ||
|
|
a5dbec5303 | ||
|
|
f3f82c4f1a | ||
|
|
653ca4b322 | ||
|
|
b57800c2e2 | ||
|
|
222c03aa67 | ||
|
|
d5ff2b5b63 | ||
|
|
0a95488146 | ||
|
|
93d21efd3d | ||
|
|
d71cd20a39 | ||
|
|
19201134a8 | ||
|
|
da2f153a43 | ||
|
|
d96b88b967 | ||
|
|
d33482e200 | ||
|
|
24ebb77860 | ||
|
|
e4bac5f81a | ||
|
|
4b9a15b003 | ||
|
|
32826467d3 | ||
|
|
886ac734f9 | ||
|
|
762c66ff42 | ||
|
|
53b8c2328e | ||
|
|
578c661730 | ||
|
|
a82bbc4e66 | ||
|
|
867cd4ee39 | ||
|
|
f7b841faf3 | ||
|
|
b80902ec10 | ||
|
|
90386cd0de | ||
|
|
e22bba0360 | ||
|
|
f82b52b017 | ||
|
|
2734b18d07 | ||
|
|
3a5a47aaa2 | ||
|
|
c7bc9aa43c | ||
|
|
c956f23def | ||
|
|
0f90efa05f | ||
|
|
e3821e1741 | ||
|
|
8bf9a910d5 | ||
|
|
83a6346a8d | ||
|
|
d9291e6457 | ||
|
|
2bd2fa3228 | ||
|
|
b03dfa9951 | ||
|
|
dd5cbb0e4c | ||
|
|
18034a334c | ||
|
|
17881b342a | ||
|
|
47e50d035f | ||
|
|
5af9f025d8 | ||
|
|
c12c43e79a | ||
|
|
9e4ed56384 | ||
|
|
8f08a32c5a | ||
|
|
fdb6137339 | ||
|
|
f173cf73d4 | ||
|
|
a91c72fb44 | ||
|
|
99abe3994c | ||
|
|
a0e3d70a3f | ||
|
|
ee7eaecdb3 | ||
|
|
a105c5cb11 | ||
|
|
4d30cc2309 | ||
|
|
ca78bf9851 | ||
|
|
d7027cc0e3 | ||
|
|
f8def524aa | ||
|
|
14532bfa9a | ||
|
|
721808d71d | ||
|
|
3c9c61056d | ||
|
|
19f7800173 | ||
|
|
df702736bf | ||
|
|
3737242226 | ||
|
|
ebff5e2f4d | ||
|
|
081781f223 | ||
|
|
c570f4a972 | ||
|
|
563c5f830d | ||
|
|
248fd92f6e | ||
|
|
757654aa9d | ||
|
|
e658304405 | ||
|
|
b5e5118450 | ||
|
|
95db675de5 | ||
|
|
cae6addf26 | ||
|
|
ed26971724 | ||
|
|
7cdcdfa3c9 | ||
|
|
8314f6c1db | ||
|
|
297fe0a538 | ||
|
|
b6592b38ad | ||
|
|
8ef0221d43 | ||
|
|
b1d6a49a82 | ||
|
|
0fcba4f4ec | ||
|
|
0ee6369884 | ||
|
|
b941a6a422 | ||
|
|
2d05d601a0 | ||
|
|
90f363a2be | ||
|
|
875b85b0fc | ||
|
|
29c1623aab | ||
|
|
a914bc349a | ||
|
|
88e20e2eb6 | ||
|
|
9d343a3f29 | ||
|
|
6b7f00ef76 | ||
|
|
c2a1d289e1 | ||
|
|
20ce8cc288 | ||
|
|
6eaeb5a201 | ||
|
|
f245bb8263 | ||
|
|
f746fda5a8 | ||
|
|
a7ab4153ef | ||
|
|
5057ac3d3d | ||
|
|
4b9d3e34ea | ||
|
|
7887e10bb6 | ||
|
|
ef88be547b | ||
|
|
dd73ba4f72 | ||
|
|
467adbd3ed | ||
|
|
2bf69c2df2 | ||
|
|
7ccc0eb488 | ||
|
|
97db997473 | ||
|
|
efbc246a72 | ||
|
|
9ce209ef42 | ||
|
|
df7ef32677 | ||
|
|
1a4945eecd | ||
|
|
e3e88d449d | ||
|
|
529f9a0e01 | ||
|
|
b5add583c9 | ||
|
|
c2d8b43eab | ||
|
|
6d823263ac | ||
|
|
a9b3640b69 | ||
|
|
17323c715d | ||
|
|
2420b8052e | ||
|
|
5c54e8a08d | ||
|
|
fa220a93eb | ||
|
|
7e164b40c7 | ||
|
|
323ceb9ced | ||
|
|
681a0dc0e4 | ||
|
|
7cbd20a038 | ||
|
|
3f5500c637 | ||
|
|
7513b0499d | ||
|
|
c4b447f7b6 | ||
|
|
177b0fbf33 | ||
|
|
7f5e53782b | ||
|
|
2184ef19ca | ||
|
|
712aa0dbf0 | ||
|
|
c33611d2d3 | ||
|
|
bf15415185 | ||
|
|
7a38e8ceb9 | ||
|
|
7f6c429a55 | ||
|
|
6eeecb271b | ||
|
|
109d5afcf5 | ||
|
|
116706c09f | ||
|
|
598b51a4bf | ||
|
|
b06b9c69ca | ||
|
|
704f946cf7 | ||
|
|
1ef9dc8de6 | ||
|
|
f9d10a9571 | ||
|
|
379c5791e6 | ||
|
|
8569f47627 | ||
|
|
555bbb550f | ||
|
|
4cf09f2e34 | ||
|
|
c9abd745c5 | ||
|
|
5d1b8dbb85 | ||
|
|
ebeb1905b3 | ||
|
|
605b217ba4 | ||
|
|
814bd9d85e | ||
|
|
8d16ebf6ae | ||
|
|
7f0af23f96 | ||
|
|
060370f356 | ||
|
|
ab384df279 | ||
|
|
9a0cc02b86 | ||
|
|
5fb86d8df3 | ||
|
|
c64c27331a | ||
|
|
cd2ca76236 | ||
|
|
9598e0e4f8 | ||
|
|
d29c2bdfb7 | ||
|
|
538b467fa6 | ||
|
|
7deca33374 | ||
|
|
c704813a6c | ||
|
|
86af7f054a | ||
|
|
a6932bb71f | ||
|
|
3384b6bc17 | ||
|
|
4bdb566fb5 | ||
|
|
5ad62a03ed | ||
|
|
280b6fae2a | ||
|
|
e07c994ddc | ||
|
|
5d974858fe | ||
|
|
5cb5992d44 | ||
|
|
fddbeda81e | ||
|
|
1c1ec10a0a | ||
|
|
cd9566fbc8 | ||
|
|
90b88f3cbf | ||
|
|
faf86b2439 | ||
|
|
5a1dadf476 | ||
|
|
6eabb17f67 | ||
|
|
4f72edeaee | ||
|
|
b0f3d04439 | ||
|
|
33a34fc149 | ||
|
|
679f573444 | ||
|
|
f35b931004 | ||
|
|
7ca50291e3 | ||
|
|
9c8a8e2e9c | ||
|
|
d45a370a4d | ||
|
|
d5907711e1 | ||
|
|
437463f1b4 | ||
|
|
d6b52bcc54 | ||
|
|
3738459fa6 | ||
|
|
be4d071250 | ||
|
|
91a2aa6781 | ||
|
|
ba08c3ad2f | ||
|
|
220c45b800 | ||
|
|
a42e724f50 | ||
|
|
1002ca4016 | ||
|
|
c1b11a55d5 | ||
|
|
a21a2079c6 | ||
|
|
07d219c77b | ||
|
|
b7b8bdc841 | ||
|
|
dd5c1bb1a4 | ||
|
|
5f46dcbab0 | ||
|
|
66b9bfbbd5 | ||
|
|
dfbe2e9739 | ||
|
|
3d10c56aac | ||
|
|
84624a4884 | ||
|
|
68ac978d45 | ||
|
|
8136eb15e1 | ||
|
|
2c95a1e71c | ||
|
|
c85d4224ad | ||
|
|
a74bee5bed | ||
|
|
9dae40f455 | ||
|
|
fe7a5a2ae5 | ||
|
|
44a3108982 | ||
|
|
c0beee9189 | ||
|
|
ea045e6c34 | ||
|
|
7c38a77f60 | ||
|
|
9174ad854c | ||
|
|
2960f2a3bb | ||
|
|
cfe073cd20 | ||
|
|
459871257e | ||
|
|
4bb4b96a10 | ||
|
|
68a18df969 | ||
|
|
8c921f427c | ||
|
|
90e1d7236e | ||
|
|
decb20d2d1 | ||
|
|
ff7cb4bbbe | ||
|
|
a68fca9dda | ||
|
|
944bfe2b06 | ||
|
|
762151f067 | ||
|
|
0327b66a1d | ||
|
|
2c95229cfc | ||
|
|
18fa4062e6 | ||
|
|
5c7520f552 | ||
|
|
875d2392b5 | ||
|
|
a68eac7cd2 | ||
|
|
42efec6e2b | ||
|
|
bcb953a45a | ||
|
|
bca5b43a2a | ||
|
|
da704539f0 | ||
|
|
bd9a1dda88 | ||
|
|
915258169e | ||
|
|
1b207251e8 | ||
|
|
b7a0829e76 | ||
|
|
48feee2bfc | ||
|
|
08e145f831 | ||
|
|
a44e28bbab | ||
|
|
21cad97f3f | ||
|
|
de97b5b15f | ||
|
|
1e8d04a07d | ||
|
|
a8a33a3a2b | ||
|
|
adafcda13d | ||
|
|
c478492227 | ||
|
|
07b11b4f4a | ||
|
|
beed8437a4 | ||
|
|
501adc503c | ||
|
|
907516eb71 | ||
|
|
9308fc7712 | ||
|
|
062d3759be | ||
|
|
c699baaa41 | ||
|
|
582e4a11d4 | ||
|
|
285744a274 | ||
|
|
faaa252fa8 | ||
|
|
b01fd89373 | ||
|
|
ed5702188c | ||
|
|
f9165a1b64 | ||
|
|
bd0ce3dd71 | ||
|
|
385a483a29 | ||
|
|
3b97f843cd | ||
|
|
3766da5a3a | ||
|
|
c3fa950a9f | ||
|
|
a114e56e06 | ||
|
|
04e60d95e4 | ||
|
|
000313ee9a | ||
|
|
dc54551d0c | ||
|
|
b3dc05e5ce | ||
|
|
3c57127a6c | ||
|
|
d16a760466 | ||
|
|
3761ebf8c7 | ||
|
|
a7d78f7f69 | ||
|
|
f59c0722e0 | ||
|
|
1735f48f23 | ||
|
|
a280c1ad39 | ||
|
|
ce4ae73f55 | ||
|
|
fd065fb7c5 | ||
|
|
5ad2511e17 | ||
|
|
8fe47391bf | ||
|
|
12279731ad | ||
|
|
a13c417352 | ||
|
|
a8d0a4dd14 | ||
|
|
f8b4a6e28a | ||
|
|
85e048f22a | ||
|
|
3257c79e69 | ||
|
|
ee54e153bf | ||
|
|
9ea6c34543 | ||
|
|
005c91eb4d | ||
|
|
806312e248 | ||
|
|
bd805bfdc4 | ||
|
|
98a8f7f072 | ||
|
|
28b7f6febc | ||
|
|
d2ad3aea44 | ||
|
|
3ffc55b539 | ||
|
|
96c58e7b1c | ||
|
|
c8171b3f43 | ||
|
|
857ae523cf | ||
|
|
232f2494e3 | ||
|
|
626eb14960 | ||
|
|
c131672870 | ||
|
|
10a2e6b959 | ||
|
|
a9c49d948a | ||
|
|
79a2304728 | ||
|
|
48edd01461 | ||
|
|
3adffdc438 | ||
|
|
655ef137c1 | ||
|
|
b11456d86b | ||
|
|
abb5e27358 | ||
|
|
42a7b5a1b2 | ||
|
|
7ba2630dd2 | ||
|
|
bbeabd20b8 | ||
|
|
7e323bc497 | ||
|
|
7e008226ec | ||
|
|
4e7c520abe | ||
|
|
dce64a0b34 | ||
|
|
aa9a1df1ab | ||
|
|
4537aaf339 | ||
|
|
44a4ffb26a | ||
|
|
9408946b36 | ||
|
|
cad6e7604d | ||
|
|
e452289603 | ||
|
|
0c95eaa1c3 | ||
|
|
c1cce6be9a | ||
|
|
0afcb893e3 | ||
|
|
c7050565b8 | ||
|
|
3c436c0259 | ||
|
|
8b6b3c77e4 | ||
|
|
5eb3771704 | ||
|
|
9fd4795cb3 | ||
|
|
23eadaeaee | ||
|
|
8ccba70788 | ||
|
|
91c2987cfe | ||
|
|
5b403da966 | ||
|
|
e6e7da89cc | ||
|
|
64e0b6c711 | ||
|
|
238c0e8d40 | ||
|
|
f35eb3054c | ||
|
|
ea25b559ed | ||
|
|
ad8e723005 | ||
|
|
4542e9511b | ||
|
|
c4b23b8c87 | ||
|
|
6f19d2d6d1 | ||
|
|
7cb4e1d00e | ||
|
|
28e8339a32 | ||
|
|
99ac42c168 | ||
|
|
8d97391bf3 | ||
|
|
2836184de3 | ||
|
|
196ff53927 | ||
|
|
aaba566b1e | ||
|
|
7191dcaa15 | ||
|
|
437b16ccd5 | ||
|
|
e4b0a99141 | ||
|
|
3e5300f03c | ||
|
|
abb09153f0 | ||
|
|
05437a3e70 | ||
|
|
c697704d04 | ||
|
|
bc09187dc1 | ||
|
|
fd53881221 | ||
|
|
2024614b68 | ||
|
|
3521f9ac36 | ||
|
|
d6973a301b | ||
|
|
ae7fcbc8ad | ||
|
|
b675018acf | ||
|
|
10984cbeb7 | ||
|
|
bae0cd5e3e | ||
|
|
e4750249e9 | ||
|
|
662bae45b7 | ||
|
|
c0e56c7c19 | ||
|
|
390653a9a6 | ||
|
|
0cd04381a4 | ||
|
|
dcefaa6b19 | ||
|
|
3063538ad0 | ||
|
|
604b694709 | ||
|
|
1c9309ac98 | ||
|
|
e7c89f28ba | ||
|
|
97a8f41e12 | ||
|
|
be5bf7961e | ||
|
|
318db58be1 | ||
|
|
0deed6e00d | ||
|
|
5ad9d51fb0 | ||
|
|
907b5e020c | ||
|
|
a8d13fadb3 | ||
|
|
0137105a6d | ||
|
|
5364d89ca8 | ||
|
|
744fa25349 | ||
|
|
3027490256 | ||
|
|
89dfcaf626 | ||
|
|
4fb0738c1a | ||
|
|
e8f4f7049b | ||
|
|
0087e382ed | ||
|
|
eb9e48ecdc | ||
|
|
34f8451ac5 | ||
|
|
894503d56b | ||
|
|
ee8c3d609f | ||
|
|
b2c1c24902 | ||
|
|
6e8ea8689b | ||
|
|
7fcb489f38 | ||
|
|
10b0a6fbb6 | ||
|
|
ecc1cce033 | ||
|
|
10d8ce86b3 | ||
|
|
b0fc69c308 | ||
|
|
5cc421cff9 | ||
|
|
ca1ba4f422 | ||
|
|
a2d9489ad5 | ||
|
|
232ee9b63b | ||
|
|
7861c76730 | ||
|
|
d7aa23681b | ||
|
|
b75016a186 | ||
|
|
6882b7074c | ||
|
|
83bca3c23f | ||
|
|
a075e31a4e | ||
|
|
bdd32688fa | ||
|
|
cb857d828f | ||
|
|
440d469fa2 | ||
|
|
82da5e5a60 | ||
|
|
a191d0de16 | ||
|
|
ae6cff5325 | ||
|
|
eb9520cdc3 | ||
|
|
f8f20097a9 | ||
|
|
cbb0f87676 | ||
|
|
a6e1488545 | ||
|
|
34c009e4e5 | ||
|
|
b67242c609 | ||
|
|
6e4516272b | ||
|
|
08383c9141 | ||
|
|
2e37175dc2 | ||
|
|
f25442337d | ||
|
|
56a34ec2f8 | ||
|
|
362962dfb3 | ||
|
|
77d572190e | ||
|
|
18f7459070 | ||
|
|
e71b08de3f | ||
|
|
e8f8473e1c | ||
|
|
1d0d032431 | ||
|
|
fac7dafca5 | ||
|
|
fbebf2d75e | ||
|
|
a51f347371 | ||
|
|
6cee137780 | ||
|
|
56b48a803a | ||
|
|
3318d682fd | ||
|
|
1fe3c337e1 | ||
|
|
2442520ef3 | ||
|
|
44183f19cd | ||
|
|
23b68a867c | ||
|
|
4d16dbf76f | ||
|
|
6911d061a7 | ||
|
|
ab9c0434e1 | ||
|
|
3b932bd6b3 | ||
|
|
256839765a | ||
|
|
46f9967dba | ||
|
|
d91d47a755 | ||
|
|
5a2c047e7a | ||
|
|
5ca8b0aef8 | ||
|
|
e249ea1f0a | ||
|
|
e1b06d3872 | ||
|
|
a4ed1644f3 | ||
|
|
ad12866bf4 | ||
|
|
b04acf98c7 | ||
|
|
6b58d86248 | ||
|
|
7f6069e76b | ||
|
|
04d5ae074a | ||
|
|
85067b2574 | ||
|
|
06340e593d | ||
|
|
a896961fc4 | ||
|
|
73a62b8123 | ||
|
|
6d8a763f4c | ||
|
|
61b5c90aa7 | ||
|
|
d7eff51805 | ||
|
|
da7a57026d | ||
|
|
643e3dc2da | ||
|
|
13086c7cac | ||
|
|
41b22e8951 | ||
|
|
d76e70b1f7 | ||
|
|
c7c5c79365 | ||
|
|
87eceb5264 | ||
|
|
7b29972af0 | ||
|
|
4258f52f86 | ||
|
|
c3a7abd5f2 | ||
|
|
a5f5472853 | ||
|
|
63fc733c88 | ||
|
|
b5944f66a7 | ||
|
|
c8a19a1d83 | ||
|
|
6ab525be7b | ||
|
|
fd1932cfd8 | ||
|
|
2eb9fe7e62 | ||
|
|
ac1943758d | ||
|
|
1f86c6ab21 | ||
|
|
44f8f5e66d | ||
|
|
0be8a56ba3 | ||
|
|
0b4d49d760 | ||
|
|
2bd266cd69 | ||
|
|
0380d80138 | ||
|
|
e297d825e3 | ||
|
|
53a639e7ae | ||
|
|
a23b6feb46 | ||
|
|
603fe9cbd8 | ||
|
|
17d61b51e9 | ||
|
|
8d85106ee8 | ||
|
|
0834610f8e | ||
|
|
2e289a1d18 | ||
|
|
b4418c02ca | ||
|
|
52b46a17cd | ||
|
|
05e056a28b | ||
|
|
7b1eefb115 | ||
|
|
d50ceaa172 | ||
|
|
34b0db57ae | ||
|
|
0c9de82e99 | ||
|
|
11ce8524ac | ||
|
|
4a8534c164 | ||
|
|
593b6fc3ac | ||
|
|
33315bc271 | ||
|
|
c3e406e95b | ||
|
|
dad71f1179 | ||
|
|
03382ea987 | ||
|
|
54eed43f94 | ||
|
|
404bc6725b | ||
|
|
1b7b3d1d28 | ||
|
|
d3662d226b | ||
|
|
d699000dc3 | ||
|
|
a18a1875d3 | ||
|
|
bf523c93d1 | ||
|
|
b58cbf85e5 | ||
|
|
e38bdffc84 | ||
|
|
89a01b3997 | ||
|
|
a4085c1a5a | ||
|
|
4fa57fd642 | ||
|
|
5f670a88a4 | ||
|
|
2cadde1187 | ||
|
|
bd7e36e38c | ||
|
|
4eb69eac66 | ||
|
|
8b5f6d1e67 | ||
|
|
3a4db0a675 | ||
|
|
b2352105e6 | ||
|
|
70cb461c32 | ||
|
|
f2628097ce | ||
|
|
49e85e2b8a | ||
|
|
d7353e01b0 | ||
|
|
6674423ea4 | ||
|
|
918ee46ecc | ||
|
|
e34c291bd6 | ||
|
|
6c39966fef | ||
|
|
32d6fd5386 | ||
|
|
f64d5446a4 | ||
|
|
ed17f1bb50 | ||
|
|
8c27ead19e | ||
|
|
247cc1ebe8 | ||
|
|
ea5ab1c2f5 | ||
|
|
1e53803353 | ||
|
|
6d1464d3f4 | ||
|
|
2d6defba11 | ||
|
|
658822166a | ||
|
|
4c6ee807a7 | ||
|
|
32b7d37861 | ||
|
|
afe767c6db | ||
|
|
b37430994d | ||
|
|
c51373dc9a | ||
|
|
421a5e8141 | ||
|
|
9fe19e763a | ||
|
|
6731ade5d9 | ||
|
|
cf3eb8b993 | ||
|
|
5333c38972 | ||
|
|
d9e057eb4f | ||
|
|
33cd80da7e | ||
|
|
8231b3aebe | ||
|
|
7fbbc5f4b8 | ||
|
|
91687339bf | ||
|
|
b3181d1429 | ||
|
|
3ef8aa9e7f | ||
|
|
1a7195386c | ||
|
|
77acdc1a17 | ||
|
|
aecf9fb9b1 | ||
|
|
c8d1304e7f | ||
|
|
796a508af0 | ||
|
|
6751acb6c4 | ||
|
|
475fb97730 | ||
|
|
acee33aae6 | ||
|
|
65f60098c8 | ||
|
|
19a75abaf3 | ||
|
|
fa36de2c78 | ||
|
|
0f49ce2f9d | ||
|
|
73b24657f5 | ||
|
|
e03db26530 | ||
|
|
3fd3777e8c | ||
|
|
7ad73cd476 | ||
|
|
c5e0fcae9a | ||
|
|
4ca25df410 | ||
|
|
56b5986fc5 | ||
|
|
05c1a31f00 | ||
|
|
e0b88b750d | ||
|
|
b0c2d6f71c | ||
|
|
4e28a10aaa | ||
|
|
49205f0361 | ||
|
|
47819180c4 | ||
|
|
be3fa19c0a | ||
|
|
32a2734082 | ||
|
|
b28b0c3018 | ||
|
|
ee5eb59e42 | ||
|
|
d3f4d8dd41 | ||
|
|
d44ecaabf7 | ||
|
|
d133ca4a0f | ||
|
|
f8df3239d5 | ||
|
|
f9d957a827 | ||
|
|
bef3e3d18f | ||
|
|
aca764c288 | ||
|
|
3c0282b04f | ||
|
|
d8c081b8d3 | ||
|
|
53ca96f158 | ||
|
|
f8895c7c78 | ||
|
|
12b45d95e0 | ||
|
|
1cdfeadd86 | ||
|
|
15fec93bf1 | ||
|
|
64d2de010d | ||
|
|
ad1cd2c993 | ||
|
|
687de97fcd | ||
|
|
9d0331e190 | ||
|
|
ca863ba8c6 | ||
|
|
b9a2279966 | ||
|
|
9a91250af7 | ||
|
|
05d01e70b7 | ||
|
|
6b313cb65e | ||
|
|
a4de84b6da | ||
|
|
31550bd010 | ||
|
|
5d63c359b3 | ||
|
|
8283816418 | ||
|
|
44be8b3791 | ||
|
|
f46a2bb618 | ||
|
|
96366aae42 | ||
|
|
fd8879b46d | ||
|
|
d962ef09ff | ||
|
|
b26d2ef906 | ||
|
|
0613886659 | ||
|
|
75d7ffb447 | ||
|
|
0b5c173945 | ||
|
|
f170aed1b9 | ||
|
|
1921b46a66 | ||
|
|
bccf90b093 | ||
|
|
deebc83f1e | ||
|
|
a319df630d | ||
|
|
ab5eb2c7ef | ||
|
|
3de06c269d | ||
|
|
876839348c | ||
|
|
755e8a007a | ||
|
|
6a2e1a8114 | ||
|
|
11b25151f7 | ||
|
|
35bb80d67a | ||
|
|
7859f5ebd6 | ||
|
|
f38d753341 | ||
|
|
d1007bbb38 | ||
|
|
0886fdabd3 | ||
|
|
891f8b143f | ||
|
|
7856716a3a | ||
|
|
4eb4b2c37f | ||
|
|
1be617c110 | ||
|
|
f1743e5912 | ||
|
|
102c1f99a7 | ||
|
|
ae3434cb89 | ||
|
|
63b743f85b | ||
|
|
73f6418db3 | ||
|
|
d9c25b1acc | ||
|
|
6c18fdb175 | ||
|
|
cd009388a4 | ||
|
|
d66c2f2f5d | ||
|
|
7534904737 | ||
|
|
bce3593110 | ||
|
|
9a92d180d0 | ||
|
|
a203c17e06 | ||
|
|
69b5134b5f | ||
|
|
8c543ee97f | ||
|
|
bafa6edd28 | ||
|
|
799567579b | ||
|
|
c10e61a165 | ||
|
|
a27e439c99 | ||
|
|
e224d9daa2 | ||
|
|
91d9f99c70 | ||
|
|
c57f0d90bb | ||
|
|
e9198e7946 | ||
|
|
25d1b08a6f | ||
|
|
50395da626 | ||
|
|
2d0209b221 | ||
|
|
44330c98b7 | ||
|
|
b7f72bf55d | ||
|
|
f6d7976eff | ||
|
|
f45a727396 | ||
|
|
d5f65eceb0 | ||
|
|
2285c453da | ||
|
|
193084927b | ||
|
|
1325d53950 | ||
|
|
fa1b56a7cf | ||
|
|
de11f1f90b | ||
|
|
9ba70424e8 | ||
|
|
c5ba5b4647 | ||
|
|
8e47497edb | ||
|
|
7f7dcffdf0 | ||
|
|
9d8a2a9680 | ||
|
|
880df7a482 | ||
|
|
a016eade01 | ||
|
|
b3167c450e | ||
|
|
6ea37c1f17 | ||
|
|
17c5849f33 | ||
|
|
7e8bd606fe | ||
|
|
51e4076084 | ||
|
|
ff0ec98a27 | ||
|
|
bbe4e5e7f5 | ||
|
|
47c25a0e5e | ||
|
|
553e56fe4c | ||
|
|
bea5d39ed5 | ||
|
|
f6932e09f7 | ||
|
|
44ca95bf85 | ||
|
|
5ba7c4ba2c | ||
|
|
605e63e1df | ||
|
|
bf34ea11bd | ||
|
|
7102214c9e | ||
|
|
e60447ecd2 | ||
|
|
77a57d2243 | ||
|
|
b129ef04f3 | ||
|
|
1f41893aab | ||
|
|
c8e8f39f9d | ||
|
|
4a79e23485 | ||
|
|
20654b0a77 | ||
|
|
8d77891f76 | ||
|
|
bea74661d1 | ||
|
|
6b7bf843a1 | ||
|
|
200ccfd092 | ||
|
|
67a0a47778 | ||
|
|
933e8cbaed | ||
|
|
daac2baf8e | ||
|
|
4a2bcf6fde | ||
|
|
cd7774f056 | ||
|
|
452fb4f990 | ||
|
|
1f72ddb8a1 | ||
|
|
9af078bb8c | ||
|
|
c88655a2a0 | ||
|
|
a27efd94c8 | ||
|
|
9a26ac380a | ||
|
|
240653c429 | ||
|
|
bac3a76d9a | ||
|
|
3a4aed0b34 | ||
|
|
7f5073476c | ||
|
|
1abc3ebea6 | ||
|
|
c21003e1b7 | ||
|
|
1fd0211725 | ||
|
|
1932c7af4f | ||
|
|
94422dab77 | ||
|
|
b10ca3ebcf | ||
|
|
aa2ff4b741 | ||
|
|
284a462936 | ||
|
|
858e0a5b21 | ||
|
|
eaa8e05373 | ||
|
|
3e3d338ed0 | ||
|
|
0c5f5c6e3f | ||
|
|
7c6118bd6f | ||
|
|
7fe99c98f0 | ||
|
|
d6c4c18d35 | ||
|
|
649676e811 | ||
|
|
98c0985657 | ||
|
|
43e93e74b1 | ||
|
|
ba7817170b | ||
|
|
88279906b5 | ||
|
|
134987cb20 | ||
|
|
7b880ae967 | ||
|
|
7e8e3fef61 | ||
|
|
c1147cb9f7 | ||
|
|
54b35ef075 | ||
|
|
fba0a59324 | ||
|
|
c5c7d36bd1 | ||
|
|
83ba55dda5 | ||
|
|
000fff210a | ||
|
|
8965b22f6d | ||
|
|
4023f2412d | ||
|
|
27d56caa48 | ||
|
|
0cc1146f0e | ||
|
|
8aa7b749ca | ||
|
|
55fad45a6c | ||
|
|
22cc12e7a9 | ||
|
|
2812b121ab | ||
|
|
ad3465f0d3 | ||
|
|
fc8b55dce7 | ||
|
|
62d67e9a38 | ||
|
|
079cd7210b | ||
|
|
b60c56f464 | ||
|
|
eb1571d3e4 | ||
|
|
9a13eb36b3 | ||
|
|
9ba5cc1f98 | ||
|
|
2778ec0d9d | ||
|
|
20b0954f8c | ||
|
|
69aa7be6c5 | ||
|
|
73dccbaf24 | ||
|
|
66d836739c | ||
|
|
ab1c44c4fb | ||
|
|
8549c22567 | ||
|
|
d0300de136 | ||
|
|
34c701e039 | ||
|
|
cf0bd6f021 | ||
|
|
3b14dd3b04 | ||
|
|
9a87adf51b | ||
|
|
ce65c7f583 | ||
|
|
82013d5737 | ||
|
|
14377ca354 | ||
|
|
75664961b8 | ||
|
|
c5969c303e | ||
|
|
f4b6b1795e | ||
|
|
b86950d0e7 | ||
|
|
3ef1ac06df | ||
|
|
4c07b6d28d | ||
|
|
7f77cbfd74 | ||
|
|
ca716a65d2 | ||
|
|
4be46cd51d | ||
|
|
bb2b8bc538 | ||
|
|
41ef4f6284 | ||
|
|
cfd3179cb8 | ||
|
|
1a3170c7db | ||
|
|
25463a929a | ||
|
|
408bd49120 | ||
|
|
3fc2d28b95 | ||
|
|
d9eff7bb5c | ||
|
|
4b1c291fca | ||
|
|
0b34b65f76 | ||
|
|
ccb5ceb9b3 | ||
|
|
9fac4f9de4 | ||
|
|
d84c4365c9 | ||
|
|
bec27e0fa6 | ||
|
|
437b02c961 | ||
|
|
e6922eae46 | ||
|
|
b92f4070d4 | ||
|
|
b9750be745 | ||
|
|
973b473100 | ||
|
|
b7606aece0 | ||
|
|
3f62730404 | ||
|
|
c58b28fd00 | ||
|
|
149b3c2e29 | ||
|
|
a412df00c4 | ||
|
|
aa067d4073 | ||
|
|
4c8917c6a0 | ||
|
|
78aefa936f | ||
|
|
2c18adf202 | ||
|
|
083f401ee5 | ||
|
|
6652a7fd83 | ||
|
|
d1b22b0f82 | ||
|
|
0fb08be6e9 | ||
|
|
2da9b99789 | ||
|
|
28bb60244f | ||
|
|
928cd9de94 | ||
|
|
0046fea684 | ||
|
|
864715af40 | ||
|
|
3684d3f9a2 | ||
|
|
69c52c48ab | ||
|
|
9cf5a66e2f | ||
|
|
ae73ef1a33 | ||
|
|
4e2ba4f810 | ||
|
|
aef88cd82f | ||
|
|
9cd40f3ec2 | ||
|
|
a368f0babc | ||
|
|
9565a47c22 | ||
|
|
0df089b3cb | ||
|
|
58efd6158f | ||
|
|
99bd1a52fb | ||
|
|
8ba1725eae | ||
|
|
0a2524fec8 | ||
|
|
162d6aa33a | ||
|
|
fdcdd0fe40 | ||
|
|
8532d388f8 | ||
|
|
ccc144556b | ||
|
|
0b7e438128 | ||
|
|
2f11268dcc | ||
|
|
81514e4192 | ||
|
|
7d5c59aa34 | ||
|
|
dc6d9367b0 | ||
|
|
6c609a6b23 | ||
|
|
b7a3c8568f | ||
|
|
80f84d4001 | ||
|
|
5cecfd14d9 | ||
|
|
8bfcc550f7 | ||
|
|
e40be243de | ||
|
|
033d3bcd4d | ||
|
|
449ec15309 | ||
|
|
8b0ccd81e2 | ||
|
|
a206fd7541 | ||
|
|
77472cb9f4 | ||
|
|
5372d4b8e7 | ||
|
|
0255f3c42f | ||
|
|
eb5c10d375 | ||
|
|
9f6766fb82 | ||
|
|
ab77eb98c0 | ||
|
|
85ab5d7741 | ||
|
|
6457ff315f | ||
|
|
c09a9c88b4 | ||
|
|
e8dc4c893f | ||
|
|
b61edb0d8e | ||
|
|
94b3b51602 | ||
|
|
5415a24f4e | ||
|
|
048ae2fcd0 | ||
|
|
3a4d425a1c | ||
|
|
0a8fc31be1 | ||
|
|
f6ae076731 | ||
|
|
76296d8d41 | ||
|
|
5024375466 | ||
|
|
527b5e6f99 | ||
|
|
17115460b7 | ||
|
|
84aaec6bff | ||
|
|
0a8f740a14 | ||
|
|
8bf230e057 | ||
|
|
1f51ee7233 | ||
|
|
4cd70ee711 | ||
|
|
3d1d73a81a | ||
|
|
ad4d142e94 | ||
|
|
0f77da15ff | ||
|
|
a05ea7c1ce | ||
|
|
8945fc27d7 | ||
|
|
ac91ecc5f6 | ||
|
|
925aaf345c | ||
|
|
2510751fdf | ||
|
|
83e94dbf4a | ||
|
|
41ab131a4d | ||
|
|
252c996abf | ||
|
|
acf5fc1ee4 | ||
|
|
c141d6efc7 | ||
|
|
3b48f11f7b | ||
|
|
9ec8e2daf7 | ||
|
|
4f84200a47 | ||
|
|
e4a99c4a3d | ||
|
|
75adf7c9d4 | ||
|
|
5fc693da22 | ||
|
|
12e2f8b35a | ||
|
|
1e7dbac34e | ||
|
|
e39876ae67 | ||
|
|
ff3bc9a0cd | ||
|
|
dfe1850b93 | ||
|
|
6f50fdc026 | ||
|
|
5c490be861 | ||
|
|
849c7b4fcf | ||
|
|
fd5bb94cb5 | ||
|
|
647bbbedb0 | ||
|
|
6cfb21f660 | ||
|
|
c709b019e1 | ||
|
|
faabe5afb2 | ||
|
|
798bf15155 | ||
|
|
543daa2628 | ||
|
|
3bdf81158a | ||
|
|
9b42094273 | ||
|
|
94f3fcba12 | ||
|
|
58b30341ee | ||
|
|
741e0f8fda | ||
|
|
d8885f9156 | ||
|
|
e9aa18fd6b | ||
|
|
7518f8b98b | ||
|
|
c9dab5402e | ||
|
|
e5169378fc | ||
|
|
ca23750c28 | ||
|
|
446fd84035 | ||
|
|
fc264d0b0f | ||
|
|
e9ad372039 | ||
|
|
b1e8efb00b | ||
|
|
73ee2498e8 | ||
|
|
6608877ef0 | ||
|
|
e9159cb2de | ||
|
|
a403c7424c | ||
|
|
de2abdcab0 | ||
|
|
088ce93701 | ||
|
|
b5a7c92c8d | ||
|
|
d4144264d5 | ||
|
|
b221530276 | ||
|
|
8476c83d62 | ||
|
|
9d624bc822 | ||
|
|
f15c841b99 | ||
|
|
019bccd24a | ||
|
|
584c0709e8 | ||
|
|
d577088b8c | ||
|
|
72f5d8addc | ||
|
|
6d959169fa | ||
|
|
076d05c103 | ||
|
|
1e91b21537 | ||
|
|
b64a0b065c | ||
|
|
faf7e5d25f | ||
|
|
fd37c6b040 | ||
|
|
bb4b5d3080 | ||
|
|
d27f17f74b | ||
|
|
3646fad197 | ||
|
|
34491967e2 | ||
|
|
3df70055b0 | ||
|
|
7c0c4ee74d | ||
|
|
ca415cc719 | ||
|
|
6c17615ecb | ||
|
|
9a1376dcb3 | ||
|
|
32161333dd | ||
|
|
a2f5120069 | ||
|
|
e067492cca | ||
|
|
1cdf2ed1ef | ||
|
|
dc90652853 | ||
|
|
459de30e9a | ||
|
|
4fe68c2c93 | ||
|
|
8b0eb9c9d0 | ||
|
|
a2fce6f4a5 | ||
|
|
78b9e5d833 | ||
|
|
4e2156bd2b | ||
|
|
fdc4d2c5d2 | ||
|
|
7a331bdb09 | ||
|
|
5f50b4522c | ||
|
|
2a630bbc7d | ||
|
|
df32569af6 | ||
|
|
361c36349b | ||
|
|
ddbbb14c72 | ||
|
|
a0899d4776 | ||
|
|
4c8761b17b | ||
|
|
7eb446d528 | ||
|
|
d0230af5c9 | ||
|
|
17564506b5 | ||
|
|
dfd18d64c2 | ||
|
|
c3eaf5a1b0 | ||
|
|
152ef7fe38 | ||
|
|
7ad59b7cb0 | ||
|
|
5d19697004 | ||
|
|
8f7c090a23 | ||
|
|
d39c59663a | ||
|
|
9232ea4fd6 | ||
|
|
cd9ff95226 | ||
|
|
54ad8606dc | ||
|
|
4e1ab821e1 | ||
|
|
3016e774ff | ||
|
|
666779b012 | ||
|
|
ba9198bd45 | ||
|
|
29460a310b | ||
|
|
3507c2016a | ||
|
|
6d996a93c8 | ||
|
|
7cd1563805 | ||
|
|
4ad51649cc | ||
|
|
17023d6afd | ||
|
|
ca85c9739a | ||
|
|
b83b7ee2bc | ||
|
|
c47d5dcba6 | ||
|
|
7335c8ea98 | ||
|
|
8d7ef29d3e | ||
|
|
31a1bf35d9 | ||
|
|
051df7401e | ||
|
|
e8cb0f561e | ||
|
|
24f0eb1a2e | ||
|
|
5f1fba0276 | ||
|
|
c88face33e | ||
|
|
c4eedca28b | ||
|
|
9ac3110d3e | ||
|
|
251f8bccaa | ||
|
|
84d3c0d3e8 | ||
|
|
074aa302bc | ||
|
|
638165aad5 | ||
|
|
65798d17ac | ||
|
|
aacce4f77b | ||
|
|
2153377c0e | ||
|
|
006fb177e6 | ||
|
|
cabc010582 | ||
|
|
ae693ed438 | ||
|
|
4c7b2bbb4e | ||
|
|
314af6d000 | ||
|
|
697e883649 | ||
|
|
f81892ea74 | ||
|
|
4e9a253cfa | ||
|
|
2c62cc37e7 | ||
|
|
2fe0ed2ca1 | ||
|
|
b5e7434c9a | ||
|
|
e3f71c26e7 | ||
|
|
7fda025c0d | ||
|
|
383cbe15a6 | ||
|
|
7cace1ee32 | ||
|
|
1be25079d4 | ||
|
|
16cc07c020 | ||
|
|
7d671c2908 | ||
|
|
df2d9ba3d8 | ||
|
|
ffa696b963 | ||
|
|
6f98e35dec | ||
|
|
39419f4ca3 | ||
|
|
e26b6d08e1 | ||
|
|
cb4fcde6f4 | ||
|
|
f12a210665 | ||
|
|
684c25dc2c | ||
|
|
b20dad57fe | ||
|
|
a41cbdde7f | ||
|
|
32ce40e19e | ||
|
|
fe71654f5b | ||
|
|
bef1f76e45 | ||
|
|
752f039411 | ||
|
|
047bbe0edb | ||
|
|
f022a57b23 | ||
|
|
235948a001 | ||
|
|
c650b5c0bb | ||
|
|
81f9f5ec60 | ||
|
|
870a9ba68f | ||
|
|
e334486e96 | ||
|
|
e9633c6522 | ||
|
|
2ea42eab62 | ||
|
|
06056de6bb | ||
|
|
067da7e1d9 | ||
|
|
8c02947c05 | ||
|
|
9d39bb2d62 | ||
|
|
6a4f2f6830 | ||
|
|
120b12feeb | ||
|
|
40853ae92b | ||
|
|
bb64329b07 | ||
|
|
5878c53aa4 | ||
|
|
f4d1c3fcf2 | ||
|
|
136adaebd5 | ||
|
|
188cc5019f | ||
|
|
e41f445e92 | ||
|
|
bd283910fc | ||
|
|
1e0113a58a | ||
|
|
8bf43648ce | ||
|
|
7d5451558d | ||
|
|
c61d5d480e | ||
|
|
960f8ddce7 | ||
|
|
dc758b767f | ||
|
|
3176d892dd | ||
|
|
495d162ef2 | ||
|
|
b61b52c57e | ||
|
|
f2f485731f | ||
|
|
1aad25776c | ||
|
|
07fa0f3e55 | ||
|
|
45105d8c6a | ||
|
|
613001a600 | ||
|
|
0ec5777f12 | ||
|
|
d066c2596b | ||
|
|
c0c1a6bbcf | ||
|
|
b7fde6390e | ||
|
|
feba8785d7 | ||
|
|
4a172a27ad | ||
|
|
ace9c2d9ec | ||
|
|
70e106eeab | ||
|
|
4d38ca1b3c | ||
|
|
576bee40fc | ||
|
|
0efb17af83 | ||
|
|
0228a2849d | ||
|
|
af53a96f67 | ||
|
|
7eab459195 | ||
|
|
5801cd1e0f | ||
|
|
6bb0f2145e | ||
|
|
15f67392dc | ||
|
|
6571c42c39 | ||
|
|
851fa4ca54 | ||
|
|
39dea80d9c | ||
|
|
c102ca7f15 | ||
|
|
9fe187c049 | ||
|
|
f56971e5ac | ||
|
|
fbaaa78b81 | ||
|
|
acb960bfdf | ||
|
|
0ada2496de | ||
|
|
b7ca30efe8 | ||
|
|
db57916af4 | ||
|
|
4f3074eca8 | ||
|
|
a6af99fdbc | ||
|
|
d6df48430b | ||
|
|
7a01376144 | ||
|
|
2fb9533575 | ||
|
|
66a4d7c2ee | ||
|
|
c66c277221 | ||
|
|
98a731e5df | ||
|
|
74cb0d5167 | ||
|
|
478812d648 | ||
|
|
e759fbb5db | ||
|
|
c24485b5f9 | ||
|
|
8eae83f218 | ||
|
|
09495695f2 | ||
|
|
14a86160d6 | ||
|
|
f59f178cec | ||
|
|
6498c010f8 | ||
|
|
909bbc43d0 | ||
|
|
ce326e24e6 | ||
|
|
4de081efda | ||
|
|
8848758578 | ||
|
|
326c6cb158 | ||
|
|
4e4b35b2e7 | ||
|
|
d7caf2ae3c | ||
|
|
700f0c293e | ||
|
|
00dedaa1ff | ||
|
|
34cba80fd8 | ||
|
|
172ac19585 | ||
|
|
05617a95b7 | ||
|
|
c46bdcf42b | ||
|
|
f739060ebb | ||
|
|
b9e4466ef0 | ||
|
|
be4af60ad1 | ||
|
|
721297bf21 | ||
|
|
9ff20f3fea | ||
|
|
566c9dbda0 | ||
|
|
ff5bb8acc6 | ||
|
|
195b89f24c | ||
|
|
012aac97ee | ||
|
|
ba70dae9ad | ||
|
|
c43e702ed9 | ||
|
|
9dfbe3b263 | ||
|
|
444eabcebf | ||
|
|
ede4fa5a5d | ||
|
|
cc4ae6eb80 | ||
|
|
0a37031418 | ||
|
|
bd9096ef6d | ||
|
|
246dc34835 | ||
|
|
f90029319e | ||
|
|
18dc323f7f | ||
|
|
a948503895 | ||
|
|
616c9474ce | ||
|
|
77dc403bb9 | ||
|
|
6fd1ee227f | ||
|
|
19eb478067 | ||
|
|
54540fb8ef | ||
|
|
5a74e129a4 | ||
|
|
12c21c9b0a | ||
|
|
61836895b0 | ||
|
|
5f36302057 | ||
|
|
1b9bf4b36e | ||
|
|
9b9cdf8b8f | ||
|
|
ab1a586b4c | ||
|
|
030a3fe4ac | ||
|
|
fd01b9a6d2 | ||
|
|
11be597d11 | ||
|
|
875e5d7252 | ||
|
|
e372a56827 | ||
|
|
471f1ae71d | ||
|
|
a27808ade1 | ||
|
|
2703e849cb | ||
|
|
d57ef2b303 | ||
|
|
5a7626f280 | ||
|
|
1c4e0051a0 | ||
|
|
b3d3921f6e | ||
|
|
976c418c9e | ||
|
|
b2669129f2 | ||
|
|
343e316e4c | ||
|
|
ce219e208c | ||
|
|
358267d6e3 | ||
|
|
786788aa23 | ||
|
|
49b20e37cb | ||
|
|
3f5362a857 | ||
|
|
c7c61df0b8 | ||
|
|
298835be42 | ||
|
|
4a51958da4 | ||
|
|
cff23db7d3 | ||
|
|
f70059b4b6 | ||
|
|
757d22da23 | ||
|
|
4bc4aa26a4 | ||
|
|
cbc0a12dd6 | ||
|
|
100a147a4a | ||
|
|
c405424500 | ||
|
|
23091d60ff | ||
|
|
f0968408b6 | ||
|
|
2bf2be071d | ||
|
|
c502e2cf7e | ||
|
|
2d8446b4e3 | ||
|
|
279162d720 | ||
|
|
a64c21da8b | ||
|
|
4d58c717cd | ||
|
|
634f92b5cd | ||
|
|
24c4af486c | ||
|
|
280fe1aed0 | ||
|
|
7cfa78557e | ||
|
|
f599583856 | ||
|
|
10688a7067 | ||
|
|
188419feb0 | ||
|
|
fd44e2e9bd | ||
|
|
e19d7e88bd | ||
|
|
2446577188 | ||
|
|
fef435b9fb | ||
|
|
1cb3b985a7 | ||
|
|
2292175e9a | ||
|
|
ef04346019 | ||
|
|
381ff1e5d3 | ||
|
|
079f8df6e0 | ||
|
|
56637f50bc | ||
|
|
914888dade | ||
|
|
8e20df57a9 | ||
|
|
7d5191fa2f | ||
|
|
08528a1745 | ||
|
|
a8e3d9ec95 | ||
|
|
e5dd9b61a4 | ||
|
|
6ee2d0574f | ||
|
|
91b5a8036c | ||
|
|
24ab0d8590 | ||
|
|
d8f55006ff | ||
|
|
0817d28b88 | ||
|
|
577c8b4eaf | ||
|
|
5b5f0dce24 | ||
|
|
a818b9a9d4 | ||
|
|
3160c076f0 | ||
|
|
6d0b28fac4 | ||
|
|
ce286cf322 | ||
|
|
7d001c61a8 | ||
|
|
a09e8b9f4d | ||
|
|
395d020411 | ||
|
|
ece4455130 | ||
|
|
cc64ffff98 | ||
|
|
dd332420e5 | ||
|
|
ce8ba6a5af | ||
|
|
21eb824395 | ||
|
|
246e5ca742 | ||
|
|
2bd03ad92c | ||
|
|
7971dc797b | ||
|
|
36c047bfa0 | ||
|
|
d7daab7e64 | ||
|
|
b925e91bbb | ||
|
|
3b1341f2b3 | ||
|
|
667ad0d059 | ||
|
|
da98722470 | ||
|
|
c92fcc9f9a | ||
|
|
8d66ce776c | ||
|
|
412202e105 | ||
|
|
35c9e4e268 | ||
|
|
81ea78e003 | ||
|
|
833698fe8a | ||
|
|
70964e9ba9 | ||
|
|
255a4d516e | ||
|
|
11d26c13b8 | ||
|
|
00b4396f86 | ||
|
|
1d5d0012e6 | ||
|
|
18c706ab8a | ||
|
|
6a65a35dee | ||
|
|
37aab2c759 | ||
|
|
18ad5da081 | ||
|
|
9f65e727c9 | ||
|
|
efa6e8ec31 | ||
|
|
a7df7715b1 | ||
|
|
a9831c842c | ||
|
|
439a5f90c1 | ||
|
|
a6491cf792 | ||
|
|
e1025afb54 | ||
|
|
a5dddf371d | ||
|
|
fe95bbf312 | ||
|
|
0bab4f62de | ||
|
|
981b5cf3bf | ||
|
|
89f47c6a6a | ||
|
|
9fd1687348 | ||
|
|
899eac0e7e | ||
|
|
efad8f41a1 | ||
|
|
ee81935a74 | ||
|
|
e3c4253c13 | ||
|
|
9d991cdd26 | ||
|
|
3fdbf5b062 | ||
|
|
40937acfa0 | ||
|
|
99e4ab22e3 | ||
|
|
8da0c4310c | ||
|
|
280da6b8e9 | ||
|
|
71ff8a773b | ||
|
|
e3c1b9bf64 | ||
|
|
a52552dcb4 | ||
|
|
e8039e158f | ||
|
|
c37ef71f72 | ||
|
|
0388f340cc | ||
|
|
5e437d26d9 | ||
|
|
c10c3547b9 | ||
|
|
528a8e5587 | ||
|
|
ea4487e33f | ||
|
|
c2578bd212 | ||
|
|
a1347dd669 | ||
|
|
3228ba65ae | ||
|
|
08b2d5b7e8 | ||
|
|
2b89dbce0e | ||
|
|
f256309487 | ||
|
|
462abb1ef9 | ||
|
|
a35408d14f | ||
|
|
81d4deaea7 | ||
|
|
9103f89aff | ||
|
|
8e4c2648a3 | ||
|
|
ad020ec329 | ||
|
|
df3be302af | ||
|
|
8e3b8cb572 | ||
|
|
ff1554556e | ||
|
|
b15c93c416 | ||
|
|
071b42c9e0 | ||
|
|
304f9b34fd | ||
|
|
c817a0e9cb | ||
|
|
744252d492 | ||
|
|
9186361a29 | ||
|
|
bf01c9ea0e | ||
|
|
bee260e2b4 | ||
|
|
21811991f1 | ||
|
|
a2809f8d5c | ||
|
|
95f2b597da | ||
|
|
fa348fbc23 | ||
|
|
d277701caa | ||
|
|
9b7f68a888 | ||
|
|
7e837ef9db | ||
|
|
eb78fe4bfc | ||
|
|
689f0fd5db | ||
|
|
32316cf3ab | ||
|
|
d450c9b4d6 | ||
|
|
622673d1d3 | ||
|
|
1209beb47d | ||
|
|
f4eeb94a2e | ||
|
|
fac7eab59e | ||
|
|
e430bfce06 | ||
|
|
dd55cc3cf2 | ||
|
|
9937a173d1 | ||
|
|
1c584040ca | ||
|
|
10a2df5a7d | ||
|
|
1bec3cf1d0 | ||
|
|
4142797380 | ||
|
|
68fc884d2a | ||
|
|
2872bdd1c3 | ||
|
|
7d29a0c0af | ||
|
|
dd6423de06 | ||
|
|
52bbf1affe | ||
|
|
cfaded6cf8 | ||
|
|
69e444f83d | ||
|
|
c896ed5f63 | ||
|
|
9f8456a336 | ||
|
|
bd11c98e45 | ||
|
|
55fccba711 | ||
|
|
783542401b | ||
|
|
2424057536 | ||
|
|
b6dbe82d16 | ||
|
|
f92b7e5b80 | ||
|
|
8093c424e2 | ||
|
|
839d46f5ed | ||
|
|
de0b9a2a68 | ||
|
|
c3bd45cd58 | ||
|
|
c4bab6c9af | ||
|
|
f33d22531b | ||
|
|
9ccbdb69c5 | ||
|
|
e9008923eb | ||
|
|
301e84d698 | ||
|
|
5aad3306eb | ||
|
|
d30bbcd4a3 | ||
|
|
003197b476 | ||
|
|
a3e15bce4d | ||
|
|
e43026231e | ||
|
|
f100f6e3f0 | ||
|
|
8ae2842e5f | ||
|
|
54be03bf77 | ||
|
|
27fc4dd684 | ||
|
|
2a1f0f812b | ||
|
|
64cde13ea7 | ||
|
|
7d23b12f85 | ||
|
|
4b3f757881 | ||
|
|
d0e7f05d50 | ||
|
|
21c957b8d5 | ||
|
|
3fe25f68b1 | ||
|
|
3354a46283 | ||
|
|
975743c76f | ||
|
|
d3b214965b | ||
|
|
eb8065ad20 | ||
|
|
7d3548956e | ||
|
|
3de961f641 | ||
|
|
59620f7f93 | ||
|
|
ba3aa4566e | ||
|
|
8445a6d9db | ||
|
|
f53c8c67e2 | ||
|
|
b4976bd302 | ||
|
|
ec848d7201 | ||
|
|
8c03a296c2 | ||
|
|
65a6e25f1b | ||
|
|
178b625ca0 | ||
|
|
152993f749 | ||
|
|
ca246f9d95 | ||
|
|
f1d53bb7ac | ||
|
|
30950a7d74 | ||
|
|
305f6b7ce2 | ||
|
|
313b794285 | ||
|
|
7031d431da | ||
|
|
655e14b36e | ||
|
|
f881f3d484 | ||
|
|
4d3302a926 | ||
|
|
b2df970af5 | ||
|
|
b7b322a525 | ||
|
|
771c00b146 | ||
|
|
23f1589c28 | ||
|
|
eb72db9a5f | ||
|
|
10fc8f846d | ||
|
|
31c9332e56 | ||
|
|
b0d64bfebd | ||
|
|
ffbd399993 | ||
|
|
aeec7e5f95 | ||
|
|
36301a595b | ||
|
|
a864bf7c18 | ||
|
|
0454169588 | ||
|
|
8ea3623a79 | ||
|
|
866e494d3c | ||
|
|
d5108061c1 | ||
|
|
396998c7fc | ||
|
|
ff3d76a387 | ||
|
|
51c469882b | ||
|
|
8b9a1750de | ||
|
|
3411c3d144 | ||
|
|
cdab5b3f5b | ||
|
|
42edffb309 | ||
|
|
42efc736c3 | ||
|
|
30bb91fc8a | ||
|
|
14daca5fea | ||
|
|
8396c5a3e3 | ||
|
|
e136d1db94 | ||
|
|
90dabce0d2 | ||
|
|
9a8a6e5b16 | ||
|
|
4840db095c | ||
|
|
b371c14a27 | ||
|
|
a1fbca11f0 | ||
|
|
0fe9ccf4a8 | ||
|
|
08713947b7 | ||
|
|
e56bce2f31 | ||
|
|
573374866b | ||
|
|
32afa2a9a3 | ||
|
|
669cbcd142 | ||
|
|
471076cbe1 | ||
|
|
79d353d458 | ||
|
|
30d477c6d2 | ||
|
|
d3f5ebdba7 | ||
|
|
4b94c8ad02 | ||
|
|
7a7c3f15d8 | ||
|
|
52610f7c66 | ||
|
|
84ee4410a6 | ||
|
|
49d51de263 | ||
|
|
848b0cf113 | ||
|
|
c4ffdc1b7c | ||
|
|
49b602994a | ||
|
|
05930ad791 | ||
|
|
e7ab232b28 | ||
|
|
3f88a16c6c | ||
|
|
1a6b98deca | ||
|
|
598863d43a | ||
|
|
b146257b1a | ||
|
|
dc01fb59b8 | ||
|
|
58ed2c0d9e | ||
|
|
3762a9d3b1 | ||
|
|
5a88963929 | ||
|
|
1b69243326 | ||
|
|
3e2a391348 | ||
|
|
a330d2b148 | ||
|
|
573f769825 | ||
|
|
9de49176fb | ||
|
|
e6220f39e5 | ||
|
|
8f656d9dac | ||
|
|
15bcf3f065 | ||
|
|
536e2e33e0 | ||
|
|
ae58f0c1ab | ||
|
|
7d9cd5bfbf | ||
|
|
25a7915c7f | ||
|
|
822d582074 | ||
|
|
d815c0e682 | ||
|
|
f8a73d5fc2 | ||
|
|
a0ad97947d | ||
|
|
6ea5d0849d | ||
|
|
eba512ef0b | ||
|
|
725ab0f713 | ||
|
|
0f96c24c78 | ||
|
|
f2e4c37cd9 | ||
|
|
f159a2250c | ||
|
|
ed311e4059 | ||
|
|
6aae98a8a9 | ||
|
|
99f9cf3340 | ||
|
|
2074039285 | ||
|
|
b438ff61a2 | ||
|
|
c36e43b573 | ||
|
|
be383a524c | ||
|
|
9c6cd22817 | ||
|
|
85de7c35ea | ||
|
|
0dd8c33aa9 | ||
|
|
8cc2538e6c | ||
|
|
04d87ebba7 | ||
|
|
8c4b5b613c | ||
|
|
6add512fe1 | ||
|
|
73b8a2fc9a | ||
|
|
03cc48c991 | ||
|
|
44544925a1 | ||
|
|
7cadf832f5 | ||
|
|
0f3daa5dc4 | ||
|
|
f258cf8c89 | ||
|
|
ca759c056e | ||
|
|
d715607826 | ||
|
|
afca92d122 | ||
|
|
ae37b34692 | ||
|
|
9e42a368e0 | ||
|
|
27982efd29 | ||
|
|
c3b343fbc8 | ||
|
|
9bedb6c741 | ||
|
|
873f4dd298 | ||
|
|
693990644f | ||
|
|
b2680d76a6 | ||
|
|
db935b454f | ||
|
|
c207a9bfff | ||
|
|
f5bd041c7b | ||
|
|
07d89b24af | ||
|
|
1d0c0c527c | ||
|
|
7a9cb86563 | ||
|
|
87b1919863 | ||
|
|
d164e413c2 | ||
|
|
76d7db044f | ||
|
|
046ebb8ecc | ||
|
|
bccde04ace | ||
|
|
9385f03722 | ||
|
|
b48fc17ead | ||
|
|
b50d0075ca | ||
|
|
84d006c71d | ||
|
|
212da9c46c | ||
|
|
8edb7048a1 | ||
|
|
abe3c4b0c9 | ||
|
|
c6d3c97c65 | ||
|
|
13c6a9d612 | ||
|
|
7d2ef743ac | ||
|
|
598d0f96d8 | ||
|
|
cbc22922d3 | ||
|
|
49783d36c2 | ||
|
|
70d91b4f87 | ||
|
|
17f3d13267 | ||
|
|
559674bf58 | ||
|
|
fbc298bc30 | ||
|
|
e36902c441 | ||
|
|
805c78989a | ||
|
|
85e416171c | ||
|
|
b55c0d0783 | ||
|
|
33b4b3835f | ||
|
|
8ccd772105 | ||
|
|
8677c632df | ||
|
|
560476c56f | ||
|
|
20bbe7cec6 | ||
|
|
1a002486d0 | ||
|
|
26fcdfe3bc | ||
|
|
4af98b220c | ||
|
|
f91fcb4ea8 | ||
|
|
b3060e0dc8 | ||
|
|
808a9a7d82 | ||
|
|
32c43e6023 | ||
|
|
4c9c50f939 | ||
|
|
ac1b35379e | ||
|
|
b743589d77 | ||
|
|
9dad0a0d5e | ||
|
|
f5b49bc9ce | ||
|
|
b3612a68b0 | ||
|
|
7385db02c2 | ||
|
|
501d2ec3a2 | ||
|
|
1217a9b7e2 | ||
|
|
6740c5c6dc | ||
|
|
44e8056fb3 | ||
|
|
d1da412cf7 | ||
|
|
6534a5414e | ||
|
|
91344a0b50 | ||
|
|
cdd9ff4469 | ||
|
|
d88b76db85 | ||
|
|
bc1d57853c | ||
|
|
27d6c12556 | ||
|
|
a76dd1ba49 | ||
|
|
1a4388b3e7 | ||
|
|
f1b81f77d6 | ||
|
|
d6edec3a55 | ||
|
|
094f4c6d58 | ||
|
|
c57d0f60f9 | ||
|
|
dd5cd1ca48 | ||
|
|
ab4a565700 | ||
|
|
f8ac54e237 | ||
|
|
089e07fe49 | ||
|
|
1d3b8f802c | ||
|
|
27283e48a2 | ||
|
|
d22584afbc | ||
|
|
249ab01425 | ||
|
|
851097de44 | ||
|
|
c095a51f7c | ||
|
|
5e62b7001e | ||
|
|
a79533bf72 | ||
|
|
e3510d01d6 | ||
|
|
8cc4ba168a | ||
|
|
264a21d092 | ||
|
|
e2585db350 | ||
|
|
a2f7a52d31 | ||
|
|
d04121202d | ||
|
|
95517ade2c | ||
|
|
c9441de7e4 | ||
|
|
dc946cb845 | ||
|
|
5fa30d9adb | ||
|
|
a7043424ec | ||
|
|
e1b3d21732 | ||
|
|
8ffc056a7e | ||
|
|
7c274fb03d | ||
|
|
3b533b5138 | ||
|
|
5665510f7e | ||
|
|
47faa21ef4 | ||
|
|
575f457830 | ||
|
|
d5bf7909e8 | ||
|
|
fdf90b7931 | ||
|
|
e3305e4eae | ||
|
|
15fe8d394e | ||
|
|
082db38c40 | ||
|
|
be54dc41d1 | ||
|
|
487e79c043 | ||
|
|
ef6390a0b8 | ||
|
|
9d9fc65633 | ||
|
|
6eac61c912 | ||
|
|
d89362a271 | ||
|
|
0a407069fa | ||
|
|
661fdb1127 | ||
|
|
9e6c0f72a8 | ||
|
|
70ad2613f1 | ||
|
|
9052946c45 | ||
|
|
3ddc43bf7b | ||
|
|
cdb757eae5 | ||
|
|
50a3e03649 | ||
|
|
957284930e | ||
|
|
198a24371c | ||
|
|
bcc994b0dd | ||
|
|
f870bd5a32 | ||
|
|
a14abd6f4f | ||
|
|
2456c3cf17 | ||
|
|
9828e4ae1d | ||
|
|
030aa887c7 | ||
|
|
ba624a2b48 | ||
|
|
e7582cb1ec | ||
|
|
82bf11fcbc | ||
|
|
ac6e8b1709 | ||
|
|
00cc545795 | ||
|
|
c7ee816aba | ||
|
|
e7f85e67f6 | ||
|
|
d239d2f967 | ||
|
|
63970c6d82 | ||
|
|
4cffdd4f64 | ||
|
|
cb3f0291b7 | ||
|
|
edaffad045 | ||
|
|
172f89940a | ||
|
|
fb4bc397c6 | ||
|
|
e595344941 | ||
|
|
05dbc53fd0 | ||
|
|
0374da573b | ||
|
|
8e64fb8c21 | ||
|
|
0f55402171 | ||
|
|
acb7372eb7 | ||
|
|
057ab050ea | ||
|
|
a01997fe53 | ||
|
|
e4adbf4a1a | ||
|
|
261d68c58e | ||
|
|
38617d1f61 | ||
|
|
cc5bcb8a64 | ||
|
|
b6794f5597 | ||
|
|
18f77308f5 | ||
|
|
6bb473ea8d | ||
|
|
7984f6400c | ||
|
|
3498d093b0 | ||
|
|
a3db32758c | ||
|
|
45952d3759 | ||
|
|
c552b12696 | ||
|
|
0ae9d9dbbf | ||
|
|
8852e3b3a3 | ||
|
|
a496b2d3a8 | ||
|
|
6198dbfe70 | ||
|
|
a81d52a54f | ||
|
|
cf20e8ac5f | ||
|
|
4f8a248c6b | ||
|
|
57d58db35e | ||
|
|
c214ca02e8 | ||
|
|
6b8b0e1771 | ||
|
|
e6671513f2 | ||
|
|
4c7b50d6fb | ||
|
|
1c9229a2fc | ||
|
|
d11c18c024 | ||
|
|
dc4b5b4d35 | ||
|
|
517299d673 | ||
|
|
a8baa7af50 | ||
|
|
a1f847c905 | ||
|
|
f3ea43b1eb | ||
|
|
551b5d0654 | ||
|
|
9f39662df6 | ||
|
|
7ea2156f37 | ||
|
|
5032e7d07e | ||
|
|
c7c6ee9fbc | ||
|
|
4431ca63c2 | ||
|
|
1fa7211cf0 | ||
|
|
de576795dc | ||
|
|
f6286bcc25 | ||
|
|
8276b212e9 | ||
|
|
aabd9247a6 | ||
|
|
997c2ad6a1 | ||
|
|
233a2ba5df | ||
|
|
ed0d5a7cfb | ||
|
|
87f083460c | ||
|
|
2d6dedefb8 | ||
|
|
8adbf36a3a | ||
|
|
8c706b665c | ||
|
|
2e3677a592 | ||
|
|
3602c5087b | ||
|
|
5c84b3d8cc | ||
|
|
7defe7129f | ||
|
|
995dc135b8 | ||
|
|
3f64fb7d5f | ||
|
|
ac8f7a00ae | ||
|
|
6893f34289 | ||
|
|
0a69d62cbe | ||
|
|
5e0096aa2c | ||
|
|
7326205495 | ||
|
|
a8212db7f2 | ||
|
|
2905d77206 | ||
|
|
cb8ec2ce20 | ||
|
|
09f484f956 | ||
|
|
c48922eb3e | ||
|
|
b701a0ef67 | ||
|
|
eb50f4e907 | ||
|
|
6480ea34fc | ||
|
|
511941462f | ||
|
|
34cc783cac | ||
|
|
ecc79b4f49 | ||
|
|
76f10c463f | ||
|
|
41d5144b57 | ||
|
|
de196f2e4f | ||
|
|
0acc2f95fb | ||
|
|
d16eb9b27e | ||
|
|
8760b53a0a | ||
|
|
a40182186f | ||
|
|
ef2b173749 | ||
|
|
75c9284cda |
No files matched your search
@@ -0,0 +1,31 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a bug report so we can fix it
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug, provide any errors**
|
||||
A clear and concise description of what the bug is. If present, can you paste the error to https://paste.gg/?
|
||||
|
||||
**How can we reproduce it?**
|
||||
Steps to reproduce the behavior:
|
||||
1. Login on 1.12'
|
||||
2. Click on '....'
|
||||
3. The '....' is displayed wrong
|
||||
|
||||
**Expected behaviour**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**ViaVersion Dump**
|
||||
- Type /viaversion dump, and put the link here.
|
||||
|
||||
**Additional server info**
|
||||
Do you use a proxy (eg. BungeeCord)? What software do you use and what plugins?
|
||||
|
||||
**Checklist**
|
||||
- [ ] I have included a Viaversion dump
|
||||
- [ ] If applicable, I have included a paste (not a screenshot) of the error
|
||||
- [ ] I have tried a build from https://ci.viaversion.com/ and the issue still persists
|
||||
@@ -0,0 +1 @@
|
||||
blank_issues_enabled: false
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for ViaVersion
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Which versions is this for?**
|
||||
Does the feature apply to any specific versions? If so put them here.
|
||||
@@ -19,9 +19,6 @@ hs_err_pid*
|
||||
# Ignore IDEA directory
|
||||
.idea/*
|
||||
|
||||
# Include the project's code style settings file
|
||||
!.idea/codeStyleSettings.xml
|
||||
|
||||
# Include the project's dictionary
|
||||
!.idea/dictionaries/
|
||||
!.idea/dictionaries/*
|
||||
|
||||
+7
-4
@@ -1,12 +1,15 @@
|
||||
sudo: false
|
||||
|
||||
language: java
|
||||
jdk: oraclejdk7
|
||||
jdk:
|
||||
- openjdk11
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- '$HOME/.m2/repository'
|
||||
- '$HOME/.m2/repository'
|
||||
|
||||
script:
|
||||
- mvn dependency:purge-local-repository -DactTransitively=false -DreResolve=false
|
||||
- mvn clean install -B -U
|
||||
- mvn dependency:purge-local-repository -DactTransitively=false -DreResolve=false
|
||||
- mvn clean install -B -U
|
||||
|
||||
install: true
|
||||
@@ -1,12 +0,0 @@
|
||||
### What version of ViaVersion are you using? Type /ver viaversion
|
||||
|
||||
### What version of Spigot are you using? Type /ver
|
||||
|
||||
### What plugins are you using? Type /plugins
|
||||
|
||||
### Are you using any additional software like BungeeCord? If so, what software and version? (Please list your plugins as well)
|
||||
|
||||
### How does this error happen? login? Using an item?
|
||||
|
||||
### Is there an error in the console? Use pastebin.com. Is there a kick message?
|
||||
|
||||
@@ -1,3 +1,21 @@
|
||||
License:
|
||||
--------
|
||||
You may modify this work, all rights are still owned by myself excluding any files in the spacebase package as they belong to the respected contributors. Please credit the original author (myself) when forking etc. (or if it helped you understand the new protocol or netty!)
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,52 +1,30 @@
|
||||
# ViaVersion 0.7.1
|
||||
[](https://travis-ci.org/MylesIsCool/ViaVersion)
|
||||
[](https://gitter.im/MylesIsCool/ViaVersion)
|
||||
# ViaVersion 3.0.1 - Spigot, Sponge, BungeeCord, Velocity
|
||||
[](https://travis-ci.com/ViaVersion/ViaVersion)
|
||||
[](https://viaversion.com/discord)
|
||||
|
||||
**Allows the connection of 1.9 clients to 1.8**
|
||||
**Allows the connection of higher client versions to lower server versions**
|
||||
|
||||
This plugin modifies netty to allow connection of 1.9 clients to 1.8,
|
||||
Supported Versions:
|
||||
|
||||
###*Don't use late bind*
|
||||

|
||||
|
||||
This uses our new API, we currently don't have javadocs yet but look at one of our protocols on how to get started then use ProtocolRegistry.registerProtocol()
|
||||
On Bukkit you may also use ProtocolSupport, but ensure you have the right build for your server version.
|
||||
|
||||
**User Docs:** https://docs.viaversion.com/display/VIAVERSION/
|
||||
|
||||
This took 100s hours of work, so if you enjoy this consider looking into contacting me and supporting my projects.
|
||||
|
||||
**Contributor Chat:** https://gitter.im/MylesIsCool/ViaVersion
|
||||
|
||||
|
||||
Sources:
|
||||
--------
|
||||
**wiki.vg** (Used for various information, we also contribute back)
|
||||
|
||||
**wiki.vg** (Protocol info, though I did have to find a lot myself)
|
||||
|
||||
**MCProtocolLib** (used for chunk reading & some of writing.)
|
||||
**Burger** (See [PAaaS](https://github.com/Matsv/Paaas))
|
||||
|
||||
**OpenNBT** (used for slot rewriting)
|
||||
|
||||
|
||||
|
||||
Contributors:
|
||||
--------
|
||||
|
||||
**Myself** (harhar)
|
||||
|
||||
**Matsv/StamBoom**
|
||||
|
||||
**HugoDaBosss**
|
||||
|
||||
**SanderGielisse**
|
||||
|
||||
**Paulomart**
|
||||
|
||||
**gigosaurus**
|
||||
|
||||
**fillefilip8**
|
||||
|
||||
**lenis0012**
|
||||
|
||||
|
||||
|
||||
Releases / Dev Builds:
|
||||
--------
|
||||
You can find official releases here:
|
||||
@@ -56,20 +34,18 @@ https://www.spigotmc.org/resources/viaversion.19254/history
|
||||
|
||||
----------
|
||||
|
||||
You can find unofficial dev builds here:
|
||||
You can find official dev builds here:
|
||||
|
||||
**fillefilip8's Build Server:** http://build.fillecraft.com:8080/job/ViaVersion
|
||||
**Jenkins:** https://ci.viaversion.com
|
||||
|
||||
**sgdc3's Build Server:** http://ci.xephi.fr/job/ViaVersion/
|
||||
**sgdc3's Maven:** http://ci.xephi.fr/plugin/repository/everything/
|
||||
**JavaDocs:** https://jd.viaversion.com
|
||||
|
||||
**JavaDocs:** https://jd.matsv.nl/
|
||||
**Maven Repo:** https://repo.viaversion.com
|
||||
|
||||
License:
|
||||
--------
|
||||
|
||||
You may modify this work, all rights are still owned by myself excluding any files in the spacebase package as they belong to the respected contributors. Please credit the original author (myself) when forking etc. (or if it helped you understand the new protocol or netty!)
|
||||
MIT License, see LICENSE for more details.
|
||||
|
||||
|
||||
Thanks!
|
||||
|
||||
Special thanks to all our [Contributors](https://github.com/ViaVersion/ViaVersion/graphs/contributors)
|
||||
@@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>viaversion-parent</artifactId>
|
||||
<groupId>us.myles</groupId>
|
||||
<version>3.1.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>viaversion-bukkit-legacy</artifactId>
|
||||
|
||||
<properties>
|
||||
<bukkitVersion>1.8.8-R0.1-SNAPSHOT</bukkitVersion>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<targetPath>.</targetPath>
|
||||
<filtering>true</filtering>
|
||||
<directory>src/main/resources/</directory>
|
||||
<includes>
|
||||
<include>*</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<!-- Common Module -->
|
||||
<dependency>
|
||||
<groupId>us.myles</groupId>
|
||||
<artifactId>viaversion-common</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Bukkit API, http://www.spigotmc.org/ or http://bukkit.org/ -->
|
||||
<dependency>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>bukkit</artifactId>
|
||||
<version>${bukkitVersion}</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>junit</artifactId>
|
||||
<groupId>junit</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>gson</artifactId>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>persistence-api</artifactId>
|
||||
<groupId>javax.persistence</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package us.myles.ViaVersion.bukkit.listeners;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import us.myles.ViaVersion.api.ViaListener;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.protocol.Protocol;
|
||||
|
||||
public class ViaBukkitListener extends ViaListener implements Listener {
|
||||
private final Plugin plugin;
|
||||
|
||||
public ViaBukkitListener(Plugin plugin, Class<? extends Protocol> requiredPipeline) {
|
||||
super(requiredPipeline);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the UserConnection from a player
|
||||
*
|
||||
* @param player Player object
|
||||
* @return The UserConnection
|
||||
*/
|
||||
protected UserConnection getUserConnection(Player player) {
|
||||
return getUserConnection(player.getUniqueId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the player is on the selected pipe
|
||||
*
|
||||
* @param player Player Object
|
||||
* @return True if on pipe
|
||||
*/
|
||||
protected boolean isOnPipe(Player player) {
|
||||
return isOnPipe(player.getUniqueId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Register as Bukkit event
|
||||
*/
|
||||
@Override
|
||||
public void register() {
|
||||
if (isRegistered()) return;
|
||||
|
||||
plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
||||
setRegistered(true);
|
||||
}
|
||||
|
||||
public Plugin getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
}
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
package us.myles.ViaVersion.bukkit.listeners.protocol1_9to1_8;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.player.PlayerChangedWorldEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.event.player.PlayerItemBreakEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerRespawnEvent;
|
||||
import org.bukkit.inventory.CraftingInventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import us.myles.ViaVersion.api.PacketWrapper;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.type.Type;
|
||||
import us.myles.ViaVersion.bukkit.listeners.ViaBukkitListener;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.ArmorType;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9To1_8;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class ArmorListener extends ViaBukkitListener {
|
||||
|
||||
private static final UUID ARMOR_ATTRIBUTE = UUID.fromString("2AD3F246-FEE1-4E67-B886-69FD380BB150");
|
||||
|
||||
public ArmorListener(Plugin plugin) {
|
||||
super(plugin, Protocol1_9To1_8.class);
|
||||
}
|
||||
|
||||
public void sendArmorUpdate(Player player) {
|
||||
// Ensure that the player is on our pipe
|
||||
if (!isOnPipe(player)) return;
|
||||
|
||||
int armor = 0;
|
||||
for (ItemStack stack : player.getInventory().getArmorContents()) {
|
||||
armor += ArmorType.findById(stack.getTypeId()).getArmorPoints();
|
||||
}
|
||||
|
||||
PacketWrapper wrapper = new PacketWrapper(0x4B, null, getUserConnection(player));
|
||||
try {
|
||||
wrapper.write(Type.VAR_INT, player.getEntityId()); // Player ID
|
||||
wrapper.write(Type.INT, 1); // only 1 property
|
||||
wrapper.write(Type.STRING, "generic.armor");
|
||||
wrapper.write(Type.DOUBLE, 0D); //default 0 armor
|
||||
wrapper.write(Type.VAR_INT, 1); // 1 modifier
|
||||
wrapper.write(Type.UUID, ARMOR_ATTRIBUTE); // armor modifier uuid
|
||||
wrapper.write(Type.DOUBLE, (double) armor); // the modifier value
|
||||
wrapper.write(Type.BYTE, (byte) 0);// the modifier operation, 0 is add number
|
||||
|
||||
wrapper.send(Protocol1_9To1_8.class);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onInventoryClick(InventoryClickEvent e) {
|
||||
HumanEntity human = e.getWhoClicked();
|
||||
if (human instanceof Player && e.getInventory() instanceof CraftingInventory) {
|
||||
final Player player = (Player) human;
|
||||
if (e.getCurrentItem() != null) {
|
||||
if (ArmorType.isArmor(e.getCurrentItem().getTypeId())) {
|
||||
sendDelayedArmorUpdate(player);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (e.getRawSlot() >= 5 && e.getRawSlot() <= 8) {
|
||||
sendDelayedArmorUpdate(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onInteract(PlayerInteractEvent e) {
|
||||
if (e.getItem() != null) {
|
||||
if (e.getAction() == Action.RIGHT_CLICK_AIR || e.getAction() == Action.RIGHT_CLICK_BLOCK) {
|
||||
final Player player = e.getPlayer();
|
||||
// Due to odd bugs it's 3 ticks later
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(getPlugin(), () -> sendArmorUpdate(player), 3L);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onItemBreak(PlayerItemBreakEvent e) {
|
||||
sendDelayedArmorUpdate(e.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onJoin(PlayerJoinEvent e) {
|
||||
sendDelayedArmorUpdate(e.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onRespawn(PlayerRespawnEvent e) {
|
||||
sendDelayedArmorUpdate(e.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onWorldChange(PlayerChangedWorldEvent e) {
|
||||
sendArmorUpdate(e.getPlayer());
|
||||
}
|
||||
|
||||
public void sendDelayedArmorUpdate(final Player player) {
|
||||
if (!isOnPipe(player)) return; // Don't start a task if the player is not on the pipe
|
||||
Via.getPlatform().runSync(() -> sendArmorUpdate(player));
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package us.myles.ViaVersion.bukkit.listeners.protocol1_9to1_8;
|
||||
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import us.myles.ViaVersion.api.minecraft.Position;
|
||||
import us.myles.ViaVersion.bukkit.listeners.ViaBukkitListener;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9To1_8;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.EntityTracker1_9;
|
||||
|
||||
public class BlockListener extends ViaBukkitListener {
|
||||
|
||||
public BlockListener(Plugin plugin) {
|
||||
super(plugin, Protocol1_9To1_8.class);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void placeBlock(BlockPlaceEvent e) {
|
||||
if (isOnPipe(e.getPlayer())) {
|
||||
Block b = e.getBlockPlaced();
|
||||
getUserConnection(e.getPlayer())
|
||||
.get(EntityTracker1_9.class)
|
||||
.addBlockInteraction(new Position(b.getX(), (short) b.getY(), b.getZ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package us.myles.ViaVersion.bukkit.listeners.protocol1_9to1_8;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.entity.PlayerDeathEvent;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import us.myles.ViaVersion.api.PacketWrapper;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.type.Type;
|
||||
import us.myles.ViaVersion.bukkit.listeners.ViaBukkitListener;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9To1_8;
|
||||
|
||||
public class DeathListener extends ViaBukkitListener {
|
||||
|
||||
public DeathListener(Plugin plugin) {
|
||||
super(plugin, Protocol1_9To1_8.class);
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
|
||||
public void onDeath(PlayerDeathEvent e) {
|
||||
Player p = e.getEntity();
|
||||
if (isOnPipe(p) && Via.getConfig().isShowNewDeathMessages() && checkGamerule(p.getWorld()) && e.getDeathMessage() != null)
|
||||
sendPacket(p, e.getDeathMessage());
|
||||
}
|
||||
|
||||
public boolean checkGamerule(World w) {
|
||||
try {
|
||||
return Boolean.parseBoolean(w.getGameRuleValue("showDeathMessages"));
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void sendPacket(final Player p, final String msg) {
|
||||
Via.getPlatform().runSync(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// If online
|
||||
UserConnection userConnection = getUserConnection(p);
|
||||
if (userConnection != null) {
|
||||
PacketWrapper wrapper = new PacketWrapper(0x2C, null, userConnection);
|
||||
try {
|
||||
wrapper.write(Type.VAR_INT, 2); // Event - Entity dead
|
||||
wrapper.write(Type.VAR_INT, p.getEntityId()); // Player ID
|
||||
wrapper.write(Type.INT, p.getEntityId()); // Entity ID
|
||||
Protocol1_9To1_8.FIX_JSON.write(wrapper, msg); // Message
|
||||
|
||||
wrapper.send(Protocol1_9To1_8.class);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package us.myles.ViaVersion.bukkit.listeners.protocol1_9to1_8;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import us.myles.ViaVersion.api.minecraft.item.Item;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class HandItemCache extends BukkitRunnable {
|
||||
|
||||
private final Map<UUID, Item> handCache = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
List<UUID> players = new ArrayList<>(handCache.keySet());
|
||||
|
||||
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||
handCache.put(p.getUniqueId(), convert(p.getItemInHand()));
|
||||
players.remove(p.getUniqueId());
|
||||
}
|
||||
// Remove offline players
|
||||
for (UUID uuid : players) {
|
||||
handCache.remove(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
public Item getHandItem(UUID player) {
|
||||
return handCache.get(player);
|
||||
}
|
||||
|
||||
public static Item convert(ItemStack itemInHand) {
|
||||
if (itemInHand == null) return new Item(0, (byte) 0, (short) 0, null);
|
||||
return new Item(itemInHand.getTypeId(), (byte) itemInHand.getAmount(), itemInHand.getDurability(), null);
|
||||
}
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
package us.myles.ViaVersion.bukkit.listeners.protocol1_9to1_8;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import us.myles.ViaVersion.bukkit.listeners.ViaBukkitListener;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9To1_8;
|
||||
|
||||
public class PaperPatch extends ViaBukkitListener {
|
||||
|
||||
public PaperPatch(Plugin plugin) {
|
||||
super(plugin, Protocol1_9To1_8.class);
|
||||
}
|
||||
|
||||
/*
|
||||
This patch is applied when Paper is detected.
|
||||
I'm unsure of what causes this but essentially,
|
||||
placing blocks where you're standing works?
|
||||
If there is a better fix then we'll replace this.
|
||||
*/
|
||||
|
||||
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
|
||||
public void onPlace(BlockPlaceEvent e) {
|
||||
if (isOnPipe(e.getPlayer())) {
|
||||
Location location = e.getPlayer().getLocation();
|
||||
Location diff = location.clone().subtract(e.getBlock().getLocation().add(0.5D, 0, 0.5D));
|
||||
Material block = e.getBlockPlaced().getType();
|
||||
if (isPlacable(block)) {
|
||||
return;
|
||||
}
|
||||
if (location.getBlock().equals(e.getBlock())) {
|
||||
e.setCancelled(true);
|
||||
} else {
|
||||
if (location.getBlock().getRelative(BlockFace.UP).equals(e.getBlock())) {
|
||||
e.setCancelled(true);
|
||||
} else {
|
||||
// Within radius of block
|
||||
if (Math.abs(diff.getX()) <= 0.8 && Math.abs(diff.getZ()) <= 0.8D) {
|
||||
// Are they on the edge / shifting ish
|
||||
if (diff.getY() <= 0.1D && diff.getY() >= -0.1D) {
|
||||
e.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
BlockFace relative = e.getBlockAgainst().getFace(e.getBlock());
|
||||
// Are they towering up, (handles some latency)
|
||||
if (relative == BlockFace.UP) {
|
||||
if (diff.getY() < 1D && diff.getY() >= 0D) {
|
||||
e.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPlacable(Material material) {
|
||||
if (!material.isSolid()) return true;
|
||||
// signs and banners
|
||||
switch (material.getId()) {
|
||||
case 63:
|
||||
case 68:
|
||||
case 176:
|
||||
case 177:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package us.myles.ViaVersion.bukkit.providers;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.minecraft.Position;
|
||||
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections.providers.BlockConnectionProvider;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class BukkitBlockConnectionProvider extends BlockConnectionProvider {
|
||||
private Chunk lastChunk;
|
||||
|
||||
@Override
|
||||
public int getWorldBlockData(UserConnection user, int bx, int by, int bz) {
|
||||
UUID uuid = user.getProtocolInfo().getUuid();
|
||||
Player player = Bukkit.getPlayer(uuid);
|
||||
if (player != null) {
|
||||
World world = player.getWorld();
|
||||
int x = bx >> 4;
|
||||
int z = bz >> 4;
|
||||
if (world.isChunkLoaded(x, z)) {
|
||||
Chunk c = getChunk(world, x, z);
|
||||
Block b = c.getBlock(bx, by, bz);
|
||||
return b.getTypeId() << 4 | b.getData();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Chunk getChunk(World world, int x, int z) {
|
||||
if (lastChunk != null && lastChunk.getX() == x && lastChunk.getZ() == z) {
|
||||
return lastChunk;
|
||||
}
|
||||
return lastChunk = world.getChunkAt(x, z);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>viaversion-parent</artifactId>
|
||||
<groupId>us.myles</groupId>
|
||||
<version>3.1.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>viaversion-bukkit</artifactId>
|
||||
|
||||
<properties>
|
||||
<!-- Change server version HERE! -->
|
||||
<serverVersion>1.16.1-R0.1-SNAPSHOT</serverVersion>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<targetPath>.</targetPath>
|
||||
<filtering>true</filtering>
|
||||
<directory>src/main/resources/</directory>
|
||||
<includes>
|
||||
<include>*</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<!-- Common Module -->
|
||||
<dependency>
|
||||
<groupId>us.myles</groupId>
|
||||
<artifactId>viaversion-common</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Bukkit API, http://www.spigotmc.org/ or http://bukkit.org/ -->
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>${serverVersion}</version>
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>junit</artifactId>
|
||||
<groupId>junit</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>gson</artifactId>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>persistence-api</artifactId>
|
||||
<groupId>javax.persistence</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- Legacy Support -->
|
||||
<dependency>
|
||||
<groupId>us.myles</groupId>
|
||||
<artifactId>viaversion-bukkit-legacy</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,291 @@
|
||||
package us.myles.ViaVersion;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.ViaAPI;
|
||||
import us.myles.ViaVersion.api.command.ViaCommandSender;
|
||||
import us.myles.ViaVersion.api.configuration.ConfigurationProvider;
|
||||
import us.myles.ViaVersion.api.data.MappingDataLoader;
|
||||
import us.myles.ViaVersion.api.platform.TaskId;
|
||||
import us.myles.ViaVersion.api.platform.ViaConnectionManager;
|
||||
import us.myles.ViaVersion.api.platform.ViaPlatform;
|
||||
import us.myles.ViaVersion.bukkit.classgenerator.ClassGenerator;
|
||||
import us.myles.ViaVersion.bukkit.commands.BukkitCommandHandler;
|
||||
import us.myles.ViaVersion.bukkit.commands.BukkitCommandSender;
|
||||
import us.myles.ViaVersion.bukkit.platform.BukkitTaskId;
|
||||
import us.myles.ViaVersion.bukkit.platform.BukkitViaAPI;
|
||||
import us.myles.ViaVersion.bukkit.platform.BukkitViaConfig;
|
||||
import us.myles.ViaVersion.bukkit.platform.BukkitViaInjector;
|
||||
import us.myles.ViaVersion.bukkit.platform.BukkitViaLoader;
|
||||
import us.myles.ViaVersion.bukkit.util.NMSUtil;
|
||||
import us.myles.ViaVersion.dump.PluginInfo;
|
||||
import us.myles.ViaVersion.util.GsonUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ViaVersionPlugin extends JavaPlugin implements ViaPlatform<Player> {
|
||||
private static ViaVersionPlugin instance;
|
||||
private final ViaConnectionManager connectionManager = new ViaConnectionManager();
|
||||
private final BukkitCommandHandler commandHandler;
|
||||
private final BukkitViaConfig conf;
|
||||
private final ViaAPI<Player> api = new BukkitViaAPI(this);
|
||||
private final List<Runnable> queuedTasks = new ArrayList<>();
|
||||
private final List<Runnable> asyncQueuedTasks = new ArrayList<>();
|
||||
private final boolean protocolSupport;
|
||||
private boolean compatSpigotBuild;
|
||||
private boolean spigot = true;
|
||||
private boolean lateBind;
|
||||
|
||||
public ViaVersionPlugin() {
|
||||
instance = this;
|
||||
|
||||
// Command handler
|
||||
commandHandler = new BukkitCommandHandler();
|
||||
// Init platform
|
||||
Via.init(ViaManager.builder()
|
||||
.platform(this)
|
||||
.commandHandler(commandHandler)
|
||||
.injector(new BukkitViaInjector())
|
||||
.loader(new BukkitViaLoader(this))
|
||||
.build());
|
||||
// Config magic
|
||||
conf = new BukkitViaConfig();
|
||||
|
||||
// Check if we're using protocol support too
|
||||
protocolSupport = Bukkit.getPluginManager().getPlugin("ProtocolSupport") != null;
|
||||
if (protocolSupport) {
|
||||
getLogger().info("Hooking into ProtocolSupport, to prevent issues!");
|
||||
try {
|
||||
BukkitViaInjector.patchLists();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
// Spigot detector
|
||||
try {
|
||||
Class.forName("org.spigotmc.SpigotConfig");
|
||||
} catch (ClassNotFoundException e) {
|
||||
spigot = false;
|
||||
}
|
||||
|
||||
// Check if it's a spigot build with a protocol mod
|
||||
try {
|
||||
NMSUtil.nms("PacketEncoder").getDeclaredField("version");
|
||||
compatSpigotBuild = true;
|
||||
} catch (Exception e) {
|
||||
compatSpigotBuild = false;
|
||||
}
|
||||
|
||||
if (getServer().getPluginManager().getPlugin("ViaBackwards") != null) {
|
||||
MappingDataLoader.enableMappingsCache();
|
||||
}
|
||||
|
||||
// Generate classes needed (only works if it's compat or ps)
|
||||
ClassGenerator.generate();
|
||||
lateBind = !BukkitViaInjector.isBinded();
|
||||
|
||||
getLogger().info("ViaVersion " + getDescription().getVersion() + (compatSpigotBuild ? "compat" : "") + " is now loaded" + (lateBind ? ", waiting for boot. (late-bind)" : ", injecting!"));
|
||||
if (!lateBind) {
|
||||
Via.getManager().init();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
if (lateBind) {
|
||||
Via.getManager().init();
|
||||
}
|
||||
|
||||
getCommand("viaversion").setExecutor(commandHandler);
|
||||
getCommand("viaversion").setTabCompleter(commandHandler);
|
||||
|
||||
// Warn them if they have anti-xray on and they aren't using spigot
|
||||
if (conf.isAntiXRay() && !spigot) {
|
||||
getLogger().info("You have anti-xray on in your config, since you're not using spigot it won't fix xray!");
|
||||
}
|
||||
|
||||
// Run queued tasks
|
||||
for (Runnable r : queuedTasks) {
|
||||
Bukkit.getScheduler().runTask(this, r);
|
||||
}
|
||||
queuedTasks.clear();
|
||||
|
||||
// Run async queued tasks
|
||||
for (Runnable r : asyncQueuedTasks) {
|
||||
Bukkit.getScheduler().runTaskAsynchronously(this, r);
|
||||
}
|
||||
asyncQueuedTasks.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
Via.getManager().destroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlatformName() {
|
||||
return Bukkit.getServer().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlatformVersion() {
|
||||
return Bukkit.getServer().getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPluginVersion() {
|
||||
return getDescription().getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskId runAsync(Runnable runnable) {
|
||||
if (isPluginEnabled()) {
|
||||
return new BukkitTaskId(getServer().getScheduler().runTaskAsynchronously(this, runnable).getTaskId());
|
||||
} else {
|
||||
asyncQueuedTasks.add(runnable);
|
||||
return new BukkitTaskId(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskId runSync(Runnable runnable) {
|
||||
if (isPluginEnabled()) {
|
||||
return new BukkitTaskId(getServer().getScheduler().runTask(this, runnable).getTaskId());
|
||||
} else {
|
||||
queuedTasks.add(runnable);
|
||||
return new BukkitTaskId(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskId runSync(Runnable runnable, Long ticks) {
|
||||
return new BukkitTaskId(getServer().getScheduler().runTaskLater(this, runnable, ticks).getTaskId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskId runRepeatingSync(Runnable runnable, Long ticks) {
|
||||
return new BukkitTaskId(getServer().getScheduler().runTaskTimer(this, runnable, 0, ticks).getTaskId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelTask(TaskId taskId) {
|
||||
if (taskId == null) return;
|
||||
if (taskId.getObject() == null) return;
|
||||
if (taskId instanceof BukkitTaskId) {
|
||||
getServer().getScheduler().cancelTask((Integer) taskId.getObject());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViaCommandSender[] getOnlinePlayers() {
|
||||
ViaCommandSender[] array = new ViaCommandSender[Bukkit.getOnlinePlayers().size()];
|
||||
int i = 0;
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
array[i++] = new BukkitCommandSender(player);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(UUID uuid, String message) {
|
||||
Player player = Bukkit.getPlayer(uuid);
|
||||
if (player != null) {
|
||||
player.sendMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean kickPlayer(UUID uuid, String message) {
|
||||
Player player = Bukkit.getPlayer(uuid);
|
||||
if (player != null) {
|
||||
player.kickPlayer(message);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPluginEnabled() {
|
||||
return Bukkit.getPluginManager().getPlugin("ViaVersion").isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigurationProvider getConfigurationProvider() {
|
||||
return conf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReload() {
|
||||
if (Bukkit.getPluginManager().getPlugin("ProtocolLib") != null) {
|
||||
getLogger().severe("ViaVersion is already loaded, we're going to kick all the players... because otherwise we'll crash because of ProtocolLib.");
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
player.kickPlayer(ChatColor.translateAlternateColorCodes('&', conf.getReloadDisconnectMsg()));
|
||||
}
|
||||
|
||||
} else {
|
||||
getLogger().severe("ViaVersion is already loaded, this should work fine. If you get any console errors, try rebooting.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObject getDump() {
|
||||
JsonObject platformSpecific = new JsonObject();
|
||||
|
||||
List<PluginInfo> plugins = new ArrayList<>();
|
||||
for (Plugin p : Bukkit.getPluginManager().getPlugins())
|
||||
plugins.add(new PluginInfo(p.isEnabled(), p.getDescription().getName(), p.getDescription().getVersion(), p.getDescription().getMain(), p.getDescription().getAuthors()));
|
||||
|
||||
platformSpecific.add("plugins", GsonUtil.getGson().toJsonTree(plugins));
|
||||
// TODO more? ProtocolLib things etc?
|
||||
|
||||
return platformSpecific;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOldClientsAllowed() {
|
||||
return !protocolSupport; // Use protocolsupport for older clients
|
||||
}
|
||||
|
||||
@Override
|
||||
public BukkitViaConfig getConf() {
|
||||
return conf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViaAPI<Player> getApi() {
|
||||
return api;
|
||||
}
|
||||
|
||||
public boolean isCompatSpigotBuild() {
|
||||
return compatSpigotBuild;
|
||||
}
|
||||
|
||||
public boolean isSpigot() {
|
||||
return this.spigot;
|
||||
}
|
||||
|
||||
public boolean isProtocolSupport() {
|
||||
return protocolSupport;
|
||||
}
|
||||
|
||||
public static ViaVersionPlugin getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViaConnectionManager getConnectionManager() {
|
||||
return connectionManager;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package us.myles.ViaVersion.boss;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import us.myles.ViaVersion.api.boss.BossBar;
|
||||
import us.myles.ViaVersion.api.boss.BossColor;
|
||||
import us.myles.ViaVersion.api.boss.BossStyle;
|
||||
|
||||
public class ViaBossBar extends CommonBoss<Player> {
|
||||
|
||||
public ViaBossBar(String title, float health, BossColor color, BossStyle style) {
|
||||
super(title, health, color, style);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BossBar addPlayer(Player player) {
|
||||
addPlayer(player.getUniqueId());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BossBar addPlayers(Player... players) {
|
||||
for (Player p : players)
|
||||
addPlayer(p);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BossBar removePlayer(Player player) {
|
||||
removePlayer(player.getUniqueId());
|
||||
return this;
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package us.myles.ViaVersion.bukkit.classgenerator;
|
||||
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.bukkit.handlers.BukkitDecodeHandler;
|
||||
import us.myles.ViaVersion.bukkit.handlers.BukkitEncodeHandler;
|
||||
|
||||
public class BasicHandlerConstructor implements HandlerConstructor {
|
||||
@Override
|
||||
public BukkitEncodeHandler newEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder) {
|
||||
return new BukkitEncodeHandler(info, minecraftEncoder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BukkitDecodeHandler newDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder) {
|
||||
return new BukkitDecodeHandler(info, minecraftDecoder);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
package us.myles.ViaVersion.bukkit.classgenerator;
|
||||
|
||||
import javassist.*;
|
||||
import javassist.expr.ConstructorCall;
|
||||
import javassist.expr.ExprEditor;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.EventException;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.EventExecutor;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import us.myles.ViaVersion.ViaVersionPlugin;
|
||||
import us.myles.ViaVersion.bukkit.handlers.BukkitDecodeHandler;
|
||||
import us.myles.ViaVersion.bukkit.handlers.BukkitEncodeHandler;
|
||||
import us.myles.ViaVersion.bukkit.util.NMSUtil;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
//TODO maybe clean this up a bit 👀
|
||||
public class ClassGenerator {
|
||||
private static HandlerConstructor constructor = new BasicHandlerConstructor();
|
||||
private static String psPackage;
|
||||
private static Class psConnectListener;
|
||||
|
||||
public static HandlerConstructor getConstructor() {
|
||||
return constructor;
|
||||
}
|
||||
|
||||
public static void generate() {
|
||||
if (ViaVersionPlugin.getInstance().isCompatSpigotBuild() || ViaVersionPlugin.getInstance().isProtocolSupport()) {
|
||||
try {
|
||||
ClassPool pool = ClassPool.getDefault();
|
||||
pool.insertClassPath(new LoaderClassPath(Bukkit.class.getClassLoader()));
|
||||
for (Plugin p : Bukkit.getPluginManager().getPlugins()) {
|
||||
pool.insertClassPath(new LoaderClassPath(p.getClass().getClassLoader()));
|
||||
}
|
||||
|
||||
if (ViaVersionPlugin.getInstance().isCompatSpigotBuild()) {
|
||||
Class decodeSuper = NMSUtil.nms("PacketDecoder");
|
||||
Class encodeSuper = NMSUtil.nms("PacketEncoder");
|
||||
// Generate the classes
|
||||
addSpigotCompatibility(pool, BukkitDecodeHandler.class, decodeSuper);
|
||||
addSpigotCompatibility(pool, BukkitEncodeHandler.class, encodeSuper);
|
||||
} else {
|
||||
// ProtocolSupport compatibility
|
||||
Class encodeSuper;
|
||||
Class decodeSuper;
|
||||
if (isMultiplatformPS()) {
|
||||
psConnectListener = makePSConnectListener(pool, shouldUseNewHandshakeVersionMethod());
|
||||
return;
|
||||
} else {
|
||||
String psPackage = getOldPSPackage();
|
||||
decodeSuper = Class.forName(psPackage.equals("unknown") ? "protocolsupport.protocol.pipeline.common.PacketDecoder" : psPackage + ".wrapped.WrappedDecoder");
|
||||
encodeSuper = Class.forName(psPackage.equals("unknown") ? "protocolsupport.protocol.pipeline.common.PacketEncoder" : psPackage + ".wrapped.WrappedEncoder");
|
||||
}
|
||||
// Generate the classes
|
||||
addPSCompatibility(pool, BukkitDecodeHandler.class, decodeSuper);
|
||||
addPSCompatibility(pool, BukkitEncodeHandler.class, encodeSuper);
|
||||
}
|
||||
|
||||
|
||||
// Implement Constructor
|
||||
CtClass generated = pool.makeClass("us.myles.ViaVersion.classgenerator.generated.GeneratedConstructor");
|
||||
CtClass handlerInterface = pool.get(HandlerConstructor.class.getName());
|
||||
|
||||
generated.setInterfaces(new CtClass[]{handlerInterface});
|
||||
// Import required classes
|
||||
pool.importPackage("us.myles.ViaVersion.classgenerator.generated");
|
||||
pool.importPackage("us.myles.ViaVersion.classgenerator");
|
||||
pool.importPackage("us.myles.ViaVersion.api.data");
|
||||
pool.importPackage("io.netty.handler.codec");
|
||||
// Implement Methods
|
||||
generated.addMethod(CtMethod.make("public MessageToByteEncoder newEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder) {\n" +
|
||||
" return new BukkitEncodeHandler(info, minecraftEncoder);\n" +
|
||||
" }", generated));
|
||||
generated.addMethod(CtMethod.make("public ByteToMessageDecoder newDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder) {\n" +
|
||||
" return new BukkitDecodeHandler(info, minecraftDecoder);\n" +
|
||||
" }", generated));
|
||||
|
||||
constructor = (HandlerConstructor) generated.toClass(HandlerConstructor.class.getClassLoader()).newInstance();
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (CannotCompileException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InstantiationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Class addSpigotCompatibility(ClassPool pool, Class input, Class superclass) {
|
||||
String newName = "us.myles.ViaVersion.classgenerator.generated." + input.getSimpleName();
|
||||
|
||||
try {
|
||||
CtClass generated = pool.getAndRename(input.getName(), newName);
|
||||
if (superclass != null) {
|
||||
CtClass toExtend = pool.get(superclass.getName());
|
||||
generated.setSuperclass(toExtend);
|
||||
|
||||
// If it's NMS satisfy constructor.
|
||||
if (superclass.getName().startsWith("net.minecraft")) {
|
||||
// Modify constructor to call super
|
||||
if (generated.getConstructors().length != 0) {
|
||||
generated.getConstructors()[0].instrument(new ExprEditor() {
|
||||
@Override
|
||||
public void edit(ConstructorCall c) throws CannotCompileException {
|
||||
if (c.isSuper()) {
|
||||
// Constructor for both has a stats thing.
|
||||
c.replace("super(null);");
|
||||
}
|
||||
super.edit(c);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return generated.toClass(HandlerConstructor.class.getClassLoader());
|
||||
} catch (NotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (CannotCompileException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Class addPSCompatibility(ClassPool pool, Class input, Class superclass) {
|
||||
boolean newPS = getOldPSPackage().equals("unknown");
|
||||
String newName = "us.myles.ViaVersion.classgenerator.generated." + input.getSimpleName();
|
||||
|
||||
try {
|
||||
CtClass generated = pool.getAndRename(input.getName(), newName);
|
||||
if (superclass != null) {
|
||||
CtClass toExtend = pool.get(superclass.getName());
|
||||
generated.setSuperclass(toExtend);
|
||||
|
||||
if (!newPS) {
|
||||
// Override setRealEncoder / setRealDecoder
|
||||
pool.importPackage(getOldPSPackage());
|
||||
pool.importPackage(getOldPSPackage() + ".wrapped");
|
||||
if (superclass.getName().endsWith("Decoder")) {
|
||||
// Decoder
|
||||
generated.addMethod(CtMethod.make("public void setRealDecoder(IPacketDecoder dec) {\n" +
|
||||
" ((WrappedDecoder) this.minecraftDecoder).setRealDecoder(dec);\n" +
|
||||
" }", generated));
|
||||
} else {
|
||||
// Encoder
|
||||
pool.importPackage("protocolsupport.api");
|
||||
pool.importPackage("java.lang.reflect");
|
||||
generated.addMethod(CtMethod.make("public void setRealEncoder(IPacketEncoder enc) {\n" +
|
||||
" try {\n" +
|
||||
// Tell ProtocolSupport to decode MINECRAFT_FUTURE packets using the default decoder (for 1.9.4)
|
||||
" Field field = enc.getClass().getDeclaredField(\"version\");\n" +
|
||||
" field.setAccessible(true);\n" +
|
||||
" ProtocolVersion version = (ProtocolVersion) field.get(enc);\n" +
|
||||
|
||||
" if (version == ProtocolVersion.MINECRAFT_FUTURE) enc = enc.getClass().getConstructor(\n" +
|
||||
" new Class[]{ProtocolVersion.class}).newInstance(new Object[] {ProtocolVersion.getLatest()});\n" +
|
||||
" } catch (Exception e) {\n" +
|
||||
// I guess we're not on 1.9.4
|
||||
" }\n" +
|
||||
" ((WrappedEncoder) this.minecraftEncoder).setRealEncoder(enc);\n" +
|
||||
" }", generated));
|
||||
}
|
||||
}
|
||||
}
|
||||
return generated.toClass(HandlerConstructor.class.getClassLoader());
|
||||
} catch (NotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (CannotCompileException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Class makePSConnectListener(ClassPool pool, boolean newVersionMethod) {
|
||||
try {
|
||||
// Reference classes
|
||||
CtClass toExtend = pool.get("protocolsupport.api.Connection$PacketListener");
|
||||
CtClass connectListenerClazz = pool.makeClass("us.myles.ViaVersion.classgenerator.generated.ProtocolSupportConnectListener");
|
||||
connectListenerClazz.setSuperclass(toExtend);
|
||||
// Import packages
|
||||
pool.importPackage("java.util.Arrays");
|
||||
pool.importPackage("us.myles.ViaVersion.api.protocol.ProtocolRegistry");
|
||||
pool.importPackage("protocolsupport.api.ProtocolVersion");
|
||||
pool.importPackage("protocolsupport.api.ProtocolType");
|
||||
pool.importPackage("protocolsupport.api.Connection");
|
||||
pool.importPackage("protocolsupport.api.Connection.PacketListener");
|
||||
pool.importPackage("protocolsupport.api.Connection.PacketListener.PacketEvent");
|
||||
pool.importPackage("protocolsupport.protocol.ConnectionImpl");
|
||||
pool.importPackage(NMSUtil.nms("PacketHandshakingInSetProtocol").getName());
|
||||
// Add connection reference field
|
||||
connectListenerClazz.addField(CtField.make("private ConnectionImpl connection;", connectListenerClazz));
|
||||
// Bake constructor
|
||||
connectListenerClazz.addConstructor(CtNewConstructor.make(
|
||||
"public ProtocolSupportConnectListener (ConnectionImpl connection) {\n"
|
||||
+ " this.connection = connection;\n"
|
||||
+ "}", connectListenerClazz));
|
||||
// Add the listening method
|
||||
connectListenerClazz.addMethod(CtNewMethod.make(
|
||||
// On packet receive
|
||||
"public void onPacketReceiving(protocolsupport.api.Connection.PacketListener.PacketEvent event) {\n"
|
||||
// Check if we are getting handshake packet.
|
||||
+ " if (event.getPacket() instanceof PacketHandshakingInSetProtocol) {\n"
|
||||
// Get protocol version.
|
||||
+ " PacketHandshakingInSetProtocol packet = (PacketHandshakingInSetProtocol) event.getPacket();\n"
|
||||
+ (newVersionMethod ? (
|
||||
" int protoVersion = packet.getProtocolVersion();\n"
|
||||
) : (
|
||||
" int protoVersion = packet.b();\n"
|
||||
))
|
||||
// ViaVersion has at this point already spoofed the connectionversion. (Since it is higher up the pipeline)
|
||||
// If via has put the protoVersion to the server we can spoof ProtocolSupport's version.
|
||||
+ " if (connection.getVersion() == ProtocolVersion.MINECRAFT_FUTURE && protoVersion == us.myles.ViaVersion.api.protocol.ProtocolRegistry.SERVER_PROTOCOL) {\n"
|
||||
+ " connection.setVersion(ProtocolVersion.getLatest(ProtocolType.PC));\n"
|
||||
+ " }\n"
|
||||
+ " }\n"
|
||||
// Id version is not serverversion viaversion will not spoof. ProtocolSupport will handle the rest.
|
||||
// In any case, remove the packet listener and wrap up.
|
||||
+ " connection.removePacketListener(this);\n"
|
||||
+ "}", connectListenerClazz));
|
||||
return connectListenerClazz.toClass(HandlerConstructor.class.getClassLoader());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void registerPSConnectListener(ViaVersionPlugin plugin) {
|
||||
if (getPSConnectListener() != null) {
|
||||
try {
|
||||
Class<? extends Event> connectionOpenEvent = (Class<? extends Event>) Class.forName("protocolsupport.api.events.ConnectionOpenEvent");
|
||||
Bukkit.getPluginManager().registerEvent(connectionOpenEvent, new Listener() { }, EventPriority.HIGH, new EventExecutor() {
|
||||
@Override
|
||||
public void execute(Listener listener, Event event) throws EventException {
|
||||
try {
|
||||
Object connection = event.getClass().getMethod("getConnection").invoke(event);
|
||||
Object connectListener = getPSConnectListener().getConstructor(connection.getClass()).newInstance(connection);
|
||||
Method addConnectListener = connection.getClass().getMethod("addPacketListener", Class.forName("protocolsupport.api.Connection$PacketListener"));
|
||||
addConnectListener.invoke(connection, connectListener);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}, plugin);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Class getPSConnectListener() {
|
||||
return psConnectListener;
|
||||
}
|
||||
|
||||
public static String getOldPSPackage() {
|
||||
if (psPackage == null) {
|
||||
try {
|
||||
Class.forName("protocolsupport.protocol.core.IPacketDecoder");
|
||||
psPackage = "protocolsupport.protocol.core";
|
||||
} catch (ClassNotFoundException e) {
|
||||
try {
|
||||
Class.forName("protocolsupport.protocol.pipeline.IPacketDecoder");
|
||||
psPackage = "protocolsupport.protocol.pipeline";
|
||||
} catch (ClassNotFoundException e1) {
|
||||
psPackage = "unknown";
|
||||
}
|
||||
}
|
||||
}
|
||||
return psPackage;
|
||||
}
|
||||
|
||||
public static boolean isMultiplatformPS() {
|
||||
try {
|
||||
Class.forName("protocolsupport.zplatform.impl.spigot.network.pipeline.SpigotPacketEncoder");
|
||||
return true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean shouldUseNewHandshakeVersionMethod() {
|
||||
try {
|
||||
NMSUtil.nms("PacketHandshakingInSetProtocol").getMethod("getProtocolVersion");
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package us.myles.ViaVersion.bukkit.classgenerator;
|
||||
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
|
||||
public interface HandlerConstructor {
|
||||
public MessageToByteEncoder newEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder);
|
||||
|
||||
public ByteToMessageDecoder newDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package us.myles.ViaVersion.bukkit.commands;
|
||||
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabExecutor;
|
||||
import us.myles.ViaVersion.commands.ViaCommandHandler;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class BukkitCommandHandler extends ViaCommandHandler implements CommandExecutor, TabExecutor {
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
return onCommand(new BukkitCommandSender(sender), args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
|
||||
return onTabComplete(new BukkitCommandSender(sender), args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package us.myles.ViaVersion.bukkit.commands;
|
||||
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import us.myles.ViaVersion.api.command.ViaCommandSender;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class BukkitCommandSender implements ViaCommandSender {
|
||||
private final CommandSender sender;
|
||||
|
||||
public BukkitCommandSender(CommandSender sender) {
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String permission) {
|
||||
return sender.hasPermission(permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(String msg) {
|
||||
sender.sendMessage(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUUID() {
|
||||
if (sender instanceof Player) {
|
||||
return ((Player) sender).getUniqueId();
|
||||
} else {
|
||||
return UUID.fromString(getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return sender.getName();
|
||||
}
|
||||
}
|
||||
+17
-9
@@ -1,4 +1,4 @@
|
||||
package us.myles.ViaVersion.handlers;
|
||||
package us.myles.ViaVersion.bukkit.handlers;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
@@ -7,16 +7,18 @@ import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolPipeline;
|
||||
import us.myles.ViaVersion.bukkit.classgenerator.ClassGenerator;
|
||||
import us.myles.ViaVersion.bukkit.classgenerator.HandlerConstructor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class ViaVersionInitializer extends ChannelInitializer<SocketChannel> {
|
||||
public class BukkitChannelInitializer extends ChannelInitializer<SocketChannel> {
|
||||
|
||||
private final ChannelInitializer<SocketChannel> oldInit;
|
||||
private final ChannelInitializer<SocketChannel> original;
|
||||
private Method method;
|
||||
|
||||
public ViaVersionInitializer(ChannelInitializer<SocketChannel> oldInit) {
|
||||
this.oldInit = oldInit;
|
||||
public BukkitChannelInitializer(ChannelInitializer<SocketChannel> oldInit) {
|
||||
this.original = oldInit;
|
||||
try {
|
||||
this.method = ChannelInitializer.class.getDeclaredMethod("initChannel", Channel.class);
|
||||
this.method.setAccessible(true);
|
||||
@@ -25,17 +27,23 @@ public class ViaVersionInitializer extends ChannelInitializer<SocketChannel> {
|
||||
}
|
||||
}
|
||||
|
||||
public ChannelInitializer<SocketChannel> getOriginal() {
|
||||
return original;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initChannel(SocketChannel socketChannel) throws Exception {
|
||||
UserConnection info = new UserConnection(socketChannel);
|
||||
// init protocol
|
||||
new ProtocolPipeline(info);
|
||||
// Add originals
|
||||
this.method.invoke(this.oldInit, socketChannel);
|
||||
this.method.invoke(this.original, socketChannel);
|
||||
|
||||
HandlerConstructor constructor = ClassGenerator.getConstructor();
|
||||
// Add our transformers
|
||||
ViaEncodeHandler encoder = new ViaEncodeHandler(info, (MessageToByteEncoder) socketChannel.pipeline().get("encoder"));
|
||||
ViaDecodeHandler decoder = new ViaDecodeHandler(info, (ByteToMessageDecoder) socketChannel.pipeline().get("decoder"));
|
||||
ViaPacketHandler chunkHandler = new ViaPacketHandler(info);
|
||||
MessageToByteEncoder encoder = constructor.newEncodeHandler(info, (MessageToByteEncoder) socketChannel.pipeline().get("encoder"));
|
||||
ByteToMessageDecoder decoder = constructor.newDecodeHandler(info, (ByteToMessageDecoder) socketChannel.pipeline().get("decoder"));
|
||||
BukkitPacketHandler chunkHandler = new BukkitPacketHandler(info);
|
||||
|
||||
socketChannel.pipeline().replace("encoder", "encoder", encoder);
|
||||
socketChannel.pipeline().replace("decoder", "decoder", decoder);
|
||||
@@ -0,0 +1,67 @@
|
||||
package us.myles.ViaVersion.bukkit.handlers;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.bukkit.util.NMSUtil;
|
||||
import us.myles.ViaVersion.exception.CancelCodecException;
|
||||
import us.myles.ViaVersion.exception.CancelDecoderException;
|
||||
import us.myles.ViaVersion.exception.InformativeException;
|
||||
import us.myles.ViaVersion.packets.State;
|
||||
import us.myles.ViaVersion.util.PipelineUtil;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.List;
|
||||
|
||||
public class BukkitDecodeHandler extends ByteToMessageDecoder {
|
||||
private final ByteToMessageDecoder minecraftDecoder;
|
||||
private final UserConnection info;
|
||||
|
||||
public BukkitDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder) {
|
||||
this.info = info;
|
||||
this.minecraftDecoder = minecraftDecoder;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> list) throws Exception {
|
||||
if (!info.checkIncomingPacket()) {
|
||||
bytebuf.clear(); // Don't accumulate
|
||||
throw CancelDecoderException.generate(null);
|
||||
}
|
||||
|
||||
ByteBuf transformedBuf = null;
|
||||
try {
|
||||
if (info.shouldTransformPacket()) {
|
||||
transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf);
|
||||
info.transformIncoming(transformedBuf, CancelDecoderException::generate);
|
||||
}
|
||||
|
||||
try {
|
||||
list.addAll(PipelineUtil.callDecode(this.minecraftDecoder, ctx, transformedBuf == null ? bytebuf : transformedBuf));
|
||||
} catch (InvocationTargetException e) {
|
||||
if (e.getCause() instanceof Exception) {
|
||||
throw (Exception) e.getCause();
|
||||
} else if (e.getCause() instanceof Error) {
|
||||
throw (Error) e.getCause();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (transformedBuf != null) {
|
||||
transformedBuf.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
if (PipelineUtil.containsCause(cause, CancelCodecException.class)) return; // ProtocolLib compat
|
||||
|
||||
super.exceptionCaught(ctx, cause);
|
||||
if (!NMSUtil.isDebugPropertySet() && PipelineUtil.containsCause(cause, InformativeException.class)
|
||||
&& (info.getProtocolInfo().getState() != State.HANDSHAKE || Via.getManager().isDebug())) {
|
||||
cause.printStackTrace(); // Print if CB doesn't already do it
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package us.myles.ViaVersion.bukkit.handlers;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.bukkit.util.NMSUtil;
|
||||
import us.myles.ViaVersion.exception.CancelCodecException;
|
||||
import us.myles.ViaVersion.exception.CancelEncoderException;
|
||||
import us.myles.ViaVersion.exception.InformativeException;
|
||||
import us.myles.ViaVersion.handlers.ChannelHandlerContextWrapper;
|
||||
import us.myles.ViaVersion.handlers.ViaHandler;
|
||||
import us.myles.ViaVersion.packets.State;
|
||||
import us.myles.ViaVersion.util.PipelineUtil;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
public class BukkitEncodeHandler extends MessageToByteEncoder implements ViaHandler {
|
||||
private static Field versionField;
|
||||
|
||||
static {
|
||||
try {
|
||||
versionField = NMSUtil.nms("PacketEncoder").getDeclaredField("version");
|
||||
versionField.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
// Not compat version
|
||||
}
|
||||
}
|
||||
|
||||
private final UserConnection info;
|
||||
private final MessageToByteEncoder minecraftEncoder;
|
||||
|
||||
public BukkitEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder) {
|
||||
this.info = info;
|
||||
this.minecraftEncoder = minecraftEncoder;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void encode(final ChannelHandlerContext ctx, Object o, final ByteBuf bytebuf) throws Exception {
|
||||
if (versionField != null) {
|
||||
versionField.set(minecraftEncoder, versionField.get(this));
|
||||
}
|
||||
// handle the packet type
|
||||
if (!(o instanceof ByteBuf)) {
|
||||
// call minecraft encoder
|
||||
try {
|
||||
PipelineUtil.callEncode(this.minecraftEncoder, new ChannelHandlerContextWrapper(ctx, this), o, bytebuf);
|
||||
} catch (InvocationTargetException e) {
|
||||
if (e.getCause() instanceof Exception) {
|
||||
throw (Exception) e.getCause();
|
||||
} else if (e.getCause() instanceof Error) {
|
||||
throw (Error) e.getCause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
transform(bytebuf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(ByteBuf bytebuf) throws Exception {
|
||||
info.checkOutgoingPacket();
|
||||
if (!info.shouldTransformPacket()) return;
|
||||
info.transformOutgoing(bytebuf, CancelEncoderException::generate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
if (PipelineUtil.containsCause(cause, CancelCodecException.class)) return; // ProtocolLib compat
|
||||
|
||||
super.exceptionCaught(ctx, cause);
|
||||
if (!NMSUtil.isDebugPropertySet() && PipelineUtil.containsCause(cause, InformativeException.class)
|
||||
&& (info.getProtocolInfo().getState() != State.HANDSHAKE || Via.getManager().isDebug())) {
|
||||
cause.printStackTrace(); // Print if CB doesn't already do it
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-7
@@ -1,4 +1,4 @@
|
||||
package us.myles.ViaVersion.handlers;
|
||||
package us.myles.ViaVersion.bukkit.handlers;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
@@ -8,23 +8,23 @@ import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ViaPacketHandler extends MessageToMessageEncoder {
|
||||
public class BukkitPacketHandler extends MessageToMessageEncoder {
|
||||
private final UserConnection info;
|
||||
|
||||
public ViaPacketHandler(UserConnection info) {
|
||||
public BukkitPacketHandler(UserConnection info) {
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, Object o, List list) throws Exception {
|
||||
// Split chunk bulk packet up in to single chunk packets before it reached the encoder.
|
||||
// This will prevent issues with several plugins and other protocol handlers due to the chunk being sent twice.
|
||||
// It also sends the chunk in the right order possible resolving some issues with added chunk/block/entity data.
|
||||
// Split chunks bulk packet up in to single chunks packets before it reached the encoder.
|
||||
// This will prevent issues with several plugins and other protocol handlers due to the chunks being sent twice.
|
||||
// It also sends the chunks in the right order possible resolving some issues with added chunks/block/entity data.
|
||||
if (!(o instanceof ByteBuf)) {
|
||||
info.setLastPacket(o);
|
||||
/* This transformer is more for fixing issues which we find hard at packet level :) */
|
||||
if (info.isActive()) {
|
||||
if (info.get(ProtocolInfo.class).getPipeline().filter(o, list)) {
|
||||
if (info.getProtocolInfo().getPipeline().filter(o, list)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
+18
-22
@@ -1,22 +1,18 @@
|
||||
package us.myles.ViaVersion.update;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import us.myles.ViaVersion.ViaVersionPlugin;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class UpdateListener implements Listener {
|
||||
|
||||
private final ViaVersionPlugin plugin;
|
||||
|
||||
@EventHandler
|
||||
public void onJoin(PlayerJoinEvent e) {
|
||||
if (e.getPlayer().hasPermission("viaversion.update")
|
||||
&& plugin.isCheckForUpdates()) {
|
||||
UpdateUtil.sendUpdateMessage(e.getPlayer().getUniqueId(), plugin);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package us.myles.ViaVersion.bukkit.listeners;
|
||||
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.update.UpdateUtil;
|
||||
|
||||
public class UpdateListener implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onJoin(PlayerJoinEvent e) {
|
||||
if (e.getPlayer().hasPermission("viaversion.update")
|
||||
&& Via.getConfig().isCheckForUpdates()) {
|
||||
UpdateUtil.sendUpdateMessage(e.getPlayer().getUniqueId());
|
||||
}
|
||||
}
|
||||
}
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
package us.myles.ViaVersion.bukkit.listeners.multiversion;
|
||||
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.event.player.PlayerToggleSneakEvent;
|
||||
import us.myles.ViaVersion.ViaVersionPlugin;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
|
||||
import us.myles.ViaVersion.bukkit.listeners.ViaBukkitListener;
|
||||
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
|
||||
public class PlayerSneakListener extends ViaBukkitListener {
|
||||
private static final float STANDING_HEIGHT = 1.8F;
|
||||
private static final float HEIGHT_1_14 = 1.5F;
|
||||
private static final float HEIGHT_1_9 = 1.6F;
|
||||
private static final float DEFAULT_WIDTH = 0.6F;
|
||||
|
||||
private final boolean is1_9Fix;
|
||||
private final boolean is1_14Fix;
|
||||
private Map<Player, Boolean> sneaking; // true = 1.14+, else false
|
||||
private Set<UUID> sneakingUuids;
|
||||
private final Method getHandle;
|
||||
private Method setSize;
|
||||
|
||||
private boolean useCache;
|
||||
|
||||
public PlayerSneakListener(ViaVersionPlugin plugin, boolean is1_9Fix, boolean is1_14Fix) throws ReflectiveOperationException {
|
||||
super(plugin, null);
|
||||
this.is1_9Fix = is1_9Fix;
|
||||
this.is1_14Fix = is1_14Fix;
|
||||
|
||||
final String packageName = plugin.getServer().getClass().getPackage().getName();
|
||||
getHandle = Class.forName(packageName + ".entity.CraftPlayer").getMethod("getHandle");
|
||||
|
||||
final Class<?> entityPlayerClass = Class.forName(packageName
|
||||
.replace("org.bukkit.craftbukkit", "net.minecraft.server") + ".EntityPlayer");
|
||||
try {
|
||||
setSize = entityPlayerClass.getMethod("setSize", Float.TYPE, Float.TYPE);
|
||||
} catch (NoSuchMethodException e) {
|
||||
// Don't catch this one
|
||||
setSize = entityPlayerClass.getMethod("a", Float.TYPE, Float.TYPE);
|
||||
}
|
||||
|
||||
|
||||
// From 1.9 upwards the server hitbox is set in every entity tick, so we have to reset it everytime
|
||||
if (ProtocolRegistry.SERVER_PROTOCOL >= ProtocolVersion.v1_9.getId()) {
|
||||
sneaking = new WeakHashMap<>();
|
||||
useCache = true;
|
||||
plugin.getServer().getScheduler().runTaskTimer(plugin, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (Map.Entry<Player, Boolean> entry : sneaking.entrySet()) {
|
||||
setHeight(entry.getKey(), entry.getValue() ? HEIGHT_1_14 : HEIGHT_1_9);
|
||||
}
|
||||
}
|
||||
}, 1, 1);
|
||||
}
|
||||
|
||||
// Suffocation removal only required for 1.14+ clients.
|
||||
if (is1_14Fix) {
|
||||
sneakingUuids = new HashSet<>();
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void playerToggleSneak(PlayerToggleSneakEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
UserConnection userConnection = getUserConnection(player);
|
||||
if (userConnection == null) return;
|
||||
ProtocolInfo info = userConnection.getProtocolInfo();
|
||||
if (info == null) return;
|
||||
|
||||
int protocolVersion = info.getProtocolVersion();
|
||||
if (is1_14Fix && protocolVersion >= ProtocolVersion.v1_14.getId()) {
|
||||
setHeight(player, event.isSneaking() ? HEIGHT_1_14 : STANDING_HEIGHT);
|
||||
if (event.isSneaking())
|
||||
sneakingUuids.add(player.getUniqueId());
|
||||
else
|
||||
sneakingUuids.remove(player.getUniqueId());
|
||||
|
||||
if (!useCache) return;
|
||||
if (event.isSneaking())
|
||||
sneaking.put(player, true);
|
||||
else
|
||||
sneaking.remove(player);
|
||||
} else if (is1_9Fix && protocolVersion >= ProtocolVersion.v1_9.getId()) {
|
||||
setHeight(player, event.isSneaking() ? HEIGHT_1_9 : STANDING_HEIGHT);
|
||||
if (!useCache) return;
|
||||
if (event.isSneaking())
|
||||
sneaking.put(player, false);
|
||||
else
|
||||
sneaking.remove(player);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void playerDamage(EntityDamageEvent event) {
|
||||
if (!is1_14Fix) return;
|
||||
if (event.getCause() != EntityDamageEvent.DamageCause.SUFFOCATION) return;
|
||||
if (event.getEntityType() != EntityType.PLAYER) return;
|
||||
|
||||
Player player = (Player) event.getEntity();
|
||||
if (!sneakingUuids.contains(player.getUniqueId())) return;
|
||||
|
||||
// Don't cancel when they should actually be suffocating; Essentially cancel when the head is in the top block only ever so slightly
|
||||
// ~0.041 should suffice, but gotta stay be safe
|
||||
double y = player.getEyeLocation().getY() + 0.045;
|
||||
y -= (int) y;
|
||||
if (y < 0.09) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void playerQuit(PlayerQuitEvent event) {
|
||||
if (sneaking != null)
|
||||
sneaking.remove(event.getPlayer());
|
||||
if (sneakingUuids != null)
|
||||
sneakingUuids.remove(event.getPlayer().getUniqueId());
|
||||
}
|
||||
|
||||
private void setHeight(Player player, float height) {
|
||||
try {
|
||||
setSize.invoke(getHandle.invoke(player), DEFAULT_WIDTH, height);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
package us.myles.ViaVersion.bukkit.listeners.protocol1_15to1_14_4;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.entity.EntityToggleGlideEvent;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import us.myles.ViaVersion.ViaVersionPlugin;
|
||||
import us.myles.ViaVersion.api.PacketWrapper;
|
||||
import us.myles.ViaVersion.api.minecraft.metadata.Metadata;
|
||||
import us.myles.ViaVersion.api.minecraft.metadata.types.MetaType1_14;
|
||||
import us.myles.ViaVersion.api.type.Type;
|
||||
import us.myles.ViaVersion.api.type.types.version.Types1_14;
|
||||
import us.myles.ViaVersion.bukkit.listeners.ViaBukkitListener;
|
||||
import us.myles.ViaVersion.protocols.protocol1_15to1_14_4.Protocol1_15To1_14_4;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class EntityToggleGlideListener extends ViaBukkitListener {
|
||||
|
||||
private boolean swimmingMethodExists;
|
||||
|
||||
public EntityToggleGlideListener(ViaVersionPlugin plugin) {
|
||||
super(plugin, Protocol1_15To1_14_4.class);
|
||||
try {
|
||||
Player.class.getMethod("isSwimming");
|
||||
swimmingMethodExists = true;
|
||||
} catch (NoSuchMethodException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void entityToggleGlide(EntityToggleGlideEvent event) {
|
||||
if (!(event.getEntity() instanceof Player)) return;
|
||||
|
||||
Player player = (Player) event.getEntity();
|
||||
if (!isOnPipe(player)) return;
|
||||
|
||||
// Cancelling can only be done by updating the player's metadata
|
||||
if (event.isGliding() && event.isCancelled()) {
|
||||
PacketWrapper packet = new PacketWrapper(0x44, null, getUserConnection(player));
|
||||
try {
|
||||
packet.write(Type.VAR_INT, player.getEntityId());
|
||||
|
||||
byte bitmask = 0;
|
||||
// Collect other metadata for the mitmask
|
||||
if (player.getFireTicks() > 0) {
|
||||
bitmask |= 0x01;
|
||||
}
|
||||
if (player.isSneaking()) {
|
||||
bitmask |= 0x02;
|
||||
}
|
||||
// 0x04 is unused
|
||||
if (player.isSprinting()) {
|
||||
bitmask |= 0x08;
|
||||
}
|
||||
if (swimmingMethodExists && player.isSwimming()) {
|
||||
bitmask |= 0x10;
|
||||
}
|
||||
if (player.hasPotionEffect(PotionEffectType.INVISIBILITY)) {
|
||||
bitmask |= 0x20;
|
||||
}
|
||||
if (player.isGlowing()) {
|
||||
bitmask |= 0x40;
|
||||
}
|
||||
|
||||
// leave 0x80 as 0 to stop gliding
|
||||
packet.write(Types1_14.METADATA_LIST, Arrays.asList(new Metadata(0, MetaType1_14.Byte, bitmask)));
|
||||
packet.send(Protocol1_15To1_14_4.class);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package us.myles.ViaVersion.bukkit.platform;
|
||||
|
||||
import us.myles.ViaVersion.api.platform.TaskId;
|
||||
|
||||
public class BukkitTaskId implements TaskId {
|
||||
private final Integer object;
|
||||
|
||||
public BukkitTaskId(Integer object) {
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getObject() {
|
||||
return object;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package us.myles.ViaVersion.bukkit.platform;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import us.myles.ViaVersion.ViaVersionPlugin;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.ViaAPI;
|
||||
import us.myles.ViaVersion.api.boss.BossBar;
|
||||
import us.myles.ViaVersion.api.boss.BossColor;
|
||||
import us.myles.ViaVersion.api.boss.BossStyle;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
|
||||
import us.myles.ViaVersion.boss.ViaBossBar;
|
||||
import us.myles.ViaVersion.bukkit.util.ProtocolSupportUtil;
|
||||
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.UUID;
|
||||
|
||||
public class BukkitViaAPI implements ViaAPI<Player> {
|
||||
private final ViaVersionPlugin plugin;
|
||||
|
||||
public BukkitViaAPI(ViaVersionPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPlayerVersion(Player player) {
|
||||
return getPlayerVersion(player.getUniqueId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPlayerVersion(UUID uuid) {
|
||||
if (!isInjected(uuid))
|
||||
return getExternalVersion(Bukkit.getPlayer(uuid));
|
||||
return Via.getManager().getConnection(uuid).getProtocolInfo().getProtocolVersion();
|
||||
}
|
||||
|
||||
private int getExternalVersion(Player player) {
|
||||
if (!isProtocolSupport()) {
|
||||
return ProtocolRegistry.SERVER_PROTOCOL;
|
||||
} else {
|
||||
return ProtocolSupportUtil.getProtocolVersion(player);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInjected(UUID playerUUID) {
|
||||
return Via.getManager().isClientConnected(playerUUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return plugin.getDescription().getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendRawPacket(UUID uuid, ByteBuf packet) throws IllegalArgumentException {
|
||||
if (!isInjected(uuid)) throw new IllegalArgumentException("This player is not controlled by ViaVersion!");
|
||||
UserConnection ci = Via.getManager().getConnection(uuid);
|
||||
ci.sendRawPacket(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendRawPacket(Player player, ByteBuf packet) throws IllegalArgumentException {
|
||||
sendRawPacket(player.getUniqueId(), packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BossBar<Player> createBossBar(String title, BossColor color, BossStyle style) {
|
||||
return new ViaBossBar(title, 1F, color, style);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BossBar<Player> createBossBar(String title, float health, BossColor color, BossStyle style) {
|
||||
return new ViaBossBar(title, health, color, style);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedSet<Integer> getSupportedVersions() {
|
||||
SortedSet<Integer> outputSet = new TreeSet<>(ProtocolRegistry.getSupportedVersions());
|
||||
outputSet.removeAll(Via.getPlatform().getConf().getBlockedProtocols());
|
||||
|
||||
return outputSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if this version is a compatibility build for spigot.
|
||||
* Eg. 1.9.1 / 1.9.2 allow certain versions to connect
|
||||
*
|
||||
* @return true if compat Spigot build
|
||||
*/
|
||||
public boolean isCompatSpigotBuild() {
|
||||
return plugin.isCompatSpigotBuild();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if ProtocolSupport is also being used.
|
||||
*
|
||||
* @return true if ProtocolSupport is used
|
||||
*/
|
||||
public boolean isProtocolSupport() {
|
||||
return plugin.isProtocolSupport();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package us.myles.ViaVersion.bukkit.platform;
|
||||
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import us.myles.ViaVersion.AbstractViaConfig;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class BukkitViaConfig extends AbstractViaConfig {
|
||||
private static final List<String> UNSUPPORTED = Arrays.asList("bungee-ping-interval", "bungee-ping-save", "bungee-servers", "velocity-ping-interval", "velocity-ping-save", "velocity-servers");
|
||||
private boolean antiXRay;
|
||||
private boolean quickMoveActionFix;
|
||||
private boolean hitboxFix1_9;
|
||||
private boolean hitboxFix1_14;
|
||||
private String blockConnectionMethod;
|
||||
|
||||
public BukkitViaConfig() {
|
||||
super(new File(((Plugin) Via.getPlatform()).getDataFolder(), "config.yml"));
|
||||
reloadConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadFields() {
|
||||
super.loadFields();
|
||||
antiXRay = getBoolean("anti-xray-patch", true);
|
||||
quickMoveActionFix = getBoolean("quick-move-action-fix", false);
|
||||
hitboxFix1_9 = getBoolean("change-1_9-hitbox", false);
|
||||
hitboxFix1_14 = getBoolean("change-1_14-hitbox", false);
|
||||
blockConnectionMethod = getString("blockconnection-method", "packet");
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getDefaultConfigURL() {
|
||||
return BukkitViaConfig.class.getClassLoader().getResource("assets/viaversion/config.yml");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleConfig(Map<String, Object> config) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAntiXRay() {
|
||||
return antiXRay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean is1_12QuickMoveActionFix() {
|
||||
return quickMoveActionFix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean is1_9HitboxFix() {
|
||||
return hitboxFix1_9;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean is1_14HitboxFix() {
|
||||
return hitboxFix1_14;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBlockConnectionMethod() {
|
||||
return blockConnectionMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getUnsupportedOptions() {
|
||||
return UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,342 @@
|
||||
package us.myles.ViaVersion.bukkit.platform;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import us.myles.ViaVersion.api.Pair;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.platform.ViaInjector;
|
||||
import us.myles.ViaVersion.bukkit.handlers.BukkitChannelInitializer;
|
||||
import us.myles.ViaVersion.bukkit.util.NMSUtil;
|
||||
import us.myles.ViaVersion.util.ConcurrentList;
|
||||
import us.myles.ViaVersion.util.ListWrapper;
|
||||
import us.myles.ViaVersion.util.ReflectionUtil;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class BukkitViaInjector implements ViaInjector {
|
||||
private final List<ChannelFuture> injectedFutures = new ArrayList<>();
|
||||
private final List<Pair<Field, Object>> injectedLists = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void inject() throws Exception {
|
||||
try {
|
||||
Object connection = getServerConnection();
|
||||
if (connection == null) {
|
||||
throw new Exception("We failed to find the core component 'ServerConnection', please file an issue on our GitHub.");
|
||||
}
|
||||
for (Field field : connection.getClass().getDeclaredFields()) {
|
||||
field.setAccessible(true);
|
||||
Object value = field.get(connection);
|
||||
if (value instanceof List) {
|
||||
// Inject the list
|
||||
List wrapper = new ListWrapper((List) value) {
|
||||
@Override
|
||||
public void handleAdd(Object o) {
|
||||
if (o instanceof ChannelFuture) {
|
||||
try {
|
||||
injectChannelFuture((ChannelFuture) o);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
injectedLists.add(new Pair<>(field, connection));
|
||||
field.set(connection, wrapper);
|
||||
// Iterate through current list
|
||||
synchronized (wrapper) {
|
||||
for (Object o : (List) value) {
|
||||
if (o instanceof ChannelFuture) {
|
||||
injectChannelFuture((ChannelFuture) o);
|
||||
} else {
|
||||
break; // not the right list.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Via.getPlatform().getLogger().severe("Unable to inject ViaVersion, please post these details on our GitHub and ensure you're using a compatible server version.");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private void injectChannelFuture(ChannelFuture future) throws Exception {
|
||||
try {
|
||||
List<String> names = future.channel().pipeline().names();
|
||||
ChannelHandler bootstrapAcceptor = null;
|
||||
// Pick best
|
||||
for (String name : names) {
|
||||
ChannelHandler handler = future.channel().pipeline().get(name);
|
||||
try {
|
||||
ReflectionUtil.get(handler, "childHandler", ChannelInitializer.class);
|
||||
bootstrapAcceptor = handler;
|
||||
} catch (Exception e) {
|
||||
// Not this one
|
||||
}
|
||||
}
|
||||
// Default to first (Also allows blame to work)
|
||||
if (bootstrapAcceptor == null) {
|
||||
bootstrapAcceptor = future.channel().pipeline().first();
|
||||
}
|
||||
try {
|
||||
ChannelInitializer<SocketChannel> oldInit = ReflectionUtil.get(bootstrapAcceptor, "childHandler", ChannelInitializer.class);
|
||||
ChannelInitializer newInit = new BukkitChannelInitializer(oldInit);
|
||||
|
||||
ReflectionUtil.set(bootstrapAcceptor, "childHandler", newInit);
|
||||
injectedFutures.add(future);
|
||||
} catch (NoSuchFieldException e) {
|
||||
// let's find who to blame!
|
||||
ClassLoader cl = bootstrapAcceptor.getClass().getClassLoader();
|
||||
if (cl.getClass().getName().equals("org.bukkit.plugin.java.PluginClassLoader")) {
|
||||
PluginDescriptionFile yaml = ReflectionUtil.get(cl, "description", PluginDescriptionFile.class);
|
||||
throw new Exception("Unable to inject, due to " + bootstrapAcceptor.getClass().getName() + ", try without the plugin " + yaml.getName() + "?");
|
||||
} else {
|
||||
throw new Exception("Unable to find core component 'childHandler', please check your plugins. issue: " + bootstrapAcceptor.getClass().getName());
|
||||
}
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Via.getPlatform().getLogger().severe("We failed to inject ViaVersion, have you got late-bind enabled with something else?");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uninject() {
|
||||
// TODO: Uninject from players currently online to prevent protocol lib issues.
|
||||
for (ChannelFuture future : injectedFutures) {
|
||||
List<String> names = future.channel().pipeline().names();
|
||||
ChannelHandler bootstrapAcceptor = null;
|
||||
// Pick best
|
||||
for (String name : names) {
|
||||
ChannelHandler handler = future.channel().pipeline().get(name);
|
||||
try {
|
||||
ChannelInitializer<SocketChannel> oldInit = ReflectionUtil.get(handler, "childHandler", ChannelInitializer.class);
|
||||
if (oldInit instanceof BukkitChannelInitializer) {
|
||||
bootstrapAcceptor = handler;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Not this one
|
||||
}
|
||||
}
|
||||
// Default to first
|
||||
if (bootstrapAcceptor == null) {
|
||||
bootstrapAcceptor = future.channel().pipeline().first();
|
||||
}
|
||||
|
||||
try {
|
||||
ChannelInitializer<SocketChannel> oldInit = ReflectionUtil.get(bootstrapAcceptor, "childHandler", ChannelInitializer.class);
|
||||
if (oldInit instanceof BukkitChannelInitializer) {
|
||||
ReflectionUtil.set(bootstrapAcceptor, "childHandler", ((BukkitChannelInitializer) oldInit).getOriginal());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Via.getPlatform().getLogger().severe("Failed to remove injection handler, reload won't work with connections, please reboot!");
|
||||
}
|
||||
}
|
||||
injectedFutures.clear();
|
||||
|
||||
for (Pair<Field, Object> pair : injectedLists) {
|
||||
try {
|
||||
Object o = pair.getKey().get(pair.getValue());
|
||||
if (o instanceof ListWrapper) {
|
||||
pair.getKey().set(pair.getValue(), ((ListWrapper) o).getOriginalList());
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
Via.getPlatform().getLogger().severe("Failed to remove injection, reload won't work with connections, please reboot!");
|
||||
}
|
||||
}
|
||||
|
||||
injectedLists.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getServerProtocolVersion() throws Exception {
|
||||
try {
|
||||
Class<?> serverClazz = NMSUtil.nms("MinecraftServer");
|
||||
Object server = ReflectionUtil.invokeStatic(serverClazz, "getServer");
|
||||
Class<?> pingClazz = NMSUtil.nms("ServerPing");
|
||||
Object ping = null;
|
||||
// Search for ping method
|
||||
for (Field f : serverClazz.getDeclaredFields()) {
|
||||
if (f.getType() != null) {
|
||||
if (f.getType().getSimpleName().equals("ServerPing")) {
|
||||
f.setAccessible(true);
|
||||
ping = f.get(server);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ping != null) {
|
||||
Object serverData = null;
|
||||
for (Field f : pingClazz.getDeclaredFields()) {
|
||||
if (f.getType() != null) {
|
||||
if (f.getType().getSimpleName().endsWith("ServerData")) {
|
||||
f.setAccessible(true);
|
||||
serverData = f.get(ping);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (serverData != null) {
|
||||
int protocolVersion = -1;
|
||||
for (Field f : serverData.getClass().getDeclaredFields()) {
|
||||
if (f.getType() != null) {
|
||||
if (f.getType() == int.class) {
|
||||
f.setAccessible(true);
|
||||
protocolVersion = (int) f.get(serverData);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (protocolVersion != -1) {
|
||||
return protocolVersion;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new Exception("Failed to get server", e);
|
||||
}
|
||||
throw new Exception("Failed to get server");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEncoderName() {
|
||||
return "encoder";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDecoderName() {
|
||||
return "decoder";
|
||||
}
|
||||
|
||||
public static Object getServerConnection() throws Exception {
|
||||
Class<?> serverClazz = NMSUtil.nms("MinecraftServer");
|
||||
Object server = ReflectionUtil.invokeStatic(serverClazz, "getServer");
|
||||
Object connection = null;
|
||||
for (Method m : serverClazz.getDeclaredMethods()) {
|
||||
if (m.getReturnType() != null) {
|
||||
if (m.getReturnType().getSimpleName().equals("ServerConnection")) {
|
||||
if (m.getParameterTypes().length == 0) {
|
||||
connection = m.invoke(server);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
|
||||
public static boolean isBinded() {
|
||||
try {
|
||||
Object connection = getServerConnection();
|
||||
if (connection == null) {
|
||||
return false;
|
||||
}
|
||||
for (Field field : connection.getClass().getDeclaredFields()) {
|
||||
field.setAccessible(true);
|
||||
final Object value = field.get(connection);
|
||||
if (value instanceof List) {
|
||||
// Inject the list
|
||||
synchronized (value) {
|
||||
for (Object o : (List) value) {
|
||||
if (o instanceof ChannelFuture) {
|
||||
return true;
|
||||
} else {
|
||||
break; // not the right list.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObject getDump() {
|
||||
JsonObject data = new JsonObject();
|
||||
|
||||
// Generate information about current injections
|
||||
JsonArray injectedChannelInitializers = new JsonArray();
|
||||
for (ChannelFuture cf : injectedFutures) {
|
||||
JsonObject info = new JsonObject();
|
||||
info.addProperty("futureClass", cf.getClass().getName());
|
||||
info.addProperty("channelClass", cf.channel().getClass().getName());
|
||||
|
||||
// Get information about the pipes for this channel future
|
||||
JsonArray pipeline = new JsonArray();
|
||||
for (String pipeName : cf.channel().pipeline().names()) {
|
||||
JsonObject pipe = new JsonObject();
|
||||
pipe.addProperty("name", pipeName);
|
||||
if (cf.channel().pipeline().get(pipeName) != null) {
|
||||
pipe.addProperty("class", cf.channel().pipeline().get(pipeName).getClass().getName());
|
||||
try {
|
||||
Object child = ReflectionUtil.get(cf.channel().pipeline().get(pipeName), "childHandler", ChannelInitializer.class);
|
||||
pipe.addProperty("childClass", child.getClass().getName());
|
||||
if (child instanceof BukkitChannelInitializer) {
|
||||
pipe.addProperty("oldInit", ((BukkitChannelInitializer) child).getOriginal().getClass().getName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Don't display
|
||||
}
|
||||
}
|
||||
// Add to the pipeline array
|
||||
pipeline.add(pipe);
|
||||
}
|
||||
info.add("pipeline", pipeline);
|
||||
|
||||
// Add to the list
|
||||
injectedChannelInitializers.add(info);
|
||||
}
|
||||
data.add("injectedChannelInitializers", injectedChannelInitializers);
|
||||
|
||||
// Generate information about lists we've injected into
|
||||
JsonObject wrappedLists = new JsonObject();
|
||||
JsonObject currentLists = new JsonObject();
|
||||
try {
|
||||
for (Pair<Field, Object> pair : injectedLists) {
|
||||
Object list = pair.getKey().get(pair.getValue());
|
||||
// Note down the current value (could be overridden by another plugin)
|
||||
currentLists.addProperty(pair.getKey().getName(), list.getClass().getName());
|
||||
// Also if it's not overridden we can display what's inside our list (possibly another plugin)
|
||||
if (list instanceof ListWrapper) {
|
||||
wrappedLists.addProperty(pair.getKey().getName(), ((ListWrapper) list).getOriginalList().getClass().getName());
|
||||
}
|
||||
}
|
||||
data.add("wrappedLists", wrappedLists);
|
||||
data.add("currentLists", currentLists);
|
||||
} catch (Exception e) {
|
||||
// Ignored, fields won't be present
|
||||
}
|
||||
|
||||
data.addProperty("binded", isBinded());
|
||||
return data;
|
||||
}
|
||||
|
||||
public static void patchLists() throws Exception {
|
||||
Object connection = getServerConnection();
|
||||
if (connection == null) {
|
||||
Via.getPlatform().getLogger().warning("We failed to find the core component 'ServerConnection', please file an issue on our GitHub.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (Field field : connection.getClass().getDeclaredFields()) {
|
||||
field.setAccessible(true);
|
||||
Object value = field.get(connection);
|
||||
if (!(value instanceof List)) continue;
|
||||
if (value instanceof ConcurrentList) continue;
|
||||
|
||||
ConcurrentList list = new ConcurrentList();
|
||||
list.addAll((Collection) value);
|
||||
field.set(connection, list);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
package us.myles.ViaVersion.bukkit.platform;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
import us.myles.ViaVersion.ViaVersionPlugin;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.minecraft.item.Item;
|
||||
import us.myles.ViaVersion.api.platform.ViaPlatformLoader;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
|
||||
import us.myles.ViaVersion.bukkit.classgenerator.ClassGenerator;
|
||||
import us.myles.ViaVersion.bukkit.listeners.UpdateListener;
|
||||
import us.myles.ViaVersion.bukkit.listeners.multiversion.PlayerSneakListener;
|
||||
import us.myles.ViaVersion.bukkit.listeners.protocol1_15to1_14_4.EntityToggleGlideListener;
|
||||
import us.myles.ViaVersion.bukkit.listeners.protocol1_9to1_8.ArmorListener;
|
||||
import us.myles.ViaVersion.bukkit.listeners.protocol1_9to1_8.BlockListener;
|
||||
import us.myles.ViaVersion.bukkit.listeners.protocol1_9to1_8.DeathListener;
|
||||
import us.myles.ViaVersion.bukkit.listeners.protocol1_9to1_8.HandItemCache;
|
||||
import us.myles.ViaVersion.bukkit.listeners.protocol1_9to1_8.PaperPatch;
|
||||
import us.myles.ViaVersion.bukkit.providers.BukkitBlockConnectionProvider;
|
||||
import us.myles.ViaVersion.bukkit.providers.BukkitInventoryQuickMoveProvider;
|
||||
import us.myles.ViaVersion.bukkit.providers.BukkitViaBulkChunkTranslator;
|
||||
import us.myles.ViaVersion.bukkit.providers.BukkitViaMovementTransmitter;
|
||||
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||
import us.myles.ViaVersion.protocols.protocol1_12to1_11_1.providers.InventoryQuickMoveProvider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections.ConnectionData;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.blockconnections.providers.BlockConnectionProvider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.BulkChunkTranslatorProvider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.HandItemProvider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.MovementTransmitterProvider;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BukkitViaLoader implements ViaPlatformLoader {
|
||||
private final ViaVersionPlugin plugin;
|
||||
|
||||
private final Set<Listener> listeners = new HashSet<>();
|
||||
private final Set<BukkitTask> tasks = new HashSet<>();
|
||||
|
||||
private HandItemCache handItemCache;
|
||||
|
||||
public BukkitViaLoader(ViaVersionPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public void registerListener(Listener listener) {
|
||||
Bukkit.getPluginManager().registerEvents(storeListener(listener), plugin);
|
||||
}
|
||||
|
||||
public <T extends Listener> T storeListener(T listener) {
|
||||
listeners.add(listener);
|
||||
return listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
// Update Listener
|
||||
registerListener(new UpdateListener());
|
||||
|
||||
/* Base Protocol */
|
||||
final ViaVersionPlugin plugin = (ViaVersionPlugin) Bukkit.getPluginManager().getPlugin("ViaVersion");
|
||||
|
||||
// Add ProtocolSupport ConnectListener if necessary.
|
||||
ClassGenerator.registerPSConnectListener(plugin);
|
||||
|
||||
/* 1.9 client to 1.8 server */
|
||||
if (ProtocolRegistry.SERVER_PROTOCOL < ProtocolVersion.v1_9.getId()) {
|
||||
storeListener(new ArmorListener(plugin)).register();
|
||||
storeListener(new DeathListener(plugin)).register();
|
||||
storeListener(new BlockListener(plugin)).register();
|
||||
|
||||
if (plugin.getConf().isItemCache()) {
|
||||
handItemCache = new HandItemCache();
|
||||
tasks.add(handItemCache.runTaskTimerAsynchronously(plugin, 2L, 2L)); // Updates player's items :)
|
||||
}
|
||||
}
|
||||
|
||||
if (ProtocolRegistry.SERVER_PROTOCOL < ProtocolVersion.v1_14.getId()) {
|
||||
boolean use1_9Fix = plugin.getConf().is1_9HitboxFix() && ProtocolRegistry.SERVER_PROTOCOL < ProtocolVersion.v1_9.getId();
|
||||
if (use1_9Fix || plugin.getConf().is1_14HitboxFix()) {
|
||||
try {
|
||||
storeListener(new PlayerSneakListener(plugin, use1_9Fix, plugin.getConf().is1_14HitboxFix())).register();
|
||||
} catch (ReflectiveOperationException e) {
|
||||
Via.getPlatform().getLogger().warning("Could not load hitbox fix - please report this on our GitHub");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ProtocolRegistry.SERVER_PROTOCOL < ProtocolVersion.v1_15.getId()) {
|
||||
try {
|
||||
Class.forName("org.bukkit.event.entity.EntityToggleGlideEvent");
|
||||
storeListener(new EntityToggleGlideListener(plugin)).register();
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
if ((Bukkit.getVersion().toLowerCase(Locale.ROOT).contains("paper")
|
||||
|| Bukkit.getVersion().toLowerCase(Locale.ROOT).contains("taco")
|
||||
|| Bukkit.getVersion().toLowerCase(Locale.ROOT).contains("torch"))
|
||||
&& ProtocolRegistry.SERVER_PROTOCOL < ProtocolVersion.v1_12.getId()) {
|
||||
plugin.getLogger().info("Enabling Paper/TacoSpigot/Torch patch: Fixes block placement.");
|
||||
storeListener(new PaperPatch(plugin)).register();
|
||||
}
|
||||
|
||||
/* Providers */
|
||||
if (ProtocolRegistry.SERVER_PROTOCOL < ProtocolVersion.v1_9.getId()) {
|
||||
Via.getManager().getProviders().use(BulkChunkTranslatorProvider.class, new BukkitViaBulkChunkTranslator());
|
||||
Via.getManager().getProviders().use(MovementTransmitterProvider.class, new BukkitViaMovementTransmitter());
|
||||
|
||||
Via.getManager().getProviders().use(HandItemProvider.class, new HandItemProvider() {
|
||||
@Override
|
||||
public Item getHandItem(final UserConnection info) {
|
||||
if (handItemCache != null) {
|
||||
return handItemCache.getHandItem(info.getProtocolInfo().getUuid());
|
||||
}
|
||||
try {
|
||||
return Bukkit.getScheduler().callSyncMethod(Bukkit.getPluginManager().getPlugin("ViaVersion"), () -> {
|
||||
UUID playerUUID = info.getProtocolInfo().getUuid();
|
||||
Player player = Bukkit.getPlayer(playerUUID);
|
||||
if (player != null) {
|
||||
return HandItemCache.convert(player.getItemInHand());
|
||||
}
|
||||
return null;
|
||||
}).get(10, TimeUnit.SECONDS);
|
||||
} catch (Exception e) {
|
||||
Via.getPlatform().getLogger().severe("Error fetching hand item: " + e.getClass().getName());
|
||||
if (Via.getManager().isDebug())
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (ProtocolRegistry.SERVER_PROTOCOL < ProtocolVersion.v1_12.getId()) {
|
||||
if (plugin.getConf().is1_12QuickMoveActionFix()) {
|
||||
Via.getManager().getProviders().use(InventoryQuickMoveProvider.class, new BukkitInventoryQuickMoveProvider());
|
||||
}
|
||||
}
|
||||
if (ProtocolRegistry.SERVER_PROTOCOL < ProtocolVersion.v1_13.getId()) {
|
||||
if (Via.getConfig().getBlockConnectionMethod().equalsIgnoreCase("world")) {
|
||||
BukkitBlockConnectionProvider blockConnectionProvider = new BukkitBlockConnectionProvider();
|
||||
Via.getManager().getProviders().use(BlockConnectionProvider.class, blockConnectionProvider);
|
||||
ConnectionData.blockConnectionProvider = blockConnectionProvider;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
for (Listener listener : listeners) {
|
||||
HandlerList.unregisterAll(listener);
|
||||
}
|
||||
listeners.clear();
|
||||
for (BukkitTask task : tasks) {
|
||||
task.cancel();
|
||||
}
|
||||
tasks.clear();
|
||||
}
|
||||
}
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
package us.myles.ViaVersion.bukkit.providers;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryView;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
|
||||
import us.myles.ViaVersion.bukkit.tasks.protocol1_12to1_11_1.BukkitInventoryUpdateTask;
|
||||
import us.myles.ViaVersion.bukkit.util.NMSUtil;
|
||||
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||
import us.myles.ViaVersion.protocols.protocol1_12to1_11_1.providers.InventoryQuickMoveProvider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_12to1_11_1.storage.ItemTransaction;
|
||||
import us.myles.ViaVersion.util.ReflectionUtil;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class BukkitInventoryQuickMoveProvider extends InventoryQuickMoveProvider {
|
||||
|
||||
private final Map<UUID, BukkitInventoryUpdateTask> updateTasks = new ConcurrentHashMap<>();
|
||||
private final boolean supported;
|
||||
// packet class
|
||||
private Class<?> windowClickPacketClass;
|
||||
private Object clickTypeEnum;
|
||||
// Use for nms
|
||||
private Method nmsItemMethod;
|
||||
private Method craftPlayerHandle;
|
||||
private Field connection;
|
||||
private Method packetMethod;
|
||||
|
||||
public BukkitInventoryQuickMoveProvider() {
|
||||
this.supported = isSupported();
|
||||
setupReflection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerQuickMoveAction(short windowId, short slotId, short actionId, UserConnection userConnection) {
|
||||
if (!supported) {
|
||||
return false;
|
||||
}
|
||||
if (slotId < 0) { // clicked out of inv slot
|
||||
return false;
|
||||
}
|
||||
if (windowId == 0) {
|
||||
/**
|
||||
* windowId is always 0 for player inventory.
|
||||
* This has almost definitely something to do with the offhand slot.
|
||||
*/
|
||||
if (slotId >= 36 && slotId <= 44) {
|
||||
int protocolId = ProtocolRegistry.SERVER_PROTOCOL;
|
||||
// this seems to be working just fine.
|
||||
if (protocolId == ProtocolVersion.v1_8.getId()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
ProtocolInfo info = userConnection.getProtocolInfo();
|
||||
UUID uuid = info.getUuid();
|
||||
BukkitInventoryUpdateTask updateTask = updateTasks.get(uuid);
|
||||
final boolean registered = updateTask != null;
|
||||
if (!registered) {
|
||||
updateTask = new BukkitInventoryUpdateTask(this, uuid);
|
||||
updateTasks.put(uuid, updateTask);
|
||||
}
|
||||
// http://wiki.vg/index.php?title=Protocol&oldid=13223#Click_Window
|
||||
updateTask.addItem(windowId, slotId, actionId);
|
||||
if (!registered) {
|
||||
Via.getPlatform().runSync(updateTask, 5L);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public Object buildWindowClickPacket(Player p, ItemTransaction storage) {
|
||||
if (!supported) {
|
||||
return null;
|
||||
}
|
||||
InventoryView inv = p.getOpenInventory();
|
||||
short slotId = storage.getSlotId();
|
||||
Inventory tinv = inv.getTopInventory();
|
||||
InventoryType tinvtype = tinv == null ? null : tinv.getType(); // can this even be null?
|
||||
if (tinvtype != null) {
|
||||
int protocolId = ProtocolRegistry.SERVER_PROTOCOL;
|
||||
if (protocolId == ProtocolVersion.v1_8.getId()) {
|
||||
if (tinvtype == InventoryType.BREWING) {
|
||||
// 1.9 added the blaze powder slot to brewing stand fix for 1.8 servers
|
||||
if (slotId >= 5 && slotId <= 40) {
|
||||
slotId -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ItemStack itemstack = null;
|
||||
// must be after top inventory slot check
|
||||
if (slotId <= inv.countSlots()) {
|
||||
itemstack = inv.getItem(slotId);
|
||||
} else {
|
||||
// if not true we got too many slots (version inventory slot changes)?
|
||||
String cause = "Too many inventory slots: slotId: " + slotId + " invSlotCount: " + inv.countSlots()
|
||||
+ " invType: " + inv.getType() + " topInvType: " + tinvtype;
|
||||
Via.getPlatform().getLogger().severe("Failed to get an item to create a window click packet. Please report this issue to the ViaVersion Github: " + cause);
|
||||
}
|
||||
Object packet = null;
|
||||
try {
|
||||
packet = windowClickPacketClass.getDeclaredConstructor().newInstance();
|
||||
Object nmsItem = itemstack == null ? null : nmsItemMethod.invoke(null, itemstack);
|
||||
ReflectionUtil.set(packet, "a", (int) storage.getWindowId());
|
||||
ReflectionUtil.set(packet, "slot", (int) slotId);
|
||||
ReflectionUtil.set(packet, "button", 0); // shift + left mouse click
|
||||
ReflectionUtil.set(packet, "d", storage.getActionId());
|
||||
ReflectionUtil.set(packet, "item", nmsItem);
|
||||
int protocolId = ProtocolRegistry.SERVER_PROTOCOL;
|
||||
if (protocolId == ProtocolVersion.v1_8.getId()) {
|
||||
ReflectionUtil.set(packet, "shift", 1);
|
||||
} else if (protocolId >= ProtocolVersion.v1_9.getId()) { // 1.9+
|
||||
ReflectionUtil.set(packet, "shift", clickTypeEnum);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Via.getPlatform().getLogger().log(Level.SEVERE, "Failed to create a window click packet. Please report this issue to the ViaVersion Github: " + e.getMessage(), e);
|
||||
}
|
||||
return packet;
|
||||
}
|
||||
|
||||
public boolean sendPacketToServer(Player p, Object packet) {
|
||||
if (packet == null) {
|
||||
// let the other packets pass through
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
Object entityPlayer = craftPlayerHandle.invoke(p);
|
||||
Object playerConnection = connection.get(entityPlayer);
|
||||
// send
|
||||
packetMethod.invoke(playerConnection, packet);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void onTaskExecuted(UUID uuid) {
|
||||
updateTasks.remove(uuid);
|
||||
}
|
||||
|
||||
private void setupReflection() {
|
||||
if (!supported) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this.windowClickPacketClass = NMSUtil.nms("PacketPlayInWindowClick");
|
||||
int protocolId = ProtocolRegistry.SERVER_PROTOCOL;
|
||||
if (protocolId >= ProtocolVersion.v1_9.getId()) {
|
||||
Class<?> eclassz = NMSUtil.nms("InventoryClickType");
|
||||
Object[] constants = eclassz.getEnumConstants();
|
||||
this.clickTypeEnum = constants[1]; // QUICK_MOVE
|
||||
}
|
||||
Class<?> craftItemStack = NMSUtil.obc("inventory.CraftItemStack");
|
||||
this.nmsItemMethod = craftItemStack.getDeclaredMethod("asNMSCopy", ItemStack.class);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Couldn't find required inventory classes", e);
|
||||
}
|
||||
try {
|
||||
this.craftPlayerHandle = NMSUtil.obc("entity.CraftPlayer").getDeclaredMethod("getHandle");
|
||||
} catch (NoSuchMethodException | ClassNotFoundException e) {
|
||||
throw new RuntimeException("Couldn't find CraftPlayer", e);
|
||||
}
|
||||
try {
|
||||
this.connection = NMSUtil.nms("EntityPlayer").getDeclaredField("playerConnection");
|
||||
} catch (NoSuchFieldException | ClassNotFoundException e) {
|
||||
throw new RuntimeException("Couldn't find Player Connection", e);
|
||||
}
|
||||
try {
|
||||
this.packetMethod = NMSUtil.nms("PlayerConnection").getDeclaredMethod("a", windowClickPacketClass);
|
||||
} catch (NoSuchMethodException | ClassNotFoundException e) {
|
||||
throw new RuntimeException("Couldn't find CraftPlayer", e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isSupported() {
|
||||
int protocolId = ProtocolRegistry.SERVER_PROTOCOL;
|
||||
if (protocolId >= ProtocolVersion.v1_8.getId() && protocolId <= ProtocolVersion.v1_11_1.getId()) {
|
||||
return true; // 1.8-1.11.2
|
||||
}
|
||||
// this is not needed on 1.12+ servers
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
package us.myles.ViaVersion.bukkit.providers;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import us.myles.ViaVersion.ViaVersionPlugin;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.bukkit.util.NMSUtil;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.BulkChunkTranslatorProvider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.ClientChunks;
|
||||
import us.myles.ViaVersion.util.ReflectionUtil;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class BukkitViaBulkChunkTranslator extends BulkChunkTranslatorProvider {
|
||||
// Reflection
|
||||
private static ReflectionUtil.ClassReflection mapChunkBulkRef;
|
||||
private static ReflectionUtil.ClassReflection mapChunkRef;
|
||||
private static Method obfuscateRef;
|
||||
|
||||
static {
|
||||
try {
|
||||
mapChunkBulkRef = new ReflectionUtil.ClassReflection(NMSUtil.nms("PacketPlayOutMapChunkBulk"));
|
||||
mapChunkRef = new ReflectionUtil.ClassReflection(NMSUtil.nms("PacketPlayOutMapChunk"));
|
||||
if (((ViaVersionPlugin) Via.getPlatform()).isSpigot()) {
|
||||
obfuscateRef = Class.forName("org.spigotmc.AntiXray").getMethod("obfuscate", int.class, int.class, int.class, byte[].class, NMSUtil.nms("World"));
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
// Ignore as server is probably 1.9+
|
||||
} catch (Exception e) {
|
||||
Via.getPlatform().getLogger().log(Level.WARNING, "Failed to initialise chunks reflection", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Object> transformMapChunkBulk(Object packet, ClientChunks clientChunks) {
|
||||
List<Object> list = Lists.newArrayList();
|
||||
try {
|
||||
int[] xcoords = mapChunkBulkRef.getFieldValue("a", packet, int[].class);
|
||||
int[] zcoords = mapChunkBulkRef.getFieldValue("b", packet, int[].class);
|
||||
Object[] chunkMaps = mapChunkBulkRef.getFieldValue("c", packet, Object[].class);
|
||||
|
||||
if (Via.getConfig().isAntiXRay() && ((ViaVersionPlugin) Via.getPlatform()).isSpigot()) { //Spigot anti-xray patch
|
||||
try {
|
||||
Object world = mapChunkBulkRef.getFieldValue("world", packet, Object.class);
|
||||
Object spigotConfig = ReflectionUtil.getPublic(world, "spigotConfig", Object.class);
|
||||
Object antiXrayInstance = ReflectionUtil.getPublic(spigotConfig, "antiXrayInstance", Object.class);
|
||||
|
||||
for (int i = 0; i < xcoords.length; ++i) {
|
||||
// TODO: Possibly optimise this
|
||||
Object b = ReflectionUtil.get(chunkMaps[i], "b", Object.class);
|
||||
Object a = ReflectionUtil.get(chunkMaps[i], "a", Object.class);
|
||||
|
||||
obfuscateRef.invoke(antiXrayInstance, xcoords[i], zcoords[i], b, a, world);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// not spigot, or it failed.
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < chunkMaps.length; i++) {
|
||||
int x = xcoords[i];
|
||||
int z = zcoords[i];
|
||||
Object chunkMap = chunkMaps[i];
|
||||
Object chunkPacket = mapChunkRef.newInstance();
|
||||
mapChunkRef.setFieldValue("a", chunkPacket, x);
|
||||
mapChunkRef.setFieldValue("b", chunkPacket, z);
|
||||
mapChunkRef.setFieldValue("c", chunkPacket, chunkMap);
|
||||
mapChunkRef.setFieldValue("d", chunkPacket, true); // Chunk bulk chunks are always ground-up
|
||||
clientChunks.getBulkChunks().add(ClientChunks.toLong(x, z)); // Store for later
|
||||
list.add(chunkPacket);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Via.getPlatform().getLogger().log(Level.WARNING, "Failed to transform chunks bulk", e);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFiltered(Class<?> packetClass) {
|
||||
return packetClass.getName().endsWith("PacketPlayOutMapChunkBulk");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPacketLevel() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
package us.myles.ViaVersion.bukkit.providers;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.bukkit.util.NMSUtil;
|
||||
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.MovementTransmitterProvider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.MovementTracker;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class BukkitViaMovementTransmitter extends MovementTransmitterProvider {
|
||||
private static boolean USE_NMS = true;
|
||||
// Used for packet mode
|
||||
private Object idlePacket;
|
||||
private Object idlePacket2;
|
||||
// Use for nms
|
||||
private Method getHandle;
|
||||
private Field connection;
|
||||
private Method handleFlying;
|
||||
|
||||
public BukkitViaMovementTransmitter() {
|
||||
USE_NMS = Via.getConfig().isNMSPlayerTicking();
|
||||
|
||||
Class<?> idlePacketClass;
|
||||
try {
|
||||
idlePacketClass = NMSUtil.nms("PacketPlayInFlying");
|
||||
} catch (ClassNotFoundException e) {
|
||||
return; // We'll hope this is 1.9.4+
|
||||
}
|
||||
try {
|
||||
idlePacket = idlePacketClass.newInstance();
|
||||
idlePacket2 = idlePacketClass.newInstance();
|
||||
|
||||
Field flying = idlePacketClass.getDeclaredField("f");
|
||||
flying.setAccessible(true);
|
||||
|
||||
flying.set(idlePacket2, true);
|
||||
} catch (NoSuchFieldException | InstantiationException | IllegalArgumentException | IllegalAccessException e) {
|
||||
throw new RuntimeException("Couldn't make player idle packet, help!", e);
|
||||
}
|
||||
if (USE_NMS) {
|
||||
try {
|
||||
getHandle = NMSUtil.obc("entity.CraftPlayer").getDeclaredMethod("getHandle");
|
||||
} catch (NoSuchMethodException | ClassNotFoundException e) {
|
||||
throw new RuntimeException("Couldn't find CraftPlayer", e);
|
||||
}
|
||||
|
||||
try {
|
||||
connection = NMSUtil.nms("EntityPlayer").getDeclaredField("playerConnection");
|
||||
} catch (NoSuchFieldException | ClassNotFoundException e) {
|
||||
throw new RuntimeException("Couldn't find Player Connection", e);
|
||||
}
|
||||
|
||||
try {
|
||||
handleFlying = NMSUtil.nms("PlayerConnection").getDeclaredMethod("a", idlePacketClass);
|
||||
} catch (NoSuchMethodException | ClassNotFoundException e) {
|
||||
throw new RuntimeException("Couldn't find CraftPlayer", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getFlyingPacket() {
|
||||
if (idlePacket == null)
|
||||
throw new NullPointerException("Could not locate flying packet");
|
||||
return idlePacket2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGroundPacket() {
|
||||
if (idlePacket == null)
|
||||
throw new NullPointerException("Could not locate flying packet");
|
||||
return idlePacket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendPlayer(UserConnection info) {
|
||||
if (USE_NMS) {
|
||||
Player player = Bukkit.getPlayer(info.getProtocolInfo().getUuid());
|
||||
if (player != null) {
|
||||
try {
|
||||
// Tick player
|
||||
Object entityPlayer = getHandle.invoke(player);
|
||||
Object pc = connection.get(entityPlayer);
|
||||
if (pc != null) {
|
||||
handleFlying.invoke(pc, (info.get(MovementTracker.class).isGround() ? idlePacket2 : idlePacket));
|
||||
// Tick world
|
||||
info.get(MovementTracker.class).incrementIdlePacket();
|
||||
}
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
super.sendPlayer(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package us.myles.ViaVersion.bukkit.tasks.protocol1_12to1_11_1;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import us.myles.ViaVersion.bukkit.providers.BukkitInventoryQuickMoveProvider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_12to1_11_1.storage.ItemTransaction;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class BukkitInventoryUpdateTask implements Runnable {
|
||||
|
||||
private final BukkitInventoryQuickMoveProvider provider;
|
||||
private final UUID uuid;
|
||||
private final List<ItemTransaction> items;
|
||||
|
||||
public BukkitInventoryUpdateTask(BukkitInventoryQuickMoveProvider provider, UUID uuid) {
|
||||
this.provider = provider;
|
||||
this.uuid = uuid;
|
||||
this.items = Collections.synchronizedList(new ArrayList<ItemTransaction>());
|
||||
}
|
||||
|
||||
public void addItem(short windowId, short slotId, short actionId) {
|
||||
ItemTransaction storage = new ItemTransaction(windowId, slotId, actionId);
|
||||
items.add(storage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Player p = Bukkit.getServer().getPlayer(uuid);
|
||||
if (p == null) {
|
||||
provider.onTaskExecuted(uuid);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
synchronized (items) {
|
||||
for (ItemTransaction storage : items) {
|
||||
Object packet = provider.buildWindowClickPacket(p, storage);
|
||||
boolean result = provider.sendPacketToServer(p, packet);
|
||||
if (!result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
items.clear();
|
||||
}
|
||||
} finally {
|
||||
provider.onTaskExecuted(uuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package us.myles.ViaVersion.bukkit.util;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
public class NMSUtil {
|
||||
private static final String BASE = Bukkit.getServer().getClass().getPackage().getName();
|
||||
private static final String NMS = BASE.replace("org.bukkit.craftbukkit", "net.minecraft.server");
|
||||
private static final boolean DEBUG_PROPERTY = loadDebugProperty();
|
||||
|
||||
private static boolean loadDebugProperty() {
|
||||
try {
|
||||
Class<?> serverClass = nms("MinecraftServer");
|
||||
Object server = serverClass.getDeclaredMethod("getServer").invoke(null);
|
||||
return (boolean) serverClass.getMethod("isDebugging").invoke(server);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static Class<?> nms(String className) throws ClassNotFoundException {
|
||||
return Class.forName(NMS + "." + className);
|
||||
}
|
||||
|
||||
public static Class<?> obc(String className) throws ClassNotFoundException {
|
||||
return Class.forName(BASE + "." + className);
|
||||
}
|
||||
|
||||
public static String getVersion() {
|
||||
return BASE.substring(BASE.lastIndexOf('.') + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if debug=true is set in the server.properties (added by CB)
|
||||
*/
|
||||
public static boolean isDebugPropertySet() {
|
||||
return DEBUG_PROPERTY;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package us.myles.ViaVersion.bukkit.util;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class ProtocolSupportUtil {
|
||||
private static Method protocolVersionMethod = null;
|
||||
private static Method getIdMethod = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
protocolVersionMethod = Class.forName("protocolsupport.api.ProtocolSupportAPI").getMethod("getProtocolVersion", Player.class);
|
||||
getIdMethod = Class.forName("protocolsupport.api.ProtocolVersion").getMethod("getId");
|
||||
} catch (Exception e) {
|
||||
// ProtocolSupport not installed.
|
||||
}
|
||||
}
|
||||
|
||||
public static int getProtocolVersion(Player player) {
|
||||
if (protocolVersionMethod == null) return -1;
|
||||
try {
|
||||
Object version = protocolVersionMethod.invoke(null, player);
|
||||
return (int) getIdMethod.invoke(version);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
name: ViaVersion
|
||||
main: us.myles.ViaVersion.ViaVersionPlugin
|
||||
authors: [_MylesC, creeper123123321, Gerrygames, KennyTV, Matsv]
|
||||
version: ${project.version}
|
||||
description: ${project.description}
|
||||
load: postworld
|
||||
api-version: 1.13
|
||||
loadbefore: [ProtocolLib, ProxyPipe, SpigotLib, SkinRestorer]
|
||||
softdepend: [ProtocolSupport, PacketListenerApi]
|
||||
commands:
|
||||
viaversion:
|
||||
description: Shows ViaVersion Version and more.
|
||||
aliases: [viaver, vvbukkit]
|
||||
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>viaversion-parent</artifactId>
|
||||
<groupId>us.myles</groupId>
|
||||
<version>3.1.0</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>viaversion-bungee</artifactId>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<targetPath>.</targetPath>
|
||||
<filtering>true</filtering>
|
||||
<directory>src/main/resources/</directory>
|
||||
<includes>
|
||||
<include>*</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<!-- BungeeCord API -->
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>1.15-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Common Module -->
|
||||
<dependency>
|
||||
<groupId>us.myles</groupId>
|
||||
<artifactId>viaversion-common</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,199 @@
|
||||
package us.myles.ViaVersion;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
import net.md_5.bungee.protocol.ProtocolConstants;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.ViaAPI;
|
||||
import us.myles.ViaVersion.api.command.ViaCommandSender;
|
||||
import us.myles.ViaVersion.api.configuration.ConfigurationProvider;
|
||||
import us.myles.ViaVersion.api.data.MappingDataLoader;
|
||||
import us.myles.ViaVersion.api.platform.TaskId;
|
||||
import us.myles.ViaVersion.api.platform.ViaConnectionManager;
|
||||
import us.myles.ViaVersion.api.platform.ViaPlatform;
|
||||
import us.myles.ViaVersion.bungee.commands.BungeeCommand;
|
||||
import us.myles.ViaVersion.bungee.commands.BungeeCommandHandler;
|
||||
import us.myles.ViaVersion.bungee.commands.BungeeCommandSender;
|
||||
import us.myles.ViaVersion.bungee.platform.BungeeTaskId;
|
||||
import us.myles.ViaVersion.bungee.platform.BungeeViaAPI;
|
||||
import us.myles.ViaVersion.bungee.platform.BungeeViaConfig;
|
||||
import us.myles.ViaVersion.bungee.platform.BungeeViaInjector;
|
||||
import us.myles.ViaVersion.bungee.platform.BungeeViaLoader;
|
||||
import us.myles.ViaVersion.bungee.service.ProtocolDetectorService;
|
||||
import us.myles.ViaVersion.dump.PluginInfo;
|
||||
import us.myles.ViaVersion.util.GsonUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BungeePlugin extends Plugin implements ViaPlatform<ProxiedPlayer>, Listener {
|
||||
private final ViaConnectionManager connectionManager = new ViaConnectionManager();
|
||||
private BungeeViaAPI api;
|
||||
private BungeeViaConfig config;
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
try {
|
||||
ProtocolConstants.class.getField("MINECRAFT_1_15_2");
|
||||
} catch (NoSuchFieldException e) {
|
||||
getLogger().warning(" / \\");
|
||||
getLogger().warning(" / \\");
|
||||
getLogger().warning(" / | \\");
|
||||
getLogger().warning(" / | \\ BUNGEECORD IS OUTDATED");
|
||||
getLogger().warning(" / \\ VIAVERSION MAY NOT WORK AS INTENDED");
|
||||
getLogger().warning(" / o \\");
|
||||
getLogger().warning("/_____________\\");
|
||||
}
|
||||
|
||||
api = new BungeeViaAPI();
|
||||
config = new BungeeViaConfig(getDataFolder());
|
||||
BungeeCommandHandler commandHandler = new BungeeCommandHandler();
|
||||
ProxyServer.getInstance().getPluginManager().registerCommand(this, new BungeeCommand(commandHandler));
|
||||
|
||||
// Init platform
|
||||
Via.init(ViaManager.builder()
|
||||
.platform(this)
|
||||
.injector(new BungeeViaInjector())
|
||||
.loader(new BungeeViaLoader(this))
|
||||
.commandHandler(commandHandler)
|
||||
.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
if (ProxyServer.getInstance().getPluginManager().getPlugin("ViaBackwards") != null) {
|
||||
MappingDataLoader.enableMappingsCache();
|
||||
}
|
||||
|
||||
// Inject
|
||||
Via.getManager().init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlatformName() {
|
||||
return getProxy().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlatformVersion() {
|
||||
return getProxy().getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPluginVersion() {
|
||||
return getDescription().getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskId runAsync(Runnable runnable) {
|
||||
return new BungeeTaskId(getProxy().getScheduler().runAsync(this, runnable).getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskId runSync(Runnable runnable) {
|
||||
return runAsync(runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskId runSync(Runnable runnable, Long ticks) {
|
||||
return new BungeeTaskId(getProxy().getScheduler().schedule(this, runnable, ticks * 50, TimeUnit.MILLISECONDS).getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskId runRepeatingSync(Runnable runnable, Long ticks) {
|
||||
return new BungeeTaskId(getProxy().getScheduler().schedule(this, runnable, 0, ticks * 50, TimeUnit.MILLISECONDS).getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelTask(TaskId taskId) {
|
||||
if (taskId == null) return;
|
||||
if (taskId.getObject() == null) return;
|
||||
if (taskId instanceof BungeeTaskId) {
|
||||
getProxy().getScheduler().cancel((Integer) taskId.getObject());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViaCommandSender[] getOnlinePlayers() {
|
||||
ViaCommandSender[] array = new ViaCommandSender[getProxy().getPlayers().size()];
|
||||
int i = 0;
|
||||
for (ProxiedPlayer player : getProxy().getPlayers()) {
|
||||
array[i++] = new BungeeCommandSender(player);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(UUID uuid, String message) {
|
||||
getProxy().getPlayer(uuid).sendMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean kickPlayer(UUID uuid, String message) {
|
||||
if (getProxy().getPlayer(uuid) != null) {
|
||||
getProxy().getPlayer(uuid).disconnect(message);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPluginEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViaAPI<ProxiedPlayer> getApi() {
|
||||
return api;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BungeeViaConfig getConf() {
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigurationProvider getConfigurationProvider() {
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReload() {
|
||||
// Injector prints a message <3
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObject getDump() {
|
||||
JsonObject platformSpecific = new JsonObject();
|
||||
|
||||
List<PluginInfo> plugins = new ArrayList<>();
|
||||
for (Plugin p : ProxyServer.getInstance().getPluginManager().getPlugins())
|
||||
plugins.add(new PluginInfo(
|
||||
true,
|
||||
p.getDescription().getName(),
|
||||
p.getDescription().getVersion(),
|
||||
p.getDescription().getMain(),
|
||||
Collections.singletonList(p.getDescription().getAuthor())
|
||||
));
|
||||
|
||||
platformSpecific.add("plugins", GsonUtil.getGson().toJsonTree(plugins));
|
||||
platformSpecific.add("servers", GsonUtil.getGson().toJsonTree(ProtocolDetectorService.getDetectedIds()));
|
||||
return platformSpecific;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOldClientsAllowed() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViaConnectionManager getConnectionManager() {
|
||||
return connectionManager;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package us.myles.ViaVersion.bungee.commands;
|
||||
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
import net.md_5.bungee.api.plugin.TabExecutor;
|
||||
|
||||
public class BungeeCommand extends Command implements TabExecutor {
|
||||
private final BungeeCommandHandler handler;
|
||||
|
||||
public BungeeCommand(BungeeCommandHandler handler) {
|
||||
super("viaversion", "", "viaver", "vvbungee"); // The CommandHandler will handle the permission
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender commandSender, String[] strings) {
|
||||
handler.onCommand(new BungeeCommandSender(commandSender), strings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<String> onTabComplete(CommandSender commandSender, String[] strings) {
|
||||
return handler.onTabComplete(new BungeeCommandSender(commandSender), strings);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package us.myles.ViaVersion.bungee.commands;
|
||||
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.bungee.commands.subs.ProbeSubCmd;
|
||||
import us.myles.ViaVersion.commands.ViaCommandHandler;
|
||||
|
||||
public class BungeeCommandHandler extends ViaCommandHandler {
|
||||
public BungeeCommandHandler() {
|
||||
try {
|
||||
registerSubCommand(new ProbeSubCmd());
|
||||
} catch (Exception e) {
|
||||
Via.getPlatform().getLogger().severe("Failed to register Bungee subcommands");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package us.myles.ViaVersion.bungee.commands;
|
||||
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import us.myles.ViaVersion.api.command.ViaCommandSender;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class BungeeCommandSender implements ViaCommandSender {
|
||||
private final CommandSender sender;
|
||||
|
||||
public BungeeCommandSender(CommandSender sender) {
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String permission) {
|
||||
return sender.hasPermission(permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(String msg) {
|
||||
sender.sendMessage(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUUID() {
|
||||
if (sender instanceof ProxiedPlayer) {
|
||||
return ((ProxiedPlayer) sender).getUniqueId();
|
||||
} else {
|
||||
return UUID.fromString(getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return sender.getName();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package us.myles.ViaVersion.bungee.commands.subs;
|
||||
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.command.ViaCommandSender;
|
||||
import us.myles.ViaVersion.api.command.ViaSubCommand;
|
||||
import us.myles.ViaVersion.bungee.platform.BungeeViaConfig;
|
||||
import us.myles.ViaVersion.bungee.service.ProtocolDetectorService;
|
||||
|
||||
public class ProbeSubCmd extends ViaSubCommand {
|
||||
@Override
|
||||
public String name() {
|
||||
return "probe";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return "Forces ViaVersion to scan server protocol versions " +
|
||||
(((BungeeViaConfig) Via.getConfig()).getBungeePingInterval() == -1 ?
|
||||
"" : "(Also happens at an interval)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(ViaCommandSender sender, String[] args) {
|
||||
ProtocolDetectorService.getInstance().run();
|
||||
sendMessage(sender, "&6Started searching for protocol versions");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package us.myles.ViaVersion.bungee.handlers;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolPipeline;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class BungeeChannelInitializer extends ChannelInitializer<Channel> {
|
||||
private final ChannelInitializer<Channel> original;
|
||||
private Method method;
|
||||
|
||||
public BungeeChannelInitializer(ChannelInitializer<Channel> oldInit) {
|
||||
this.original = oldInit;
|
||||
try {
|
||||
this.method = ChannelInitializer.class.getDeclaredMethod("initChannel", Channel.class);
|
||||
this.method.setAccessible(true);
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initChannel(Channel socketChannel) throws Exception {
|
||||
UserConnection info = new UserConnection(socketChannel);
|
||||
// init protocol
|
||||
new ProtocolPipeline(info);
|
||||
// Add originals
|
||||
this.method.invoke(this.original, socketChannel);
|
||||
|
||||
if (socketChannel.pipeline().get("packet-encoder") == null) return; // Don't inject if no packet-encoder
|
||||
if (socketChannel.pipeline().get("packet-decoder") == null) return; // Don't inject if no packet-decoder
|
||||
// Add our transformers
|
||||
BungeeEncodeHandler encoder = new BungeeEncodeHandler(info);
|
||||
BungeeDecodeHandler decoder = new BungeeDecodeHandler(info);
|
||||
|
||||
socketChannel.pipeline().addBefore("packet-encoder", "via-encoder", encoder);
|
||||
socketChannel.pipeline().addBefore("packet-decoder", "via-decoder", decoder);
|
||||
}
|
||||
|
||||
public ChannelInitializer<Channel> getOriginal() {
|
||||
return original;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package us.myles.ViaVersion.bungee.handlers;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.exception.CancelDecoderException;
|
||||
import us.myles.ViaVersion.exception.CancelCodecException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
public class BungeeDecodeHandler extends MessageToMessageDecoder<ByteBuf> {
|
||||
private final UserConnection info;
|
||||
|
||||
public BungeeDecodeHandler(UserConnection info) {
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(final ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> out) throws Exception {
|
||||
if (!info.checkIncomingPacket()) throw CancelDecoderException.generate(null);
|
||||
if (!info.shouldTransformPacket()) {
|
||||
out.add(bytebuf.retain());
|
||||
return;
|
||||
}
|
||||
|
||||
ByteBuf transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf);
|
||||
try {
|
||||
info.transformIncoming(transformedBuf, CancelDecoderException::generate);
|
||||
out.add(transformedBuf.retain());
|
||||
} finally {
|
||||
transformedBuf.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
if (cause instanceof CancelCodecException) return;
|
||||
super.exceptionCaught(ctx, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package us.myles.ViaVersion.bungee.handlers;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToMessageEncoder;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.bungee.util.BungeePipelineUtil;
|
||||
import us.myles.ViaVersion.exception.CancelEncoderException;
|
||||
import us.myles.ViaVersion.exception.CancelCodecException;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
public class BungeeEncodeHandler extends MessageToMessageEncoder<ByteBuf> {
|
||||
private final UserConnection info;
|
||||
private boolean handledCompression;
|
||||
|
||||
public BungeeEncodeHandler(UserConnection info) {
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void encode(final ChannelHandlerContext ctx, ByteBuf bytebuf, List<Object> out) throws Exception {
|
||||
info.checkOutgoingPacket();
|
||||
if (!info.shouldTransformPacket()) {
|
||||
out.add(bytebuf.retain());
|
||||
return;
|
||||
}
|
||||
|
||||
ByteBuf transformedBuf = ctx.alloc().buffer().writeBytes(bytebuf);
|
||||
try {
|
||||
boolean needsCompress = handleCompressionOrder(ctx, transformedBuf);
|
||||
info.transformOutgoing(transformedBuf, CancelEncoderException::generate);
|
||||
|
||||
if (needsCompress) {
|
||||
recompress(ctx, transformedBuf);
|
||||
}
|
||||
|
||||
out.add(transformedBuf.retain());
|
||||
} finally {
|
||||
transformedBuf.release();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean handleCompressionOrder(ChannelHandlerContext ctx, ByteBuf buf) {
|
||||
boolean needsCompress = false;
|
||||
if (!handledCompression) {
|
||||
if (ctx.pipeline().names().indexOf("compress") > ctx.pipeline().names().indexOf("via-encoder")) {
|
||||
// Need to decompress this packet due to bad order
|
||||
ByteBuf decompressed = BungeePipelineUtil.decompress(ctx, buf);
|
||||
try {
|
||||
buf.clear().writeBytes(decompressed);
|
||||
} finally {
|
||||
decompressed.release();
|
||||
}
|
||||
ChannelHandler dec = ctx.pipeline().get("via-decoder");
|
||||
ChannelHandler enc = ctx.pipeline().get("via-encoder");
|
||||
ctx.pipeline().remove(dec);
|
||||
ctx.pipeline().remove(enc);
|
||||
ctx.pipeline().addAfter("decompress", "via-decoder", dec);
|
||||
ctx.pipeline().addAfter("compress", "via-encoder", enc);
|
||||
needsCompress = true;
|
||||
handledCompression = true;
|
||||
}
|
||||
}
|
||||
return needsCompress;
|
||||
}
|
||||
|
||||
private void recompress(ChannelHandlerContext ctx, ByteBuf buf) {
|
||||
ByteBuf compressed = BungeePipelineUtil.compress(ctx, buf);
|
||||
try {
|
||||
buf.clear().writeBytes(compressed);
|
||||
} finally {
|
||||
compressed.release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
if (cause instanceof CancelCodecException) return;
|
||||
super.exceptionCaught(ctx, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
package us.myles.ViaVersion.bungee.handlers;
|
||||
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.ServerConnectEvent;
|
||||
import net.md_5.bungee.api.event.ServerConnectedEvent;
|
||||
import net.md_5.bungee.api.event.ServerSwitchEvent;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.api.score.Team;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
import net.md_5.bungee.event.EventPriority;
|
||||
import net.md_5.bungee.protocol.packet.PluginMessage;
|
||||
import us.myles.ViaVersion.api.PacketWrapper;
|
||||
import us.myles.ViaVersion.api.Pair;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.data.ExternalJoinGameListener;
|
||||
import us.myles.ViaVersion.api.data.StoredObject;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.protocol.Protocol;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolPipeline;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
|
||||
import us.myles.ViaVersion.api.type.Type;
|
||||
import us.myles.ViaVersion.bungee.service.ProtocolDetectorService;
|
||||
import us.myles.ViaVersion.bungee.storage.BungeeStorage;
|
||||
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.packets.InventoryPackets;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9To1_8;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.EntityIdProvider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.EntityTracker1_9;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class BungeeServerHandler implements Listener {
|
||||
private static Method getHandshake;
|
||||
private static Method getRelayMessages;
|
||||
private static Method setProtocol;
|
||||
private static Method getEntityMap = null;
|
||||
private static Method setVersion = null;
|
||||
private static Field entityRewrite = null;
|
||||
private static Field channelWrapper = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
getHandshake = Class.forName("net.md_5.bungee.connection.InitialHandler").getDeclaredMethod("getHandshake");
|
||||
getRelayMessages = Class.forName("net.md_5.bungee.connection.InitialHandler").getDeclaredMethod("getRelayMessages");
|
||||
setProtocol = Class.forName("net.md_5.bungee.protocol.packet.Handshake").getDeclaredMethod("setProtocolVersion", int.class);
|
||||
getEntityMap = Class.forName("net.md_5.bungee.entitymap.EntityMap").getDeclaredMethod("getEntityMap", int.class);
|
||||
setVersion = Class.forName("net.md_5.bungee.netty.ChannelWrapper").getDeclaredMethod("setVersion", int.class);
|
||||
channelWrapper = Class.forName("net.md_5.bungee.UserConnection").getDeclaredField("ch");
|
||||
channelWrapper.setAccessible(true);
|
||||
entityRewrite = Class.forName("net.md_5.bungee.UserConnection").getDeclaredField("entityRewrite");
|
||||
entityRewrite.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// Set the handshake version every time someone connects to any server
|
||||
@EventHandler(priority = 120)
|
||||
public void onServerConnect(ServerConnectEvent e) {
|
||||
if (e.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
UserConnection user = Via.getManager().getConnection(e.getPlayer().getUniqueId());
|
||||
if (user == null) return;
|
||||
if (!user.has(BungeeStorage.class)) {
|
||||
user.put(new BungeeStorage(user, e.getPlayer()));
|
||||
}
|
||||
|
||||
int protocolId = ProtocolDetectorService.getProtocolId(e.getTarget().getName());
|
||||
List<Pair<Integer, Protocol>> protocols = ProtocolRegistry.getProtocolPath(user.getProtocolInfo().getProtocolVersion(), protocolId);
|
||||
|
||||
// Check if ViaVersion can support that version
|
||||
try {
|
||||
//Object pendingConnection = getPendingConnection.invoke(e.getPlayer());
|
||||
Object handshake = getHandshake.invoke(e.getPlayer().getPendingConnection());
|
||||
setProtocol.invoke(handshake, protocols == null ? user.getProtocolInfo().getProtocolVersion() : protocolId);
|
||||
} catch (InvocationTargetException | IllegalAccessException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = -120)
|
||||
public void onServerConnected(ServerConnectedEvent e) {
|
||||
try {
|
||||
checkServerChange(e, Via.getManager().getConnection(e.getPlayer().getUniqueId()));
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = -120)
|
||||
public void onServerSwitch(ServerSwitchEvent e) {
|
||||
// Update entity id
|
||||
UserConnection userConnection = Via.getManager().getConnection(e.getPlayer().getUniqueId());
|
||||
if (userConnection == null) return;
|
||||
int playerId;
|
||||
try {
|
||||
playerId = Via.getManager().getProviders().get(EntityIdProvider.class).getEntityId(userConnection);
|
||||
} catch (Exception ex) {
|
||||
return; // Ignored
|
||||
}
|
||||
for (StoredObject storedObject : userConnection.getStoredObjects().values()) {
|
||||
if (storedObject instanceof ExternalJoinGameListener) {
|
||||
((ExternalJoinGameListener) storedObject).onExternalJoinGame(playerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void checkServerChange(ServerConnectedEvent e, UserConnection user) throws Exception {
|
||||
if (user == null) return;
|
||||
// Auto-team handling
|
||||
// Handle server/version change
|
||||
if (user.has(BungeeStorage.class)) {
|
||||
BungeeStorage storage = user.get(BungeeStorage.class);
|
||||
ProxiedPlayer player = storage.getPlayer();
|
||||
|
||||
if (e.getServer() != null) {
|
||||
if (!e.getServer().getInfo().getName().equals(storage.getCurrentServer())) {
|
||||
// Clear auto-team
|
||||
EntityTracker1_9 oldEntityTracker = user.get(EntityTracker1_9.class);
|
||||
if (oldEntityTracker != null) {
|
||||
if (oldEntityTracker.isAutoTeam() && oldEntityTracker.isTeamExists()) {
|
||||
oldEntityTracker.sendTeamPacket(false, true);
|
||||
}
|
||||
}
|
||||
|
||||
String serverName = e.getServer().getInfo().getName();
|
||||
|
||||
storage.setCurrentServer(serverName);
|
||||
|
||||
int protocolId = ProtocolDetectorService.getProtocolId(serverName);
|
||||
|
||||
if (protocolId <= ProtocolVersion.v1_8.getId()) { // 1.8 doesn't have BossBar packet
|
||||
if (storage.getBossbar() != null) {
|
||||
// TODO: Verify whether this packet needs to be sent when 1.8 -> 1.9 protocol isn't present in the pipeline
|
||||
// This ensures we can encode it properly as only the 1.9 protocol is currently implemented.
|
||||
if (user.getProtocolInfo().getPipeline().contains(Protocol1_9To1_8.class)) {
|
||||
for (UUID uuid : storage.getBossbar()) {
|
||||
PacketWrapper wrapper = new PacketWrapper(0x0C, null, user);
|
||||
wrapper.write(Type.UUID, uuid);
|
||||
wrapper.write(Type.VAR_INT, 1); // remove
|
||||
wrapper.send(Protocol1_9To1_8.class, true, true);
|
||||
}
|
||||
}
|
||||
storage.getBossbar().clear();
|
||||
}
|
||||
}
|
||||
|
||||
ProtocolInfo info = user.getProtocolInfo();
|
||||
int previousServerProtocol = info.getServerProtocolVersion();
|
||||
|
||||
// Refresh the pipes
|
||||
List<Pair<Integer, Protocol>> protocols = ProtocolRegistry.getProtocolPath(info.getProtocolVersion(), protocolId);
|
||||
ProtocolPipeline pipeline = user.getProtocolInfo().getPipeline();
|
||||
user.clearStoredObjects();
|
||||
pipeline.cleanPipes();
|
||||
if (protocols == null) {
|
||||
// TODO Check Bungee Supported Protocols? *shrugs*
|
||||
protocolId = info.getProtocolVersion();
|
||||
} else {
|
||||
for (Pair<Integer, Protocol> prot : protocols) {
|
||||
pipeline.add(prot.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
info.setServerProtocolVersion(protocolId);
|
||||
// Add version-specific base Protocol
|
||||
pipeline.add(ProtocolRegistry.getBaseProtocol(protocolId));
|
||||
|
||||
// Workaround 1.13 server change
|
||||
Object relayMessages = getRelayMessages.invoke(e.getPlayer().getPendingConnection());
|
||||
for (Object message : (List) relayMessages) {
|
||||
PluginMessage plMsg = (PluginMessage) message;
|
||||
String channel = plMsg.getTag();
|
||||
int id1_13 = ProtocolVersion.v1_13.getId();
|
||||
if (previousServerProtocol != -1) {
|
||||
String oldChannel = channel;
|
||||
if (previousServerProtocol < id1_13 && protocolId >= id1_13) {
|
||||
channel = InventoryPackets.getNewPluginChannelId(channel);
|
||||
if (channel == null) {
|
||||
throw new RuntimeException(oldChannel + " found in relayMessages");
|
||||
}
|
||||
if (channel.equals("minecraft:register")) {
|
||||
plMsg.setData(Arrays.stream(new String(plMsg.getData(), StandardCharsets.UTF_8).split("\0"))
|
||||
.map(InventoryPackets::getNewPluginChannelId)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.joining("\0")).getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
} else if (previousServerProtocol >= id1_13 && protocolId < id1_13) {
|
||||
channel = InventoryPackets.getOldPluginChannelId(channel);
|
||||
if (channel == null) {
|
||||
throw new RuntimeException(oldChannel + " found in relayMessages");
|
||||
}
|
||||
if (channel.equals("REGISTER")) {
|
||||
plMsg.setData(Arrays.stream(new String(plMsg.getData(), StandardCharsets.UTF_8).split("\0"))
|
||||
.map(InventoryPackets::getOldPluginChannelId)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.joining("\0")).getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
||||
}
|
||||
plMsg.setTag(channel);
|
||||
}
|
||||
|
||||
user.put(info);
|
||||
user.put(storage);
|
||||
|
||||
user.setActive(protocols != null);
|
||||
|
||||
// Init all protocols TODO check if this can get moved up to the previous for loop, and doesn't require the pipeline to already exist.
|
||||
for (Protocol protocol : pipeline.pipes()) {
|
||||
protocol.init(user);
|
||||
}
|
||||
|
||||
EntityTracker1_9 newTracker = user.get(EntityTracker1_9.class);
|
||||
if (newTracker != null) {
|
||||
if (Via.getConfig().isAutoTeam()) {
|
||||
String currentTeam = null;
|
||||
for (Team team : player.getScoreboard().getTeams()) {
|
||||
if (team.getPlayers().contains(info.getUsername())) {
|
||||
currentTeam = team.getName();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Reinitialize auto-team
|
||||
newTracker.setAutoTeam(true);
|
||||
if (currentTeam == null) {
|
||||
// Send auto-team as it was cleared above
|
||||
newTracker.sendTeamPacket(true, true);
|
||||
newTracker.setCurrentTeam("viaversion");
|
||||
} else {
|
||||
// Auto-team will be sent when bungee send remove packet
|
||||
newTracker.setAutoTeam(Via.getConfig().isAutoTeam());
|
||||
newTracker.setCurrentTeam(currentTeam);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Object wrapper = channelWrapper.get(player);
|
||||
setVersion.invoke(wrapper, protocolId);
|
||||
|
||||
Object entityMap = getEntityMap.invoke(null, protocolId);
|
||||
entityRewrite.set(player, entityMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package us.myles.ViaVersion.bungee.listeners;
|
||||
|
||||
import net.md_5.bungee.api.event.ServerConnectedEvent;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
import net.md_5.bungee.event.EventPriority;
|
||||
import us.myles.ViaVersion.api.PacketWrapper;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.minecraft.metadata.Metadata;
|
||||
import us.myles.ViaVersion.api.minecraft.metadata.types.MetaType1_9;
|
||||
import us.myles.ViaVersion.api.type.Type;
|
||||
import us.myles.ViaVersion.api.type.types.version.Types1_9;
|
||||
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9To1_8;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.EntityTracker1_9;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
/*
|
||||
* This patches https://github.com/ViaVersion/ViaVersion/issues/555
|
||||
*/
|
||||
public class ElytraPatch implements Listener {
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGH)
|
||||
public void onServerConnected(ServerConnectedEvent event) {
|
||||
UserConnection user = Via.getManager().getConnection(event.getPlayer().getUniqueId());
|
||||
if (user == null) return;
|
||||
|
||||
try {
|
||||
if (user.getProtocolInfo().getPipeline().contains(Protocol1_9To1_8.class)) {
|
||||
int entityId = user.get(EntityTracker1_9.class).getProvidedEntityId();
|
||||
|
||||
PacketWrapper wrapper = new PacketWrapper(0x39, null, user);
|
||||
|
||||
wrapper.write(Type.VAR_INT, entityId);
|
||||
wrapper.write(Types1_9.METADATA_LIST, Collections.singletonList(new Metadata(0, MetaType1_9.Byte, (byte) 0)));
|
||||
|
||||
wrapper.send(Protocol1_9To1_8.class);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package us.myles.ViaVersion.bungee.listeners;
|
||||
|
||||
import net.md_5.bungee.api.event.PostLoginEvent;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.update.UpdateUtil;
|
||||
|
||||
public class UpdateListener implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onJoin(PostLoginEvent e) {
|
||||
if (e.getPlayer().hasPermission("viaversion.update")
|
||||
&& Via.getConfig().isCheckForUpdates()) {
|
||||
UpdateUtil.sendUpdateMessage(e.getPlayer().getUniqueId());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package us.myles.ViaVersion.bungee.platform;
|
||||
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import us.myles.ViaVersion.api.boss.BossBar;
|
||||
import us.myles.ViaVersion.api.boss.BossColor;
|
||||
import us.myles.ViaVersion.api.boss.BossStyle;
|
||||
import us.myles.ViaVersion.boss.CommonBoss;
|
||||
|
||||
public class BungeeBossBar extends CommonBoss<ProxiedPlayer> {
|
||||
|
||||
public BungeeBossBar(String title, float health, BossColor color, BossStyle style) {
|
||||
super(title, health, color, style);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BossBar addPlayer(ProxiedPlayer player) {
|
||||
addPlayer(player.getUniqueId());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BossBar addPlayers(ProxiedPlayer... players) {
|
||||
for (ProxiedPlayer p : players)
|
||||
addPlayer(p);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BossBar removePlayer(ProxiedPlayer player) {
|
||||
removePlayer(player.getUniqueId());
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package us.myles.ViaVersion.bungee.platform;
|
||||
|
||||
import us.myles.ViaVersion.api.platform.TaskId;
|
||||
|
||||
public class BungeeTaskId implements TaskId {
|
||||
private final Integer object;
|
||||
|
||||
public BungeeTaskId(Integer object) {
|
||||
this.object = object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getObject() {
|
||||
return object;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package us.myles.ViaVersion.bungee.platform;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.ViaAPI;
|
||||
import us.myles.ViaVersion.api.boss.BossBar;
|
||||
import us.myles.ViaVersion.api.boss.BossColor;
|
||||
import us.myles.ViaVersion.api.boss.BossStyle;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
|
||||
import us.myles.ViaVersion.bungee.service.ProtocolDetectorService;
|
||||
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.UUID;
|
||||
|
||||
public class BungeeViaAPI implements ViaAPI<ProxiedPlayer> {
|
||||
|
||||
@Override
|
||||
public int getPlayerVersion(ProxiedPlayer player) {
|
||||
UserConnection conn = Via.getManager().getConnection(player.getUniqueId());
|
||||
if (conn == null) {
|
||||
return player.getPendingConnection().getVersion();
|
||||
}
|
||||
return conn.getProtocolInfo().getProtocolVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPlayerVersion(UUID uuid) {
|
||||
return getPlayerVersion(ProxyServer.getInstance().getPlayer(uuid));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInjected(UUID playerUUID) {
|
||||
return Via.getManager().isClientConnected(playerUUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return Via.getPlatform().getPluginVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendRawPacket(UUID uuid, ByteBuf packet) throws IllegalArgumentException {
|
||||
if (!isInjected(uuid)) {
|
||||
throw new IllegalArgumentException("This player is not controlled by ViaVersion!");
|
||||
}
|
||||
UserConnection ci = Via.getManager().getConnection(uuid);
|
||||
ci.sendRawPacket(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendRawPacket(ProxiedPlayer player, ByteBuf packet) throws IllegalArgumentException {
|
||||
sendRawPacket(player.getUniqueId(), packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BossBar createBossBar(String title, BossColor color, BossStyle style) {
|
||||
return new BungeeBossBar(title, 1F, color, style);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BossBar createBossBar(String title, float health, BossColor color, BossStyle style) {
|
||||
return new BungeeBossBar(title, health, color, style);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedSet<Integer> getSupportedVersions() {
|
||||
SortedSet<Integer> outputSet = new TreeSet<>(ProtocolRegistry.getSupportedVersions());
|
||||
outputSet.removeAll(Via.getPlatform().getConf().getBlockedProtocols());
|
||||
|
||||
return outputSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces ViaVersion to probe a server
|
||||
*
|
||||
* @param serverInfo The serverinfo to probe
|
||||
*/
|
||||
public void probeServer(ServerInfo serverInfo) {
|
||||
ProtocolDetectorService.probeServer(serverInfo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package us.myles.ViaVersion.bungee.platform;
|
||||
|
||||
import us.myles.ViaVersion.AbstractViaConfig;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
|
||||
import us.myles.ViaVersion.bungee.providers.BungeeVersionProvider;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
|
||||
public class BungeeViaConfig extends AbstractViaConfig {
|
||||
private static final List<String> UNSUPPORTED = Arrays.asList("nms-player-ticking", "item-cache", "anti-xray-patch", "quick-move-action-fix", "velocity-ping-interval", "velocity-ping-save", "velocity-servers", "blockconnection-method", "change-1_9-hitbox", "change-1_14-hitbox");
|
||||
private int bungeePingInterval;
|
||||
private boolean bungeePingSave;
|
||||
private Map<String, Integer> bungeeServerProtocols;
|
||||
|
||||
public BungeeViaConfig(File configFile) {
|
||||
super(new File(configFile, "config.yml"));
|
||||
reloadConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadFields() {
|
||||
super.loadFields();
|
||||
bungeePingInterval = getInt("bungee-ping-interval", 60);
|
||||
bungeePingSave = getBoolean("bungee-ping-save", true);
|
||||
bungeeServerProtocols = get("bungee-servers", Map.class, new HashMap<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getDefaultConfigURL() {
|
||||
return BungeeViaConfig.class.getClassLoader().getResource("assets/viaversion/config.yml");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleConfig(Map<String, Object> config) {
|
||||
// Parse servers
|
||||
Map<String, Object> servers;
|
||||
if (!(config.get("bungee-servers") instanceof Map)) {
|
||||
servers = new HashMap<>();
|
||||
} else {
|
||||
servers = (Map) config.get("bungee-servers");
|
||||
}
|
||||
// Convert any bad Protocol Ids
|
||||
for (Map.Entry<String, Object> entry : new HashSet<>(servers.entrySet())) {
|
||||
if (!(entry.getValue() instanceof Integer)) {
|
||||
if (entry.getValue() instanceof String) {
|
||||
ProtocolVersion found = ProtocolVersion.getClosest((String) entry.getValue());
|
||||
if (found != null) {
|
||||
servers.put(entry.getKey(), found.getId());
|
||||
} else {
|
||||
servers.remove(entry.getKey()); // Remove!
|
||||
}
|
||||
} else {
|
||||
servers.remove(entry.getKey()); // Remove!
|
||||
}
|
||||
}
|
||||
}
|
||||
// Ensure default exists
|
||||
if (!servers.containsKey("default")) {
|
||||
servers.put("default", BungeeVersionProvider.getLowestSupportedVersion());
|
||||
}
|
||||
// Put back
|
||||
config.put("bungee-servers", servers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getUnsupportedOptions() {
|
||||
return UNSUPPORTED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemCache() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNMSPlayerTicking() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* What is the interval for checking servers via ping
|
||||
* -1 for disabled
|
||||
*
|
||||
* @return Ping interval in seconds
|
||||
*/
|
||||
public int getBungeePingInterval() {
|
||||
return bungeePingInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should the bungee ping be saved to the config on change.
|
||||
*
|
||||
* @return True if it should save
|
||||
*/
|
||||
public boolean isBungeePingSave() {
|
||||
return bungeePingSave;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the listed server protocols in the config.
|
||||
* default will be listed as default.
|
||||
*
|
||||
* @return Map of String, Integer
|
||||
*/
|
||||
public Map<String, Integer> getBungeeServerProtocols() {
|
||||
return bungeeServerProtocols;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package us.myles.ViaVersion.bungee.platform;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.platform.ViaInjector;
|
||||
import us.myles.ViaVersion.bungee.handlers.BungeeChannelInitializer;
|
||||
import us.myles.ViaVersion.util.ReflectionUtil;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.List;
|
||||
|
||||
public class BungeeViaInjector implements ViaInjector {
|
||||
|
||||
@Override
|
||||
public void inject() throws Exception {
|
||||
try {
|
||||
Class<?> pipelineUtils = Class.forName("net.md_5.bungee.netty.PipelineUtils");
|
||||
Field field = pipelineUtils.getDeclaredField("SERVER_CHILD");
|
||||
field.setAccessible(true);
|
||||
|
||||
// Remove the final modifier (unless removed by a fork)
|
||||
int modifiers = field.getModifiers();
|
||||
if (Modifier.isFinal(modifiers)) {
|
||||
try {
|
||||
Field modifiersField = Field.class.getDeclaredField("modifiers");
|
||||
modifiersField.setAccessible(true);
|
||||
modifiersField.setInt(field, modifiers & ~Modifier.FINAL);
|
||||
} catch (NoSuchFieldException e) {
|
||||
// Java 12 compatibility *this is fine*
|
||||
Method getDeclaredFields0 = Class.class.getDeclaredMethod("getDeclaredFields0", boolean.class);
|
||||
getDeclaredFields0.setAccessible(true);
|
||||
Field[] fields = (Field[]) getDeclaredFields0.invoke(Field.class, false);
|
||||
for (Field classField : fields) {
|
||||
if ("modifiers".equals(classField.getName())) {
|
||||
classField.setAccessible(true);
|
||||
classField.set(field, modifiers & ~Modifier.FINAL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BungeeChannelInitializer newInit = new BungeeChannelInitializer((ChannelInitializer<Channel>) field.get(null));
|
||||
field.set(null, newInit);
|
||||
} catch (Exception e) {
|
||||
Via.getPlatform().getLogger().severe("Unable to inject ViaVersion, please post these details on our GitHub and ensure you're using a compatible server version.");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uninject() {
|
||||
Via.getPlatform().getLogger().severe("ViaVersion cannot remove itself from Bungee without a reboot!");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getServerProtocolVersion() throws Exception {
|
||||
return (int) ReflectionUtil.getStatic(Class.forName("net.md_5.bungee.protocol.ProtocolConstants"), "SUPPORTED_VERSION_IDS", List.class).get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEncoderName() {
|
||||
return "via-encoder";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDecoderName() {
|
||||
return "via-decoder";
|
||||
}
|
||||
|
||||
private ChannelInitializer<Channel> getChannelInitializer() throws Exception {
|
||||
Class<?> pipelineUtils = Class.forName("net.md_5.bungee.netty.PipelineUtils");
|
||||
Field field = pipelineUtils.getDeclaredField("SERVER_CHILD");
|
||||
field.setAccessible(true);
|
||||
return (ChannelInitializer<Channel>) field.get(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObject getDump() {
|
||||
JsonObject data = new JsonObject();
|
||||
try {
|
||||
ChannelInitializer<Channel> initializer = getChannelInitializer();
|
||||
data.addProperty("currentInitializer", initializer.getClass().getName());
|
||||
if (initializer instanceof BungeeChannelInitializer) {
|
||||
data.addProperty("originalInitializer", ((BungeeChannelInitializer) initializer).getOriginal().getClass().getName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Ignored, not printed in the dump
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package us.myles.ViaVersion.bungee.platform;
|
||||
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.api.scheduler.ScheduledTask;
|
||||
import us.myles.ViaVersion.BungeePlugin;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.platform.ViaPlatformLoader;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
|
||||
import us.myles.ViaVersion.bungee.handlers.BungeeServerHandler;
|
||||
import us.myles.ViaVersion.bungee.listeners.ElytraPatch;
|
||||
import us.myles.ViaVersion.bungee.listeners.UpdateListener;
|
||||
import us.myles.ViaVersion.bungee.providers.*;
|
||||
import us.myles.ViaVersion.bungee.service.ProtocolDetectorService;
|
||||
import us.myles.ViaVersion.protocols.base.VersionProvider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.BossBarProvider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.EntityIdProvider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.MainHandProvider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.MovementTransmitterProvider;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BungeeViaLoader implements ViaPlatformLoader {
|
||||
private final BungeePlugin plugin;
|
||||
|
||||
private final Set<Listener> listeners = new HashSet<>();
|
||||
private final Set<ScheduledTask> tasks = new HashSet<>();
|
||||
|
||||
public BungeeViaLoader(BungeePlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
private void registerListener(Listener listener) {
|
||||
listeners.add(listener);
|
||||
ProxyServer.getInstance().getPluginManager().registerListener(plugin, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
// Listeners
|
||||
registerListener(plugin);
|
||||
registerListener(new UpdateListener());
|
||||
registerListener(new BungeeServerHandler());
|
||||
|
||||
if (ProtocolRegistry.SERVER_PROTOCOL < ProtocolVersion.v1_9.getId()) {
|
||||
registerListener(new ElytraPatch());
|
||||
}
|
||||
|
||||
// Providers
|
||||
Via.getManager().getProviders().use(VersionProvider.class, new BungeeVersionProvider());
|
||||
Via.getManager().getProviders().use(EntityIdProvider.class, new BungeeEntityIdProvider());
|
||||
|
||||
if (ProtocolRegistry.SERVER_PROTOCOL < ProtocolVersion.v1_9.getId()) {
|
||||
Via.getManager().getProviders().use(MovementTransmitterProvider.class, new BungeeMovementTransmitter());
|
||||
Via.getManager().getProviders().use(BossBarProvider.class, new BungeeBossBarProvider());
|
||||
Via.getManager().getProviders().use(MainHandProvider.class, new BungeeMainHandProvider());
|
||||
}
|
||||
|
||||
if (plugin.getConf().getBungeePingInterval() > 0) {
|
||||
tasks.add(plugin.getProxy().getScheduler().schedule(
|
||||
plugin,
|
||||
new ProtocolDetectorService(plugin),
|
||||
0, plugin.getConf().getBungeePingInterval(),
|
||||
TimeUnit.SECONDS
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
for (Listener listener : listeners) {
|
||||
ProxyServer.getInstance().getPluginManager().unregisterListener(listener);
|
||||
}
|
||||
listeners.clear();
|
||||
for (ScheduledTask task : tasks) {
|
||||
task.cancel();
|
||||
}
|
||||
tasks.clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package us.myles.ViaVersion.bungee.providers;
|
||||
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.bungee.storage.BungeeStorage;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.BossBarProvider;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class BungeeBossBarProvider extends BossBarProvider {
|
||||
@Override
|
||||
public void handleAdd(UserConnection user, UUID barUUID) {
|
||||
if (user.has(BungeeStorage.class)) {
|
||||
BungeeStorage storage = user.get(BungeeStorage.class);
|
||||
// Check if bossbars are supported by bungee, static maybe
|
||||
if (storage.getBossbar() != null) {
|
||||
storage.getBossbar().add(barUUID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRemove(UserConnection user, UUID barUUID) {
|
||||
if (user.has(BungeeStorage.class)) {
|
||||
BungeeStorage storage = user.get(BungeeStorage.class);
|
||||
if (storage.getBossbar() != null) {
|
||||
storage.getBossbar().remove(barUUID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package us.myles.ViaVersion.bungee.providers;
|
||||
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.bungee.storage.BungeeStorage;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.EntityIdProvider;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class BungeeEntityIdProvider extends EntityIdProvider {
|
||||
private static Method getClientEntityId;
|
||||
|
||||
static {
|
||||
try {
|
||||
getClientEntityId = Class.forName("net.md_5.bungee.UserConnection").getDeclaredMethod("getClientEntityId");
|
||||
} catch (NoSuchMethodException | ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEntityId(UserConnection user) throws Exception {
|
||||
BungeeStorage storage = user.get(BungeeStorage.class);
|
||||
ProxiedPlayer player = storage.getPlayer();
|
||||
|
||||
return (int) getClientEntityId.invoke(player);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package us.myles.ViaVersion.bungee.providers;
|
||||
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.MainHandProvider;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/*
|
||||
This solves the wrong mainhand issue when you join with BungeeCord on a 1.8 server, and switch to a 1.9 or higher.
|
||||
*/
|
||||
public class BungeeMainHandProvider extends MainHandProvider {
|
||||
private static Method getSettings = null;
|
||||
private static Method setMainHand = null;
|
||||
|
||||
static {
|
||||
try {
|
||||
getSettings = Class.forName("net.md_5.bungee.UserConnection").getDeclaredMethod("getSettings");
|
||||
setMainHand = Class.forName("net.md_5.bungee.protocol.packet.ClientSettings").getDeclaredMethod("setMainHand", int.class);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMainHand(UserConnection user, int hand) {
|
||||
ProtocolInfo info = user.getProtocolInfo();
|
||||
if (info == null || info.getUuid() == null) return;
|
||||
ProxiedPlayer player = ProxyServer.getInstance().getPlayer(info.getUuid());
|
||||
if (player == null) return;
|
||||
try {
|
||||
Object settings = getSettings.invoke(player);
|
||||
if (settings != null) {
|
||||
setMainHand.invoke(settings, hand);
|
||||
}
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package us.myles.ViaVersion.bungee.providers;
|
||||
|
||||
import us.myles.ViaVersion.api.PacketWrapper;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.type.Type;
|
||||
import us.myles.ViaVersion.packets.State;
|
||||
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9To1_8;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.MovementTransmitterProvider;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.MovementTracker;
|
||||
|
||||
public class BungeeMovementTransmitter extends MovementTransmitterProvider {
|
||||
@Override
|
||||
public Object getFlyingPacket() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGroundPacket() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void sendPlayer(UserConnection userConnection) {
|
||||
if (userConnection.getProtocolInfo().getState() == State.PLAY) {
|
||||
PacketWrapper wrapper = new PacketWrapper(0x03, null, userConnection);
|
||||
wrapper.write(Type.BOOLEAN, userConnection.get(MovementTracker.class).isGround());
|
||||
try {
|
||||
wrapper.sendToServer(Protocol1_9To1_8.class);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// PlayerPackets will increment idle
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package us.myles.ViaVersion.bungee.providers;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
|
||||
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||
import us.myles.ViaVersion.protocols.base.VersionProvider;
|
||||
import us.myles.ViaVersion.util.ReflectionUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class BungeeVersionProvider extends VersionProvider {
|
||||
private static Class<?> ref;
|
||||
|
||||
static {
|
||||
try {
|
||||
ref = Class.forName("net.md_5.bungee.protocol.ProtocolConstants");
|
||||
} catch (Exception e) {
|
||||
Via.getPlatform().getLogger().severe("Could not detect the ProtocolConstants class");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getServerProtocol(UserConnection user) throws Exception {
|
||||
if (ref == null)
|
||||
return super.getServerProtocol(user);
|
||||
// TODO Have one constant list forever until restart? (Might limit plugins if they change this)
|
||||
List<Integer> list = ReflectionUtil.getStatic(ref, "SUPPORTED_VERSION_IDS", List.class);
|
||||
List<Integer> sorted = new ArrayList<>(list);
|
||||
Collections.sort(sorted);
|
||||
|
||||
ProtocolInfo info = user.getProtocolInfo();
|
||||
|
||||
// Bungee supports it
|
||||
if (sorted.contains(info.getProtocolVersion()))
|
||||
return info.getProtocolVersion();
|
||||
|
||||
// Older than bungee supports, get the lowest version
|
||||
if (info.getProtocolVersion() < sorted.get(0)) {
|
||||
return getLowestSupportedVersion();
|
||||
}
|
||||
|
||||
// Loop through all protocols to get the closest protocol id that bungee supports (and that viaversion does too)
|
||||
|
||||
// TODO: This needs a better fix, i.e checking ProtocolRegistry to see if it would work.
|
||||
// This is more of a workaround for snapshot support by bungee.
|
||||
for (Integer protocol : Lists.reverse(sorted)) {
|
||||
if (info.getProtocolVersion() > protocol && ProtocolVersion.isRegistered(protocol))
|
||||
return protocol;
|
||||
}
|
||||
|
||||
Via.getPlatform().getLogger().severe("Panic, no protocol id found for " + info.getProtocolVersion());
|
||||
return info.getProtocolVersion();
|
||||
}
|
||||
|
||||
public static int getLowestSupportedVersion() {
|
||||
List<Integer> list;
|
||||
try {
|
||||
list = ReflectionUtil.getStatic(ref, "SUPPORTED_VERSION_IDS", List.class);
|
||||
return list.get(0);
|
||||
} catch (NoSuchFieldException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// Fallback
|
||||
return ProxyServer.getInstance().getProtocolVersion();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package us.myles.ViaVersion.bungee.service;
|
||||
|
||||
import net.md_5.bungee.api.Callback;
|
||||
import net.md_5.bungee.api.ServerPing;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import us.myles.ViaVersion.BungeePlugin;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.bungee.platform.BungeeViaConfig;
|
||||
import us.myles.ViaVersion.bungee.providers.BungeeVersionProvider;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class ProtocolDetectorService implements Runnable {
|
||||
private static final Map<String, Integer> detectedProtocolIds = new ConcurrentHashMap<>();
|
||||
private static ProtocolDetectorService instance;
|
||||
private final BungeePlugin plugin;
|
||||
|
||||
public ProtocolDetectorService(BungeePlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
instance = this;
|
||||
}
|
||||
|
||||
public static Integer getProtocolId(String serverName) {
|
||||
// Step 1. Check Config
|
||||
Map<String, Integer> servers = ((BungeeViaConfig) Via.getConfig()).getBungeeServerProtocols();
|
||||
Integer protocol = servers.get(serverName);
|
||||
if (protocol != null) {
|
||||
return protocol;
|
||||
}
|
||||
// Step 2. Check Detected
|
||||
Integer detectedProtocol = detectedProtocolIds.get(serverName);
|
||||
if (detectedProtocol != null) {
|
||||
return detectedProtocol;
|
||||
}
|
||||
// Step 3. Use Default
|
||||
Integer defaultProtocol = servers.get("default");
|
||||
if (defaultProtocol != null) {
|
||||
return defaultProtocol;
|
||||
}
|
||||
// Step 4: Use bungee lowest supported... *cries*
|
||||
return BungeeVersionProvider.getLowestSupportedVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for (final Map.Entry<String, ServerInfo> lists : plugin.getProxy().getServers().entrySet()) {
|
||||
probeServer(lists.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
public static void probeServer(final ServerInfo serverInfo) {
|
||||
final String key = serverInfo.getName();
|
||||
serverInfo.ping(new Callback<ServerPing>() {
|
||||
@Override
|
||||
public void done(ServerPing serverPing, Throwable throwable) {
|
||||
if (throwable == null && serverPing != null && serverPing.getVersion() != null) {
|
||||
// Ensure protocol is positive, some services will return -1
|
||||
if (serverPing.getVersion().getProtocol() > 0) {
|
||||
detectedProtocolIds.put(key, serverPing.getVersion().getProtocol());
|
||||
if (((BungeeViaConfig) Via.getConfig()).isBungeePingSave()) {
|
||||
Map<String, Integer> servers = ((BungeeViaConfig) Via.getConfig()).getBungeeServerProtocols();
|
||||
Integer protocol = servers.get(key);
|
||||
if (protocol != null && protocol == serverPing.getVersion().getProtocol()) {
|
||||
return;
|
||||
}
|
||||
// Ensure we're the only ones writing to the config
|
||||
synchronized (Via.getPlatform().getConfigurationProvider()) {
|
||||
servers.put(key, serverPing.getVersion().getProtocol());
|
||||
}
|
||||
// Save
|
||||
Via.getPlatform().getConfigurationProvider().saveConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static Map<String, Integer> getDetectedIds() {
|
||||
return new HashMap<>(detectedProtocolIds);
|
||||
}
|
||||
|
||||
public static ProtocolDetectorService getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public BungeePlugin getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package us.myles.ViaVersion.bungee.storage;
|
||||
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import us.myles.ViaVersion.api.data.StoredObject;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public class BungeeStorage extends StoredObject {
|
||||
private static Field bossField;
|
||||
|
||||
static {
|
||||
try {
|
||||
Class<?> user = Class.forName("net.md_5.bungee.UserConnection");
|
||||
bossField = user.getDeclaredField("sentBossBars");
|
||||
bossField.setAccessible(true);
|
||||
} catch (ClassNotFoundException e) {
|
||||
// Not supported *shrug* probably modified
|
||||
} catch (NoSuchFieldException e) {
|
||||
// Not supported, old version probably
|
||||
}
|
||||
}
|
||||
|
||||
private final ProxiedPlayer player;
|
||||
private String currentServer;
|
||||
private Set<UUID> bossbar;
|
||||
|
||||
public BungeeStorage(UserConnection user, ProxiedPlayer player) {
|
||||
super(user);
|
||||
this.player = player;
|
||||
this.currentServer = "";
|
||||
|
||||
// Get bossbar list if it's supported
|
||||
if (bossField != null) {
|
||||
try {
|
||||
bossbar = (Set<UUID>) bossField.get(player);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ProxiedPlayer getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public String getCurrentServer() {
|
||||
return currentServer;
|
||||
}
|
||||
|
||||
public void setCurrentServer(String currentServer) {
|
||||
this.currentServer = currentServer;
|
||||
}
|
||||
|
||||
public Set<UUID> getBossbar() {
|
||||
return bossbar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
BungeeStorage that = (BungeeStorage) o;
|
||||
if (!Objects.equals(player, that.player)) return false;
|
||||
if (!Objects.equals(currentServer, that.currentServer)) return false;
|
||||
return Objects.equals(bossbar, that.bossbar);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = player != null ? player.hashCode() : 0;
|
||||
result = 31 * result + (currentServer != null ? currentServer.hashCode() : 0);
|
||||
result = 31 * result + (bossbar != null ? bossbar.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package us.myles.ViaVersion.bungee.util;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class BungeePipelineUtil {
|
||||
private static Method DECODE_METHOD;
|
||||
private static Method ENCODE_METHOD;
|
||||
|
||||
static {
|
||||
try {
|
||||
DECODE_METHOD = MessageToMessageDecoder.class.getDeclaredMethod("decode", ChannelHandlerContext.class, Object.class, List.class);
|
||||
DECODE_METHOD.setAccessible(true);
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
ENCODE_METHOD = MessageToByteEncoder.class.getDeclaredMethod("encode", ChannelHandlerContext.class, Object.class, ByteBuf.class);
|
||||
ENCODE_METHOD.setAccessible(true);
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Object> callDecode(MessageToMessageDecoder decoder, ChannelHandlerContext ctx, ByteBuf input) throws InvocationTargetException {
|
||||
List<Object> output = new ArrayList<>();
|
||||
try {
|
||||
BungeePipelineUtil.DECODE_METHOD.invoke(decoder, ctx, input, output);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
public static ByteBuf callEncode(MessageToByteEncoder encoder, ChannelHandlerContext ctx, ByteBuf input) throws InvocationTargetException {
|
||||
ByteBuf output = ctx.alloc().buffer();
|
||||
try {
|
||||
BungeePipelineUtil.ENCODE_METHOD.invoke(encoder, ctx, input, output);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
public static ByteBuf decompress(ChannelHandlerContext ctx, ByteBuf bytebuf) {
|
||||
try {
|
||||
return (ByteBuf) callDecode((MessageToMessageDecoder) ctx.pipeline().get("decompress"), ctx.pipeline().context("decompress"), bytebuf).get(0);
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
return ctx.alloc().buffer();
|
||||
}
|
||||
}
|
||||
|
||||
public static ByteBuf compress(ChannelHandlerContext ctx, ByteBuf bytebuf) {
|
||||
try {
|
||||
return callEncode((MessageToByteEncoder) ctx.pipeline().get("compress"), ctx.pipeline().context("compress"), bytebuf);
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
return ctx.alloc().buffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
name: ViaVersion
|
||||
main: us.myles.ViaVersion.BungeePlugin
|
||||
description: ${project.description}
|
||||
author: _MylesC, creeper123123321, Gerrygames, KennyTV, Matsv
|
||||
version: ${project.version}
|
||||
+4
-4
@@ -1,11 +1,11 @@
|
||||
machine:
|
||||
java:
|
||||
version: oraclejdk7
|
||||
version: oraclejdk8
|
||||
general:
|
||||
artifacts:
|
||||
- "target/*.jar"
|
||||
- "target/*.jar"
|
||||
test:
|
||||
override:
|
||||
- mvn clean install -B
|
||||
- mvn clean install -B
|
||||
post:
|
||||
- cp ./target/*.jar $CIRCLE_ARTIFACTS
|
||||
- cp ./target/*.jar $CIRCLE_ARTIFACTS
|
||||
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>viaversion-parent</artifactId>
|
||||
<groupId>us.myles</groupId>
|
||||
<version>3.1.0</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>viaversion-common</artifactId>
|
||||
<dependencies>
|
||||
<!-- Snake YAML -->
|
||||
<dependency>
|
||||
<groupId>org.yaml</groupId>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
<version>1.18</version>
|
||||
<scope>compile</scope> <!-- Velocity doesn't have snakeyaml -->
|
||||
</dependency>
|
||||
|
||||
<!-- FastUtil for performance increases -->
|
||||
<dependency>
|
||||
<groupId>it.unimi.dsi</groupId>
|
||||
<artifactId>fastutil</artifactId>
|
||||
<version>8.3.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,373 @@
|
||||
package us.myles.ViaVersion;
|
||||
|
||||
import us.myles.ViaVersion.api.ViaVersionConfig;
|
||||
import us.myles.ViaVersion.util.Config;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public abstract class AbstractViaConfig extends Config implements ViaVersionConfig {
|
||||
|
||||
private boolean checkForUpdates;
|
||||
private boolean preventCollision;
|
||||
private boolean useNewEffectIndicator;
|
||||
private boolean useNewDeathmessages;
|
||||
private boolean suppressMetadataErrors;
|
||||
private boolean shieldBlocking;
|
||||
private boolean hologramPatch;
|
||||
private boolean pistonAnimationPatch;
|
||||
private boolean bossbarPatch;
|
||||
private boolean bossbarAntiFlicker;
|
||||
private double hologramOffset;
|
||||
private int maxPPS;
|
||||
private String maxPPSKickMessage;
|
||||
private int trackingPeriod;
|
||||
private int warningPPS;
|
||||
private int maxPPSWarnings;
|
||||
private String maxPPSWarningsKickMessage;
|
||||
private boolean sendSupportedVersions;
|
||||
private boolean simulatePlayerTick;
|
||||
private boolean itemCache;
|
||||
private boolean nmsPlayerTicking;
|
||||
private boolean replacePistons;
|
||||
private int pistonReplacementId;
|
||||
private boolean autoTeam;
|
||||
private boolean forceJsonTransform;
|
||||
private boolean nbtArrayFix;
|
||||
private Set<Integer> blockedProtocols;
|
||||
private String blockedDisconnectMessage;
|
||||
private String reloadDisconnectMessage;
|
||||
private boolean suppressConversionWarnings;
|
||||
private boolean disable1_13TabComplete;
|
||||
private boolean minimizeCooldown;
|
||||
private boolean teamColourFix;
|
||||
private boolean serversideBlockConnections;
|
||||
private boolean reduceBlockStorageMemory;
|
||||
private boolean flowerStemWhenBlockAbove;
|
||||
private boolean vineClimbFix;
|
||||
private boolean snowCollisionFix;
|
||||
private boolean infestedBlocksFix;
|
||||
private int tabCompleteDelay;
|
||||
private boolean truncate1_14Books;
|
||||
private boolean leftHandedHandling;
|
||||
private boolean fullBlockLightFix;
|
||||
private boolean healthNaNFix;
|
||||
private boolean instantRespawn;
|
||||
private boolean ignoreLongChannelNames;
|
||||
|
||||
protected AbstractViaConfig(File configFile) {
|
||||
super(configFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reloadConfig() {
|
||||
super.reloadConfig();
|
||||
loadFields();
|
||||
}
|
||||
|
||||
protected void loadFields() {
|
||||
checkForUpdates = getBoolean("checkforupdates", true);
|
||||
preventCollision = getBoolean("prevent-collision", true);
|
||||
useNewEffectIndicator = getBoolean("use-new-effect-indicator", true);
|
||||
useNewDeathmessages = getBoolean("use-new-deathmessages", true);
|
||||
suppressMetadataErrors = getBoolean("suppress-metadata-errors", false);
|
||||
shieldBlocking = getBoolean("shield-blocking", true);
|
||||
hologramPatch = getBoolean("hologram-patch", false);
|
||||
pistonAnimationPatch = getBoolean("piston-animation-patch", false);
|
||||
bossbarPatch = getBoolean("bossbar-patch", true);
|
||||
bossbarAntiFlicker = getBoolean("bossbar-anti-flicker", false);
|
||||
hologramOffset = getDouble("hologram-y", -0.96D);
|
||||
maxPPS = getInt("max-pps", 800);
|
||||
maxPPSKickMessage = getString("max-pps-kick-msg", "Sending packets too fast? lag?");
|
||||
trackingPeriod = getInt("tracking-period", 6);
|
||||
warningPPS = getInt("tracking-warning-pps", 120);
|
||||
maxPPSWarnings = getInt("tracking-max-warnings", 3);
|
||||
maxPPSWarningsKickMessage = getString("tracking-max-kick-msg", "You are sending too many packets, :(");
|
||||
sendSupportedVersions = getBoolean("send-supported-versions", false);
|
||||
simulatePlayerTick = getBoolean("simulate-pt", true);
|
||||
itemCache = getBoolean("item-cache", true);
|
||||
nmsPlayerTicking = getBoolean("nms-player-ticking", true);
|
||||
replacePistons = getBoolean("replace-pistons", false);
|
||||
pistonReplacementId = getInt("replacement-piston-id", 0);
|
||||
autoTeam = getBoolean("auto-team", true);
|
||||
forceJsonTransform = getBoolean("force-json-transform", false);
|
||||
nbtArrayFix = getBoolean("chat-nbt-fix", true);
|
||||
blockedProtocols = new HashSet<>(getIntegerList("block-protocols"));
|
||||
blockedDisconnectMessage = getString("block-disconnect-msg", "You are using an unsupported Minecraft version!");
|
||||
reloadDisconnectMessage = getString("reload-disconnect-msg", "Server reload, please rejoin!");
|
||||
minimizeCooldown = getBoolean("minimize-cooldown", true);
|
||||
teamColourFix = getBoolean("team-colour-fix", true);
|
||||
suppressConversionWarnings = getBoolean("suppress-conversion-warnings", false);
|
||||
disable1_13TabComplete = getBoolean("disable-1_13-auto-complete", false);
|
||||
serversideBlockConnections = getBoolean("serverside-blockconnections", true);
|
||||
reduceBlockStorageMemory = getBoolean("reduce-blockstorage-memory", false);
|
||||
flowerStemWhenBlockAbove = getBoolean("flowerstem-when-block-above", false);
|
||||
vineClimbFix = getBoolean("vine-climb-fix", false);
|
||||
snowCollisionFix = getBoolean("fix-low-snow-collision", false);
|
||||
infestedBlocksFix = getBoolean("fix-infested-block-breaking", true);
|
||||
tabCompleteDelay = getInt("1_13-tab-complete-delay", 0);
|
||||
truncate1_14Books = getBoolean("truncate-1_14-books", false);
|
||||
leftHandedHandling = getBoolean("left-handed-handling", true);
|
||||
fullBlockLightFix = getBoolean("fix-non-full-blocklight", false);
|
||||
healthNaNFix = getBoolean("fix-1_14-health-nan", true);
|
||||
instantRespawn = getBoolean("use-1_15-instant-respawn", false);
|
||||
ignoreLongChannelNames = getBoolean("ignore-long-1_16-channel-names", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCheckForUpdates() {
|
||||
return checkForUpdates;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPreventCollision() {
|
||||
return preventCollision;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNewEffectIndicator() {
|
||||
return useNewEffectIndicator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShowNewDeathMessages() {
|
||||
return useNewDeathmessages;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuppressMetadataErrors() {
|
||||
return suppressMetadataErrors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShieldBlocking() {
|
||||
return shieldBlocking;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHologramPatch() {
|
||||
return hologramPatch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPistonAnimationPatch() {
|
||||
return pistonAnimationPatch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBossbarPatch() {
|
||||
return bossbarPatch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBossbarAntiflicker() {
|
||||
return bossbarAntiFlicker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getHologramYOffset() {
|
||||
return hologramOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxPPS() {
|
||||
return maxPPS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMaxPPSKickMessage() {
|
||||
return maxPPSKickMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTrackingPeriod() {
|
||||
return trackingPeriod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWarningPPS() {
|
||||
return warningPPS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxWarnings() {
|
||||
return maxPPSWarnings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMaxWarningsKickMessage() {
|
||||
return maxPPSWarningsKickMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAntiXRay() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSendSupportedVersions() {
|
||||
return sendSupportedVersions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSimulatePlayerTick() {
|
||||
return simulatePlayerTick;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemCache() {
|
||||
return itemCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNMSPlayerTicking() {
|
||||
return nmsPlayerTicking;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReplacePistons() {
|
||||
return replacePistons;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPistonReplacementId() {
|
||||
return pistonReplacementId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoTeam() {
|
||||
// Collision has to be enabled first
|
||||
return preventCollision && autoTeam;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForceJsonTransform() {
|
||||
return forceJsonTransform;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean is1_12NBTArrayFix() {
|
||||
return nbtArrayFix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean is1_12QuickMoveActionFix() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Integer> getBlockedProtocols() {
|
||||
return blockedProtocols;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBlockedDisconnectMsg() {
|
||||
return blockedDisconnectMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReloadDisconnectMsg() {
|
||||
return reloadDisconnectMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMinimizeCooldown() {
|
||||
return minimizeCooldown;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean is1_13TeamColourFix() {
|
||||
return teamColourFix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuppressConversionWarnings() {
|
||||
return suppressConversionWarnings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDisable1_13AutoComplete() {
|
||||
return disable1_13TabComplete;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isServersideBlockConnections() {
|
||||
return serversideBlockConnections;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBlockConnectionMethod() {
|
||||
return "packet";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReduceBlockStorageMemory() {
|
||||
return reduceBlockStorageMemory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStemWhenBlockAbove() {
|
||||
return flowerStemWhenBlockAbove;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVineClimbFix() {
|
||||
return vineClimbFix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSnowCollisionFix() {
|
||||
return snowCollisionFix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInfestedBlocksFix() {
|
||||
return infestedBlocksFix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int get1_13TabCompleteDelay() {
|
||||
return tabCompleteDelay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTruncate1_14Books() {
|
||||
return truncate1_14Books;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeftHandedHandling() {
|
||||
return leftHandedHandling;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean is1_9HitboxFix() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean is1_14HitboxFix() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNonFullBlockLightFix() {
|
||||
return fullBlockLightFix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean is1_14HealthNaNFix() {
|
||||
return healthNaNFix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean is1_15InstantRespawn() {
|
||||
return instantRespawn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIgnoreLong1_16ChannelNames() {
|
||||
return ignoreLongChannelNames;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
package us.myles.ViaVersion;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.platform.TaskId;
|
||||
import us.myles.ViaVersion.api.platform.ViaConnectionManager;
|
||||
import us.myles.ViaVersion.api.platform.ViaInjector;
|
||||
import us.myles.ViaVersion.api.platform.ViaPlatform;
|
||||
import us.myles.ViaVersion.api.platform.ViaPlatformLoader;
|
||||
import us.myles.ViaVersion.api.platform.providers.ViaProviders;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolVersion;
|
||||
import us.myles.ViaVersion.commands.ViaCommandHandler;
|
||||
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.TabCompleteThread;
|
||||
import us.myles.ViaVersion.protocols.protocol1_9to1_8.ViaIdleThread;
|
||||
import us.myles.ViaVersion.update.UpdateUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ViaManager {
|
||||
private final ViaPlatform<?> platform;
|
||||
private final ViaProviders providers = new ViaProviders();
|
||||
// Internals
|
||||
private final ViaInjector injector;
|
||||
private final ViaCommandHandler commandHandler;
|
||||
private final ViaPlatformLoader loader;
|
||||
private final Set<String> subPlatforms = new HashSet<>();
|
||||
private List<Runnable> enableListeners = new ArrayList<>();
|
||||
private TaskId mappingLoadingTask;
|
||||
private boolean debug;
|
||||
|
||||
public ViaManager(ViaPlatform<?> platform, ViaInjector injector, ViaCommandHandler commandHandler, ViaPlatformLoader loader) {
|
||||
this.platform = platform;
|
||||
this.injector = injector;
|
||||
this.commandHandler = commandHandler;
|
||||
this.loader = loader;
|
||||
}
|
||||
|
||||
public static ViaManagerBuilder builder() {
|
||||
return new ViaManagerBuilder();
|
||||
}
|
||||
|
||||
public void init() {
|
||||
if (System.getProperty("ViaVersion") != null) {
|
||||
// Reload?
|
||||
platform.onReload();
|
||||
}
|
||||
// Check for updates
|
||||
if (platform.getConf().isCheckForUpdates()) {
|
||||
UpdateUtil.sendUpdateMessage();
|
||||
}
|
||||
|
||||
// Force class load
|
||||
ProtocolRegistry.init();
|
||||
|
||||
// Inject
|
||||
try {
|
||||
injector.inject();
|
||||
} catch (Exception e) {
|
||||
platform.getLogger().severe("ViaVersion failed to inject:");
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
|
||||
// Mark as injected
|
||||
System.setProperty("ViaVersion", platform.getPluginVersion());
|
||||
|
||||
for (Runnable listener : enableListeners) {
|
||||
listener.run();
|
||||
}
|
||||
enableListeners = null;
|
||||
|
||||
// If successful
|
||||
platform.runSync(this::onServerLoaded);
|
||||
}
|
||||
|
||||
public void onServerLoaded() {
|
||||
// Load Server Protocol
|
||||
try {
|
||||
ProtocolRegistry.SERVER_PROTOCOL = injector.getServerProtocolVersion();
|
||||
} catch (Exception e) {
|
||||
platform.getLogger().severe("ViaVersion failed to get the server protocol!");
|
||||
e.printStackTrace();
|
||||
}
|
||||
// Check if there are any pipes to this version
|
||||
if (ProtocolRegistry.SERVER_PROTOCOL != -1) {
|
||||
platform.getLogger().info("ViaVersion detected server version: " + ProtocolVersion.getProtocol(ProtocolRegistry.SERVER_PROTOCOL));
|
||||
if (!ProtocolRegistry.isWorkingPipe()) {
|
||||
platform.getLogger().warning("ViaVersion does not have any compatible versions for this server version!");
|
||||
platform.getLogger().warning("Please remember that ViaVersion only adds support for versions newer than the server version.");
|
||||
platform.getLogger().warning("If you need support for older versions you may need to use one or more ViaVersion addons too.");
|
||||
platform.getLogger().warning("In that case please read the ViaVersion resource page carefully, and if you're");
|
||||
platform.getLogger().warning("still unsure, feel free to join our Discord-Server for further assistance.");
|
||||
}
|
||||
}
|
||||
// Load Listeners / Tasks
|
||||
ProtocolRegistry.onServerLoaded();
|
||||
|
||||
// Load Platform
|
||||
loader.load();
|
||||
// Common tasks
|
||||
mappingLoadingTask = Via.getPlatform().runRepeatingSync(() -> {
|
||||
if (ProtocolRegistry.checkForMappingCompletion()) {
|
||||
platform.cancelTask(mappingLoadingTask);
|
||||
mappingLoadingTask = null;
|
||||
}
|
||||
}, 10L);
|
||||
if (ProtocolRegistry.SERVER_PROTOCOL < ProtocolVersion.v1_9.getId()) {
|
||||
if (Via.getConfig().isSimulatePlayerTick()) {
|
||||
Via.getPlatform().runRepeatingSync(new ViaIdleThread(), 1L);
|
||||
}
|
||||
}
|
||||
if (ProtocolRegistry.SERVER_PROTOCOL < ProtocolVersion.v1_13.getId()) {
|
||||
if (Via.getConfig().get1_13TabCompleteDelay() > 0) {
|
||||
Via.getPlatform().runRepeatingSync(new TabCompleteThread(), 1L);
|
||||
}
|
||||
}
|
||||
|
||||
// Refresh Versions
|
||||
ProtocolRegistry.refreshVersions();
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
// Uninject
|
||||
platform.getLogger().info("ViaVersion is disabling, if this is a reload and you experience issues consider rebooting.");
|
||||
try {
|
||||
injector.uninject();
|
||||
} catch (Exception e) {
|
||||
platform.getLogger().severe("ViaVersion failed to uninject:");
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// Unload
|
||||
loader.unload();
|
||||
}
|
||||
|
||||
public Set<UserConnection> getConnections() {
|
||||
return platform.getConnectionManager().getConnections();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use getConnectedClients()
|
||||
*/
|
||||
@Deprecated
|
||||
public Map<UUID, UserConnection> getPortedPlayers() {
|
||||
return getConnectedClients();
|
||||
}
|
||||
|
||||
public Map<UUID, UserConnection> getConnectedClients() {
|
||||
return platform.getConnectionManager().getConnectedClients();
|
||||
}
|
||||
|
||||
public UUID getConnectedClientId(UserConnection conn) {
|
||||
return platform.getConnectionManager().getConnectedClientId(conn);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ViaConnectionManager#isClientConnected(UUID)
|
||||
*/
|
||||
public boolean isClientConnected(UUID player) {
|
||||
return platform.getConnectionManager().isClientConnected(player);
|
||||
}
|
||||
|
||||
public void handleLoginSuccess(UserConnection info) {
|
||||
platform.getConnectionManager().onLoginSuccess(info);
|
||||
}
|
||||
|
||||
public ViaPlatform<?> getPlatform() {
|
||||
return platform;
|
||||
}
|
||||
|
||||
public ViaProviders getProviders() {
|
||||
return providers;
|
||||
}
|
||||
|
||||
public boolean isDebug() {
|
||||
return debug;
|
||||
}
|
||||
|
||||
public void setDebug(boolean debug) {
|
||||
this.debug = debug;
|
||||
}
|
||||
|
||||
public ViaInjector getInjector() {
|
||||
return injector;
|
||||
}
|
||||
|
||||
public ViaCommandHandler getCommandHandler() {
|
||||
return commandHandler;
|
||||
}
|
||||
|
||||
public ViaPlatformLoader getLoader() {
|
||||
return loader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a mutable set of self-added subplatform version strings.
|
||||
* This set is expanded by the subplatform itself (e.g. ViaBackwards), and may not contain all running ones.
|
||||
*
|
||||
* @return mutable set of subplatform versions
|
||||
*/
|
||||
public Set<String> getSubPlatforms() {
|
||||
return subPlatforms;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ViaConnectionManager#getConnectedClient(UUID)
|
||||
*/
|
||||
@Nullable
|
||||
public UserConnection getConnection(UUID playerUUID) {
|
||||
return platform.getConnectionManager().getConnectedClient(playerUUID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a runnable to be executed when ViaVersion has finished its init before the full server load.
|
||||
*
|
||||
* @param runnable runnable to be executed
|
||||
*/
|
||||
public void addEnableListener(Runnable runnable) {
|
||||
enableListeners.add(runnable);
|
||||
}
|
||||
|
||||
public static final class ViaManagerBuilder {
|
||||
private ViaPlatform<?> platform;
|
||||
private ViaInjector injector;
|
||||
private ViaCommandHandler commandHandler;
|
||||
private ViaPlatformLoader loader;
|
||||
|
||||
public ViaManagerBuilder platform(ViaPlatform<?> platform) {
|
||||
this.platform = platform;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ViaManagerBuilder injector(ViaInjector injector) {
|
||||
this.injector = injector;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ViaManagerBuilder loader(ViaPlatformLoader loader) {
|
||||
this.loader = loader;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ViaManagerBuilder commandHandler(ViaCommandHandler commandHandler) {
|
||||
this.commandHandler = commandHandler;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ViaManager build() {
|
||||
return new ViaManager(platform, injector, commandHandler, loader);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,537 @@
|
||||
package us.myles.ViaVersion.api;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.protocol.Protocol;
|
||||
import us.myles.ViaVersion.api.remapper.ValueCreator;
|
||||
import us.myles.ViaVersion.api.type.Type;
|
||||
import us.myles.ViaVersion.api.type.TypeConverter;
|
||||
import us.myles.ViaVersion.exception.CancelException;
|
||||
import us.myles.ViaVersion.exception.InformativeException;
|
||||
import us.myles.ViaVersion.packets.Direction;
|
||||
import us.myles.ViaVersion.packets.State;
|
||||
import us.myles.ViaVersion.util.PipelineUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
public class PacketWrapper {
|
||||
public static final int PASSTHROUGH_ID = 1000;
|
||||
|
||||
private final ByteBuf inputBuffer;
|
||||
private final UserConnection userConnection;
|
||||
private boolean send = true;
|
||||
private int id = -1;
|
||||
private final LinkedList<Pair<Type, Object>> readableObjects = new LinkedList<>();
|
||||
private final List<Pair<Type, Object>> packetValues = new ArrayList<>();
|
||||
|
||||
public PacketWrapper(int packetID, ByteBuf inputBuffer, UserConnection userConnection) {
|
||||
this.id = packetID;
|
||||
this.inputBuffer = inputBuffer;
|
||||
this.userConnection = userConnection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a part from the output
|
||||
*
|
||||
* @param type The type of the part you wish to get.
|
||||
* @param <T> The return type of the type you wish to get.
|
||||
* @param index The index of the part (relative to the type)
|
||||
* @return The requested type or throws ArrayIndexOutOfBounds
|
||||
* @throws InformativeException If it fails to find it, an exception will be thrown.
|
||||
*/
|
||||
public <T> T get(Type<T> type, int index) throws Exception {
|
||||
int currentIndex = 0;
|
||||
for (Pair<Type, Object> packetValue : packetValues) {
|
||||
if (packetValue.getKey() == type) { // Ref check
|
||||
if (currentIndex == index) {
|
||||
return (T) packetValue.getValue();
|
||||
}
|
||||
currentIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
Exception e = new ArrayIndexOutOfBoundsException("Could not find type " + type.getTypeName() + " at " + index);
|
||||
throw new InformativeException(e).set("Type", type.getTypeName()).set("Index", index).set("Packet ID", getId()).set("Data", packetValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a type is at an index
|
||||
*
|
||||
* @param type The type of the part you wish to get.
|
||||
* @param index The index of the part (relative to the type)
|
||||
* @return True if the type is at the index
|
||||
*/
|
||||
public boolean is(Type type, int index) {
|
||||
int currentIndex = 0;
|
||||
for (Pair<Type, Object> packetValue : packetValues) {
|
||||
if (packetValue.getKey() == type) { // Ref check
|
||||
if (currentIndex == index) {
|
||||
return true;
|
||||
}
|
||||
currentIndex++;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a type is at an index
|
||||
*
|
||||
* @param type The type of the part you wish to get.
|
||||
* @param index The index of the part (relative to the type)
|
||||
* @return True if the type is at the index
|
||||
*/
|
||||
public boolean isReadable(Type type, int index) {
|
||||
int currentIndex = 0;
|
||||
for (Pair<Type, Object> packetValue : readableObjects) {
|
||||
if (packetValue.getKey().getBaseClass() == type.getBaseClass()) { // Ref check
|
||||
if (currentIndex == index) {
|
||||
return true;
|
||||
}
|
||||
currentIndex++;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set a currently existing part in the output
|
||||
*
|
||||
* @param type The type of the part you wish to set.
|
||||
* @param <T> The return type of the type you wish to set.
|
||||
* @param index The index of the part (relative to the type)
|
||||
* @param value The value of the part you wish to set it to.
|
||||
* @throws InformativeException If it fails to set it, an exception will be thrown.
|
||||
*/
|
||||
public <T> void set(Type<T> type, int index, T value) throws Exception {
|
||||
int currentIndex = 0;
|
||||
for (Pair<Type, Object> packetValue : packetValues) {
|
||||
if (packetValue.getKey() == type) { // Ref check
|
||||
if (currentIndex == index) {
|
||||
packetValue.setValue(value);
|
||||
return;
|
||||
}
|
||||
currentIndex++;
|
||||
}
|
||||
}
|
||||
Exception e = new ArrayIndexOutOfBoundsException("Could not find type " + type.getTypeName() + " at " + index);
|
||||
throw new InformativeException(e).set("Type", type.getTypeName()).set("Index", index).set("Packet ID", getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a type from the input.
|
||||
*
|
||||
* @param type The type you wish to read
|
||||
* @param <T> The return type of the type you wish to read.
|
||||
* @return The requested type
|
||||
* @throws InformativeException If it fails to read
|
||||
*/
|
||||
public <T> T read(Type<T> type) throws Exception {
|
||||
if (type == Type.NOTHING) return null;
|
||||
if (readableObjects.isEmpty()) {
|
||||
Preconditions.checkNotNull(inputBuffer, "This packet does not have an input buffer.");
|
||||
// We could in the future log input read values, but honestly for things like bulk maps, mem waste D:
|
||||
try {
|
||||
return type.read(inputBuffer);
|
||||
} catch (Exception e) {
|
||||
throw new InformativeException(e).set("Type", type.getTypeName()).set("Packet ID", getId()).set("Data", packetValues);
|
||||
}
|
||||
} else {
|
||||
Pair<Type, Object> read = readableObjects.poll();
|
||||
Type rtype = read.getKey();
|
||||
if (rtype.equals(type) || (type.getBaseClass().equals(rtype.getBaseClass()) && type.getOutputClass().equals(rtype.getOutputClass()))) {
|
||||
return (T) read.getValue();
|
||||
} else {
|
||||
if (rtype == Type.NOTHING) {
|
||||
return read(type); // retry
|
||||
} else {
|
||||
Exception e = new IOException("Unable to read type " + type.getTypeName() + ", found " + read.getKey().getTypeName());
|
||||
throw new InformativeException(e).set("Type", type.getTypeName()).set("Packet ID", getId()).set("Data", packetValues);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a type to the output.
|
||||
*
|
||||
* @param type The type to write.
|
||||
* @param <T> The return type of the type you wish to write.
|
||||
* @param value The value of the type to write.
|
||||
*/
|
||||
public <T> void write(Type<T> type, T value) {
|
||||
if (value != null) {
|
||||
if (!type.getOutputClass().isAssignableFrom(value.getClass())) {
|
||||
// attempt conversion
|
||||
if (type instanceof TypeConverter) {
|
||||
value = (T) ((TypeConverter) type).from(value);
|
||||
} else {
|
||||
Via.getPlatform().getLogger().warning("Possible type mismatch: " + value.getClass().getName() + " -> " + type.getOutputClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
packetValues.add(new Pair<Type, Object>(type, value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Take a value from the input and write to the output.
|
||||
*
|
||||
* @param type The type to read and write.
|
||||
* @param <T> The return type of the type you wish to pass through.
|
||||
* @return The type which was read/written.
|
||||
* @throws Exception If it failed to read or write
|
||||
*/
|
||||
public <T> T passthrough(Type<T> type) throws Exception {
|
||||
T value = read(type);
|
||||
write(type, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take all the inputs and write them to the output.
|
||||
*
|
||||
* @throws Exception If it failed to read or write
|
||||
*/
|
||||
public void passthroughAll() throws Exception {
|
||||
// Copy previous objects
|
||||
packetValues.addAll(readableObjects);
|
||||
readableObjects.clear();
|
||||
// If the buffer has readable bytes, copy them.
|
||||
if (inputBuffer.readableBytes() > 0) {
|
||||
passthrough(Type.REMAINING_BYTES);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the current output to a buffer.
|
||||
*
|
||||
* @param buffer The buffer to write to.
|
||||
* @throws InformativeException Throws an exception if it fails to write a value.
|
||||
*/
|
||||
public void writeToBuffer(ByteBuf buffer) throws Exception {
|
||||
if (id != -1) {
|
||||
Type.VAR_INT.writePrimitive(buffer, id);
|
||||
}
|
||||
if (!readableObjects.isEmpty()) {
|
||||
packetValues.addAll(readableObjects);
|
||||
readableObjects.clear();
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
for (Pair<Type, Object> packetValue : packetValues) {
|
||||
try {
|
||||
Object value = packetValue.getValue();
|
||||
if (value != null) {
|
||||
if (!packetValue.getKey().getOutputClass().isAssignableFrom(value.getClass())) {
|
||||
// attempt conversion
|
||||
if (packetValue.getKey() instanceof TypeConverter) {
|
||||
value = ((TypeConverter) packetValue.getKey()).from(value);
|
||||
} else {
|
||||
Via.getPlatform().getLogger().warning("Possible type mismatch: " + value.getClass().getName() + " -> " + packetValue.getKey().getOutputClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
packetValue.getKey().write(buffer, value);
|
||||
} catch (Exception e) {
|
||||
throw new InformativeException(e).set("Index", index).set("Type", packetValue.getKey().getTypeName()).set("Packet ID", getId()).set("Data", packetValues);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
writeRemaining(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the input buffer / readable objects
|
||||
*/
|
||||
public void clearInputBuffer() {
|
||||
if (inputBuffer != null) {
|
||||
inputBuffer.clear();
|
||||
}
|
||||
readableObjects.clear(); // :(
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the packet, used if you have to change the packet completely
|
||||
*/
|
||||
public void clearPacket() {
|
||||
clearInputBuffer();
|
||||
packetValues.clear();
|
||||
}
|
||||
|
||||
private void writeRemaining(ByteBuf output) {
|
||||
if (inputBuffer != null) {
|
||||
output.writeBytes(inputBuffer, inputBuffer.readableBytes());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send this packet to the associated user.
|
||||
* Be careful not to send packets twice.
|
||||
* (Sends it after current)
|
||||
*
|
||||
* @param packetProtocol The protocol version of the packet.
|
||||
* @param skipCurrentPipeline Skip the current pipeline
|
||||
* @throws Exception if it fails to write
|
||||
*/
|
||||
public void send(Class<? extends Protocol> packetProtocol, boolean skipCurrentPipeline) throws Exception {
|
||||
send(packetProtocol, skipCurrentPipeline, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send this packet to the associated user.
|
||||
* Be careful not to send packets twice.
|
||||
* (Sends it after current)
|
||||
*
|
||||
* @param packetProtocol The protocol version of the packet.
|
||||
* @param skipCurrentPipeline Skip the current pipeline
|
||||
* @param currentThread Run in the same thread
|
||||
* @throws Exception if it fails to write
|
||||
*/
|
||||
public void send(Class<? extends Protocol> packetProtocol, boolean skipCurrentPipeline, boolean currentThread) throws Exception {
|
||||
if (!isCancelled()) {
|
||||
try {
|
||||
ByteBuf output = constructPacket(packetProtocol, skipCurrentPipeline, Direction.OUTGOING);
|
||||
user().sendRawPacket(output, currentThread);
|
||||
} catch (Exception e) {
|
||||
if (!PipelineUtil.containsCause(e, CancelException.class)) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Let the packet go through the protocol pipes and write it to ByteBuf
|
||||
*
|
||||
* @param packetProtocol The protocol version of the packet.
|
||||
* @param skipCurrentPipeline Skip the current pipeline
|
||||
* @return Packet buffer
|
||||
* @throws Exception if it fails to write
|
||||
*/
|
||||
private ByteBuf constructPacket(Class<? extends Protocol> packetProtocol, boolean skipCurrentPipeline, Direction direction) throws Exception {
|
||||
// Apply current pipeline
|
||||
List<Protocol> protocols = new ArrayList<>(user().getProtocolInfo().getPipeline().pipes());
|
||||
if (direction == Direction.OUTGOING) {
|
||||
// Other way if outgoing
|
||||
Collections.reverse(protocols);
|
||||
}
|
||||
int index = -1;
|
||||
for (int i = 0; i < protocols.size(); i++) {
|
||||
if (protocols.get(i).getClass().equals(packetProtocol)) {
|
||||
index = skipCurrentPipeline ? (i + 1) : (i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index == -1) throw new NoSuchElementException(packetProtocol.getCanonicalName());
|
||||
|
||||
// Reset reader before we start
|
||||
resetReader();
|
||||
|
||||
// Apply other protocols
|
||||
apply(direction, user().getProtocolInfo().getState(), index, protocols);
|
||||
// Send
|
||||
ByteBuf output = inputBuffer == null ? user().getChannel().alloc().buffer() : inputBuffer.alloc().buffer();
|
||||
writeToBuffer(output);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send this packet to the associated user.
|
||||
* Be careful not to send packets twice.
|
||||
* (Sends it after current)
|
||||
*
|
||||
* @param packetProtocol The protocol version of the packet.
|
||||
* @throws Exception if it fails to write
|
||||
*/
|
||||
public void send(Class<? extends Protocol> packetProtocol) throws Exception {
|
||||
send(packetProtocol, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send this packet to the associated user.
|
||||
* Be careful not to send packets twice.
|
||||
* (Sends it after current)
|
||||
* Also returns the packets ChannelFuture
|
||||
*
|
||||
* @param packetProtocol The protocol version of the packet.
|
||||
* @return The packets ChannelFuture
|
||||
* @throws Exception if it fails to write
|
||||
*/
|
||||
public ChannelFuture sendFuture(Class<? extends Protocol> packetProtocol) throws Exception {
|
||||
if (!isCancelled()) {
|
||||
ByteBuf output = constructPacket(packetProtocol, true, Direction.OUTGOING);
|
||||
return user().sendRawPacketFuture(output);
|
||||
}
|
||||
return user().getChannel().newFailedFuture(new Exception("Cancelled packet"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send this packet to the associated user.
|
||||
* Be careful not to send packets twice.
|
||||
* (Sends it after current)
|
||||
* <b>This method is no longer used, it's favoured to use {@link #send(Class)} as it will handle the pipeline properly.</b>
|
||||
*
|
||||
* @throws Exception if it fails to write
|
||||
*/
|
||||
@Deprecated
|
||||
public void send() throws Exception {
|
||||
if (!isCancelled()) {
|
||||
// Send
|
||||
ByteBuf output = inputBuffer == null ? user().getChannel().alloc().buffer() : inputBuffer.alloc().buffer();
|
||||
writeToBuffer(output);
|
||||
user().sendRawPacket(output);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new packet for the target of this packet.
|
||||
*
|
||||
* @param packetID The ID of the new packet
|
||||
* @return The newly created packet wrapper
|
||||
*/
|
||||
public PacketWrapper create(int packetID) {
|
||||
return new PacketWrapper(packetID, null, user());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new packet with values.
|
||||
*
|
||||
* @param packetID The ID of the new packet
|
||||
* @param init A ValueCreator to write to the packet.
|
||||
* @return The newly created packet wrapper
|
||||
* @throws Exception If it failed to write the values from the ValueCreator.
|
||||
*/
|
||||
public PacketWrapper create(int packetID, ValueCreator init) throws Exception {
|
||||
PacketWrapper wrapper = create(packetID);
|
||||
init.write(wrapper);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a pipeline from an index to the wrapper
|
||||
*
|
||||
* @param direction The direction
|
||||
* @param state The state
|
||||
* @param index The index to start from
|
||||
* @param pipeline The pipeline
|
||||
* @return The current packetwrapper
|
||||
* @throws Exception If it fails to transform a packet, exception will be thrown
|
||||
*/
|
||||
public PacketWrapper apply(Direction direction, State state, int index, List<Protocol> pipeline) throws Exception {
|
||||
for (int i = index; i < pipeline.size(); i++) { // Copy to prevent from removal.
|
||||
pipeline.get(i).transform(direction, state, this);
|
||||
// Reset the reader for the packetWrapper (So it can be recycled across packets)
|
||||
resetReader();
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel this packet from sending
|
||||
*/
|
||||
public void cancel() {
|
||||
this.send = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this packet is cancelled.
|
||||
*
|
||||
* @return True if the packet won't be sent.
|
||||
*/
|
||||
public boolean isCancelled() {
|
||||
return !this.send;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user associated with this Packet
|
||||
*
|
||||
* @return The user
|
||||
*/
|
||||
public UserConnection user() {
|
||||
return this.userConnection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the reader, so that it can be read again.
|
||||
*/
|
||||
public void resetReader() {
|
||||
// Move readable objects are packet values
|
||||
this.packetValues.addAll(readableObjects);
|
||||
this.readableObjects.clear();
|
||||
// Move all packet values to the readable for next packet.
|
||||
this.readableObjects.addAll(packetValues);
|
||||
this.packetValues.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the current packet to the server.
|
||||
* (Ensure the ID is suitable for viaversion)
|
||||
*
|
||||
* @throws Exception If it failed to write
|
||||
*/
|
||||
@Deprecated
|
||||
public void sendToServer() throws Exception {
|
||||
if (!isCancelled()) {
|
||||
ByteBuf output = inputBuffer == null ? user().getChannel().alloc().buffer() : inputBuffer.alloc().buffer();
|
||||
writeToBuffer(output);
|
||||
|
||||
user().sendRawPacketToServer(output, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send this packet to the server.
|
||||
*
|
||||
* @param packetProtocol The protocol version of the packet.
|
||||
* @param skipCurrentPipeline Skip the current pipeline
|
||||
* @param currentThread Run in the same thread
|
||||
* @throws Exception if it fails to write
|
||||
*/
|
||||
public void sendToServer(Class<? extends Protocol> packetProtocol, boolean skipCurrentPipeline, boolean currentThread) throws Exception {
|
||||
if (!isCancelled()) {
|
||||
try {
|
||||
ByteBuf output = constructPacket(packetProtocol, skipCurrentPipeline, Direction.INCOMING);
|
||||
user().sendRawPacketToServer(output, currentThread);
|
||||
} catch (Exception e) {
|
||||
if (!PipelineUtil.containsCause(e, CancelException.class)) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void sendToServer(Class<? extends Protocol> packetProtocol, boolean skipCurrentPipeline) throws Exception {
|
||||
sendToServer(packetProtocol, skipCurrentPipeline, false);
|
||||
}
|
||||
|
||||
public void sendToServer(Class<? extends Protocol> packetProtocol) throws Exception {
|
||||
sendToServer(packetProtocol, true);
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PacketWrapper{" +
|
||||
"packetValues=" + packetValues +
|
||||
", readableObjects=" + readableObjects +
|
||||
", id=" + id +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package us.myles.ViaVersion.api;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class Pair<X, Y> {
|
||||
private final X key;
|
||||
private Y value;
|
||||
|
||||
public Pair(@Nullable X key, @Nullable Y value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public X getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public Y getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(@Nullable Y value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Pair{" + key + ", " + value + '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Pair<?, ?> pair = (Pair<?, ?>) o;
|
||||
if (!Objects.equals(key, pair.key)) return false;
|
||||
return Objects.equals(value, pair.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = key != null ? key.hashCode() : 0;
|
||||
result = 31 * result + (value != null ? value.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package us.myles.ViaVersion.api;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class Triple<A, B, C> {
|
||||
private final A first;
|
||||
private final B second;
|
||||
private final C third;
|
||||
|
||||
public Triple(@Nullable A first, @Nullable B second, @Nullable C third) {
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
this.third = third;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public A getFirst() {
|
||||
return first;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public B getSecond() {
|
||||
return second;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public C getThird() {
|
||||
return third;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Triple{" + first + ", " + second + ", " + third + '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Triple<?, ?, ?> triple = (Triple<?, ?, ?>) o;
|
||||
if (!Objects.equals(first, triple.first)) return false;
|
||||
if (!Objects.equals(second, triple.second)) return false;
|
||||
return Objects.equals(third, triple.third);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = first != null ? first.hashCode() : 0;
|
||||
result = 31 * result + (second != null ? second.hashCode() : 0);
|
||||
result = 31 * result + (third != null ? third.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package us.myles.ViaVersion.api;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import us.myles.ViaVersion.ViaManager;
|
||||
import us.myles.ViaVersion.api.platform.ViaPlatform;
|
||||
|
||||
public class Via {
|
||||
private static ViaPlatform platform;
|
||||
private static ViaManager manager;
|
||||
|
||||
/**
|
||||
* Register the ViaManager associated with the platform.
|
||||
*
|
||||
* @param viaManager The ViaManager
|
||||
*/
|
||||
public static void init(ViaManager viaManager) {
|
||||
Preconditions.checkArgument(manager == null, "ViaManager is already set");
|
||||
|
||||
Via.platform = viaManager.getPlatform();
|
||||
Via.manager = viaManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the API associated with the current platform.
|
||||
*
|
||||
* @return API instance
|
||||
*/
|
||||
public static ViaAPI getAPI() {
|
||||
Preconditions.checkArgument(platform != null, "ViaVersion has not loaded the Platform");
|
||||
return Via.platform.getApi();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the config associated with the current platform.
|
||||
*
|
||||
* @return Config instance
|
||||
*/
|
||||
public static ViaVersionConfig getConfig() {
|
||||
Preconditions.checkArgument(platform != null, "ViaVersion has not loaded the Platform");
|
||||
return Via.platform.getConf();
|
||||
}
|
||||
|
||||
public static ViaPlatform getPlatform() {
|
||||
return platform;
|
||||
}
|
||||
|
||||
public static ViaManager getManager() {
|
||||
return manager;
|
||||
}
|
||||
}
|
||||
+111
-96
@@ -1,96 +1,111 @@
|
||||
package us.myles.ViaVersion.api;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import org.bukkit.entity.Player;
|
||||
import us.myles.ViaVersion.api.boss.BossBar;
|
||||
import us.myles.ViaVersion.api.boss.BossColor;
|
||||
import us.myles.ViaVersion.api.boss.BossStyle;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public interface ViaVersionAPI {
|
||||
/**
|
||||
* Is the player connection modified by ViaVersion?
|
||||
*
|
||||
* @param player Bukkit player object
|
||||
* @return True if the client is modified (At the moment it also means version 1.9 and higher)
|
||||
*/
|
||||
boolean isPorted(Player player);
|
||||
|
||||
/**
|
||||
* Get protocol number from a player
|
||||
*
|
||||
* @param player Bukkit player object
|
||||
* @return Protocol ID, For example (47=1.8-1.8.8, 107=1.9, 108=1.9.1)
|
||||
*/
|
||||
int getPlayerVersion(Player player);
|
||||
|
||||
/**
|
||||
* Get protocol number from a player
|
||||
*
|
||||
* @param uuid UUID of a player
|
||||
* @return Protocol ID, For example (47=1.8-1.8.8, 107=1.9, 108=1.9.1)
|
||||
*/
|
||||
int getPlayerVersion(UUID uuid);
|
||||
|
||||
/**
|
||||
* Is player using 1.9?
|
||||
*
|
||||
* @param playerUUID
|
||||
* @return True if the client is on 1.9
|
||||
*/
|
||||
boolean isPorted(UUID playerUUID);
|
||||
|
||||
/**
|
||||
* Get the version of the plugin
|
||||
*
|
||||
* @return Plugin version
|
||||
*/
|
||||
String getVersion();
|
||||
|
||||
/**
|
||||
* Send a raw packet to the player (Use new IDs)
|
||||
*
|
||||
* @param player The player to send packet
|
||||
* @param packet The packet, you need a VarInt ID then the packet contents.
|
||||
* @throws IllegalArgumentException If not on 1.9 throws IllegalArg
|
||||
*/
|
||||
void sendRawPacket(Player player, ByteBuf packet) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Send a raw packet to the player (Use new IDs)
|
||||
*
|
||||
* @param uuid The uuid from the player to send packet
|
||||
* @param packet The packet, you need a VarInt ID then the packet contents.
|
||||
* @throws IllegalArgumentException If not on 1.9 throws IllegalArg
|
||||
*/
|
||||
void sendRawPacket(UUID uuid, ByteBuf packet) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Create a new bossbar instance
|
||||
*
|
||||
* @param title The title
|
||||
* @param color The color
|
||||
* @param style The style
|
||||
* @return Bossbar instance
|
||||
*/
|
||||
BossBar createBossBar(String title, BossColor color, BossStyle style);
|
||||
|
||||
/**
|
||||
* Create a new bossbar instance
|
||||
*
|
||||
* @param title The title
|
||||
* @param health Number between 0 and 1
|
||||
* @param color The color
|
||||
* @param style The style
|
||||
* @return Bossbar instance
|
||||
*/
|
||||
BossBar createBossBar(String title, float health, BossColor color, BossStyle style);
|
||||
|
||||
/**
|
||||
* Get if global debug is enabled
|
||||
*
|
||||
* @return true if debug is enabled
|
||||
*/
|
||||
boolean isDebug();
|
||||
}
|
||||
package us.myles.ViaVersion.api;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import us.myles.ViaVersion.api.boss.BossBar;
|
||||
import us.myles.ViaVersion.api.boss.BossColor;
|
||||
import us.myles.ViaVersion.api.boss.BossStyle;
|
||||
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
|
||||
|
||||
import java.util.SortedSet;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Represents the ViaAPI
|
||||
*
|
||||
* @param <T> The player type for the specific platform, for bukkit it's {@code ViaAPI<Player>}
|
||||
*/
|
||||
public interface ViaAPI<T> {
|
||||
|
||||
/**
|
||||
* Get protocol number from a player
|
||||
* Will also retrieve version from ProtocolSupport if it's being used.
|
||||
*
|
||||
* @param player Platform player object, eg. Bukkit this is Player
|
||||
* @return Protocol ID, For example (47=1.8-1.8.8, 107=1.9, 108=1.9.1)
|
||||
*/
|
||||
int getPlayerVersion(T player);
|
||||
|
||||
/**
|
||||
* Get protocol number from a player
|
||||
*
|
||||
* @param uuid UUID of a player
|
||||
* @return Protocol ID, For example (47=1.8-1.8.8, 107=1.9, 108=1.9.1)
|
||||
*/
|
||||
int getPlayerVersion(UUID uuid);
|
||||
|
||||
/**
|
||||
* Returns if the player is ported by Via.
|
||||
*
|
||||
* @param playerUUID UUID of a player
|
||||
* @return true if Via has a cached userconnection for this player
|
||||
* @deprecated use {@link #isInjected(UUID)}
|
||||
* @see #isInjected(UUID)
|
||||
*/
|
||||
@Deprecated
|
||||
default boolean isPorted(UUID playerUUID) {
|
||||
return isInjected(playerUUID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if Via injected into this player connection
|
||||
*
|
||||
* @param playerUUID UUID of a player
|
||||
* @return true if Via has a cached UserConnection for this player
|
||||
*/
|
||||
boolean isInjected(UUID playerUUID);
|
||||
|
||||
/**
|
||||
* Get the version of the plugin
|
||||
*
|
||||
* @return Plugin version
|
||||
*/
|
||||
String getVersion();
|
||||
|
||||
/**
|
||||
* Send a raw packet to the player (Use new IDs)
|
||||
*
|
||||
* @param player Platform player object, eg. Bukkit this is Player
|
||||
* @param packet The packet, you need a VarInt ID then the packet contents.
|
||||
* @throws IllegalArgumentException if the player is not injected by Via
|
||||
*/
|
||||
void sendRawPacket(T player, ByteBuf packet);
|
||||
|
||||
/**
|
||||
* Send a raw packet to the player (Use new IDs)
|
||||
*
|
||||
* @param uuid The uuid from the player to send packet
|
||||
* @param packet The packet, you need a VarInt ID then the packet contents.
|
||||
* @throws IllegalArgumentException if the player is not injected by Via
|
||||
*/
|
||||
void sendRawPacket(UUID uuid, ByteBuf packet);
|
||||
|
||||
/**
|
||||
* Create a new bossbar instance
|
||||
*
|
||||
* @param title The title
|
||||
* @param color The color
|
||||
* @param style The style
|
||||
* @return BossBar instance
|
||||
*/
|
||||
BossBar createBossBar(String title, BossColor color, BossStyle style);
|
||||
|
||||
/**
|
||||
* Create a new bossbar instance
|
||||
*
|
||||
* @param title The title
|
||||
* @param health Number between 0 and 1
|
||||
* @param color The color
|
||||
* @param style The style
|
||||
* @return BossBar instance
|
||||
*/
|
||||
BossBar createBossBar(String title, float health, BossColor color, BossStyle style);
|
||||
|
||||
/**
|
||||
* Get the supported protocol versions
|
||||
* This method removes any blocked protocol versions.
|
||||
*
|
||||
* @return a list of protocol versions
|
||||
* @see ProtocolRegistry#getSupportedVersions() for full list.
|
||||
*/
|
||||
SortedSet<Integer> getSupportedVersions();
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package us.myles.ViaVersion.api;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
import us.myles.ViaVersion.api.protocol.Protocol;
|
||||
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public abstract class ViaListener {
|
||||
private final Class<? extends Protocol> requiredPipeline;
|
||||
private boolean registered;
|
||||
|
||||
public ViaListener(Class<? extends Protocol> requiredPipeline) {
|
||||
this.requiredPipeline = requiredPipeline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the UserConnection from an UUID
|
||||
*
|
||||
* @param uuid UUID object
|
||||
* @return The UserConnection
|
||||
*/
|
||||
@Nullable
|
||||
protected UserConnection getUserConnection(UUID uuid) {
|
||||
return Via.getManager().getConnection(uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the UUID is on the selected pipe
|
||||
*
|
||||
* @param uuid UUID Object
|
||||
* @return True if on pipe
|
||||
*/
|
||||
protected boolean isOnPipe(UUID uuid) {
|
||||
UserConnection userConnection = getUserConnection(uuid);
|
||||
return userConnection != null &&
|
||||
(requiredPipeline == null || userConnection.getProtocolInfo().getPipeline().contains(requiredPipeline));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the event
|
||||
*/
|
||||
public abstract void register();
|
||||
|
||||
protected Class<? extends Protocol> getRequiredPipeline() {
|
||||
return requiredPipeline;
|
||||
}
|
||||
|
||||
protected boolean isRegistered() {
|
||||
return registered;
|
||||
}
|
||||
|
||||
protected void setRegistered(boolean registered) {
|
||||
this.registered = registered;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,361 @@
|
||||
package us.myles.ViaVersion.api;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public interface ViaVersionConfig {
|
||||
|
||||
/**
|
||||
* Get if the plugin should check for updates
|
||||
*
|
||||
* @return true if update checking is enabled
|
||||
*/
|
||||
boolean isCheckForUpdates();
|
||||
|
||||
/**
|
||||
* Get if collision preventing for players is enabled
|
||||
*
|
||||
* @return true if collision preventing is enabled
|
||||
*/
|
||||
boolean isPreventCollision();
|
||||
|
||||
/**
|
||||
* Get if 1.9 & 1.10 clients are shown the new effect indicator in the top-right corner
|
||||
*
|
||||
* @return true if the using of the new effect indicator is enabled
|
||||
*/
|
||||
boolean isNewEffectIndicator();
|
||||
|
||||
/**
|
||||
* Get if 1.9 & 1.10 clients are shown the new death message on the death screen
|
||||
*
|
||||
* @return true if enabled
|
||||
*/
|
||||
boolean isShowNewDeathMessages();
|
||||
|
||||
/**
|
||||
* Get if metadata errors will be suppressed
|
||||
*
|
||||
* @return true if metadata errors suppression is enabled
|
||||
*/
|
||||
boolean isSuppressMetadataErrors();
|
||||
|
||||
/**
|
||||
* Get if blocking in 1.9 & 1.10 appears as a player holding a shield
|
||||
*
|
||||
* @return true if shield blocking is enabled
|
||||
*/
|
||||
boolean isShieldBlocking();
|
||||
|
||||
/**
|
||||
* Get if armor stand positions are fixed so holograms show up at the correct height in 1.9 & 1.10
|
||||
*
|
||||
* @return true if hologram patching is enabled
|
||||
*/
|
||||
boolean isHologramPatch();
|
||||
|
||||
/**
|
||||
* Get if the 1.11 piston animation patch is enabled
|
||||
*
|
||||
* @return true if the piston patch is enabled.
|
||||
*/
|
||||
boolean isPistonAnimationPatch();
|
||||
|
||||
/**
|
||||
* Get if boss bars are fixed for 1.9 & 1.10 clients
|
||||
*
|
||||
* @return true if boss bar patching is enabled
|
||||
*/
|
||||
boolean isBossbarPatch();
|
||||
|
||||
/**
|
||||
* Get if the boss bars for 1.9 & 1.10 clients are being stopped from flickering
|
||||
* This will keep all boss bars on 100% (not recommended)
|
||||
*
|
||||
* @return true if boss bar anti flickering is enabled
|
||||
*/
|
||||
boolean isBossbarAntiflicker();
|
||||
|
||||
/**
|
||||
* Get the vertical offset armor stands are being moved with when the hologram patch is enabled
|
||||
*
|
||||
* @return the vertical offset holograms will be moved with
|
||||
*/
|
||||
double getHologramYOffset();
|
||||
|
||||
/**
|
||||
* Get if players will be automatically put in the same team when collision preventing is enabled
|
||||
*
|
||||
* @return true if automatic teaming is enabled
|
||||
*/
|
||||
boolean isAutoTeam();
|
||||
|
||||
/**
|
||||
* Get the maximum number of packets a client can send per second.
|
||||
*
|
||||
* @return The number of packets a client can send per second.
|
||||
*/
|
||||
int getMaxPPS();
|
||||
|
||||
/**
|
||||
* Get the kick message sent if the user hits the max packets per second.
|
||||
*
|
||||
* @return Kick message, with colour codes using '&amp;'
|
||||
*/
|
||||
String getMaxPPSKickMessage();
|
||||
|
||||
/**
|
||||
* The time in seconds that should be tracked for warnings
|
||||
*
|
||||
* @return Time in seconds that should be tracked for warnings
|
||||
*/
|
||||
int getTrackingPeriod();
|
||||
|
||||
/**
|
||||
* The number of packets per second to count as a warning
|
||||
*
|
||||
* @return The number of packets per second to count as a warning.
|
||||
*/
|
||||
int getWarningPPS();
|
||||
|
||||
/**
|
||||
* Get the maximum number of warnings the client can have in the interval
|
||||
*
|
||||
* @return The number of packets a client can send per second.
|
||||
*/
|
||||
int getMaxWarnings();
|
||||
|
||||
/**
|
||||
* Get the kick message sent if the user goes over the warnings in the interval
|
||||
*
|
||||
* @return Kick message, with colour codes using '&amp;'
|
||||
*/
|
||||
String getMaxWarningsKickMessage();
|
||||
|
||||
/**
|
||||
* Is anti-xray enabled?
|
||||
*
|
||||
* @return A boolean
|
||||
*/
|
||||
boolean isAntiXRay();
|
||||
|
||||
/**
|
||||
* Send supported versions in the status response packet
|
||||
*
|
||||
* @return If true, enabled
|
||||
*/
|
||||
boolean isSendSupportedVersions();
|
||||
|
||||
/**
|
||||
* Stimulate the player tick
|
||||
*
|
||||
* @return if true, enabled
|
||||
*/
|
||||
boolean isSimulatePlayerTick();
|
||||
|
||||
/**
|
||||
* Use the item cache to prevent high resource usage
|
||||
*
|
||||
* @return if true, enabled
|
||||
*/
|
||||
boolean isItemCache();
|
||||
|
||||
/**
|
||||
* Use the NMS player ticking
|
||||
*
|
||||
* @return if true, enabled
|
||||
*/
|
||||
boolean isNMSPlayerTicking();
|
||||
|
||||
/**
|
||||
* Replace extended pistons on 1.10 chunk loading.
|
||||
*
|
||||
* @return true if to replace them
|
||||
*/
|
||||
boolean isReplacePistons();
|
||||
|
||||
/**
|
||||
* Get the id for replacing extended pistons.
|
||||
*
|
||||
* @return The integer id
|
||||
*/
|
||||
int getPistonReplacementId();
|
||||
|
||||
/**
|
||||
* Force json transform
|
||||
*
|
||||
* @return true if enabled
|
||||
*/
|
||||
boolean isForceJsonTransform();
|
||||
|
||||
/**
|
||||
* Should we fix nbt array's in json chat messages for 1.12 clients
|
||||
*
|
||||
* @return true if enabled
|
||||
*/
|
||||
boolean is1_12NBTArrayFix();
|
||||
|
||||
/**
|
||||
* Should we make team colours based on the last colour in team prefix
|
||||
*
|
||||
* @return true if enabled
|
||||
*/
|
||||
boolean is1_13TeamColourFix();
|
||||
|
||||
/**
|
||||
* Should we fix shift quick move action for 1.12 clients
|
||||
*
|
||||
* @return true if enabled
|
||||
*/
|
||||
boolean is1_12QuickMoveActionFix();
|
||||
|
||||
/**
|
||||
* Get the blocked protocols
|
||||
*
|
||||
* @return An Integer list
|
||||
*/
|
||||
Set<Integer> getBlockedProtocols();
|
||||
|
||||
/**
|
||||
* Get the custom disconnect message
|
||||
*
|
||||
* @return Disconnect message
|
||||
*/
|
||||
String getBlockedDisconnectMsg();
|
||||
|
||||
/**
|
||||
* Get the message sent to players being kicked on reload.
|
||||
* Players are kicked to stop the server crashing
|
||||
*
|
||||
* @return Disconnect message
|
||||
*/
|
||||
String getReloadDisconnectMsg();
|
||||
|
||||
/**
|
||||
* Should we hide errors that occur when trying to convert block and item data over versions?
|
||||
*
|
||||
* @return true if enabled
|
||||
*/
|
||||
boolean isSuppressConversionWarnings();
|
||||
|
||||
/**
|
||||
* Should we disable the 1.13 auto-complete feature to stop spam kicks? (for any server lower than 1.13)
|
||||
*
|
||||
* @return true if enabled
|
||||
*/
|
||||
boolean isDisable1_13AutoComplete();
|
||||
|
||||
/**
|
||||
* Tries to minimize cooldown animation.
|
||||
*
|
||||
* @return true if enabled
|
||||
*/
|
||||
boolean isMinimizeCooldown();
|
||||
|
||||
/**
|
||||
* Enable the serverside blockconnections for 1.13+ clients
|
||||
*
|
||||
* @return true if enabled
|
||||
*/
|
||||
boolean isServersideBlockConnections();
|
||||
|
||||
/**
|
||||
* Get the type of block-connection provider which should be used
|
||||
*
|
||||
* @return String world for world-level or packet for packet-level
|
||||
*/
|
||||
String getBlockConnectionMethod();
|
||||
|
||||
/**
|
||||
* When activated, only the most important blocks are saved in the BlockStorage.
|
||||
*
|
||||
* @return true if enabled
|
||||
*/
|
||||
boolean isReduceBlockStorageMemory();
|
||||
|
||||
/**
|
||||
* When activated with serverside-blockconnections, flower parts with blocks above will be sent as stems.
|
||||
* Useful for lobbyservers where users can't build and those stems are used decoratively.
|
||||
*
|
||||
* @return true if enabled
|
||||
*/
|
||||
boolean isStemWhenBlockAbove();
|
||||
|
||||
/**
|
||||
* Vines not connected to any blocks will be mapped to air for 1.13+ clients to prevent them from climbing up.
|
||||
*
|
||||
* @return true if enabled
|
||||
*/
|
||||
boolean isVineClimbFix();
|
||||
|
||||
/**
|
||||
* When activated, the 1-layer snow will be sent as 2-layer snow to 1.13+ clients to have collision.
|
||||
*
|
||||
* @return true if enabled
|
||||
*/
|
||||
boolean isSnowCollisionFix();
|
||||
|
||||
/**
|
||||
* When activated, infested blocks will be mapped to their normal stone variants for 1.13+ clients.
|
||||
*
|
||||
* @return true if enabled
|
||||
*/
|
||||
boolean isInfestedBlocksFix();
|
||||
|
||||
/**
|
||||
* When greater than 0, enables tab complete request delaying by x ticks
|
||||
*
|
||||
* @return the delay in ticks
|
||||
*/
|
||||
int get1_13TabCompleteDelay();
|
||||
|
||||
/**
|
||||
* When activated, edited books with more than 50 pages will be shortened to 50.
|
||||
*
|
||||
* @return true if enabled
|
||||
*/
|
||||
boolean isTruncate1_14Books();
|
||||
|
||||
/**
|
||||
* Handles left handed info by using unused bit 7 on Client Settings packet
|
||||
*
|
||||
* @return true if enabled
|
||||
*/
|
||||
boolean isLeftHandedHandling();
|
||||
|
||||
/**
|
||||
* Fixes velocity bugs due to different hitbox for 1.9-1.13 clients on 1.8 servers.
|
||||
*
|
||||
* @return true if enabled
|
||||
*/
|
||||
boolean is1_9HitboxFix();
|
||||
|
||||
/**
|
||||
* Fixes velocity bugs due to different hitbox for 1.14+ clients on sub 1.14 servers.
|
||||
*
|
||||
* @return true if enabled
|
||||
*/
|
||||
boolean is1_14HitboxFix();
|
||||
|
||||
/**
|
||||
* Fixes non full blocks having 0 light for 1.14+ clients on sub 1.14 servers.
|
||||
*
|
||||
* @return true if enabled
|
||||
*/
|
||||
boolean isNonFullBlockLightFix();
|
||||
|
||||
boolean is1_14HealthNaNFix();
|
||||
|
||||
/**
|
||||
* Should 1.15 clients respawn instantly / without showing the death screen.
|
||||
*
|
||||
* @return true if enabled
|
||||
*/
|
||||
boolean is1_15InstantRespawn();
|
||||
|
||||
/**
|
||||
* Ignores incoming plugin channel messages of 1.16+ clients with channel names longer than 32 charatcers.
|
||||
*
|
||||
* @return true if enabled
|
||||
*/
|
||||
boolean isIgnoreLong1_16ChannelNames();
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
package us.myles.ViaVersion.api.boss;
|
||||
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.data.UserConnection;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public abstract class BossBar<T> {
|
||||
|
||||
/**
|
||||
* Get the current title
|
||||
*
|
||||
* @return the title
|
||||
*/
|
||||
public abstract String getTitle();
|
||||
|
||||
/**
|
||||
* Change the title
|
||||
*
|
||||
* @param title Title can be in either JSON or just text
|
||||
* @return The BossBar object
|
||||
*/
|
||||
public abstract BossBar setTitle(String title);
|
||||
|
||||
/**
|
||||
* Get the health
|
||||
*
|
||||
* @return float between 0F - 1F
|
||||
*/
|
||||
public abstract float getHealth();
|
||||
|
||||
/**
|
||||
* Change the health
|
||||
*
|
||||
* @param health this float has to be between 0F - 1F
|
||||
* @return The BossBar object
|
||||
*/
|
||||
public abstract BossBar setHealth(float health);
|
||||
|
||||
/**
|
||||
* Get the bossbar color
|
||||
*
|
||||
* @return The colour
|
||||
*/
|
||||
public abstract BossColor getColor();
|
||||
|
||||
/**
|
||||
* Yay colors!
|
||||
*
|
||||
* @param color Whatever color you want!
|
||||
* @return The BossBar object
|
||||
*/
|
||||
public abstract BossBar setColor(BossColor color);
|
||||
|
||||
/**
|
||||
* Get the bosbar style
|
||||
*
|
||||
* @return BossStyle
|
||||
*/
|
||||
public abstract BossStyle getStyle();
|
||||
|
||||
/**
|
||||
* Change the bosbar style
|
||||
*
|
||||
* @param style BossStyle
|
||||
* @return The BossBar object
|
||||
*/
|
||||
public abstract BossBar setStyle(BossStyle style);
|
||||
|
||||
/**
|
||||
* Show the bossbar to a player.
|
||||
*
|
||||
* @param player The player
|
||||
* @return The BossBar object
|
||||
* @deprecated Deprecated use UUID's instead of Player objects {@link #addPlayer(UUID)}
|
||||
*/
|
||||
@Deprecated
|
||||
public BossBar addPlayer(T player) {
|
||||
throw new UnsupportedOperationException("This method is not implemented for the platform " + Via.getPlatform().getPlatformName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the bossbar to a player (uuid). This only works for frontend connections. Use #addConnection(UserConnection) for other types.
|
||||
*
|
||||
* @param player uuid of the player
|
||||
* @return The BossBar object
|
||||
*/
|
||||
public abstract BossBar addPlayer(UUID player);
|
||||
|
||||
/**
|
||||
* Show the bossbar to a player connection.
|
||||
*
|
||||
* @param conn UserConnection of the connection
|
||||
* @return The BossBar object
|
||||
*/
|
||||
public abstract BossBar addConnection(UserConnection conn);
|
||||
|
||||
/**
|
||||
* add multiple players
|
||||
*
|
||||
* @param players list of players
|
||||
* @return The BossBar object
|
||||
* @deprecated Deprecated use UUID's instead of Player objects {@link #addPlayer(UUID)}
|
||||
*/
|
||||
@Deprecated
|
||||
public BossBar addPlayers(T... players) {
|
||||
throw new UnsupportedOperationException("This method is not implemented for the platform " + Via.getPlatform().getPlatformName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the bossbar from a player
|
||||
*
|
||||
* @param player The player
|
||||
* @return The BossBar object
|
||||
* @deprecated Deprecated use UUID's instead of Player objects {@link #removePlayer(UUID)}
|
||||
*/
|
||||
@Deprecated
|
||||
public BossBar removePlayer(T player) {
|
||||
throw new UnsupportedOperationException("This method is not implemented for the platform " + Via.getPlatform().getPlatformName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the bossbar from a player. This only works for frontend connections. For others types, use #removeConnection(UserConnection)
|
||||
*
|
||||
* @param uuid The players UUID
|
||||
* @return The BossBar object
|
||||
*/
|
||||
public abstract BossBar removePlayer(UUID uuid);
|
||||
|
||||
/**
|
||||
* Removes the bossbar from a player connection.
|
||||
*
|
||||
* @param conn The UserConnection
|
||||
* @return The BossBar object
|
||||
*/
|
||||
public abstract BossBar removeConnection(UserConnection conn);
|
||||
|
||||
/**
|
||||
* Add flags
|
||||
*
|
||||
* @param flag The flag to add
|
||||
* @return The BossBar object
|
||||
*/
|
||||
public abstract BossBar addFlag(BossFlag flag);
|
||||
|
||||
/**
|
||||
* Remove flags.
|
||||
*
|
||||
* @param flag The flag to remove
|
||||
* @return The BossBar object
|
||||
*/
|
||||
public abstract BossBar removeFlag(BossFlag flag);
|
||||
|
||||
/**
|
||||
* @param flag The flag to check against
|
||||
* @return True if it has the flag
|
||||
*/
|
||||
public abstract boolean hasFlag(BossFlag flag);
|
||||
|
||||
/**
|
||||
* Get players. Only returns UUIDs which are front-end. For all connections, use #getConnections()
|
||||
*
|
||||
* @return UUIDS from players (sorry I lied)
|
||||
*/
|
||||
public abstract Set<UUID> getPlayers();
|
||||
|
||||
/**
|
||||
* Get UserConnections.
|
||||
*
|
||||
* @return UserConnection from players
|
||||
*/
|
||||
public abstract Set<UserConnection> getConnections();
|
||||
|
||||
/**
|
||||
* Show the bossbar to everyone (In the getPlayer set)
|
||||
*
|
||||
* @return The BossBar object
|
||||
*/
|
||||
public abstract BossBar show();
|
||||
|
||||
/**
|
||||
* Hide the bossbar from everyone (In the getPlayer set)
|
||||
*
|
||||
* @return The BossBar object
|
||||
*/
|
||||
public abstract BossBar hide();
|
||||
|
||||
/**
|
||||
* Is it visible?
|
||||
*
|
||||
* @return visibility changable with show() and hide()
|
||||
*/
|
||||
public abstract boolean isVisible();
|
||||
|
||||
/**
|
||||
* Get the UUID of this bossbar
|
||||
*
|
||||
* @return Unique Id for this bossbar
|
||||
*/
|
||||
public abstract UUID getId();
|
||||
}
|
||||
+9
-5
@@ -1,11 +1,7 @@
|
||||
package us.myles.ViaVersion.api.boss;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum BossColor {
|
||||
|
||||
PINK(0),
|
||||
BLUE(1),
|
||||
RED(2),
|
||||
@@ -15,4 +11,12 @@ public enum BossColor {
|
||||
WHITE(6);
|
||||
|
||||
private final int id;
|
||||
|
||||
BossColor(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
+9
-5
@@ -1,13 +1,17 @@
|
||||
package us.myles.ViaVersion.api.boss;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum BossFlag {
|
||||
|
||||
DARKEN_SKY(1),
|
||||
PLAY_BOSS_MUSIC(2);
|
||||
|
||||
private final int id;
|
||||
|
||||
BossFlag(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
+9
-5
@@ -1,11 +1,7 @@
|
||||
package us.myles.ViaVersion.api.boss;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum BossStyle {
|
||||
|
||||
SOLID(0),
|
||||
SEGMENTED_6(1),
|
||||
SEGMENTED_10(2),
|
||||
@@ -13,4 +9,12 @@ public enum BossStyle {
|
||||
SEGMENTED_20(4);
|
||||
|
||||
private final int id;
|
||||
|
||||
BossStyle(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package us.myles.ViaVersion.api.command;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public interface ViaCommandSender {
|
||||
/**
|
||||
* Check if the sender has a permission.
|
||||
*
|
||||
* @param permission Permission string eg. viaversion.admin
|
||||
* @return True if the sender has the permission
|
||||
*/
|
||||
boolean hasPermission(String permission);
|
||||
|
||||
/**
|
||||
* Send a message to the sender
|
||||
*
|
||||
* @param msg The message to send
|
||||
*/
|
||||
void sendMessage(String msg);
|
||||
|
||||
/**
|
||||
* Get the senders UUID.
|
||||
*
|
||||
* @return The senders UUID
|
||||
*/
|
||||
UUID getUUID();
|
||||
|
||||
/**
|
||||
* Get the senders name.
|
||||
*
|
||||
* @return The senders name
|
||||
*/
|
||||
String getName();
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package us.myles.ViaVersion.api.command;
|
||||
|
||||
import us.myles.ViaVersion.commands.ViaCommandHandler;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class ViaSubCommand {
|
||||
/**
|
||||
* Subcommand name
|
||||
*
|
||||
* @return The commands name
|
||||
*/
|
||||
public abstract String name();
|
||||
|
||||
/**
|
||||
* subcommand description, this'll show in /viaversion list
|
||||
*
|
||||
* @return The commands description
|
||||
*/
|
||||
public abstract String description();
|
||||
|
||||
/**
|
||||
* Usage example:
|
||||
* "playerversion [name]"
|
||||
*
|
||||
* @return The commands usage
|
||||
*/
|
||||
public String usage() {
|
||||
return name();
|
||||
}
|
||||
|
||||
/**
|
||||
* Permission, null for everyone
|
||||
*
|
||||
* @return The permission required to use the commands
|
||||
*/
|
||||
public String permission() {
|
||||
return "viaversion.admin";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets triggered on execution
|
||||
*
|
||||
* @param sender Command sender
|
||||
* @param args Arguments
|
||||
* @return commands executed succesfully if false, show usage
|
||||
*/
|
||||
public abstract boolean execute(ViaCommandSender sender, String[] args);
|
||||
|
||||
/**
|
||||
* Yay, possibility to implement tab-completion
|
||||
*
|
||||
* @param sender Command sender
|
||||
* @param args args
|
||||
* @return tab complete possibilities
|
||||
*/
|
||||
public List<String> onTabComplete(ViaCommandSender sender, String[] args) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public String color(String s) {
|
||||
return ViaCommandHandler.color(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send message formatted / colored
|
||||
*
|
||||
* @param sender commands sender
|
||||
* @param message string message
|
||||
* @param args optional objects
|
||||
*/
|
||||
public void sendMessage(ViaCommandSender sender, String message, Object... args) {
|
||||
ViaCommandHandler.sendMessage(sender, message, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package us.myles.ViaVersion.api.command;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ViaVersionCommand {
|
||||
/**
|
||||
* Register your own subcommand inside ViaVersion
|
||||
*
|
||||
* @param command Your own SubCommand instance to handle it.
|
||||
* @throws Exception throws an exception when the subcommand already exists or if it's not valid, example: spacee
|
||||
*/
|
||||
void registerSubCommand(ViaSubCommand command) throws Exception;
|
||||
|
||||
/**
|
||||
* Check if a subcommand is registered.
|
||||
*
|
||||
* @param name Subcommand name
|
||||
* @return true if it exists
|
||||
*/
|
||||
boolean hasSubCommand(String name);
|
||||
|
||||
/**
|
||||
* Get subcommand instance by name
|
||||
*
|
||||
* @param name subcommand name
|
||||
* @return ViaSubCommand instance
|
||||
*/
|
||||
@Nullable
|
||||
ViaSubCommand getSubCommand(String name);
|
||||
|
||||
/**
|
||||
* Executed when the Command sender executes the commands
|
||||
*
|
||||
* @param sender Sender object
|
||||
* @param args arguments provided
|
||||
* @return was successful
|
||||
*/
|
||||
boolean onCommand(ViaCommandSender sender, String[] args);
|
||||
|
||||
/**
|
||||
* Executed when the Command sender tab-completes
|
||||
*
|
||||
* @param sender Sender object
|
||||
* @param args arguments provided
|
||||
* @return was successful
|
||||
*/
|
||||
List<String> onTabComplete(ViaCommandSender sender, String[] args);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package us.myles.ViaVersion.api.configuration;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface ConfigurationProvider {
|
||||
|
||||
/**
|
||||
* Sets the specified path to the given value.
|
||||
*
|
||||
* @param path Path of the object to set.
|
||||
* @param value New value to set the path to
|
||||
*/
|
||||
void set(String path, Object value);
|
||||
|
||||
/**
|
||||
* Saves the config
|
||||
*/
|
||||
void saveConfig();
|
||||
|
||||
/**
|
||||
* Reloads the config
|
||||
*/
|
||||
void reloadConfig();
|
||||
|
||||
/**
|
||||
* Get all the configuration values
|
||||
*
|
||||
* @return Map with key-values
|
||||
*/
|
||||
Map<String, Object> getValues();
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package us.myles.ViaVersion.api.data;
|
||||
|
||||
public interface ExternalJoinGameListener {
|
||||
|
||||
void onExternalJoinGame(int playerEntityId);
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
package us.myles.ViaVersion.api.data;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonIOException;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.util.GsonUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class MappingDataLoader {
|
||||
|
||||
private static final Map<String, JsonObject> MAPPINGS_CACHE = new ConcurrentHashMap<>();
|
||||
private static boolean cacheJsonMappings;
|
||||
|
||||
/**
|
||||
* Returns true if a selected number of mappings should be cached.
|
||||
* If enabled, cleanup should be done after the cache is no longer needed.
|
||||
*
|
||||
* @return true if mappings should be cached
|
||||
*/
|
||||
public static boolean isCacheJsonMappings() {
|
||||
return cacheJsonMappings;
|
||||
}
|
||||
|
||||
public static void enableMappingsCache() {
|
||||
cacheJsonMappings = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cached mappings. Cleared after Via has been fully loaded.
|
||||
*
|
||||
* @see #isCacheJsonMappings()
|
||||
*/
|
||||
public static Map<String, JsonObject> getMappingsCache() {
|
||||
return MAPPINGS_CACHE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the file from the plugin folder if present, else from the bundled resources.
|
||||
*/
|
||||
public static JsonObject loadFromDataDir(String name) {
|
||||
File file = new File(Via.getPlatform().getDataFolder(), name);
|
||||
if (!file.exists()) return loadData(name);
|
||||
|
||||
// Load the file from the platform's directory if present
|
||||
try (FileReader reader = new FileReader(file)) {
|
||||
return GsonUtil.getGson().fromJson(reader, JsonObject.class);
|
||||
} catch (JsonSyntaxException e) {
|
||||
// Users might mess up the format, so let's catch the syntax error
|
||||
Via.getPlatform().getLogger().warning(name + " is badly formatted!");
|
||||
e.printStackTrace();
|
||||
} catch (IOException | JsonIOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the file from the bundled resources. Uses the cache if enabled.
|
||||
*/
|
||||
public static JsonObject loadData(String name) {
|
||||
return loadData(name, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the file from the bundled resources. Uses the cache if enabled.
|
||||
*
|
||||
* @param cacheIfEnabled whether loaded files should be cached
|
||||
*/
|
||||
public static JsonObject loadData(String name, boolean cacheIfEnabled) {
|
||||
if (cacheJsonMappings) {
|
||||
JsonObject cached = MAPPINGS_CACHE.get(name);
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
}
|
||||
|
||||
InputStream stream = getResource(name);
|
||||
InputStreamReader reader = new InputStreamReader(stream);
|
||||
try {
|
||||
JsonObject object = GsonUtil.getGson().fromJson(reader, JsonObject.class);
|
||||
if (cacheIfEnabled && cacheJsonMappings) {
|
||||
MAPPINGS_CACHE.put(name, object);
|
||||
}
|
||||
return object;
|
||||
} finally {
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException ignored) {
|
||||
// Ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void mapIdentifiers(Map<Integer, Integer> output, JsonObject oldIdentifiers, JsonObject newIdentifiers) {
|
||||
mapIdentifiers(output, oldIdentifiers, newIdentifiers, null);
|
||||
}
|
||||
|
||||
public static void mapIdentifiers(Map<Integer, Integer> output, JsonObject oldIdentifiers, JsonObject newIdentifiers, JsonObject diffIdentifiers) {
|
||||
for (Map.Entry<String, JsonElement> entry : oldIdentifiers.entrySet()) {
|
||||
Map.Entry<String, JsonElement> value = mapIdentifierEntry(entry, oldIdentifiers, newIdentifiers, diffIdentifiers);
|
||||
if (value != null) {
|
||||
output.put(Integer.parseInt(entry.getKey()), Integer.parseInt(value.getKey()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void mapIdentifiers(short[] output, JsonObject oldIdentifiers, JsonObject newIdentifiers) {
|
||||
MappingDataLoader.mapIdentifiers(output, oldIdentifiers, newIdentifiers, null);
|
||||
}
|
||||
|
||||
public static void mapIdentifiers(short[] output, JsonObject oldIdentifiers, JsonObject newIdentifiers, JsonObject diffIdentifiers) {
|
||||
for (Map.Entry<String, JsonElement> entry : oldIdentifiers.entrySet()) {
|
||||
Map.Entry<String, JsonElement> value = mapIdentifierEntry(entry, oldIdentifiers, newIdentifiers, diffIdentifiers);
|
||||
if (value != null) {
|
||||
output[Integer.parseInt(entry.getKey())] = Short.parseShort(value.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Map.Entry<String, JsonElement> mapIdentifierEntry(Map.Entry<String, JsonElement> entry, JsonObject oldIdentifiers, JsonObject newIdentifiers, JsonObject diffIdentifiers) {
|
||||
Map.Entry<String, JsonElement> value = findValue(newIdentifiers, entry.getValue().getAsString());
|
||||
if (value == null) {
|
||||
// Search in diff mappings
|
||||
if (diffIdentifiers != null) {
|
||||
JsonElement diffElement = diffIdentifiers.get(entry.getKey());
|
||||
if (diffElement != null) {
|
||||
value = findValue(newIdentifiers, diffElement.getAsString());
|
||||
}
|
||||
}
|
||||
if (value == null) {
|
||||
if (!Via.getConfig().isSuppressConversionWarnings() || Via.getManager().isDebug()) {
|
||||
Via.getPlatform().getLogger().warning("No key for " + entry.getValue() + " :( ");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public static void mapIdentifiers(short[] output, JsonArray oldIdentifiers, JsonArray newIdentifiers, boolean warnOnMissing) {
|
||||
mapIdentifiers(output, oldIdentifiers, newIdentifiers, null, warnOnMissing);
|
||||
}
|
||||
|
||||
public static void mapIdentifiers(short[] output, JsonArray oldIdentifiers, JsonArray newIdentifiers, JsonObject diffIdentifiers, boolean warnOnMissing) {
|
||||
for (int i = 0; i < oldIdentifiers.size(); i++) {
|
||||
JsonElement value = oldIdentifiers.get(i);
|
||||
Integer index = findIndex(newIdentifiers, value.getAsString());
|
||||
if (index == null) {
|
||||
if (diffIdentifiers != null) {
|
||||
JsonElement diffElement = diffIdentifiers.get(value.getAsString());
|
||||
if (diffElement != null) {
|
||||
index = findIndex(newIdentifiers, diffElement.getAsString());
|
||||
}
|
||||
}
|
||||
if (index == null) {
|
||||
if (warnOnMissing && !Via.getConfig().isSuppressConversionWarnings() || Via.getManager().isDebug()) {
|
||||
Via.getPlatform().getLogger().warning("No key for " + value + " :( ");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
output[i] = index.shortValue();
|
||||
}
|
||||
}
|
||||
|
||||
public static void mapIdentifiers(byte[] output, JsonObject oldIdentifiers, JsonObject newIdentifiers) {
|
||||
for (Map.Entry<String, JsonElement> entry : oldIdentifiers.entrySet()) {
|
||||
Map.Entry<String, JsonElement> value = MappingDataLoader.findValue(newIdentifiers, entry.getValue().getAsString());
|
||||
if (value == null) {
|
||||
Via.getPlatform().getLogger().warning("No key for " + entry.getValue() + " :( ");
|
||||
continue;
|
||||
}
|
||||
output[Integer.parseInt(entry.getKey())] = Byte.parseByte(value.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Map.Entry<String, JsonElement> findValue(JsonObject object, String needle) {
|
||||
for (Map.Entry<String, JsonElement> entry : object.entrySet()) {
|
||||
String value = entry.getValue().getAsString();
|
||||
if (value.equals(needle)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Integer findIndex(JsonArray array, String value) {
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
JsonElement v = array.get(i);
|
||||
if (v.getAsString().equals(value)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static InputStream getResource(String name) {
|
||||
return MappingDataLoader.class.getClassLoader().getResourceAsStream("assets/viaversion/data/" + name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package us.myles.ViaVersion.api.data;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class Mappings {
|
||||
protected final short[] oldToNew;
|
||||
|
||||
protected Mappings(short[] oldToNew) {
|
||||
this.oldToNew = oldToNew;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps old identifiers to the new ones.
|
||||
* If an old value cannot be found in the new mappings, the diffmapping will be checked for the given entry.
|
||||
*
|
||||
* @param size set size of the underlying short array
|
||||
* @param oldMapping mappings to map from
|
||||
* @param newMapping mappings to map to
|
||||
* @param diffMapping extra mappings that will be used/scanned when an entry cannot be found
|
||||
*/
|
||||
public Mappings(int size, JsonObject oldMapping, JsonObject newMapping, JsonObject diffMapping) {
|
||||
oldToNew = new short[size];
|
||||
Arrays.fill(oldToNew, (short) -1);
|
||||
MappingDataLoader.mapIdentifiers(oldToNew, oldMapping, newMapping, diffMapping);
|
||||
}
|
||||
|
||||
public Mappings(JsonObject oldMapping, JsonObject newMapping, JsonObject diffMapping) {
|
||||
this(oldMapping.entrySet().size(), oldMapping, newMapping, diffMapping);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps old identifiers to the new ones.
|
||||
*
|
||||
* @param size set size of the underlying short array
|
||||
* @param oldMapping mappings to map from
|
||||
* @param newMapping mappings to map to
|
||||
*/
|
||||
public Mappings(int size, JsonObject oldMapping, JsonObject newMapping) {
|
||||
oldToNew = new short[size];
|
||||
Arrays.fill(oldToNew, (short) -1);
|
||||
MappingDataLoader.mapIdentifiers(oldToNew, oldMapping, newMapping);
|
||||
}
|
||||
|
||||
public Mappings(JsonObject oldMapping, JsonObject newMapping) {
|
||||
this(oldMapping.entrySet().size(), oldMapping, newMapping);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps old identifiers to the new ones.
|
||||
*
|
||||
* @param size set size of the underlying short array
|
||||
* @param oldMapping mappings to map from
|
||||
* @param newMapping mappings to map to
|
||||
* @param diffMapping extra mappings that will be used/scanned when an entry cannot be found
|
||||
* @param warnOnMissing should "No key for x" be printed if there is no matching identifier
|
||||
*/
|
||||
public Mappings(int size, JsonArray oldMapping, JsonArray newMapping, JsonObject diffMapping, boolean warnOnMissing) {
|
||||
oldToNew = new short[size];
|
||||
Arrays.fill(oldToNew, (short) -1);
|
||||
MappingDataLoader.mapIdentifiers(oldToNew, oldMapping, newMapping, diffMapping, warnOnMissing);
|
||||
}
|
||||
|
||||
public Mappings(int size, JsonArray oldMapping, JsonArray newMapping, boolean warnOnMissing) {
|
||||
this(size, oldMapping, newMapping, null, warnOnMissing);
|
||||
}
|
||||
|
||||
public Mappings(JsonArray oldMapping, JsonArray newMapping, boolean warnOnMissing) {
|
||||
this(oldMapping.size(), oldMapping, newMapping, warnOnMissing);
|
||||
}
|
||||
|
||||
public Mappings(int size, JsonArray oldMapping, JsonArray newMapping) {
|
||||
this(size, oldMapping, newMapping, true);
|
||||
}
|
||||
|
||||
public Mappings(JsonArray oldMapping, JsonArray newMapping, JsonObject diffMapping) {
|
||||
this(oldMapping.size(), oldMapping, newMapping, diffMapping, true);
|
||||
}
|
||||
|
||||
public Mappings(JsonArray oldMapping, JsonArray newMapping) {
|
||||
this(oldMapping.size(), oldMapping, newMapping, true);
|
||||
}
|
||||
|
||||
public int getNewId(int old) {
|
||||
return old >= 0 && old < oldToNew.length ? oldToNew[old] : -1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package us.myles.ViaVersion.api.data;
|
||||
|
||||
public class StoredObject {
|
||||
private final UserConnection user;
|
||||
|
||||
public StoredObject(UserConnection user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public UserConnection getUser() {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,462 @@
|
||||
package us.myles.ViaVersion.api.data;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import us.myles.ViaVersion.api.PacketWrapper;
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
import us.myles.ViaVersion.api.ViaVersionConfig;
|
||||
import us.myles.ViaVersion.api.type.Type;
|
||||
import us.myles.ViaVersion.exception.CancelException;
|
||||
import us.myles.ViaVersion.exception.InformativeException;
|
||||
import us.myles.ViaVersion.packets.Direction;
|
||||
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||
import us.myles.ViaVersion.util.PipelineUtil;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class UserConnection {
|
||||
private static final AtomicLong IDS = new AtomicLong();
|
||||
private final long id = IDS.incrementAndGet();
|
||||
private final Channel channel;
|
||||
private ProtocolInfo protocolInfo;
|
||||
Map<Class, StoredObject> storedObjects = new ConcurrentHashMap<>();
|
||||
private boolean active = true;
|
||||
private boolean pendingDisconnect;
|
||||
private Object lastPacket;
|
||||
private long sentPackets;
|
||||
private long receivedPackets;
|
||||
// Used for tracking pps
|
||||
private long startTime;
|
||||
private long intervalPackets;
|
||||
private long packetsPerSecond = -1L;
|
||||
// Used for handling warnings (over time)
|
||||
private int secondsObserved;
|
||||
private int warnings;
|
||||
|
||||
public UserConnection(@Nullable Channel channel) {
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an object from the storage.
|
||||
*
|
||||
* @param objectClass The class of the object to get
|
||||
* @param <T> The type of the class you want to get.
|
||||
* @return The requested object
|
||||
*/
|
||||
@Nullable
|
||||
public <T extends StoredObject> T get(Class<T> objectClass) {
|
||||
return (T) storedObjects.get(objectClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the storage has an object.
|
||||
*
|
||||
* @param objectClass The object class to check
|
||||
* @return True if the object is in the storage
|
||||
*/
|
||||
public boolean has(Class<? extends StoredObject> objectClass) {
|
||||
return storedObjects.containsKey(objectClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put an object into the stored objects based on class.
|
||||
*
|
||||
* @param object The object to store.
|
||||
*/
|
||||
public void put(StoredObject object) {
|
||||
storedObjects.put(object.getClass(), object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all the stored objects.
|
||||
* Used for bungee when switching servers.
|
||||
*/
|
||||
public void clearStoredObjects() {
|
||||
storedObjects.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a raw packet to the player.
|
||||
*
|
||||
* @param packet The raw packet to send
|
||||
* @param currentThread Should it run in the same thread
|
||||
*/
|
||||
public void sendRawPacket(ByteBuf packet, boolean currentThread) {
|
||||
ChannelHandler handler = channel.pipeline().get(Via.getManager().getInjector().getEncoderName());
|
||||
if (currentThread) {
|
||||
channel.pipeline().context(handler).writeAndFlush(packet);
|
||||
} else {
|
||||
channel.eventLoop().submit(() -> channel.pipeline().context(handler).writeAndFlush(packet));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a raw packet to the player with returning the future.
|
||||
*
|
||||
* @param packet The raw packet to send
|
||||
* @return ChannelFuture of the packet being sent
|
||||
*/
|
||||
public ChannelFuture sendRawPacketFuture(ByteBuf packet) {
|
||||
ChannelHandler handler = channel.pipeline().get(Via.getManager().getInjector().getEncoderName());
|
||||
return channel.pipeline().context(handler).writeAndFlush(packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a raw packet to the player (netty thread).
|
||||
*
|
||||
* @param packet The packet to send
|
||||
*/
|
||||
public void sendRawPacket(ByteBuf packet) {
|
||||
sendRawPacket(packet, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for incrementing the number of packets sent to the client.
|
||||
*/
|
||||
public void incrementSent() {
|
||||
this.sentPackets++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for incrementing the number of packets received from the client.
|
||||
*
|
||||
* @return true if the interval has reset and can now be checked for the packets sent
|
||||
*/
|
||||
public boolean incrementReceived() {
|
||||
// handle stats
|
||||
long diff = System.currentTimeMillis() - startTime;
|
||||
if (diff >= 1000) {
|
||||
packetsPerSecond = intervalPackets;
|
||||
startTime = System.currentTimeMillis();
|
||||
intervalPackets = 1;
|
||||
return true;
|
||||
} else {
|
||||
intervalPackets++;
|
||||
}
|
||||
// increase total
|
||||
this.receivedPackets++;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for packet flood with the packets sent in the last second.
|
||||
* ALWAYS check for {@link #incrementReceived()} before using this method.
|
||||
*
|
||||
* @return true if the packet should be cancelled
|
||||
* @see #incrementReceived()
|
||||
*/
|
||||
public boolean exceedsMaxPPS() {
|
||||
ViaVersionConfig conf = Via.getConfig();
|
||||
// Max PPS Checker
|
||||
if (conf.getMaxPPS() > 0) {
|
||||
if (packetsPerSecond >= conf.getMaxPPS()) {
|
||||
disconnect(conf.getMaxPPSKickMessage().replace("%pps", Long.toString(packetsPerSecond)));
|
||||
return true; // don't send current packet
|
||||
}
|
||||
}
|
||||
|
||||
// Tracking PPS Checker
|
||||
if (conf.getMaxWarnings() > 0 && conf.getTrackingPeriod() > 0) {
|
||||
if (secondsObserved > conf.getTrackingPeriod()) {
|
||||
// Reset
|
||||
warnings = 0;
|
||||
secondsObserved = 1;
|
||||
} else {
|
||||
secondsObserved++;
|
||||
if (packetsPerSecond >= conf.getWarningPPS()) {
|
||||
warnings++;
|
||||
}
|
||||
|
||||
if (warnings >= conf.getMaxWarnings()) {
|
||||
disconnect(conf.getMaxWarningsKickMessage().replace("%pps", Long.toString(packetsPerSecond)));
|
||||
return true; // don't send current packet
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect a connection.
|
||||
*
|
||||
* @param reason The reason to use, not used if player is not active.
|
||||
*/
|
||||
public void disconnect(String reason) {
|
||||
if (!channel.isOpen() || pendingDisconnect) return;
|
||||
|
||||
pendingDisconnect = true;
|
||||
UUID uuid = protocolInfo.getUuid();
|
||||
if (uuid == null) {
|
||||
channel.close(); // Just disconnect, we don't know what the connection is
|
||||
return;
|
||||
}
|
||||
|
||||
Via.getPlatform().runSync(() -> {
|
||||
if (!Via.getPlatform().kickPlayer(uuid, ChatColor.translateAlternateColorCodes('&', reason))) {
|
||||
channel.close(); // =)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a raw packet to the server.
|
||||
*
|
||||
* @param packet Raw packet to be sent
|
||||
* @param currentThread If {@code true} executes immediately, {@code false} submits a task to EventLoop
|
||||
*/
|
||||
public void sendRawPacketToServer(ByteBuf packet, boolean currentThread) {
|
||||
ByteBuf buf = packet.alloc().buffer();
|
||||
try {
|
||||
try {
|
||||
Type.VAR_INT.writePrimitive(buf, PacketWrapper.PASSTHROUGH_ID);
|
||||
} catch (Exception e) {
|
||||
// Should not happen
|
||||
Via.getPlatform().getLogger().warning("Type.VAR_INT.write thrown an exception: " + e);
|
||||
}
|
||||
buf.writeBytes(packet);
|
||||
ChannelHandlerContext context = PipelineUtil
|
||||
.getPreviousContext(Via.getManager().getInjector().getDecoderName(), channel.pipeline());
|
||||
if (currentThread) {
|
||||
if (context != null) {
|
||||
context.fireChannelRead(buf);
|
||||
} else {
|
||||
channel.pipeline().fireChannelRead(buf);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
channel.eventLoop().submit(() -> {
|
||||
if (context != null) {
|
||||
context.fireChannelRead(buf);
|
||||
} else {
|
||||
channel.pipeline().fireChannelRead(buf);
|
||||
}
|
||||
});
|
||||
} catch (Throwable t) {
|
||||
// Couldn't schedule
|
||||
buf.release();
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
packet.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a raw packet to the server. It will submit a task to EventLoop.
|
||||
*
|
||||
* @param packet Raw packet to be sent
|
||||
*/
|
||||
public void sendRawPacketToServer(ByteBuf packet) {
|
||||
sendRawPacketToServer(packet, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Monitors serverbound packets.
|
||||
*
|
||||
* @return false if this packet should be cancelled
|
||||
*/
|
||||
public boolean checkIncomingPacket() {
|
||||
// Ignore if pending disconnect
|
||||
if (pendingDisconnect) return false;
|
||||
// Increment received + Check PPS
|
||||
return !incrementReceived() || !exceedsMaxPPS();
|
||||
}
|
||||
|
||||
/**
|
||||
* Monitors clientbound packets.
|
||||
*/
|
||||
public void checkOutgoingPacket() {
|
||||
incrementSent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if packets needs transforming.
|
||||
*
|
||||
* @return if packets should be passed through
|
||||
*/
|
||||
public boolean shouldTransformPacket() {
|
||||
return active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the clientbound packet contained in an outgoing ByteBuf.
|
||||
*
|
||||
* @param buf ByteBuf with packet id and packet contents
|
||||
* @param cancelSupplier Function called with original CancelException for generating the Exception used when
|
||||
* packet is cancelled
|
||||
* @throws CancelException if the packet should be cancelled
|
||||
* @throws InformativeException if packet transforming failed
|
||||
* @throws Exception if any other processing outside of transforming fails
|
||||
*/
|
||||
public void transformOutgoing(ByteBuf buf, Function<Throwable, Exception> cancelSupplier) throws Exception {
|
||||
if (!buf.isReadable()) return;
|
||||
transform(buf, Direction.OUTGOING, cancelSupplier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the serverbound packet contained in an incoming ByteBuf.
|
||||
*
|
||||
* @param buf ByteBuf with packet id and packet contents
|
||||
* @param cancelSupplier Function called with original CancelException for generating the Exception used when
|
||||
* packet is cancelled
|
||||
* @throws CancelException if the packet should be cancelled
|
||||
* @throws InformativeException if packet transforming failed
|
||||
* @throws Exception if any other processing outside of transforming fails
|
||||
*/
|
||||
public void transformIncoming(ByteBuf buf, Function<Throwable, Exception> cancelSupplier) throws Exception {
|
||||
if (!buf.isReadable()) return;
|
||||
transform(buf, Direction.INCOMING, cancelSupplier);
|
||||
}
|
||||
|
||||
private void transform(ByteBuf buf, Direction direction, Function<Throwable, Exception> cancelSupplier) throws Exception {
|
||||
int id = Type.VAR_INT.readPrimitive(buf);
|
||||
if (id == PacketWrapper.PASSTHROUGH_ID) return;
|
||||
|
||||
PacketWrapper wrapper = new PacketWrapper(id, buf, this);
|
||||
try {
|
||||
protocolInfo.getPipeline().transform(direction, protocolInfo.getState(), wrapper);
|
||||
} catch (CancelException ex) {
|
||||
throw cancelSupplier.apply(ex);
|
||||
}
|
||||
|
||||
ByteBuf transformed = buf.alloc().buffer();
|
||||
try {
|
||||
wrapper.writeToBuffer(transformed);
|
||||
buf.clear().writeBytes(transformed);
|
||||
} finally {
|
||||
transformed.release();
|
||||
}
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Channel getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ProtocolInfo getProtocolInfo() {
|
||||
return protocolInfo;
|
||||
}
|
||||
|
||||
public void setProtocolInfo(@Nullable ProtocolInfo protocolInfo) {
|
||||
this.protocolInfo = protocolInfo;
|
||||
if (protocolInfo != null) {
|
||||
storedObjects.put(ProtocolInfo.class, protocolInfo);
|
||||
} else {
|
||||
storedObjects.remove(ProtocolInfo.class);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<Class, StoredObject> getStoredObjects() {
|
||||
return storedObjects;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return active;
|
||||
}
|
||||
|
||||
public void setActive(boolean active) {
|
||||
this.active = active;
|
||||
}
|
||||
|
||||
public boolean isPendingDisconnect() {
|
||||
return pendingDisconnect;
|
||||
}
|
||||
|
||||
public void setPendingDisconnect(boolean pendingDisconnect) {
|
||||
this.pendingDisconnect = pendingDisconnect;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Object getLastPacket() {
|
||||
return lastPacket;
|
||||
}
|
||||
|
||||
public void setLastPacket(@Nullable Object lastPacket) {
|
||||
this.lastPacket = lastPacket;
|
||||
}
|
||||
|
||||
public long getSentPackets() {
|
||||
return sentPackets;
|
||||
}
|
||||
|
||||
public void setSentPackets(long sentPackets) {
|
||||
this.sentPackets = sentPackets;
|
||||
}
|
||||
|
||||
public long getReceivedPackets() {
|
||||
return receivedPackets;
|
||||
}
|
||||
|
||||
public void setReceivedPackets(long receivedPackets) {
|
||||
this.receivedPackets = receivedPackets;
|
||||
}
|
||||
|
||||
public long getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public void setStartTime(long startTime) {
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
public long getIntervalPackets() {
|
||||
return intervalPackets;
|
||||
}
|
||||
|
||||
public void setIntervalPackets(long intervalPackets) {
|
||||
this.intervalPackets = intervalPackets;
|
||||
}
|
||||
|
||||
public long getPacketsPerSecond() {
|
||||
return packetsPerSecond;
|
||||
}
|
||||
|
||||
public void setPacketsPerSecond(long packetsPerSecond) {
|
||||
this.packetsPerSecond = packetsPerSecond;
|
||||
}
|
||||
|
||||
public int getSecondsObserved() {
|
||||
return secondsObserved;
|
||||
}
|
||||
|
||||
public void setSecondsObserved(int secondsObserved) {
|
||||
this.secondsObserved = secondsObserved;
|
||||
}
|
||||
|
||||
public int getWarnings() {
|
||||
return warnings;
|
||||
}
|
||||
|
||||
public void setWarnings(int warnings) {
|
||||
this.warnings = warnings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
UserConnection that = (UserConnection) o;
|
||||
return id == that.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Long.hashCode(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
package us.myles.ViaVersion.api.entities;
|
||||
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
// 1.10 Entity / Object ids
|
||||
public class Entity1_10Types {
|
||||
|
||||
public static EntityType getTypeFromId(int typeID, boolean isObject) {
|
||||
Optional<EntityType> type;
|
||||
|
||||
if (isObject)
|
||||
type = ObjectType.getPCEntity(typeID);
|
||||
else
|
||||
type = EntityType.findById(typeID);
|
||||
|
||||
if (!type.isPresent()) {
|
||||
Via.getPlatform().getLogger().severe("Could not find 1.10 type id " + typeID + " isObject=" + isObject);
|
||||
return EntityType.ENTITY; // Fall back to the basic ENTITY
|
||||
}
|
||||
|
||||
return type.get();
|
||||
}
|
||||
|
||||
public enum EntityType implements us.myles.ViaVersion.api.entities.EntityType {
|
||||
ENTITY(-1),
|
||||
DROPPED_ITEM(1, ENTITY),
|
||||
EXPERIENCE_ORB(2, ENTITY),
|
||||
LEASH_HITCH(8, ENTITY), // Actually entity hanging but it doesn't make a lot of difference for metadata
|
||||
PAINTING(9, ENTITY), // Actually entity hanging but it doesn't make a lot of difference for metadata
|
||||
ARROW(10, ENTITY),
|
||||
SNOWBALL(11, ENTITY), // Actually EntityProjectile
|
||||
FIREBALL(12, ENTITY),
|
||||
SMALL_FIREBALL(13, ENTITY),
|
||||
ENDER_PEARL(14, ENTITY), // Actually EntityProjectile
|
||||
ENDER_SIGNAL(15, ENTITY),
|
||||
THROWN_EXP_BOTTLE(17, ENTITY),
|
||||
ITEM_FRAME(18, ENTITY), // Actually EntityHanging
|
||||
WITHER_SKULL(19, ENTITY),
|
||||
PRIMED_TNT(20, ENTITY),
|
||||
FALLING_BLOCK(21, ENTITY),
|
||||
FIREWORK(22, ENTITY),
|
||||
TIPPED_ARROW(23, ARROW),
|
||||
SPECTRAL_ARROW(24, ARROW),
|
||||
SHULKER_BULLET(25, ENTITY),
|
||||
DRAGON_FIREBALL(26, FIREBALL),
|
||||
|
||||
ENTITY_LIVING(-1, ENTITY),
|
||||
ENTITY_INSENTIENT(-1, ENTITY_LIVING),
|
||||
ENTITY_AGEABLE(-1, ENTITY_INSENTIENT),
|
||||
ENTITY_TAMEABLE_ANIMAL(-1, ENTITY_AGEABLE),
|
||||
ENTITY_HUMAN(-1, ENTITY_LIVING),
|
||||
|
||||
ARMOR_STAND(30, ENTITY_LIVING),
|
||||
|
||||
// Vehicles
|
||||
MINECART_ABSTRACT(-1, ENTITY),
|
||||
MINECART_COMMAND(40, MINECART_ABSTRACT),
|
||||
BOAT(41, ENTITY),
|
||||
MINECART_RIDEABLE(42, MINECART_ABSTRACT),
|
||||
MINECART_CHEST(43, MINECART_ABSTRACT),
|
||||
MINECART_FURNACE(44, MINECART_ABSTRACT),
|
||||
MINECART_TNT(45, MINECART_ABSTRACT),
|
||||
MINECART_HOPPER(46, MINECART_ABSTRACT),
|
||||
MINECART_MOB_SPAWNER(47, MINECART_ABSTRACT),
|
||||
|
||||
CREEPER(50, ENTITY_INSENTIENT),
|
||||
SKELETON(51, ENTITY_INSENTIENT),
|
||||
SPIDER(52, ENTITY_INSENTIENT),
|
||||
GIANT(53, ENTITY_INSENTIENT),
|
||||
ZOMBIE(54, ENTITY_INSENTIENT),
|
||||
SLIME(55, ENTITY_INSENTIENT),
|
||||
GHAST(56, ENTITY_INSENTIENT),
|
||||
PIG_ZOMBIE(57, ZOMBIE),
|
||||
ENDERMAN(58, ENTITY_INSENTIENT),
|
||||
CAVE_SPIDER(59, SPIDER),
|
||||
SILVERFISH(60, ENTITY_INSENTIENT),
|
||||
BLAZE(61, ENTITY_INSENTIENT),
|
||||
MAGMA_CUBE(62, SLIME),
|
||||
ENDER_DRAGON(63, ENTITY_INSENTIENT),
|
||||
WITHER(64, ENTITY_INSENTIENT),
|
||||
BAT(65, ENTITY_INSENTIENT),
|
||||
WITCH(66, ENTITY_INSENTIENT),
|
||||
ENDERMITE(67, ENTITY_INSENTIENT),
|
||||
GUARDIAN(68, ENTITY_INSENTIENT),
|
||||
IRON_GOLEM(99, ENTITY_INSENTIENT), // moved up to avoid illegal forward references
|
||||
SHULKER(69, IRON_GOLEM),
|
||||
PIG(90, ENTITY_AGEABLE),
|
||||
SHEEP(91, ENTITY_AGEABLE),
|
||||
COW(92, ENTITY_AGEABLE),
|
||||
CHICKEN(93, ENTITY_AGEABLE),
|
||||
SQUID(94, ENTITY_INSENTIENT),
|
||||
WOLF(95, ENTITY_TAMEABLE_ANIMAL),
|
||||
MUSHROOM_COW(96, COW),
|
||||
SNOWMAN(97, IRON_GOLEM),
|
||||
OCELOT(98, ENTITY_TAMEABLE_ANIMAL),
|
||||
HORSE(100, ENTITY_AGEABLE),
|
||||
RABBIT(101, ENTITY_AGEABLE),
|
||||
POLAR_BEAR(102, ENTITY_AGEABLE),
|
||||
VILLAGER(120, ENTITY_AGEABLE),
|
||||
ENDER_CRYSTAL(200, ENTITY),
|
||||
SPLASH_POTION(-1, ENTITY),
|
||||
LINGERING_POTION(-1, SPLASH_POTION),
|
||||
AREA_EFFECT_CLOUD(-1, ENTITY),
|
||||
EGG(-1, ENTITY),
|
||||
FISHING_HOOK(-1, ENTITY),
|
||||
LIGHTNING(-1, ENTITY),
|
||||
WEATHER(-1, ENTITY),
|
||||
PLAYER(-1, ENTITY_HUMAN),
|
||||
COMPLEX_PART(-1, ENTITY);
|
||||
|
||||
private static final Map<Integer, EntityType> TYPES = new HashMap<>();
|
||||
|
||||
private final int id;
|
||||
private final EntityType parent;
|
||||
|
||||
EntityType(int id) {
|
||||
this.id = id;
|
||||
this.parent = null;
|
||||
}
|
||||
|
||||
EntityType(int id, EntityType parent) {
|
||||
this.id = id;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
static {
|
||||
for (EntityType type : EntityType.values()) {
|
||||
TYPES.put(type.id, type);
|
||||
}
|
||||
}
|
||||
|
||||
public static Optional<EntityType> findById(int id) {
|
||||
if (id == -1) // Check if this is called
|
||||
return Optional.empty();
|
||||
return Optional.ofNullable(TYPES.get(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityType getParent() {
|
||||
return parent;
|
||||
}
|
||||
}
|
||||
|
||||
public enum ObjectType implements us.myles.ViaVersion.api.entities.ObjectType {
|
||||
BOAT(1, EntityType.BOAT),
|
||||
ITEM(2, EntityType.DROPPED_ITEM),
|
||||
AREA_EFFECT_CLOUD(3, EntityType.AREA_EFFECT_CLOUD),
|
||||
MINECART(10, EntityType.MINECART_RIDEABLE),
|
||||
TNT_PRIMED(50, EntityType.PRIMED_TNT),
|
||||
ENDER_CRYSTAL(51, EntityType.ENDER_CRYSTAL),
|
||||
TIPPED_ARROW(60, EntityType.TIPPED_ARROW),
|
||||
SNOWBALL(61, EntityType.SNOWBALL),
|
||||
EGG(62, EntityType.EGG),
|
||||
FIREBALL(63, EntityType.FIREBALL),
|
||||
SMALL_FIREBALL(64, EntityType.SMALL_FIREBALL),
|
||||
ENDER_PEARL(65, EntityType.ENDER_PEARL),
|
||||
WITHER_SKULL(66, EntityType.WITHER_SKULL),
|
||||
SHULKER_BULLET(67, EntityType.SHULKER_BULLET),
|
||||
FALLING_BLOCK(70, EntityType.FALLING_BLOCK),
|
||||
ITEM_FRAME(71, EntityType.ITEM_FRAME),
|
||||
ENDER_SIGNAL(72, EntityType.ENDER_SIGNAL),
|
||||
POTION(73, EntityType.SPLASH_POTION),
|
||||
THROWN_EXP_BOTTLE(75, EntityType.THROWN_EXP_BOTTLE),
|
||||
FIREWORK(76, EntityType.FIREWORK),
|
||||
LEASH(77, EntityType.LEASH_HITCH),
|
||||
ARMOR_STAND(78, EntityType.ARMOR_STAND),
|
||||
FISHIHNG_HOOK(90, EntityType.FISHING_HOOK),
|
||||
SPECTRAL_ARROW(91, EntityType.SPECTRAL_ARROW),
|
||||
DRAGON_FIREBALL(93, EntityType.DRAGON_FIREBALL);
|
||||
|
||||
private static final Map<Integer, ObjectType> TYPES = new HashMap<>();
|
||||
|
||||
private final int id;
|
||||
private final EntityType type;
|
||||
|
||||
static {
|
||||
for (ObjectType type : ObjectType.values()) {
|
||||
TYPES.put(type.id, type);
|
||||
}
|
||||
}
|
||||
|
||||
ObjectType(int id, EntityType type) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public static Optional<ObjectType> findById(int id) {
|
||||
if (id == -1)
|
||||
return Optional.empty();
|
||||
return Optional.ofNullable(TYPES.get(id));
|
||||
}
|
||||
|
||||
public static Optional<EntityType> getPCEntity(int id) {
|
||||
Optional<ObjectType> output = findById(id);
|
||||
|
||||
if (!output.isPresent())
|
||||
return Optional.empty();
|
||||
return Optional.of(output.get().type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
package us.myles.ViaVersion.api.entities;
|
||||
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
// 1.11 Entity / Object ids TODO maybe in the future instead of copying it, some api.
|
||||
public class Entity1_11Types {
|
||||
|
||||
public static EntityType getTypeFromId(int typeID, boolean isObject) {
|
||||
Optional<EntityType> type;
|
||||
|
||||
if (isObject)
|
||||
type = ObjectType.getPCEntity(typeID);
|
||||
else
|
||||
type = EntityType.findById(typeID);
|
||||
|
||||
if (!type.isPresent()) {
|
||||
Via.getPlatform().getLogger().severe("Could not find 1.11 type id " + typeID + " isObject=" + isObject);
|
||||
return EntityType.ENTITY; // Fall back to the basic ENTITY
|
||||
}
|
||||
|
||||
return type.get();
|
||||
}
|
||||
|
||||
public enum EntityType implements us.myles.ViaVersion.api.entities.EntityType {
|
||||
ENTITY(-1),
|
||||
DROPPED_ITEM(1, ENTITY),
|
||||
EXPERIENCE_ORB(2, ENTITY),
|
||||
LEASH_HITCH(8, ENTITY), // Actually entity hanging but it doesn't make a lot of difference for metadata
|
||||
PAINTING(9, ENTITY), // Actually entity hanging but it doesn't make a lot of difference for metadata
|
||||
ARROW(10, ENTITY),
|
||||
SNOWBALL(11, ENTITY), // Actually EntityProjectile
|
||||
FIREBALL(12, ENTITY),
|
||||
SMALL_FIREBALL(13, ENTITY),
|
||||
ENDER_PEARL(14, ENTITY), // Actually EntityProjectile
|
||||
ENDER_SIGNAL(15, ENTITY),
|
||||
THROWN_EXP_BOTTLE(17, ENTITY),
|
||||
ITEM_FRAME(18, ENTITY), // Actually EntityHanging
|
||||
WITHER_SKULL(19, ENTITY),
|
||||
PRIMED_TNT(20, ENTITY),
|
||||
FALLING_BLOCK(21, ENTITY),
|
||||
FIREWORK(22, ENTITY),
|
||||
SPECTRAL_ARROW(24, ARROW),
|
||||
SHULKER_BULLET(25, ENTITY),
|
||||
DRAGON_FIREBALL(26, FIREBALL),
|
||||
EVOCATION_FANGS(33, ENTITY),
|
||||
|
||||
|
||||
ENTITY_LIVING(-1, ENTITY),
|
||||
ENTITY_INSENTIENT(-1, ENTITY_LIVING),
|
||||
ENTITY_AGEABLE(-1, ENTITY_INSENTIENT),
|
||||
ENTITY_TAMEABLE_ANIMAL(-1, ENTITY_AGEABLE),
|
||||
ENTITY_HUMAN(-1, ENTITY_LIVING),
|
||||
|
||||
ARMOR_STAND(30, ENTITY_LIVING),
|
||||
EVOCATION_ILLAGER(34, ENTITY_INSENTIENT),
|
||||
VEX(35, ENTITY_INSENTIENT),
|
||||
VINDICATION_ILLAGER(36, ENTITY_INSENTIENT),
|
||||
|
||||
// Vehicles
|
||||
MINECART_ABSTRACT(-1, ENTITY),
|
||||
MINECART_COMMAND(40, MINECART_ABSTRACT),
|
||||
BOAT(41, ENTITY),
|
||||
MINECART_RIDEABLE(42, MINECART_ABSTRACT),
|
||||
MINECART_CHEST(43, MINECART_ABSTRACT),
|
||||
MINECART_FURNACE(44, MINECART_ABSTRACT),
|
||||
MINECART_TNT(45, MINECART_ABSTRACT),
|
||||
MINECART_HOPPER(46, MINECART_ABSTRACT),
|
||||
MINECART_MOB_SPAWNER(47, MINECART_ABSTRACT),
|
||||
|
||||
CREEPER(50, ENTITY_INSENTIENT),
|
||||
|
||||
ABSTRACT_SKELETON(-1, ENTITY_INSENTIENT),
|
||||
SKELETON(51, ABSTRACT_SKELETON),
|
||||
WITHER_SKELETON(5, ABSTRACT_SKELETON),
|
||||
STRAY(6, ABSTRACT_SKELETON),
|
||||
|
||||
SPIDER(52, ENTITY_INSENTIENT),
|
||||
GIANT(53, ENTITY_INSENTIENT),
|
||||
|
||||
ZOMBIE(54, ENTITY_INSENTIENT),
|
||||
HUSK(23, ZOMBIE),
|
||||
ZOMBIE_VILLAGER(27, ZOMBIE),
|
||||
|
||||
SLIME(55, ENTITY_INSENTIENT),
|
||||
GHAST(56, ENTITY_INSENTIENT),
|
||||
PIG_ZOMBIE(57, ZOMBIE),
|
||||
ENDERMAN(58, ENTITY_INSENTIENT),
|
||||
CAVE_SPIDER(59, SPIDER),
|
||||
SILVERFISH(60, ENTITY_INSENTIENT),
|
||||
BLAZE(61, ENTITY_INSENTIENT),
|
||||
MAGMA_CUBE(62, SLIME),
|
||||
ENDER_DRAGON(63, ENTITY_INSENTIENT),
|
||||
WITHER(64, ENTITY_INSENTIENT),
|
||||
BAT(65, ENTITY_INSENTIENT),
|
||||
WITCH(66, ENTITY_INSENTIENT),
|
||||
ENDERMITE(67, ENTITY_INSENTIENT),
|
||||
|
||||
GUARDIAN(68, ENTITY_INSENTIENT),
|
||||
ELDER_GUARDIAN(4, GUARDIAN), // Moved down to avoid illegal forward reference
|
||||
|
||||
IRON_GOLEM(99, ENTITY_INSENTIENT), // moved up to avoid illegal forward references
|
||||
SHULKER(69, IRON_GOLEM),
|
||||
PIG(90, ENTITY_AGEABLE),
|
||||
SHEEP(91, ENTITY_AGEABLE),
|
||||
COW(92, ENTITY_AGEABLE),
|
||||
CHICKEN(93, ENTITY_AGEABLE),
|
||||
SQUID(94, ENTITY_INSENTIENT),
|
||||
WOLF(95, ENTITY_TAMEABLE_ANIMAL),
|
||||
MUSHROOM_COW(96, COW),
|
||||
SNOWMAN(97, IRON_GOLEM),
|
||||
OCELOT(98, ENTITY_TAMEABLE_ANIMAL),
|
||||
|
||||
ABSTRACT_HORSE(-1, ENTITY_AGEABLE),
|
||||
HORSE(100, ABSTRACT_HORSE),
|
||||
SKELETON_HORSE(28, ABSTRACT_HORSE),
|
||||
ZOMBIE_HORSE(29, ABSTRACT_HORSE),
|
||||
|
||||
CHESTED_HORSE(-1, ABSTRACT_HORSE),
|
||||
DONKEY(31, CHESTED_HORSE),
|
||||
MULE(32, CHESTED_HORSE),
|
||||
LIAMA(103, CHESTED_HORSE),
|
||||
|
||||
|
||||
RABBIT(101, ENTITY_AGEABLE),
|
||||
POLAR_BEAR(102, ENTITY_AGEABLE),
|
||||
VILLAGER(120, ENTITY_AGEABLE),
|
||||
ENDER_CRYSTAL(200, ENTITY),
|
||||
SPLASH_POTION(-1, ENTITY),
|
||||
LINGERING_POTION(-1, SPLASH_POTION),
|
||||
AREA_EFFECT_CLOUD(-1, ENTITY),
|
||||
EGG(-1, ENTITY),
|
||||
FISHING_HOOK(-1, ENTITY),
|
||||
LIGHTNING(-1, ENTITY),
|
||||
WEATHER(-1, ENTITY),
|
||||
PLAYER(-1, ENTITY_HUMAN),
|
||||
COMPLEX_PART(-1, ENTITY),
|
||||
LIAMA_SPIT(-1, ENTITY);
|
||||
|
||||
private static final Map<Integer, EntityType> TYPES = new HashMap<>();
|
||||
|
||||
private final int id;
|
||||
private final EntityType parent;
|
||||
|
||||
EntityType(int id) {
|
||||
this.id = id;
|
||||
this.parent = null;
|
||||
}
|
||||
|
||||
EntityType(int id, EntityType parent) {
|
||||
this.id = id;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityType getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
static {
|
||||
for (EntityType type : EntityType.values()) {
|
||||
TYPES.put(type.id, type);
|
||||
}
|
||||
}
|
||||
|
||||
public static Optional<EntityType> findById(int id) {
|
||||
if (id == -1) // Check if this is called
|
||||
return Optional.empty();
|
||||
return Optional.ofNullable(TYPES.get(id));
|
||||
}
|
||||
}
|
||||
|
||||
public enum ObjectType implements us.myles.ViaVersion.api.entities.ObjectType {
|
||||
BOAT(1, EntityType.BOAT),
|
||||
ITEM(2, EntityType.DROPPED_ITEM),
|
||||
AREA_EFFECT_CLOUD(3, EntityType.AREA_EFFECT_CLOUD),
|
||||
MINECART(10, EntityType.MINECART_RIDEABLE),
|
||||
TNT_PRIMED(50, EntityType.PRIMED_TNT),
|
||||
ENDER_CRYSTAL(51, EntityType.ENDER_CRYSTAL),
|
||||
TIPPED_ARROW(60, EntityType.ARROW),
|
||||
SNOWBALL(61, EntityType.SNOWBALL),
|
||||
EGG(62, EntityType.EGG),
|
||||
FIREBALL(63, EntityType.FIREBALL),
|
||||
SMALL_FIREBALL(64, EntityType.SMALL_FIREBALL),
|
||||
ENDER_PEARL(65, EntityType.ENDER_PEARL),
|
||||
WITHER_SKULL(66, EntityType.WITHER_SKULL),
|
||||
SHULKER_BULLET(67, EntityType.SHULKER_BULLET),
|
||||
LIAMA_SPIT(68, EntityType.LIAMA_SPIT),
|
||||
FALLING_BLOCK(70, EntityType.FALLING_BLOCK),
|
||||
ITEM_FRAME(71, EntityType.ITEM_FRAME),
|
||||
ENDER_SIGNAL(72, EntityType.ENDER_SIGNAL),
|
||||
POTION(73, EntityType.SPLASH_POTION),
|
||||
THROWN_EXP_BOTTLE(75, EntityType.THROWN_EXP_BOTTLE),
|
||||
FIREWORK(76, EntityType.FIREWORK),
|
||||
LEASH(77, EntityType.LEASH_HITCH),
|
||||
ARMOR_STAND(78, EntityType.ARMOR_STAND),
|
||||
EVOCATION_FANGS(79, EntityType.EVOCATION_FANGS),
|
||||
FISHIHNG_HOOK(90, EntityType.FISHING_HOOK),
|
||||
SPECTRAL_ARROW(91, EntityType.SPECTRAL_ARROW),
|
||||
DRAGON_FIREBALL(93, EntityType.DRAGON_FIREBALL);
|
||||
|
||||
private static final Map<Integer, ObjectType> TYPES = new HashMap<>();
|
||||
|
||||
private final int id;
|
||||
private final EntityType type;
|
||||
|
||||
static {
|
||||
for (ObjectType type : ObjectType.values()) {
|
||||
TYPES.put(type.id, type);
|
||||
}
|
||||
}
|
||||
|
||||
ObjectType(int id, EntityType type) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public static Optional<ObjectType> findById(int id) {
|
||||
if (id == -1)
|
||||
return Optional.empty();
|
||||
return Optional.ofNullable(TYPES.get(id));
|
||||
}
|
||||
|
||||
public static Optional<EntityType> getPCEntity(int id) {
|
||||
Optional<ObjectType> output = findById(id);
|
||||
|
||||
if (!output.isPresent())
|
||||
return Optional.empty();
|
||||
return Optional.of(output.get().type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Matsv
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package us.myles.ViaVersion.api.entities;
|
||||
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
// 1.12 Entity / Object taken from https://github.com/Matsv/ViaBackwards/blob/master/core/src/main/java/nl/matsv/viabackwards/api/entities/types/EntityType1_12.java
|
||||
public class Entity1_12Types {
|
||||
|
||||
public static EntityType getTypeFromId(int typeID, boolean isObject) {
|
||||
Optional<EntityType> type;
|
||||
|
||||
if (isObject)
|
||||
type = ObjectType.getPCEntity(typeID);
|
||||
else
|
||||
type = EntityType.findById(typeID);
|
||||
|
||||
if (!type.isPresent()) {
|
||||
Via.getPlatform().getLogger().severe("Could not find 1.12 type id " + typeID + " isObject=" + isObject);
|
||||
return EntityType.ENTITY; // Fall back to the basic ENTITY
|
||||
}
|
||||
|
||||
return type.get();
|
||||
}
|
||||
|
||||
public enum EntityType implements us.myles.ViaVersion.api.entities.EntityType {
|
||||
ENTITY(-1),
|
||||
DROPPED_ITEM(1, ENTITY),
|
||||
EXPERIENCE_ORB(2, ENTITY),
|
||||
LEASH_HITCH(8, ENTITY), // Actually entity hanging but it doesn't make a lot of difference for metadata
|
||||
PAINTING(9, ENTITY), // Actually entity hanging but it doesn't make a lot of difference for metadata
|
||||
ARROW(10, ENTITY),
|
||||
SNOWBALL(11, ENTITY), // Actually EntityProjectile
|
||||
FIREBALL(12, ENTITY),
|
||||
SMALL_FIREBALL(13, ENTITY),
|
||||
ENDER_PEARL(14, ENTITY), // Actually EntityProjectile
|
||||
ENDER_SIGNAL(15, ENTITY),
|
||||
THROWN_EXP_BOTTLE(17, ENTITY),
|
||||
ITEM_FRAME(18, ENTITY), // Actually EntityHanging
|
||||
WITHER_SKULL(19, ENTITY),
|
||||
PRIMED_TNT(20, ENTITY),
|
||||
FALLING_BLOCK(21, ENTITY),
|
||||
FIREWORK(22, ENTITY),
|
||||
SPECTRAL_ARROW(24, ARROW),
|
||||
SHULKER_BULLET(25, ENTITY),
|
||||
DRAGON_FIREBALL(26, FIREBALL),
|
||||
EVOCATION_FANGS(33, ENTITY),
|
||||
|
||||
|
||||
ENTITY_LIVING(-1, ENTITY),
|
||||
ENTITY_INSENTIENT(-1, ENTITY_LIVING),
|
||||
ENTITY_AGEABLE(-1, ENTITY_INSENTIENT),
|
||||
ENTITY_TAMEABLE_ANIMAL(-1, ENTITY_AGEABLE),
|
||||
ENTITY_HUMAN(-1, ENTITY_LIVING),
|
||||
|
||||
ARMOR_STAND(30, ENTITY_LIVING),
|
||||
ENTITY_ILLAGER_ABSTRACT(-1, ENTITY_INSENTIENT),
|
||||
EVOCATION_ILLAGER(34, ENTITY_ILLAGER_ABSTRACT),
|
||||
VEX(35, ENTITY_INSENTIENT),
|
||||
VINDICATION_ILLAGER(36, ENTITY_ILLAGER_ABSTRACT),
|
||||
ILLUSION_ILLAGER(37, EVOCATION_ILLAGER),
|
||||
|
||||
// Vehicles
|
||||
MINECART_ABSTRACT(-1, ENTITY),
|
||||
MINECART_COMMAND(40, MINECART_ABSTRACT),
|
||||
BOAT(41, ENTITY),
|
||||
MINECART_RIDEABLE(42, MINECART_ABSTRACT),
|
||||
MINECART_CHEST(43, MINECART_ABSTRACT),
|
||||
MINECART_FURNACE(44, MINECART_ABSTRACT),
|
||||
MINECART_TNT(45, MINECART_ABSTRACT),
|
||||
MINECART_HOPPER(46, MINECART_ABSTRACT),
|
||||
MINECART_MOB_SPAWNER(47, MINECART_ABSTRACT),
|
||||
|
||||
CREEPER(50, ENTITY_INSENTIENT),
|
||||
|
||||
ABSTRACT_SKELETON(-1, ENTITY_INSENTIENT),
|
||||
SKELETON(51, ABSTRACT_SKELETON),
|
||||
WITHER_SKELETON(5, ABSTRACT_SKELETON),
|
||||
STRAY(6, ABSTRACT_SKELETON),
|
||||
|
||||
SPIDER(52, ENTITY_INSENTIENT),
|
||||
GIANT(53, ENTITY_INSENTIENT),
|
||||
|
||||
ZOMBIE(54, ENTITY_INSENTIENT),
|
||||
HUSK(23, ZOMBIE),
|
||||
ZOMBIE_VILLAGER(27, ZOMBIE),
|
||||
|
||||
SLIME(55, ENTITY_INSENTIENT),
|
||||
GHAST(56, ENTITY_INSENTIENT),
|
||||
PIG_ZOMBIE(57, ZOMBIE),
|
||||
ENDERMAN(58, ENTITY_INSENTIENT),
|
||||
CAVE_SPIDER(59, SPIDER),
|
||||
SILVERFISH(60, ENTITY_INSENTIENT),
|
||||
BLAZE(61, ENTITY_INSENTIENT),
|
||||
MAGMA_CUBE(62, SLIME),
|
||||
ENDER_DRAGON(63, ENTITY_INSENTIENT),
|
||||
WITHER(64, ENTITY_INSENTIENT),
|
||||
BAT(65, ENTITY_INSENTIENT),
|
||||
WITCH(66, ENTITY_INSENTIENT),
|
||||
ENDERMITE(67, ENTITY_INSENTIENT),
|
||||
|
||||
GUARDIAN(68, ENTITY_INSENTIENT),
|
||||
ELDER_GUARDIAN(4, GUARDIAN), // Moved down to avoid illegal forward reference
|
||||
|
||||
IRON_GOLEM(99, ENTITY_INSENTIENT), // moved up to avoid illegal forward references
|
||||
SHULKER(69, IRON_GOLEM),
|
||||
PIG(90, ENTITY_AGEABLE),
|
||||
SHEEP(91, ENTITY_AGEABLE),
|
||||
COW(92, ENTITY_AGEABLE),
|
||||
CHICKEN(93, ENTITY_AGEABLE),
|
||||
SQUID(94, ENTITY_INSENTIENT),
|
||||
WOLF(95, ENTITY_TAMEABLE_ANIMAL),
|
||||
MUSHROOM_COW(96, COW),
|
||||
SNOWMAN(97, IRON_GOLEM),
|
||||
OCELOT(98, ENTITY_TAMEABLE_ANIMAL),
|
||||
PARROT(105, ENTITY_TAMEABLE_ANIMAL),
|
||||
|
||||
ABSTRACT_HORSE(-1, ENTITY_AGEABLE),
|
||||
HORSE(100, ABSTRACT_HORSE),
|
||||
SKELETON_HORSE(28, ABSTRACT_HORSE),
|
||||
ZOMBIE_HORSE(29, ABSTRACT_HORSE),
|
||||
|
||||
CHESTED_HORSE(-1, ABSTRACT_HORSE),
|
||||
DONKEY(31, CHESTED_HORSE),
|
||||
MULE(32, CHESTED_HORSE),
|
||||
LIAMA(103, CHESTED_HORSE),
|
||||
|
||||
|
||||
RABBIT(101, ENTITY_AGEABLE),
|
||||
POLAR_BEAR(102, ENTITY_AGEABLE),
|
||||
VILLAGER(120, ENTITY_AGEABLE),
|
||||
ENDER_CRYSTAL(200, ENTITY),
|
||||
SPLASH_POTION(-1, ENTITY),
|
||||
LINGERING_POTION(-1, SPLASH_POTION),
|
||||
AREA_EFFECT_CLOUD(-1, ENTITY),
|
||||
EGG(-1, ENTITY),
|
||||
FISHING_HOOK(-1, ENTITY),
|
||||
LIGHTNING(-1, ENTITY),
|
||||
WEATHER(-1, ENTITY),
|
||||
PLAYER(-1, ENTITY_HUMAN),
|
||||
COMPLEX_PART(-1, ENTITY),
|
||||
LIAMA_SPIT(-1, ENTITY);
|
||||
|
||||
private static final Map<Integer, EntityType> TYPES = new HashMap<>();
|
||||
|
||||
private final int id;
|
||||
private final EntityType parent;
|
||||
|
||||
EntityType(int id) {
|
||||
this.id = id;
|
||||
this.parent = null;
|
||||
}
|
||||
|
||||
EntityType(int id, EntityType parent) {
|
||||
this.id = id;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityType getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
static {
|
||||
for (EntityType type : EntityType.values()) {
|
||||
TYPES.put(type.id, type);
|
||||
}
|
||||
}
|
||||
|
||||
public static Optional<EntityType> findById(int id) {
|
||||
if (id == -1) // Check if this is called
|
||||
return Optional.empty();
|
||||
return Optional.ofNullable(TYPES.get(id));
|
||||
}
|
||||
}
|
||||
|
||||
public enum ObjectType implements us.myles.ViaVersion.api.entities.ObjectType {
|
||||
BOAT(1, EntityType.BOAT),
|
||||
ITEM(2, EntityType.DROPPED_ITEM),
|
||||
AREA_EFFECT_CLOUD(3, EntityType.AREA_EFFECT_CLOUD),
|
||||
MINECART(10, EntityType.MINECART_RIDEABLE),
|
||||
TNT_PRIMED(50, EntityType.PRIMED_TNT),
|
||||
ENDER_CRYSTAL(51, EntityType.ENDER_CRYSTAL),
|
||||
TIPPED_ARROW(60, EntityType.ARROW),
|
||||
SNOWBALL(61, EntityType.SNOWBALL),
|
||||
EGG(62, EntityType.EGG),
|
||||
FIREBALL(63, EntityType.FIREBALL),
|
||||
SMALL_FIREBALL(64, EntityType.SMALL_FIREBALL),
|
||||
ENDER_PEARL(65, EntityType.ENDER_PEARL),
|
||||
WITHER_SKULL(66, EntityType.WITHER_SKULL),
|
||||
SHULKER_BULLET(67, EntityType.SHULKER_BULLET),
|
||||
LIAMA_SPIT(68, EntityType.LIAMA_SPIT),
|
||||
FALLING_BLOCK(70, EntityType.FALLING_BLOCK),
|
||||
ITEM_FRAME(71, EntityType.ITEM_FRAME),
|
||||
ENDER_SIGNAL(72, EntityType.ENDER_SIGNAL),
|
||||
POTION(73, EntityType.SPLASH_POTION),
|
||||
THROWN_EXP_BOTTLE(75, EntityType.THROWN_EXP_BOTTLE),
|
||||
FIREWORK(76, EntityType.FIREWORK),
|
||||
LEASH(77, EntityType.LEASH_HITCH),
|
||||
ARMOR_STAND(78, EntityType.ARMOR_STAND),
|
||||
EVOCATION_FANGS(79, EntityType.EVOCATION_FANGS),
|
||||
FISHIHNG_HOOK(90, EntityType.FISHING_HOOK),
|
||||
SPECTRAL_ARROW(91, EntityType.SPECTRAL_ARROW),
|
||||
DRAGON_FIREBALL(93, EntityType.DRAGON_FIREBALL);
|
||||
|
||||
private static final Map<Integer, ObjectType> TYPES = new HashMap<>();
|
||||
|
||||
private final int id;
|
||||
private final EntityType type;
|
||||
|
||||
static {
|
||||
for (ObjectType type : ObjectType.values()) {
|
||||
TYPES.put(type.id, type);
|
||||
}
|
||||
}
|
||||
|
||||
ObjectType(int id, EntityType type) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public static Optional<ObjectType> findById(int id) {
|
||||
if (id == -1)
|
||||
return Optional.empty();
|
||||
return Optional.ofNullable(TYPES.get(id));
|
||||
}
|
||||
|
||||
public static Optional<EntityType> getPCEntity(int id) {
|
||||
Optional<ObjectType> output = findById(id);
|
||||
|
||||
if (!output.isPresent())
|
||||
return Optional.empty();
|
||||
return Optional.of(output.get().type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,311 @@
|
||||
package us.myles.ViaVersion.api.entities;
|
||||
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
// TODO auto generate 18w11a with PAaaS
|
||||
public class Entity1_13Types {
|
||||
|
||||
public static EntityType getTypeFromId(int typeID, boolean isObject) {
|
||||
Optional<EntityType> type;
|
||||
|
||||
if (isObject)
|
||||
type = ObjectType.getPCEntity(typeID);
|
||||
else
|
||||
type = EntityType.findById(typeID);
|
||||
|
||||
if (!type.isPresent()) {
|
||||
Via.getPlatform().getLogger().severe("Could not find 1.13 type id " + typeID + " isObject=" + isObject);
|
||||
return EntityType.ENTITY; // Fall back to the basic ENTITY
|
||||
}
|
||||
|
||||
return type.get();
|
||||
}
|
||||
|
||||
public enum EntityType implements us.myles.ViaVersion.api.entities.EntityType {
|
||||
// Auto generated
|
||||
|
||||
ENTITY(-1), // abm
|
||||
|
||||
AREA_EFFECT_CLOUD(0, ENTITY), // abk
|
||||
END_CRYSTAL(16, ENTITY), // aho
|
||||
EVOKER_FANGS(20, ENTITY), // ala
|
||||
EXPERIENCE_ORB(22, ENTITY), // abs
|
||||
EYE_OF_ENDER(23, ENTITY), // alb
|
||||
FALLING_BLOCK(24, ENTITY), // aix
|
||||
FIREWORK_ROCKET(25, ENTITY), // alc
|
||||
ITEM(32, ENTITY), // aiy
|
||||
LLAMA_SPIT(37, ENTITY), // ale
|
||||
TNT(55, ENTITY), // aiz
|
||||
SHULKER_BULLET(60, ENTITY), // alh
|
||||
FISHING_BOBBER(93, ENTITY), // ais
|
||||
|
||||
LIVINGENTITY(-1, ENTITY), // abv
|
||||
ARMOR_STAND(1, LIVINGENTITY), // ail
|
||||
PLAYER(92, LIVINGENTITY), // aks
|
||||
|
||||
ABSTRACT_INSENTIENT(-1, LIVINGENTITY), // abw
|
||||
ENDER_DRAGON(17, ABSTRACT_INSENTIENT), // ahp
|
||||
|
||||
ABSTRACT_CREATURE(-1, ABSTRACT_INSENTIENT), // acd
|
||||
|
||||
ABSTRACT_AGEABLE(-1, ABSTRACT_CREATURE), // abj
|
||||
VILLAGER(79, ABSTRACT_AGEABLE), // akn
|
||||
|
||||
// Animals
|
||||
ABSTRACT_ANIMAL(-1, ABSTRACT_AGEABLE), // agd
|
||||
CHICKEN(7, ABSTRACT_ANIMAL), // age
|
||||
COW(9, ABSTRACT_ANIMAL), // agg
|
||||
MOOSHROOM(47, COW), // agi
|
||||
PIG(51, ABSTRACT_ANIMAL), // agl
|
||||
POLAR_BEAR(54, ABSTRACT_ANIMAL), // agm
|
||||
RABBIT(56, ABSTRACT_ANIMAL), // ago
|
||||
SHEEP(58, ABSTRACT_ANIMAL), // agq
|
||||
TURTLE(73, ABSTRACT_ANIMAL), // agv
|
||||
|
||||
ABSTRACT_TAMEABLE_ANIMAL(-1, ABSTRACT_ANIMAL), // acg
|
||||
OCELOT(48, ABSTRACT_TAMEABLE_ANIMAL), // agj
|
||||
WOLF(86, ABSTRACT_TAMEABLE_ANIMAL), // agy
|
||||
|
||||
ABSTRACT_PARROT(-1, ABSTRACT_TAMEABLE_ANIMAL), // agr
|
||||
PARROT(50, ABSTRACT_PARROT), // agk
|
||||
|
||||
// Horses
|
||||
ABSTRACT_HORSE(-1, ABSTRACT_ANIMAL), // aha
|
||||
CHESTED_HORSE(-1, ABSTRACT_HORSE), // agz
|
||||
DONKEY(11, CHESTED_HORSE), // ahb
|
||||
MULE(46, CHESTED_HORSE), // ahf
|
||||
LLAMA(36, CHESTED_HORSE), // ahe
|
||||
HORSE(29, ABSTRACT_HORSE), // ahc
|
||||
SKELETON_HORSE(63, ABSTRACT_HORSE), // ahg
|
||||
ZOMBIE_HORSE(88, ABSTRACT_HORSE), // ahi
|
||||
|
||||
// Golem
|
||||
ABSTRACT_GOLEM(-1, ABSTRACT_CREATURE), // agc
|
||||
SNOW_GOLEM(66, ABSTRACT_GOLEM), // ags
|
||||
IRON_GOLEM(80, ABSTRACT_GOLEM), // agw
|
||||
SHULKER(59, ABSTRACT_GOLEM), // ajx
|
||||
|
||||
// Fish
|
||||
ABSTRACT_FISHES(-1, ABSTRACT_CREATURE), // agb
|
||||
COD(8, ABSTRACT_FISHES), // agf
|
||||
PUFFERFISH(52, ABSTRACT_FISHES), // agn
|
||||
SALMON(57, ABSTRACT_FISHES), // agp
|
||||
TROPICAL_FISH(72, ABSTRACT_FISHES), // agu
|
||||
|
||||
// Monsters
|
||||
ABSTRACT_MONSTER(-1, ABSTRACT_CREATURE), // ajs
|
||||
BLAZE(4, ABSTRACT_MONSTER), // ajd
|
||||
CREEPER(10, ABSTRACT_MONSTER), // ajf
|
||||
ENDERMITE(19, ABSTRACT_MONSTER), // ajj
|
||||
ENDERMAN(18, ABSTRACT_MONSTER), // aji
|
||||
GIANT(27, ABSTRACT_MONSTER), // ajn
|
||||
SILVERFISH(61, ABSTRACT_MONSTER), // ajy
|
||||
VEX(78, ABSTRACT_MONSTER), // ake
|
||||
WITCH(82, ABSTRACT_MONSTER), // akg
|
||||
WITHER(83, ABSTRACT_MONSTER), // aij
|
||||
|
||||
// Illagers
|
||||
ABSTRACT_ILLAGER_BASE(-1, ABSTRACT_MONSTER), // ajb
|
||||
ABSTRACT_EVO_ILLU_ILLAGER(-1, ABSTRACT_ILLAGER_BASE), // akb
|
||||
EVOKER(21, ABSTRACT_EVO_ILLU_ILLAGER), // ajl
|
||||
ILLUSIONER(31, ABSTRACT_EVO_ILLU_ILLAGER), // ajq
|
||||
VINDICATOR(81, ABSTRACT_ILLAGER_BASE), // akf
|
||||
|
||||
// Skeletons
|
||||
ABSTRACT_SKELETON(-1, ABSTRACT_MONSTER), // ajc
|
||||
SKELETON(62, ABSTRACT_SKELETON), // ajz
|
||||
STRAY(71, ABSTRACT_SKELETON), // akd
|
||||
WITHER_SKELETON(84, ABSTRACT_SKELETON), // akh
|
||||
|
||||
// Guardians
|
||||
GUARDIAN(28, ABSTRACT_MONSTER), // ajo
|
||||
ELDER_GUARDIAN(15, GUARDIAN), // ajh
|
||||
|
||||
// Spiders
|
||||
SPIDER(69, ABSTRACT_MONSTER), // akc
|
||||
CAVE_SPIDER(6, SPIDER), // aje
|
||||
|
||||
// Zombies - META CHECKED
|
||||
ZOMBIE(87, ABSTRACT_MONSTER), // aki
|
||||
DROWNED(14, ZOMBIE), // ajg
|
||||
HUSK(30, ZOMBIE), // ajp
|
||||
ZOMBIE_PIGMAN(53, ZOMBIE), // aju
|
||||
ZOMBIE_VILLAGER(89, ZOMBIE), // akj
|
||||
|
||||
// Flying entities
|
||||
ABSTRACT_FLYING(-1, ABSTRACT_INSENTIENT), // abt
|
||||
GHAST(26, ABSTRACT_FLYING), // ajm
|
||||
PHANTOM(90, ABSTRACT_FLYING), // ajt
|
||||
|
||||
ABSTRACT_AMBIENT(-1, ABSTRACT_INSENTIENT), // afy
|
||||
BAT(3, ABSTRACT_AMBIENT), // afz
|
||||
|
||||
ABSTRACT_WATERMOB(-1, ABSTRACT_INSENTIENT), // agx
|
||||
SQUID(70, ABSTRACT_WATERMOB), // agt
|
||||
DOLPHIN(12, ABSTRACT_WATERMOB),
|
||||
|
||||
// Slimes
|
||||
SLIME(64, ABSTRACT_INSENTIENT), // aka
|
||||
MAGMA_CUBE(38, SLIME), // ajr
|
||||
|
||||
// Hangable objects
|
||||
ABSTRACT_HANGING(-1, ENTITY), // aim
|
||||
LEASH_KNOT(35, ABSTRACT_HANGING), // aio
|
||||
ITEM_FRAME(33, ABSTRACT_HANGING), // ain
|
||||
PAINTING(49, ABSTRACT_HANGING), // aiq
|
||||
|
||||
ABSTRACT_LIGHTNING(-1, ENTITY), // aiu
|
||||
LIGHTNING_BOLT(91, ABSTRACT_LIGHTNING), // aiv
|
||||
|
||||
// Arrows
|
||||
ABSTRACT_ARROW(-1, ENTITY), // akw
|
||||
ARROW(2, ABSTRACT_ARROW), // aky
|
||||
SPECTRAL_ARROW(68, ABSTRACT_ARROW), // alk
|
||||
TRIDENT(94, ABSTRACT_ARROW), // alq
|
||||
|
||||
// Fireballs
|
||||
ABSTRACT_FIREBALL(-1, ENTITY), // akx
|
||||
DRAGON_FIREBALL(13, ABSTRACT_FIREBALL), // akz
|
||||
FIREBALL(34, ABSTRACT_FIREBALL), // ald
|
||||
SMALL_FIREBALL(65, ABSTRACT_FIREBALL), // ali
|
||||
WITHER_SKULL(85, ABSTRACT_FIREBALL), // alr
|
||||
|
||||
// Projectiles
|
||||
PROJECTILE_ABSTRACT(-1, ENTITY), // all
|
||||
SNOWBALL(67, PROJECTILE_ABSTRACT), // alj
|
||||
ENDER_PEARL(75, PROJECTILE_ABSTRACT), // aln
|
||||
EGG(74, PROJECTILE_ABSTRACT), // alm
|
||||
POTION(77, PROJECTILE_ABSTRACT), // alp
|
||||
EXPERIENCE_BOTTLE(76, PROJECTILE_ABSTRACT), // alo
|
||||
|
||||
// Vehicles
|
||||
MINECART_ABSTRACT(-1, ENTITY), // alt
|
||||
CHESTED_MINECART_ABSTRACT(-1, MINECART_ABSTRACT), // alu
|
||||
CHEST_MINECART(40, CHESTED_MINECART_ABSTRACT), // alx
|
||||
HOPPER_MINECART(43, CHESTED_MINECART_ABSTRACT), // ama
|
||||
MINECART(39, MINECART_ABSTRACT), // alw
|
||||
FURNACE_MINECART(42, MINECART_ABSTRACT), // alz
|
||||
COMMAND_BLOCK_MINECART(41, MINECART_ABSTRACT), // aly
|
||||
TNT_MINECART(45, MINECART_ABSTRACT), // amc
|
||||
SPAWNER_MINECART(44, MINECART_ABSTRACT), // amb
|
||||
BOAT(5, ENTITY); // alv
|
||||
|
||||
private static final Map<Integer, EntityType> TYPES = new HashMap<>();
|
||||
|
||||
private final int id;
|
||||
private final EntityType parent;
|
||||
|
||||
EntityType(int id) {
|
||||
this.id = id;
|
||||
this.parent = null;
|
||||
}
|
||||
|
||||
EntityType(int id, EntityType parent) {
|
||||
this.id = id;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityType getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
static {
|
||||
for (EntityType type : EntityType.values()) {
|
||||
TYPES.put(type.id, type);
|
||||
}
|
||||
}
|
||||
|
||||
public static Optional<EntityType> findById(int id) {
|
||||
if (id == -1) // Check if this is called
|
||||
return Optional.empty();
|
||||
return Optional.ofNullable(TYPES.get(id));
|
||||
}
|
||||
}
|
||||
|
||||
public enum ObjectType implements us.myles.ViaVersion.api.entities.ObjectType {
|
||||
BOAT(1, EntityType.BOAT),
|
||||
ITEM(2, EntityType.ITEM),
|
||||
AREA_EFFECT_CLOUD(3, EntityType.AREA_EFFECT_CLOUD),
|
||||
MINECART(10, EntityType.MINECART),
|
||||
TNT_PRIMED(50, EntityType.TNT),
|
||||
ENDER_CRYSTAL(51, EntityType.END_CRYSTAL),
|
||||
TIPPED_ARROW(60, EntityType.ARROW),
|
||||
SNOWBALL(61, EntityType.SNOWBALL),
|
||||
EGG(62, EntityType.EGG),
|
||||
FIREBALL(63, EntityType.FIREBALL),
|
||||
SMALL_FIREBALL(64, EntityType.SMALL_FIREBALL),
|
||||
ENDER_PEARL(65, EntityType.ENDER_PEARL),
|
||||
WITHER_SKULL(66, EntityType.WITHER_SKULL),
|
||||
SHULKER_BULLET(67, EntityType.SHULKER_BULLET),
|
||||
LLAMA_SPIT(68, EntityType.LLAMA_SPIT),
|
||||
FALLING_BLOCK(70, EntityType.FALLING_BLOCK),
|
||||
ITEM_FRAME(71, EntityType.ITEM_FRAME),
|
||||
EYE_OF_ENDER(72, EntityType.EYE_OF_ENDER),
|
||||
POTION(73, EntityType.POTION),
|
||||
EXPERIENCE_BOTTLE(75, EntityType.EXPERIENCE_BOTTLE),
|
||||
FIREWORK_ROCKET(76, EntityType.FIREWORK_ROCKET),
|
||||
LEASH(77, EntityType.LEASH_KNOT),
|
||||
ARMOR_STAND(78, EntityType.ARMOR_STAND),
|
||||
EVOKER_FANGS(79, EntityType.EVOKER_FANGS),
|
||||
FISHIHNG_HOOK(90, EntityType.FISHING_BOBBER),
|
||||
SPECTRAL_ARROW(91, EntityType.SPECTRAL_ARROW),
|
||||
DRAGON_FIREBALL(93, EntityType.DRAGON_FIREBALL),
|
||||
TRIDENT(94, EntityType.TRIDENT);
|
||||
|
||||
private static final Map<Integer, ObjectType> TYPES = new HashMap<>();
|
||||
|
||||
private final int id;
|
||||
private final EntityType type;
|
||||
|
||||
static {
|
||||
for (ObjectType type : ObjectType.values()) {
|
||||
TYPES.put(type.id, type);
|
||||
}
|
||||
}
|
||||
|
||||
ObjectType(int id, EntityType type) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public static Optional<ObjectType> findById(int id) {
|
||||
if (id == -1)
|
||||
return Optional.empty();
|
||||
return Optional.ofNullable(TYPES.get(id));
|
||||
}
|
||||
|
||||
public static Optional<EntityType> getPCEntity(int id) {
|
||||
Optional<ObjectType> output = findById(id);
|
||||
if (!output.isPresent())
|
||||
return Optional.empty();
|
||||
return Optional.of(output.get().type);
|
||||
}
|
||||
|
||||
public static Optional<ObjectType> fromEntityType(EntityType type) {
|
||||
for (ObjectType ent : ObjectType.values())
|
||||
if (ent.type == type)
|
||||
return Optional.of(ent);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
package us.myles.ViaVersion.api.entities;
|
||||
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
|
||||
public class Entity1_14Types {
|
||||
|
||||
public static EntityType getTypeFromId(int typeID) {
|
||||
Optional<EntityType> type = EntityType.findById(typeID);
|
||||
|
||||
if (!type.isPresent()) {
|
||||
Via.getPlatform().getLogger().severe("Could not find 1.14 type id " + typeID);
|
||||
return EntityType.ENTITY; // Fall back to the basic ENTITY
|
||||
}
|
||||
|
||||
return type.get();
|
||||
}
|
||||
|
||||
public enum EntityType implements us.myles.ViaVersion.api.entities.EntityType {
|
||||
// Auto generated
|
||||
|
||||
ENTITY(-1),
|
||||
|
||||
AREA_EFFECT_CLOUD(0, ENTITY),
|
||||
END_CRYSTAL(17, ENTITY),
|
||||
EVOKER_FANGS(21, ENTITY),
|
||||
EXPERIENCE_ORB(23, ENTITY),
|
||||
EYE_OF_ENDER(24, ENTITY),
|
||||
FALLING_BLOCK(25, ENTITY),
|
||||
FIREWORK_ROCKET(26, ENTITY),
|
||||
ITEM(34, ENTITY),
|
||||
LLAMA_SPIT(39, ENTITY),
|
||||
TNT(58, ENTITY),
|
||||
SHULKER_BULLET(63, ENTITY),
|
||||
FISHING_BOBBER(101, ENTITY),
|
||||
|
||||
LIVINGENTITY(-1, ENTITY),
|
||||
ARMOR_STAND(1, LIVINGENTITY),
|
||||
PLAYER(100, LIVINGENTITY),
|
||||
|
||||
ABSTRACT_INSENTIENT(-1, LIVINGENTITY),
|
||||
ENDER_DRAGON(18, ABSTRACT_INSENTIENT),
|
||||
|
||||
ABSTRACT_CREATURE(-1, ABSTRACT_INSENTIENT),
|
||||
|
||||
ABSTRACT_AGEABLE(-1, ABSTRACT_CREATURE),
|
||||
VILLAGER(84, ABSTRACT_AGEABLE),
|
||||
WANDERING_TRADER(88, ABSTRACT_AGEABLE),
|
||||
|
||||
// Animals
|
||||
ABSTRACT_ANIMAL(-1, ABSTRACT_AGEABLE),
|
||||
DOLPHIN(13, ABSTRACT_INSENTIENT),
|
||||
CHICKEN(8, ABSTRACT_ANIMAL),
|
||||
COW(10, ABSTRACT_ANIMAL),
|
||||
MOOSHROOM(49, COW),
|
||||
PANDA(52, ABSTRACT_INSENTIENT),
|
||||
PIG(54, ABSTRACT_ANIMAL),
|
||||
POLAR_BEAR(57, ABSTRACT_ANIMAL),
|
||||
RABBIT(59, ABSTRACT_ANIMAL),
|
||||
SHEEP(61, ABSTRACT_ANIMAL),
|
||||
TURTLE(77, ABSTRACT_ANIMAL),
|
||||
FOX(27, ABSTRACT_ANIMAL),
|
||||
|
||||
ABSTRACT_TAMEABLE_ANIMAL(-1, ABSTRACT_ANIMAL),
|
||||
CAT(6, ABSTRACT_TAMEABLE_ANIMAL),
|
||||
OCELOT(50, ABSTRACT_TAMEABLE_ANIMAL),
|
||||
WOLF(93, ABSTRACT_TAMEABLE_ANIMAL),
|
||||
|
||||
ABSTRACT_PARROT(-1, ABSTRACT_TAMEABLE_ANIMAL),
|
||||
PARROT(53, ABSTRACT_PARROT),
|
||||
|
||||
// Horses
|
||||
ABSTRACT_HORSE(-1, ABSTRACT_ANIMAL),
|
||||
CHESTED_HORSE(-1, ABSTRACT_HORSE),
|
||||
DONKEY(12, CHESTED_HORSE),
|
||||
MULE(48, CHESTED_HORSE),
|
||||
LLAMA(38, CHESTED_HORSE),
|
||||
TRADER_LLAMA(75, CHESTED_HORSE),
|
||||
HORSE(31, ABSTRACT_HORSE),
|
||||
SKELETON_HORSE(66, ABSTRACT_HORSE),
|
||||
ZOMBIE_HORSE(95, ABSTRACT_HORSE),
|
||||
|
||||
// Golem
|
||||
ABSTRACT_GOLEM(-1, ABSTRACT_CREATURE),
|
||||
SNOW_GOLEM(69, ABSTRACT_GOLEM),
|
||||
IRON_GOLEM(85, ABSTRACT_GOLEM),
|
||||
SHULKER(62, ABSTRACT_GOLEM),
|
||||
|
||||
// Fish
|
||||
ABSTRACT_FISHES(-1, ABSTRACT_CREATURE),
|
||||
COD(9, ABSTRACT_FISHES),
|
||||
PUFFERFISH(55, ABSTRACT_FISHES),
|
||||
SALMON(60, ABSTRACT_FISHES),
|
||||
TROPICAL_FISH(76, ABSTRACT_FISHES),
|
||||
|
||||
// Monsters
|
||||
ABSTRACT_MONSTER(-1, ABSTRACT_CREATURE),
|
||||
BLAZE(4, ABSTRACT_MONSTER),
|
||||
CREEPER(11, ABSTRACT_MONSTER),
|
||||
ENDERMITE(20, ABSTRACT_MONSTER),
|
||||
ENDERMAN(19, ABSTRACT_MONSTER),
|
||||
GIANT(29, ABSTRACT_MONSTER),
|
||||
SILVERFISH(64, ABSTRACT_MONSTER),
|
||||
VEX(83, ABSTRACT_MONSTER),
|
||||
WITCH(89, ABSTRACT_MONSTER),
|
||||
WITHER(90, ABSTRACT_MONSTER),
|
||||
RAVAGER(98, ABSTRACT_MONSTER),
|
||||
|
||||
// Illagers
|
||||
ABSTRACT_ILLAGER_BASE(-1, ABSTRACT_MONSTER),
|
||||
ABSTRACT_EVO_ILLU_ILLAGER(-1, ABSTRACT_ILLAGER_BASE),
|
||||
EVOKER(22, ABSTRACT_EVO_ILLU_ILLAGER),
|
||||
ILLUSIONER(33, ABSTRACT_EVO_ILLU_ILLAGER),
|
||||
VINDICATOR(86, ABSTRACT_ILLAGER_BASE),
|
||||
PILLAGER(87, ABSTRACT_ILLAGER_BASE),
|
||||
|
||||
// Skeletons
|
||||
ABSTRACT_SKELETON(-1, ABSTRACT_MONSTER),
|
||||
SKELETON(65, ABSTRACT_SKELETON),
|
||||
STRAY(74, ABSTRACT_SKELETON),
|
||||
WITHER_SKELETON(91, ABSTRACT_SKELETON),
|
||||
|
||||
// Guardians
|
||||
GUARDIAN(30, ABSTRACT_MONSTER),
|
||||
ELDER_GUARDIAN(16, GUARDIAN),
|
||||
|
||||
// Spiders
|
||||
SPIDER(72, ABSTRACT_MONSTER),
|
||||
CAVE_SPIDER(7, SPIDER),
|
||||
|
||||
// Zombies - META CHECKED
|
||||
ZOMBIE(94, ABSTRACT_MONSTER),
|
||||
DROWNED(15, ZOMBIE),
|
||||
HUSK(32, ZOMBIE),
|
||||
ZOMBIE_PIGMAN(56, ZOMBIE),
|
||||
ZOMBIE_VILLAGER(96, ZOMBIE),
|
||||
|
||||
// Flying entities
|
||||
ABSTRACT_FLYING(-1, ABSTRACT_INSENTIENT),
|
||||
GHAST(28, ABSTRACT_FLYING),
|
||||
PHANTOM(97, ABSTRACT_FLYING),
|
||||
|
||||
ABSTRACT_AMBIENT(-1, ABSTRACT_INSENTIENT),
|
||||
BAT(3, ABSTRACT_AMBIENT),
|
||||
|
||||
ABSTRACT_WATERMOB(-1, ABSTRACT_INSENTIENT),
|
||||
SQUID(73, ABSTRACT_WATERMOB),
|
||||
|
||||
// Slimes
|
||||
SLIME(67, ABSTRACT_INSENTIENT),
|
||||
MAGMA_CUBE(40, SLIME),
|
||||
|
||||
// Hangable objects
|
||||
ABSTRACT_HANGING(-1, ENTITY),
|
||||
LEASH_KNOT(37, ABSTRACT_HANGING),
|
||||
ITEM_FRAME(35, ABSTRACT_HANGING),
|
||||
PAINTING(51, ABSTRACT_HANGING),
|
||||
|
||||
ABSTRACT_LIGHTNING(-1, ENTITY),
|
||||
LIGHTNING_BOLT(99, ABSTRACT_LIGHTNING),
|
||||
|
||||
// Arrows
|
||||
ABSTRACT_ARROW(-1, ENTITY),
|
||||
ARROW(2, ABSTRACT_ARROW),
|
||||
SPECTRAL_ARROW(71, ABSTRACT_ARROW),
|
||||
TRIDENT(82, ABSTRACT_ARROW),
|
||||
|
||||
// Fireballs
|
||||
ABSTRACT_FIREBALL(-1, ENTITY),
|
||||
DRAGON_FIREBALL(14, ABSTRACT_FIREBALL),
|
||||
FIREBALL(36, ABSTRACT_FIREBALL),
|
||||
SMALL_FIREBALL(68, ABSTRACT_FIREBALL),
|
||||
WITHER_SKULL(92, ABSTRACT_FIREBALL),
|
||||
|
||||
// Projectiles
|
||||
PROJECTILE_ABSTRACT(-1, ENTITY),
|
||||
SNOWBALL(70, PROJECTILE_ABSTRACT),
|
||||
ENDER_PEARL(79, PROJECTILE_ABSTRACT),
|
||||
EGG(78, PROJECTILE_ABSTRACT),
|
||||
POTION(81, PROJECTILE_ABSTRACT),
|
||||
EXPERIENCE_BOTTLE(80, PROJECTILE_ABSTRACT),
|
||||
|
||||
// Vehicles
|
||||
MINECART_ABSTRACT(-1, ENTITY),
|
||||
CHESTED_MINECART_ABSTRACT(-1, MINECART_ABSTRACT),
|
||||
CHEST_MINECART(42, CHESTED_MINECART_ABSTRACT),
|
||||
HOPPER_MINECART(45, CHESTED_MINECART_ABSTRACT),
|
||||
MINECART(41, MINECART_ABSTRACT),
|
||||
FURNACE_MINECART(44, MINECART_ABSTRACT),
|
||||
COMMAND_BLOCK_MINECART(43, MINECART_ABSTRACT),
|
||||
TNT_MINECART(47, MINECART_ABSTRACT),
|
||||
SPAWNER_MINECART(46, MINECART_ABSTRACT),
|
||||
BOAT(5, ENTITY),
|
||||
;
|
||||
|
||||
private static final Map<Integer, EntityType> TYPES = new HashMap<>();
|
||||
|
||||
private final int id;
|
||||
private final EntityType parent;
|
||||
|
||||
EntityType(int id) {
|
||||
this.id = id;
|
||||
this.parent = null;
|
||||
}
|
||||
|
||||
EntityType(int id, EntityType parent) {
|
||||
this.id = id;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityType getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
static {
|
||||
for (EntityType type : EntityType.values()) {
|
||||
TYPES.put(type.id, type);
|
||||
}
|
||||
}
|
||||
|
||||
public static Optional<EntityType> findById(int id) {
|
||||
if (id == -1)
|
||||
return Optional.empty();
|
||||
return Optional.ofNullable(TYPES.get(id));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
package us.myles.ViaVersion.api.entities;
|
||||
|
||||
import us.myles.ViaVersion.api.Via;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
|
||||
public class Entity1_15Types {
|
||||
|
||||
public static EntityType getTypeFromId(int typeID) {
|
||||
Optional<EntityType> type = EntityType.findById(typeID);
|
||||
|
||||
if (!type.isPresent()) {
|
||||
Via.getPlatform().getLogger().severe("Could not find 1.15 type id " + typeID);
|
||||
return EntityType.ENTITY; // Fall back to the basic ENTITY
|
||||
}
|
||||
|
||||
return type.get();
|
||||
}
|
||||
|
||||
public enum EntityType implements us.myles.ViaVersion.api.entities.EntityType {
|
||||
ENTITY(-1),
|
||||
|
||||
AREA_EFFECT_CLOUD(0, ENTITY),
|
||||
END_CRYSTAL(18, ENTITY),
|
||||
EVOKER_FANGS(22, ENTITY),
|
||||
EXPERIENCE_ORB(24, ENTITY),
|
||||
EYE_OF_ENDER(25, ENTITY),
|
||||
FALLING_BLOCK(26, ENTITY),
|
||||
FIREWORK_ROCKET(27, ENTITY),
|
||||
ITEM(35, ENTITY),
|
||||
LLAMA_SPIT(40, ENTITY),
|
||||
TNT(59, ENTITY),
|
||||
SHULKER_BULLET(64, ENTITY),
|
||||
FISHING_BOBBER(102, ENTITY),
|
||||
|
||||
LIVINGENTITY(-1, ENTITY),
|
||||
ARMOR_STAND(1, LIVINGENTITY),
|
||||
PLAYER(101, LIVINGENTITY),
|
||||
|
||||
ABSTRACT_INSENTIENT(-1, LIVINGENTITY),
|
||||
ENDER_DRAGON(19, ABSTRACT_INSENTIENT),
|
||||
|
||||
BEE(4, ABSTRACT_INSENTIENT),
|
||||
|
||||
ABSTRACT_CREATURE(-1, ABSTRACT_INSENTIENT),
|
||||
|
||||
ABSTRACT_AGEABLE(-1, ABSTRACT_CREATURE),
|
||||
VILLAGER(85, ABSTRACT_AGEABLE),
|
||||
WANDERING_TRADER(89, ABSTRACT_AGEABLE),
|
||||
|
||||
// Animals
|
||||
ABSTRACT_ANIMAL(-1, ABSTRACT_AGEABLE),
|
||||
DOLPHIN(14, ABSTRACT_INSENTIENT),
|
||||
CHICKEN(9, ABSTRACT_ANIMAL),
|
||||
COW(11, ABSTRACT_ANIMAL),
|
||||
MOOSHROOM(50, COW),
|
||||
PANDA(53, ABSTRACT_INSENTIENT),
|
||||
PIG(55, ABSTRACT_ANIMAL),
|
||||
POLAR_BEAR(58, ABSTRACT_ANIMAL),
|
||||
RABBIT(60, ABSTRACT_ANIMAL),
|
||||
SHEEP(62, ABSTRACT_ANIMAL),
|
||||
TURTLE(78, ABSTRACT_ANIMAL),
|
||||
FOX(28, ABSTRACT_ANIMAL),
|
||||
|
||||
ABSTRACT_TAMEABLE_ANIMAL(-1, ABSTRACT_ANIMAL),
|
||||
CAT(7, ABSTRACT_TAMEABLE_ANIMAL),
|
||||
OCELOT(51, ABSTRACT_TAMEABLE_ANIMAL),
|
||||
WOLF(94, ABSTRACT_TAMEABLE_ANIMAL),
|
||||
|
||||
ABSTRACT_PARROT(-1, ABSTRACT_TAMEABLE_ANIMAL),
|
||||
PARROT(54, ABSTRACT_PARROT),
|
||||
|
||||
// Horses
|
||||
ABSTRACT_HORSE(-1, ABSTRACT_ANIMAL),
|
||||
CHESTED_HORSE(-1, ABSTRACT_HORSE),
|
||||
DONKEY(13, CHESTED_HORSE),
|
||||
MULE(49, CHESTED_HORSE),
|
||||
LLAMA(39, CHESTED_HORSE),
|
||||
TRADER_LLAMA(76, CHESTED_HORSE),
|
||||
HORSE(32, ABSTRACT_HORSE),
|
||||
SKELETON_HORSE(67, ABSTRACT_HORSE),
|
||||
ZOMBIE_HORSE(96, ABSTRACT_HORSE),
|
||||
|
||||
// Golem
|
||||
ABSTRACT_GOLEM(-1, ABSTRACT_CREATURE),
|
||||
SNOW_GOLEM(70, ABSTRACT_GOLEM),
|
||||
IRON_GOLEM(86, ABSTRACT_GOLEM),
|
||||
SHULKER(63, ABSTRACT_GOLEM),
|
||||
|
||||
// Fish
|
||||
ABSTRACT_FISHES(-1, ABSTRACT_CREATURE),
|
||||
COD(10, ABSTRACT_FISHES),
|
||||
PUFFERFISH(56, ABSTRACT_FISHES),
|
||||
SALMON(61, ABSTRACT_FISHES),
|
||||
TROPICAL_FISH(77, ABSTRACT_FISHES),
|
||||
|
||||
// Monsters
|
||||
ABSTRACT_MONSTER(-1, ABSTRACT_CREATURE),
|
||||
BLAZE(5, ABSTRACT_MONSTER),
|
||||
CREEPER(12, ABSTRACT_MONSTER),
|
||||
ENDERMITE(21, ABSTRACT_MONSTER),
|
||||
ENDERMAN(20, ABSTRACT_MONSTER),
|
||||
GIANT(30, ABSTRACT_MONSTER),
|
||||
SILVERFISH(65, ABSTRACT_MONSTER),
|
||||
VEX(84, ABSTRACT_MONSTER),
|
||||
WITCH(90, ABSTRACT_MONSTER),
|
||||
WITHER(91, ABSTRACT_MONSTER),
|
||||
RAVAGER(99, ABSTRACT_MONSTER),
|
||||
|
||||
// Illagers
|
||||
ABSTRACT_ILLAGER_BASE(-1, ABSTRACT_MONSTER),
|
||||
ABSTRACT_EVO_ILLU_ILLAGER(-1, ABSTRACT_ILLAGER_BASE),
|
||||
EVOKER(23, ABSTRACT_EVO_ILLU_ILLAGER),
|
||||
ILLUSIONER(34, ABSTRACT_EVO_ILLU_ILLAGER),
|
||||
VINDICATOR(87, ABSTRACT_ILLAGER_BASE),
|
||||
PILLAGER(88, ABSTRACT_ILLAGER_BASE),
|
||||
|
||||
// Skeletons
|
||||
ABSTRACT_SKELETON(-1, ABSTRACT_MONSTER),
|
||||
SKELETON(66, ABSTRACT_SKELETON),
|
||||
STRAY(75, ABSTRACT_SKELETON),
|
||||
WITHER_SKELETON(92, ABSTRACT_SKELETON),
|
||||
|
||||
// Guardians
|
||||
GUARDIAN(31, ABSTRACT_MONSTER),
|
||||
ELDER_GUARDIAN(17, GUARDIAN),
|
||||
|
||||
// Spiders
|
||||
SPIDER(73, ABSTRACT_MONSTER),
|
||||
CAVE_SPIDER(8, SPIDER),
|
||||
|
||||
// Zombies
|
||||
ZOMBIE(95, ABSTRACT_MONSTER),
|
||||
DROWNED(16, ZOMBIE),
|
||||
HUSK(33, ZOMBIE),
|
||||
ZOMBIE_PIGMAN(57, ZOMBIE),
|
||||
ZOMBIE_VILLAGER(97, ZOMBIE),
|
||||
|
||||
// Flying entities
|
||||
ABSTRACT_FLYING(-1, ABSTRACT_INSENTIENT),
|
||||
GHAST(29, ABSTRACT_FLYING),
|
||||
PHANTOM(98, ABSTRACT_FLYING),
|
||||
|
||||
ABSTRACT_AMBIENT(-1, ABSTRACT_INSENTIENT),
|
||||
BAT(3, ABSTRACT_AMBIENT),
|
||||
|
||||
ABSTRACT_WATERMOB(-1, ABSTRACT_INSENTIENT),
|
||||
SQUID(74, ABSTRACT_WATERMOB),
|
||||
|
||||
// Slimes
|
||||
SLIME(68, ABSTRACT_INSENTIENT),
|
||||
MAGMA_CUBE(41, SLIME),
|
||||
|
||||
// Hangable objects
|
||||
ABSTRACT_HANGING(-1, ENTITY),
|
||||
LEASH_KNOT(38, ABSTRACT_HANGING),
|
||||
ITEM_FRAME(36, ABSTRACT_HANGING),
|
||||
PAINTING(52, ABSTRACT_HANGING),
|
||||
|
||||
ABSTRACT_LIGHTNING(-1, ENTITY),
|
||||
LIGHTNING_BOLT(100, ABSTRACT_LIGHTNING),
|
||||
|
||||
// Arrows
|
||||
ABSTRACT_ARROW(-1, ENTITY),
|
||||
ARROW(2, ABSTRACT_ARROW),
|
||||
SPECTRAL_ARROW(72, ABSTRACT_ARROW),
|
||||
TRIDENT(83, ABSTRACT_ARROW),
|
||||
|
||||
// Fireballs
|
||||
ABSTRACT_FIREBALL(-1, ENTITY),
|
||||
DRAGON_FIREBALL(15, ABSTRACT_FIREBALL),
|
||||
FIREBALL(37, ABSTRACT_FIREBALL),
|
||||
SMALL_FIREBALL(69, ABSTRACT_FIREBALL),
|
||||
WITHER_SKULL(93, ABSTRACT_FIREBALL),
|
||||
|
||||
// Projectiles
|
||||
PROJECTILE_ABSTRACT(-1, ENTITY),
|
||||
SNOWBALL(71, PROJECTILE_ABSTRACT),
|
||||
ENDER_PEARL(80, PROJECTILE_ABSTRACT),
|
||||
EGG(79, PROJECTILE_ABSTRACT),
|
||||
POTION(82, PROJECTILE_ABSTRACT),
|
||||
EXPERIENCE_BOTTLE(81, PROJECTILE_ABSTRACT),
|
||||
|
||||
// Vehicles
|
||||
MINECART_ABSTRACT(-1, ENTITY),
|
||||
CHESTED_MINECART_ABSTRACT(-1, MINECART_ABSTRACT),
|
||||
CHEST_MINECART(43, CHESTED_MINECART_ABSTRACT),
|
||||
HOPPER_MINECART(46, CHESTED_MINECART_ABSTRACT),
|
||||
MINECART(42, MINECART_ABSTRACT),
|
||||
FURNACE_MINECART(45, MINECART_ABSTRACT),
|
||||
COMMAND_BLOCK_MINECART(44, MINECART_ABSTRACT),
|
||||
TNT_MINECART(48, MINECART_ABSTRACT),
|
||||
SPAWNER_MINECART(47, MINECART_ABSTRACT),
|
||||
BOAT(6, ENTITY);
|
||||
|
||||
private static final Map<Integer, EntityType> TYPES = new HashMap<>();
|
||||
|
||||
private final int id;
|
||||
private final EntityType parent;
|
||||
|
||||
EntityType(int id) {
|
||||
this.id = id;
|
||||
this.parent = null;
|
||||
}
|
||||
|
||||
EntityType(int id, EntityType parent) {
|
||||
this.id = id;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityType getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
static {
|
||||
for (EntityType type : EntityType.values()) {
|
||||
TYPES.put(type.id, type);
|
||||
}
|
||||
}
|
||||
|
||||
public static Optional<EntityType> findById(int id) {
|
||||
if (id == -1)
|
||||
return Optional.empty();
|
||||
return Optional.ofNullable(TYPES.get(id));
|
||||
}
|
||||
}
|
||||
}
|
||||
Loaded 100 of 615 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user