Compare commits
675 Commits
Minecraft-
...
Minecraft-
Author | SHA1 | Date | |
---|---|---|---|
![]() |
7d2c2ab074 | ||
![]() |
0646a3090a | ||
![]() |
afc02082e6 | ||
![]() |
848cad2a59 | ||
![]() |
9c4380a201 | ||
![]() |
8490d611bf | ||
![]() |
a0f2c42d38 | ||
![]() |
40c0618a3a | ||
![]() |
fa3678bcdd | ||
![]() |
e556fd7150 | ||
![]() |
841c81cdc4 | ||
![]() |
052131c1fa | ||
![]() |
79dbdea107 | ||
![]() |
7fb1f4b81f | ||
![]() |
255d7fde9a | ||
![]() |
7907610eeb | ||
![]() |
83e27f07e6 | ||
![]() |
5cff0b2171 | ||
![]() |
2c86592ecd | ||
![]() |
f5552963b8 | ||
![]() |
1182affa09 | ||
![]() |
a1895c556f | ||
![]() |
aa214c0b54 | ||
![]() |
81bd3b5f71 | ||
![]() |
b6e26e0c09 | ||
![]() |
19f2e7b13e | ||
![]() |
ba448b5670 | ||
![]() |
013320fd9e | ||
![]() |
8a1030e21c | ||
![]() |
c626254825 | ||
![]() |
4e94c278da | ||
![]() |
06ad0f9310 | ||
![]() |
c4a3a052d7 | ||
![]() |
7ec1a1aa4e | ||
![]() |
59208aad86 | ||
![]() |
bd07be8772 | ||
![]() |
b3d15d53d6 | ||
![]() |
6343416c0c | ||
![]() |
81d1c46a0d | ||
![]() |
6e5132f914 | ||
![]() |
f3c14cf064 | ||
![]() |
a3a31fd2dd | ||
![]() |
cc3a8c067e | ||
![]() |
918d7229c2 | ||
![]() |
6c4e684de9 | ||
![]() |
9cf57ca929 | ||
![]() |
70564d9f44 | ||
![]() |
8622cf3af4 | ||
![]() |
5236dd301a | ||
![]() |
ddfd76ebda | ||
![]() |
93959cab4b | ||
![]() |
585ab4f453 | ||
![]() |
76052b92d3 | ||
![]() |
f9773a69c3 | ||
![]() |
88e71ead05 | ||
![]() |
d1e1ce4cdb | ||
![]() |
fa828eba31 | ||
![]() |
d76c8d4f33 | ||
![]() |
a48c458306 | ||
![]() |
3973c511f5 | ||
![]() |
78ea41015f | ||
![]() |
bd2eaf6879 | ||
![]() |
f2d17cb216 | ||
![]() |
f2673c5876 | ||
![]() |
e1951c5d66 | ||
![]() |
988490ba87 | ||
![]() |
62981e4c70 | ||
![]() |
5699e86270 | ||
![]() |
61cee2d27c | ||
![]() |
2055c98ebe | ||
![]() |
415d5860e4 | ||
![]() |
3776feb559 | ||
![]() |
668cdabdf7 | ||
![]() |
3e26eecd4e | ||
![]() |
7c1f232e85 | ||
![]() |
2b49358bea | ||
![]() |
b4997f6379 | ||
![]() |
eeaa44e1e7 | ||
![]() |
f4ae511af0 | ||
![]() |
32693aeaff | ||
![]() |
0d569ac0d1 | ||
![]() |
e6da9cbba8 | ||
![]() |
61d2765715 | ||
![]() |
e68ed48fc3 | ||
![]() |
cf722de1d2 | ||
![]() |
28496e0471 | ||
![]() |
4809f1f80a | ||
![]() |
ae12554316 | ||
![]() |
5091515f0b | ||
![]() |
52b75cd18b | ||
![]() |
a5f2b423d4 | ||
![]() |
54c9ade1a6 | ||
![]() |
bc6d7719a7 | ||
![]() |
2ab0715226 | ||
![]() |
1711223b02 | ||
![]() |
cd15b82361 | ||
![]() |
22084b2c75 | ||
![]() |
972b4c1fe5 | ||
![]() |
36c4af35de | ||
![]() |
02d3660f32 | ||
![]() |
37e37e9a55 | ||
![]() |
a03c21cc09 | ||
![]() |
45bf7a9ab9 | ||
![]() |
ef364d9053 | ||
![]() |
f19cc7fe4f | ||
![]() |
772c8d7f2b | ||
![]() |
830f18a357 | ||
![]() |
c21275b877 | ||
![]() |
532a94382b | ||
![]() |
56c372a3ce | ||
![]() |
faf903469e | ||
![]() |
4d389df7c8 | ||
![]() |
cfad2c65d4 | ||
![]() |
8715c5fd82 | ||
![]() |
cbb190cfd3 | ||
![]() |
acf5f2f443 | ||
![]() |
57a07dc2e2 | ||
![]() |
6fcfb5aecb | ||
![]() |
4e3b5670a0 | ||
![]() |
ee3b209c2d | ||
![]() |
25ee8a1496 | ||
![]() |
988905331f | ||
![]() |
dd1a28ea1e | ||
![]() |
0a0146b68a | ||
![]() |
ca2227bad4 | ||
![]() |
3cd4f169bd | ||
![]() |
5ec36efb52 | ||
![]() |
dcc9be9dfe | ||
![]() |
efdedbd4e8 | ||
![]() |
1623fb6952 | ||
![]() |
4e353e9277 | ||
![]() |
d6b7157c1c | ||
![]() |
bc48ab3fb8 | ||
![]() |
65ae8b4c6a | ||
![]() |
73d7e0cf99 | ||
![]() |
2cec5f344a | ||
![]() |
4573285a70 | ||
![]() |
5282a8f45a | ||
![]() |
6eedc77954 | ||
![]() |
f15eed338d | ||
![]() |
faa284c8fc | ||
![]() |
4bb3850b40 | ||
![]() |
1f132876e6 | ||
![]() |
c822c48fef | ||
![]() |
26521cf2ff | ||
![]() |
e99bbff22e | ||
![]() |
19b48672af | ||
![]() |
f81b8a3550 | ||
![]() |
87797ef719 | ||
![]() |
86c5e321f2 | ||
![]() |
41ccf3f9d3 | ||
![]() |
e573f7b89c | ||
![]() |
664c66fb97 | ||
![]() |
caa562c4a1 | ||
![]() |
483805067d | ||
![]() |
5e0aa2e60d | ||
![]() |
f9f9c3213d | ||
![]() |
be35e283ec | ||
![]() |
dd9bd2a2e3 | ||
![]() |
3188d946b3 | ||
![]() |
072e360d0f | ||
![]() |
ee3efd75d7 | ||
![]() |
d85400bc69 | ||
![]() |
b544bb34cb | ||
![]() |
8676dd47f6 | ||
![]() |
089a8dd311 | ||
![]() |
d1d4cc7bbf | ||
![]() |
74f5ffd08b | ||
![]() |
9fc862cb74 | ||
![]() |
0d174b51c5 | ||
![]() |
1b18e64fb2 | ||
![]() |
c42d3a375f | ||
![]() |
fc0a21f548 | ||
![]() |
65eba06980 | ||
![]() |
87a64c3f3e | ||
![]() |
be13a00386 | ||
![]() |
949f150ea0 | ||
![]() |
c965e60f5e | ||
![]() |
02e219262a | ||
![]() |
a0e8b172ef | ||
![]() |
215b70dcd7 | ||
![]() |
a6095c680f | ||
![]() |
9d5c886045 | ||
![]() |
19bb8f72c7 | ||
![]() |
4dfd510583 | ||
![]() |
705b554b3b | ||
![]() |
6615500f08 | ||
![]() |
d63d5a2791 | ||
![]() |
2444dd15ab | ||
![]() |
2dd3d2101d | ||
![]() |
8ce26e0370 | ||
![]() |
5d1b660e32 | ||
![]() |
7347daf203 | ||
![]() |
02cb1fc65b | ||
![]() |
7318750ed0 | ||
![]() |
21be93a1b1 | ||
![]() |
bb69af5cd0 | ||
![]() |
a668da76d0 | ||
![]() |
4cc009a9c0 | ||
![]() |
4ef58d53b1 | ||
![]() |
afa37505c5 | ||
![]() |
a53b63720b | ||
![]() |
348457f613 | ||
![]() |
fbb2f695b0 | ||
![]() |
350cbd7bb6 | ||
![]() |
489242b1ef | ||
![]() |
4ac117fb4c | ||
![]() |
500b0af782 | ||
![]() |
2b304ecebc | ||
![]() |
81d83bdd8a | ||
![]() |
b9f2f3cfae | ||
![]() |
923aa05d4a | ||
![]() |
e54388a5e0 | ||
![]() |
59ba644623 | ||
![]() |
fbc69543fd | ||
![]() |
4d1f0cbb26 | ||
![]() |
e849afbb23 | ||
![]() |
1a7efeabc4 | ||
![]() |
f6e41c856c | ||
![]() |
151344aaff | ||
![]() |
b167a45690 | ||
![]() |
31bd836203 | ||
![]() |
4dce37cd13 | ||
![]() |
107d6b011d | ||
![]() |
f23691df23 | ||
![]() |
77f6930280 | ||
![]() |
9604a9a31e | ||
![]() |
91989564e5 | ||
![]() |
3c938c03c7 | ||
![]() |
9226df86f0 | ||
![]() |
00db351dd6 | ||
![]() |
ad2ff54b76 | ||
![]() |
ece641da23 | ||
![]() |
2af8dac70c | ||
![]() |
33a098f4ba | ||
![]() |
e4e01ccb55 | ||
![]() |
6c9e6abc9f | ||
![]() |
84c7e073e0 | ||
![]() |
9e46739343 | ||
![]() |
8fe72383a1 | ||
![]() |
a56bbe38b2 | ||
![]() |
312a74c5f1 | ||
![]() |
71c86f9f90 | ||
![]() |
6475385f87 | ||
![]() |
6775b9230c | ||
![]() |
c8e6b6fd7a | ||
![]() |
bca3663a1f | ||
![]() |
f71272a1c0 | ||
![]() |
ca7c755ecd | ||
![]() |
5a638f2290 | ||
![]() |
3715756be7 | ||
![]() |
1a1a51b38d | ||
![]() |
bc2b4db419 | ||
![]() |
994a996981 | ||
![]() |
e2eba52162 | ||
![]() |
13decac4b9 | ||
![]() |
7ebe5184a4 | ||
![]() |
b08f1995f6 | ||
![]() |
a642346a2c | ||
![]() |
18316eb5f8 | ||
![]() |
3ced0b675d | ||
![]() |
66a70fef5b | ||
![]() |
dc2da29c16 | ||
![]() |
3b71a2b570 | ||
![]() |
1aa5379030 | ||
![]() |
153bca00be | ||
![]() |
747628f40c | ||
![]() |
bf9521472b | ||
![]() |
86ef046544 | ||
![]() |
cd518690fd | ||
![]() |
1d3adc5317 | ||
![]() |
13848def72 | ||
![]() |
a4dd0dba88 | ||
![]() |
e025ad8ed7 | ||
![]() |
720f5df2f4 | ||
![]() |
52bf6184c7 | ||
![]() |
f7a5748464 | ||
![]() |
61e3d27ae9 | ||
![]() |
1bbbfdb0d5 | ||
![]() |
a8584f81ed | ||
![]() |
5ae2e24c84 | ||
![]() |
c29676e4fc | ||
![]() |
92ebce2ec6 | ||
![]() |
9cd7c1ac03 | ||
![]() |
924dcaab38 | ||
![]() |
8502ab54c0 | ||
![]() |
3301c95066 | ||
![]() |
49f4dcb5b7 | ||
![]() |
13d679e7d7 | ||
![]() |
72cadac76e | ||
![]() |
227301ec73 | ||
![]() |
f2b0e3e3c3 | ||
![]() |
575a6b6ea0 | ||
![]() |
5beafed279 | ||
![]() |
2a7ad3c2b2 | ||
![]() |
00352f585a | ||
![]() |
290e31b4c5 | ||
![]() |
1fb7a3bf1d | ||
![]() |
52fbceec54 | ||
![]() |
e609145a0d | ||
![]() |
4a7f8015e5 | ||
![]() |
003a1973d4 | ||
![]() |
db7f3c770d | ||
![]() |
eec3c09c32 | ||
![]() |
565af4d53e | ||
![]() |
37ed331515 | ||
![]() |
38f12840ca | ||
![]() |
941450b4e4 | ||
![]() |
e87d25c321 | ||
![]() |
886f7499fb | ||
![]() |
8064a3d4fb | ||
![]() |
5039922fa7 | ||
![]() |
eb753c8109 | ||
![]() |
7bfa024c23 | ||
![]() |
d98ade5a9b | ||
![]() |
a272afd693 | ||
![]() |
0f24eaeea3 | ||
![]() |
56e9e6a245 | ||
![]() |
87f3706736 | ||
![]() |
90104b03b7 | ||
![]() |
a9b2660aa8 | ||
![]() |
0b7789035f | ||
![]() |
3f7850dc5a | ||
![]() |
2e80bf30dd | ||
![]() |
b3627652f2 | ||
![]() |
b5216148d6 | ||
![]() |
4faf507ad9 | ||
![]() |
9a4f0a6f59 | ||
![]() |
98a5db9abf | ||
![]() |
015dc0c65a | ||
![]() |
c1b9e9032f | ||
![]() |
5e5038c839 | ||
![]() |
36ea27454d | ||
![]() |
2eb2953442 | ||
![]() |
4abffa9f24 | ||
![]() |
f08df9555c | ||
![]() |
4c5689d10e | ||
![]() |
224db6596e | ||
![]() |
df82720ade | ||
![]() |
33f87498be | ||
![]() |
d0af22a0f2 | ||
![]() |
4fa137a465 | ||
![]() |
0d7ee821d2 | ||
![]() |
1f1cdb47e4 | ||
![]() |
ddab9a84c4 | ||
![]() |
5adc0000d8 | ||
![]() |
a0cc5d84be | ||
![]() |
edce7f7c3d | ||
![]() |
19b4c09a16 | ||
![]() |
35a5230b52 | ||
![]() |
90fcfecb7c | ||
![]() |
542d2c2a5b | ||
![]() |
649f83dee2 | ||
![]() |
842392d59c | ||
![]() |
b2f517fa63 | ||
![]() |
5c12f900b3 | ||
![]() |
6641d199b3 | ||
![]() |
83b0229277 | ||
![]() |
5f7963b0c4 | ||
![]() |
dae96ac18b | ||
![]() |
aa91354666 | ||
![]() |
05f4e69afd | ||
![]() |
71e64bf532 | ||
![]() |
219d485835 | ||
![]() |
b698fa9806 | ||
![]() |
6602c22147 | ||
![]() |
f1b329bf21 | ||
![]() |
d4e4796739 | ||
![]() |
ab1aacbdc9 | ||
![]() |
a426a5ec22 | ||
![]() |
93cf50b4e1 | ||
![]() |
7483b4d276 | ||
![]() |
4be58a7c00 | ||
![]() |
90d68bd38e | ||
![]() |
7dba8c8a87 | ||
![]() |
cb4f70ecc7 | ||
![]() |
2100da2a9f | ||
![]() |
986f52b1e1 | ||
![]() |
7faefde51b | ||
![]() |
8c367d86e7 | ||
![]() |
80caa2b669 | ||
![]() |
9f8c04ef86 | ||
![]() |
b0a8371570 | ||
![]() |
0d7cd78901 | ||
![]() |
e7f1a88e6e | ||
![]() |
28c8bf47ff | ||
![]() |
5e57356e6a | ||
![]() |
f3766bc10b | ||
![]() |
6c795a25ff | ||
![]() |
d3159fe6ca | ||
![]() |
93ba9b3a3e | ||
![]() |
c184667a26 | ||
![]() |
5ea4763ae9 | ||
![]() |
d0d0f4ec9f | ||
![]() |
0ff1f4724a | ||
![]() |
1baba3cd7d | ||
![]() |
608eaace1c | ||
![]() |
075518b643 | ||
![]() |
f7d3dfd61d | ||
![]() |
b713ccff10 | ||
![]() |
f0e1625078 | ||
![]() |
60d6f31876 | ||
![]() |
359e2b2a16 | ||
![]() |
0dcba749dc | ||
![]() |
00ac965d42 | ||
![]() |
32c6ab710a | ||
![]() |
5d68b422e5 | ||
![]() |
6093cde93f | ||
![]() |
4537055caa | ||
![]() |
17fc120e07 | ||
![]() |
230cca0f9e | ||
![]() |
cfda905d98 | ||
![]() |
bc746a546f | ||
![]() |
70bb3ddcce | ||
![]() |
4ef15ae764 | ||
![]() |
3f9ca85831 | ||
![]() |
c17fa03ccd | ||
![]() |
0040955204 | ||
![]() |
60e2e6bfa4 | ||
![]() |
2cb3b6f934 | ||
![]() |
c7e590e286 | ||
![]() |
696679809d | ||
![]() |
e3e551d825 | ||
![]() |
854b6faf0e | ||
![]() |
890fac27c5 | ||
![]() |
35c1b26a20 | ||
![]() |
2c8b15cb1e | ||
![]() |
c20d8f9cd6 | ||
![]() |
85c27f30ee | ||
![]() |
0446351f9d | ||
![]() |
54d307da57 | ||
![]() |
81e43aab98 | ||
![]() |
18db187347 | ||
![]() |
63d49ac296 | ||
![]() |
aad83d787f | ||
![]() |
af751dae5a | ||
![]() |
f7851b0436 | ||
![]() |
d7e78d0945 | ||
![]() |
94ee61cd35 | ||
![]() |
897a59254c | ||
![]() |
c1ba555553 | ||
![]() |
c70006a36c | ||
![]() |
12ef019d69 | ||
![]() |
c18537f294 | ||
![]() |
fc189e81d5 | ||
![]() |
aaa8b4a53d | ||
![]() |
e39428ea0b | ||
![]() |
e4602f027e | ||
![]() |
2f2406206e | ||
![]() |
3ae8308a4b | ||
![]() |
8a38921f21 | ||
![]() |
cc0d3a8e49 | ||
![]() |
f81bf8e7c5 | ||
![]() |
e755573fb3 | ||
![]() |
a201b5897a | ||
![]() |
b4cd88c13d | ||
![]() |
8e390b5714 | ||
![]() |
14371a1a8c | ||
![]() |
61326db3ee | ||
![]() |
90625bc196 | ||
![]() |
155e274e72 | ||
![]() |
04b52aa4f4 | ||
![]() |
4040d9f20a | ||
![]() |
02619c6132 | ||
![]() |
26863032a1 | ||
![]() |
a0d3bf97d1 | ||
![]() |
3becbe4d38 | ||
![]() |
7205e69ce6 | ||
![]() |
c84d6f0035 | ||
![]() |
20b1b37e54 | ||
![]() |
2117a6b7de | ||
![]() |
e6c1015027 | ||
![]() |
8665784bb5 | ||
![]() |
efd5bd58e4 | ||
![]() |
e006673550 | ||
![]() |
2129cb3614 | ||
![]() |
6ce43fb876 | ||
![]() |
b9158b7322 | ||
![]() |
5dfd14fbe5 | ||
![]() |
e1f7b7b126 | ||
![]() |
4dff25f880 | ||
![]() |
5dc91e3a01 | ||
![]() |
e2e32100cd | ||
![]() |
a7e4854661 | ||
![]() |
6e69d476ef | ||
![]() |
1e2eda94db | ||
![]() |
37dc600fe0 | ||
![]() |
07d9a56567 | ||
![]() |
0952e53d11 | ||
![]() |
2101964330 | ||
![]() |
cdf47d84d8 | ||
![]() |
b7babd2888 | ||
![]() |
da5fa4bb7c | ||
![]() |
00854988fb | ||
![]() |
4f8085678c | ||
![]() |
6341ad4c5a | ||
![]() |
9b84e75eaa | ||
![]() |
194b09b2dd | ||
![]() |
3b9af0ab85 | ||
![]() |
18db20fe42 | ||
![]() |
062dd38b2b | ||
![]() |
69b209bcc6 | ||
![]() |
d96e561a6f | ||
![]() |
26be0566f4 | ||
![]() |
1551bf6f3a | ||
![]() |
e0ebf1af21 | ||
![]() |
b8c9330bd6 | ||
![]() |
1b41682e37 | ||
![]() |
b358fd25f5 | ||
![]() |
dbdae87ec6 | ||
![]() |
7121c20338 | ||
![]() |
d900417d95 | ||
![]() |
7be929bb08 | ||
![]() |
4257b81d8c | ||
![]() |
96acdb97fd | ||
![]() |
edc5b4dc91 | ||
![]() |
220a95aece | ||
![]() |
4685099808 | ||
![]() |
6c14f40108 | ||
![]() |
b041d84063 | ||
![]() |
a9d3d9461f | ||
![]() |
3fc7064997 | ||
![]() |
80001aa1f0 | ||
![]() |
a0d94282f6 | ||
![]() |
33e11f4c44 | ||
![]() |
b541e7aa76 | ||
![]() |
dd06937a3b | ||
![]() |
891dc87b16 | ||
![]() |
8e77cb35ff | ||
![]() |
59b32a8621 | ||
![]() |
02324206e3 | ||
![]() |
73ce828e6e | ||
![]() |
79d04bec2e | ||
![]() |
cbcd874d47 | ||
![]() |
09f123ce9a | ||
![]() |
0a5f8556fe | ||
![]() |
103a509f26 | ||
![]() |
32a5271dc3 | ||
![]() |
14389eb370 | ||
![]() |
a8b6a6b4aa | ||
![]() |
8133304cce | ||
![]() |
3e8c21a485 | ||
![]() |
f12dcc72d9 | ||
![]() |
a7a32509c7 | ||
![]() |
703a393888 | ||
![]() |
3c961cd5d9 | ||
![]() |
12ee68a315 | ||
![]() |
db5510cc4e | ||
![]() |
5ed5c71aea | ||
![]() |
38a8469ab4 | ||
![]() |
9538dcf4d4 | ||
![]() |
33f654ce6f | ||
![]() |
c108e4e1ce | ||
![]() |
e998faeec1 | ||
![]() |
d67acd7bc9 | ||
![]() |
702f434db1 | ||
![]() |
47b5631562 | ||
![]() |
80e23d6646 | ||
![]() |
1dca12cffb | ||
![]() |
29c897c9cf | ||
![]() |
042f47cbb9 | ||
![]() |
422e97f495 | ||
![]() |
08789d8f9f | ||
![]() |
96444ae304 | ||
![]() |
af58db8a67 | ||
![]() |
49cffebd9b | ||
![]() |
ffdb917f2c | ||
![]() |
9c9657e36d | ||
![]() |
1342baed47 | ||
![]() |
e3a7490bcd | ||
![]() |
3e8693793c | ||
![]() |
bb47aba682 | ||
![]() |
d0e5ee4e09 | ||
![]() |
07e330b005 | ||
![]() |
024288e587 | ||
![]() |
53a6bb1dee | ||
![]() |
0f06b2c4e0 | ||
![]() |
d3c1acce83 | ||
![]() |
eaea090d37 | ||
![]() |
7384e797fc | ||
![]() |
d4d93ddbb9 | ||
![]() |
ccdf2a89d8 | ||
![]() |
89edb00c05 | ||
![]() |
00a0277a13 | ||
![]() |
68f11e46f7 | ||
![]() |
c352e854ee | ||
![]() |
d8c92cd311 | ||
![]() |
99f361ca77 | ||
![]() |
738ed99d54 | ||
![]() |
ad0da59267 | ||
![]() |
1dcc8d6a4b | ||
![]() |
0840a77153 | ||
![]() |
61a93a54a9 | ||
![]() |
da0281508e | ||
![]() |
51e92de2dd | ||
![]() |
f948acd634 | ||
![]() |
773ce089c1 | ||
![]() |
a07eba7965 | ||
![]() |
b68b6a76c7 | ||
![]() |
332033bb02 | ||
![]() |
172b8bc75b | ||
![]() |
db5a147491 | ||
![]() |
f083e27649 | ||
![]() |
b64a7be19b | ||
![]() |
c4d60a8fa9 | ||
![]() |
f07cfe0cf7 | ||
![]() |
4463b0c1b2 | ||
![]() |
ee8f33c196 | ||
![]() |
14ac2dd308 | ||
![]() |
fb94612315 | ||
![]() |
4c96880580 | ||
![]() |
4c4cdd51a1 | ||
![]() |
1f38152530 | ||
![]() |
911f08d52c | ||
![]() |
8f961c9d4e | ||
![]() |
8a5d8a57f7 | ||
![]() |
c54553d0f9 | ||
![]() |
600a1b4ff5 | ||
![]() |
09e592295f | ||
![]() |
fa0ee02beb | ||
![]() |
b23b54d9e4 | ||
![]() |
b3e8feb4cb | ||
![]() |
d0d1562155 | ||
![]() |
f510ab2a0b | ||
![]() |
fb1cab499d | ||
![]() |
58ca63e2b1 | ||
![]() |
499337c98e | ||
![]() |
526137be7b | ||
![]() |
47839cb11c | ||
![]() |
55a6cc56ef | ||
![]() |
8c2bea5be2 | ||
![]() |
daa58ffe58 | ||
![]() |
0189ad9c17 | ||
![]() |
9adcb05d45 | ||
![]() |
10e81041b2 | ||
![]() |
0c56945ffd | ||
![]() |
0a36cbd5bc | ||
![]() |
61b4777177 | ||
![]() |
7d1904584b | ||
![]() |
475571986c | ||
![]() |
55c2bcd634 | ||
![]() |
db4abfe486 | ||
![]() |
9424bdedca | ||
![]() |
52b3c6b77c | ||
![]() |
be29799f5a | ||
![]() |
c0d581d41f | ||
![]() |
6b50c7c599 | ||
![]() |
b4101874cc | ||
![]() |
66de4c95ef | ||
![]() |
927a295add | ||
![]() |
2cbea83c02 | ||
![]() |
87884ad084 | ||
![]() |
94cc2412e7 | ||
![]() |
924b90e325 | ||
![]() |
3f476a30b4 | ||
![]() |
f579b31bca | ||
![]() |
cac35116c3 | ||
![]() |
bd42fb23a0 | ||
![]() |
ffbebaff69 | ||
![]() |
b741722e5d | ||
![]() |
07288c722c | ||
![]() |
85e82a2e34 | ||
![]() |
3aef35ccbb | ||
![]() |
d1760dad93 | ||
![]() |
d3d11cf283 | ||
![]() |
d3bada58d4 | ||
![]() |
23517a9a97 | ||
![]() |
fdc87e88f5 | ||
![]() |
12941ffe62 | ||
![]() |
06e732d8c7 | ||
![]() |
5c4ea3c7a0 | ||
![]() |
632fa8bd94 | ||
![]() |
8732904bfd | ||
![]() |
788b96dc0a | ||
![]() |
1296783d9b |
6
.gitignore
vendored
6
.gitignore
vendored
@@ -1,7 +1,7 @@
|
|||||||
# Eclipse stuff
|
# Eclipse stuff
|
||||||
.classpath
|
.classpath
|
||||||
.project
|
.project
|
||||||
.settings
|
.settings/
|
||||||
|
|
||||||
# netbeans
|
# netbeans
|
||||||
nbproject/
|
nbproject/
|
||||||
@@ -34,4 +34,6 @@ manifest.mf
|
|||||||
|
|
||||||
# other files
|
# other files
|
||||||
*.log*
|
*.log*
|
||||||
*.yml
|
|
||||||
|
# delombok
|
||||||
|
*/src/main/lombok
|
||||||
|
@@ -1,5 +1,8 @@
|
|||||||
|
sudo: false
|
||||||
language: java
|
language: java
|
||||||
jdk:
|
jdk:
|
||||||
- openjdk7
|
- openjdk7
|
||||||
|
- oraclejdk7
|
||||||
|
- oraclejdk8
|
||||||
notifications:
|
notifications:
|
||||||
email: false
|
email: false
|
||||||
|
22
api/pom.xml
22
api/pom.xml
@@ -6,13 +6,13 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>net.md-5</groupId>
|
<groupId>net.md-5</groupId>
|
||||||
<artifactId>bungeecord-parent</artifactId>
|
<artifactId>bungeecord-parent</artifactId>
|
||||||
<version>1.5-SNAPSHOT</version>
|
<version>1.8-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<groupId>net.md-5</groupId>
|
<groupId>net.md-5</groupId>
|
||||||
<artifactId>bungeecord-api</artifactId>
|
<artifactId>bungeecord-api</artifactId>
|
||||||
<version>1.5-SNAPSHOT</version>
|
<version>1.8-SNAPSHOT</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>BungeeCord-API</name>
|
<name>BungeeCord-API</name>
|
||||||
@@ -20,15 +20,15 @@
|
|||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.guava</groupId>
|
<groupId>net.md-5</groupId>
|
||||||
<artifactId>guava</artifactId>
|
<artifactId>bungeecord-chat</artifactId>
|
||||||
<version>14.0.1</version>
|
<version>${project.version}</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.ning</groupId>
|
<groupId>net.md-5</groupId>
|
||||||
<artifactId>async-http-client</artifactId>
|
<artifactId>bungeecord-config</artifactId>
|
||||||
<version>1.7.17</version>
|
<version>${project.version}</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -43,11 +43,5 @@
|
|||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.yaml</groupId>
|
|
||||||
<artifactId>snakeyaml</artifactId>
|
|
||||||
<version>1.12</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
@@ -1,7 +1,10 @@
|
|||||||
package net.md_5.bungee;
|
package net.md_5.bungee;
|
||||||
|
|
||||||
|
import com.google.common.base.Joiner;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.Collection;
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Series of utility classes to perform various operations.
|
* Series of utility classes to perform various operations.
|
||||||
@@ -9,7 +12,7 @@ import java.util.Collection;
|
|||||||
public class Util
|
public class Util
|
||||||
{
|
{
|
||||||
|
|
||||||
private static final int DEFAULT_PORT = 25565;
|
public static final int DEFAULT_PORT = 25565;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to transform human readable addresses into usable address objects.
|
* Method to transform human readable addresses into usable address objects.
|
||||||
@@ -19,13 +22,16 @@ public class Util
|
|||||||
*/
|
*/
|
||||||
public static InetSocketAddress getAddr(String hostline)
|
public static InetSocketAddress getAddr(String hostline)
|
||||||
{
|
{
|
||||||
String[] split = hostline.split( ":" );
|
URI uri;
|
||||||
int port = DEFAULT_PORT;
|
try
|
||||||
if ( split.length > 1 )
|
|
||||||
{
|
{
|
||||||
port = Integer.parseInt( split[1] );
|
uri = new URI( "tcp://" + hostline );
|
||||||
|
} catch ( URISyntaxException ex )
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException( "Bad hostline", ex );
|
||||||
}
|
}
|
||||||
return new InetSocketAddress( split[0], port );
|
|
||||||
|
return new InetSocketAddress( uri.getHost(), ( uri.getPort() ) == -1 ? DEFAULT_PORT : uri.getPort() );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -54,20 +60,24 @@ public class Util
|
|||||||
+ ( ( trace.length > 0 ) ? " @ " + t.getStackTrace()[0].getClassName() + ":" + t.getStackTrace()[0].getLineNumber() : "" );
|
+ ( ( trace.length > 0 ) ? " @ " + t.getStackTrace()[0].getClassName() + ":" + t.getStackTrace()[0].getLineNumber() : "" );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String csv(Collection<?> objects)
|
public static String csv(Iterable<?> objects)
|
||||||
{
|
{
|
||||||
return format( objects, ", " );
|
return format( objects, ", " );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String format(Collection<?> objects, String separators)
|
public static String format(Iterable<?> objects, String separators)
|
||||||
{
|
{
|
||||||
StringBuilder ret = new StringBuilder();
|
return Joiner.on( separators ).join( objects );
|
||||||
for ( Object o : objects )
|
}
|
||||||
{
|
|
||||||
ret.append( o );
|
|
||||||
ret.append( separators );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ( ret.length() == 0 ) ? "" : ret.substring( 0, ret.length() - separators.length() );
|
/**
|
||||||
|
* Converts a String to a UUID
|
||||||
|
*
|
||||||
|
* @param uuid The string to be converted
|
||||||
|
* @return The result
|
||||||
|
*/
|
||||||
|
public static UUID getUUID(String uuid)
|
||||||
|
{
|
||||||
|
return UUID.fromString( uuid.substring( 0, 8 ) + "-" + uuid.substring( 8, 12 ) + "-" + uuid.substring( 12, 16 ) + "-" + uuid.substring( 16, 20 ) + "-" + uuid.substring( 20, 32 ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -0,0 +1,46 @@
|
|||||||
|
package net.md_5.bungee.api;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import net.md_5.bungee.api.config.ServerInfo;
|
||||||
|
import net.md_5.bungee.api.connection.PendingConnection;
|
||||||
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
|
|
||||||
|
public abstract class AbstractReconnectHandler implements ReconnectHandler
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ServerInfo getServer(ProxiedPlayer player)
|
||||||
|
{
|
||||||
|
ServerInfo server = getForcedHost( player.getPendingConnection() );
|
||||||
|
if ( server == null )
|
||||||
|
{
|
||||||
|
server = getStoredServer( player );
|
||||||
|
if ( server == null )
|
||||||
|
{
|
||||||
|
server = ProxyServer.getInstance().getServerInfo( player.getPendingConnection().getListener().getDefaultServer() );
|
||||||
|
}
|
||||||
|
|
||||||
|
Preconditions.checkState( server != null, "Default server not defined" );
|
||||||
|
}
|
||||||
|
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ServerInfo getForcedHost(PendingConnection con)
|
||||||
|
{
|
||||||
|
if ( con.getVirtualHost() == null )
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String forced = con.getListener().getForcedHosts().get( con.getVirtualHost().getHostString() );
|
||||||
|
|
||||||
|
if ( forced == null && con.getListener().isForceDefault() )
|
||||||
|
{
|
||||||
|
forced = con.getListener().getDefaultServer();
|
||||||
|
}
|
||||||
|
return ProxyServer.getInstance().getServerInfo( forced );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract ServerInfo getStoredServer(ProxiedPlayer player);
|
||||||
|
}
|
@@ -1,5 +1,7 @@
|
|||||||
package net.md_5.bungee.api;
|
package net.md_5.bungee.api;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
public interface CommandSender
|
public interface CommandSender
|
||||||
@@ -17,6 +19,7 @@ public interface CommandSender
|
|||||||
*
|
*
|
||||||
* @param message the message to send
|
* @param message the message to send
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void sendMessage(String message);
|
public void sendMessage(String message);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -25,8 +28,23 @@ public interface CommandSender
|
|||||||
*
|
*
|
||||||
* @param messages the messages to send
|
* @param messages the messages to send
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void sendMessages(String... messages);
|
public void sendMessages(String... messages);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a message to this sender.
|
||||||
|
*
|
||||||
|
* @param message the message to send
|
||||||
|
*/
|
||||||
|
public void sendMessage(BaseComponent... message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a message to this sender.
|
||||||
|
*
|
||||||
|
* @param message the message to send
|
||||||
|
*/
|
||||||
|
public void sendMessage(BaseComponent message);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all groups this user is part of. This returns an unmodifiable
|
* Get all groups this user is part of. This returns an unmodifiable
|
||||||
* collection.
|
* collection.
|
||||||
@@ -64,4 +82,12 @@ public interface CommandSender
|
|||||||
* @param value the value of the node
|
* @param value the value of the node
|
||||||
*/
|
*/
|
||||||
public void setPermission(String permission, boolean value);
|
public void setPermission(String permission, boolean value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all Permissions which this CommandSender has
|
||||||
|
*
|
||||||
|
* @return a unmodifiable Collection of Strings which represent their
|
||||||
|
* permissions
|
||||||
|
*/
|
||||||
|
public Collection<String> getPermissions();
|
||||||
}
|
}
|
||||||
|
106
api/src/main/java/net/md_5/bungee/api/Favicon.java
Normal file
106
api/src/main/java/net/md_5/bungee/api/Favicon.java
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
package net.md_5.bungee.api;
|
||||||
|
|
||||||
|
import com.google.common.io.BaseEncoding;
|
||||||
|
import com.google.gson.TypeAdapter;
|
||||||
|
import com.google.gson.internal.bind.TypeAdapters;
|
||||||
|
import com.google.gson.stream.JsonReader;
|
||||||
|
import com.google.gson.stream.JsonWriter;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Favicon shown in the server list.
|
||||||
|
*/
|
||||||
|
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public class Favicon
|
||||||
|
{
|
||||||
|
|
||||||
|
private static final TypeAdapter<Favicon> FAVICON_TYPE_ADAPTER = new TypeAdapter<Favicon>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void write(JsonWriter out, Favicon value) throws IOException
|
||||||
|
{
|
||||||
|
TypeAdapters.STRING.write( out, value == null ? null : value.getEncoded() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Favicon read(JsonReader in) throws IOException
|
||||||
|
{
|
||||||
|
String enc = TypeAdapters.STRING.read( in );
|
||||||
|
return enc == null ? null : create( enc );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static TypeAdapter<Favicon> getFaviconTypeAdapter()
|
||||||
|
{
|
||||||
|
return FAVICON_TYPE_ADAPTER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base64 encoded favicon, including MIME header.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
@Getter
|
||||||
|
private final String encoded;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a favicon from an image.
|
||||||
|
*
|
||||||
|
* @param image the image to create on
|
||||||
|
* @return the created favicon instance
|
||||||
|
* @throws IllegalArgumentException if the favicon is larger than
|
||||||
|
* {@link Short#MAX_VALUE} or not of dimensions 64x64 pixels.
|
||||||
|
*/
|
||||||
|
public static Favicon create(BufferedImage image)
|
||||||
|
{
|
||||||
|
// check size
|
||||||
|
if ( image.getWidth() != 64 || image.getHeight() != 64 )
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException( "Server icon must be exactly 64x64 pixels" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// dump image PNG
|
||||||
|
byte[] imageBytes;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||||
|
ImageIO.write( image, "PNG", stream );
|
||||||
|
imageBytes = stream.toByteArray();
|
||||||
|
} catch ( IOException e )
|
||||||
|
{
|
||||||
|
// ByteArrayOutputStream should never throw this
|
||||||
|
throw new AssertionError( e );
|
||||||
|
}
|
||||||
|
|
||||||
|
// encode with header
|
||||||
|
String encoded = "data:image/png;base64," + BaseEncoding.base64().encode( imageBytes );
|
||||||
|
|
||||||
|
// check encoded image size
|
||||||
|
if ( encoded.length() > Short.MAX_VALUE )
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException( "Favicon file too large for server to process" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// create
|
||||||
|
return new Favicon( encoded );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Favicon from an encoded PNG.
|
||||||
|
*
|
||||||
|
* @param encodedString a base64 mime encoded PNG string
|
||||||
|
* @return the created favicon
|
||||||
|
* @deprecated Use #create(java.awt.image.BufferedImage) instead
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static Favicon create(String encodedString)
|
||||||
|
{
|
||||||
|
return new Favicon( encodedString );
|
||||||
|
}
|
||||||
|
}
|
82
api/src/main/java/net/md_5/bungee/api/ProxyConfig.java
Normal file
82
api/src/main/java/net/md_5/bungee/api/ProxyConfig.java
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package net.md_5.bungee.api;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.config.ListenerInfo;
|
||||||
|
import net.md_5.bungee.api.config.ServerInfo;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Core configuration adaptor for the proxy api.
|
||||||
|
*
|
||||||
|
* @deprecated This class is subject to rapid change between releases
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public interface ProxyConfig
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time before users are disconnected due to no network activity.
|
||||||
|
*/
|
||||||
|
int getTimeout();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UUID used for metrics.
|
||||||
|
*/
|
||||||
|
String getUuid();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set of all listeners.
|
||||||
|
*/
|
||||||
|
Collection<ListenerInfo> getListeners();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set of all servers.
|
||||||
|
*/
|
||||||
|
Map<String, ServerInfo> getServers();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does the server authenticate with mojang
|
||||||
|
*/
|
||||||
|
boolean isOnlineMode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether proxy commands are logged to the proxy log
|
||||||
|
*/
|
||||||
|
boolean isLogCommands();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the player max.
|
||||||
|
*/
|
||||||
|
int getPlayerLimit();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A collection of disabled commands.
|
||||||
|
*/
|
||||||
|
Collection<String> getDisabledCommands();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The connection throttle delay.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
int getThrottle();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the proxy will parse IPs with spigot or not
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
boolean isIpForward();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The encoded favicon.
|
||||||
|
*
|
||||||
|
* @deprecated Use #getFaviconObject instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
String getFavicon();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The favicon used for the server ping list.
|
||||||
|
*/
|
||||||
|
Favicon getFaviconObject();
|
||||||
|
}
|
@@ -1,12 +1,13 @@
|
|||||||
package net.md_5.bungee.api;
|
package net.md_5.bungee.api;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
import net.md_5.bungee.api.plugin.PluginManager;
|
import net.md_5.bungee.api.plugin.PluginManager;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.ning.http.client.AsyncHttpClient;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import net.md_5.bungee.api.config.ConfigurationAdapter;
|
import net.md_5.bungee.api.config.ConfigurationAdapter;
|
||||||
@@ -14,7 +15,6 @@ import net.md_5.bungee.api.config.ServerInfo;
|
|||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
import net.md_5.bungee.api.plugin.Plugin;
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
import net.md_5.bungee.api.scheduler.TaskScheduler;
|
import net.md_5.bungee.api.scheduler.TaskScheduler;
|
||||||
import net.md_5.bungee.api.tab.CustomTabList;
|
|
||||||
|
|
||||||
public abstract class ProxyServer
|
public abstract class ProxyServer
|
||||||
{
|
{
|
||||||
@@ -54,7 +54,7 @@ public abstract class ProxyServer
|
|||||||
*
|
*
|
||||||
* @return the localized string
|
* @return the localized string
|
||||||
*/
|
*/
|
||||||
public abstract String getTranslation(String name);
|
public abstract String getTranslation(String name, Object... args);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the main logger which can be used as a suitable replacement for
|
* Gets the main logger which can be used as a suitable replacement for
|
||||||
@@ -79,6 +79,14 @@ public abstract class ProxyServer
|
|||||||
*/
|
*/
|
||||||
public abstract ProxiedPlayer getPlayer(String name);
|
public abstract ProxiedPlayer getPlayer(String name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a connected player via their UUID
|
||||||
|
*
|
||||||
|
* @param uuid of the player
|
||||||
|
* @return their player instance
|
||||||
|
*/
|
||||||
|
public abstract ProxiedPlayer getPlayer(UUID uuid);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return all servers registered to this proxy, keyed by name. Unlike the
|
* Return all servers registered to this proxy, keyed by name. Unlike the
|
||||||
* methods in {@link ConfigurationAdapter#getServers()}, this will not
|
* methods in {@link ConfigurationAdapter#getServers()}, this will not
|
||||||
@@ -139,6 +147,13 @@ public abstract class ProxyServer
|
|||||||
*/
|
*/
|
||||||
public abstract void stop();
|
public abstract void stop();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gracefully mark this instance for shutdown.
|
||||||
|
*
|
||||||
|
* @param reason the reason for stopping. This will be shown to players.
|
||||||
|
*/
|
||||||
|
public abstract void stop(String reason);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start this instance so that it may accept connections.
|
* Start this instance so that it may accept connections.
|
||||||
*
|
*
|
||||||
@@ -174,6 +189,7 @@ public abstract class ProxyServer
|
|||||||
*
|
*
|
||||||
* @return the supported Minecraft version
|
* @return the supported Minecraft version
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public abstract String getGameVersion();
|
public abstract String getGameVersion();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -181,7 +197,8 @@ public abstract class ProxyServer
|
|||||||
*
|
*
|
||||||
* @return the Minecraft protocol version
|
* @return the Minecraft protocol version
|
||||||
*/
|
*/
|
||||||
public abstract byte getProtocolVersion();
|
@Deprecated
|
||||||
|
public abstract int getProtocolVersion();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory method to construct an implementation specific server info
|
* Factory method to construct an implementation specific server info
|
||||||
@@ -189,10 +206,11 @@ public abstract class ProxyServer
|
|||||||
*
|
*
|
||||||
* @param name name of the server
|
* @param name name of the server
|
||||||
* @param address connectable Minecraft address + port of the server
|
* @param address connectable Minecraft address + port of the server
|
||||||
|
* @param motd the motd when used as a forced server
|
||||||
* @param restricted whether the server info restricted property will be set
|
* @param restricted whether the server info restricted property will be set
|
||||||
* @return the constructed instance
|
* @return the constructed instance
|
||||||
*/
|
*/
|
||||||
public abstract ServerInfo constructServerInfo(String name, InetSocketAddress address, boolean restricted);
|
public abstract ServerInfo constructServerInfo(String name, InetSocketAddress address, String motd, boolean restricted);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the console overlord for this proxy. Being the console, this
|
* Returns the console overlord for this proxy. Being the console, this
|
||||||
@@ -217,15 +235,6 @@ public abstract class ProxyServer
|
|||||||
*/
|
*/
|
||||||
public abstract TaskScheduler getScheduler();
|
public abstract TaskScheduler getScheduler();
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the the web client used by this proxy to facilitate making web
|
|
||||||
* requests. Care should be taken to ensure that all operations are non
|
|
||||||
* blocking where applicable.
|
|
||||||
*
|
|
||||||
* @return the server's {@link AsyncHttpClient} instance
|
|
||||||
*/
|
|
||||||
public abstract AsyncHttpClient getHttpClient();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the current number of connected users. The default implementation is
|
* Get the current number of connected users. The default implementation is
|
||||||
* more efficient than {@link #getPlayers()} as it does not take a lock or
|
* more efficient than {@link #getPlayers()} as it does not take a lock or
|
||||||
@@ -240,13 +249,59 @@ public abstract class ProxyServer
|
|||||||
*
|
*
|
||||||
* @param message the message to broadcast
|
* @param message the message to broadcast
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public abstract void broadcast(String message);
|
public abstract void broadcast(String message);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a new instance of this proxies custom tab list.
|
* Send the specified message to the console and all connected players.
|
||||||
*
|
*
|
||||||
* @param player the player to generate this list in the context of
|
* @param message the message to broadcast
|
||||||
* @return a new {@link CustomTabList} instance
|
|
||||||
*/
|
*/
|
||||||
public abstract CustomTabList customTabList(ProxiedPlayer player);
|
public abstract void broadcast(BaseComponent... message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the specified message to the console and all connected players.
|
||||||
|
*
|
||||||
|
* @param message the message to broadcast
|
||||||
|
*/
|
||||||
|
public abstract void broadcast(BaseComponent message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the commands which are disabled and will not be run on this proxy.
|
||||||
|
*
|
||||||
|
* @return the set of disabled commands
|
||||||
|
*/
|
||||||
|
public abstract Collection<String> getDisabledCommands();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets BungeeCord's core config.
|
||||||
|
*
|
||||||
|
* @return the config.
|
||||||
|
*/
|
||||||
|
public abstract ProxyConfig getConfig();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to match any players with the given name, and returns a list of
|
||||||
|
* all possible matches.
|
||||||
|
*
|
||||||
|
* The exact algorithm to use to match players is implementation specific,
|
||||||
|
* but in general you can expect this method to return player's whose names
|
||||||
|
* begin with the specified prefix.
|
||||||
|
*
|
||||||
|
* @param match the (partial) name to match
|
||||||
|
* @return list of all possible players, singleton if there is an exact
|
||||||
|
* match
|
||||||
|
*/
|
||||||
|
public abstract Collection<ProxiedPlayer> matchPlayer(String match);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new empty title configuration. In most cases you will want to
|
||||||
|
* {@link Title#reset()} the current title first so your title won't be
|
||||||
|
* affected by a previous one.
|
||||||
|
*
|
||||||
|
* @return A new empty title configuration.
|
||||||
|
* @see Title
|
||||||
|
*/
|
||||||
|
public abstract Title createTitle();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,33 +1,127 @@
|
|||||||
package net.md_5.bungee.api;
|
package net.md_5.bungee.api;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import net.md_5.bungee.Util;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the standard list data returned by opening a server in the
|
* Represents the standard list data returned by opening a server in the
|
||||||
* Minecraft client server list, or hitting it with a packet 0xFE.
|
* Minecraft client server list, or hitting it with a packet 0xFE.
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
public class ServerPing
|
public class ServerPing
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
private Protocol version;
|
||||||
* Numeric protocol version supported by the server.
|
|
||||||
*/
|
@Data
|
||||||
private final byte protocolVersion;
|
@AllArgsConstructor
|
||||||
/**
|
public static class Protocol
|
||||||
* Human readable game version.
|
{
|
||||||
*/
|
|
||||||
private final String gameVersion;
|
private String name;
|
||||||
/**
|
private int protocol;
|
||||||
* Server MOTD.
|
}
|
||||||
*/
|
private Players players;
|
||||||
private final String motd;
|
|
||||||
/**
|
@Data
|
||||||
* Current amount of players on the server.
|
@AllArgsConstructor
|
||||||
*/
|
public static class Players
|
||||||
private final int currentPlayers;
|
{
|
||||||
/**
|
|
||||||
* Max amount of players the server will allow.
|
private int max;
|
||||||
*/
|
private int online;
|
||||||
private final int maxPlayers;
|
private PlayerInfo[] sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class PlayerInfo
|
||||||
|
{
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private UUID uniqueId;
|
||||||
|
|
||||||
|
private static final UUID md5UUID = Util.getUUID( "af74a02d19cb445bb07f6866a861f783" );
|
||||||
|
|
||||||
|
public PlayerInfo(String name, String id)
|
||||||
|
{
|
||||||
|
setName( name );
|
||||||
|
setId( id );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(String id)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
uniqueId = Util.getUUID( id );
|
||||||
|
} catch ( Exception e )
|
||||||
|
{
|
||||||
|
// Fallback on a valid uuid otherwise Minecraft complains
|
||||||
|
uniqueId = md5UUID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId()
|
||||||
|
{
|
||||||
|
return uniqueId.toString().replaceAll( "-", "" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private String description;
|
||||||
|
private Favicon favicon;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class ModInfo
|
||||||
|
{
|
||||||
|
|
||||||
|
private String type = "FML";
|
||||||
|
private List<ModItem> modList = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class ModItem
|
||||||
|
{
|
||||||
|
|
||||||
|
private String modid;
|
||||||
|
private String version;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Right now, we don't get the mods from the user, so we just use a stock ModInfo object to
|
||||||
|
// create the server ping. Vanilla clients will ignore this.
|
||||||
|
private final ModInfo modinfo = new ModInfo();
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public ServerPing(Protocol version, Players players, String description, String favicon)
|
||||||
|
{
|
||||||
|
this( version, players, description, favicon == null ? null : Favicon.create( favicon ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public String getFavicon()
|
||||||
|
{
|
||||||
|
return getFaviconObject() == null ? null : getFaviconObject().getEncoded();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Favicon getFaviconObject()
|
||||||
|
{
|
||||||
|
return this.favicon;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public void setFavicon(String favicon)
|
||||||
|
{
|
||||||
|
setFavicon( favicon == null ? null : Favicon.create( favicon ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFavicon(Favicon favicon)
|
||||||
|
{
|
||||||
|
this.favicon = favicon;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
106
api/src/main/java/net/md_5/bungee/api/Title.java
Normal file
106
api/src/main/java/net/md_5/bungee/api/Title.java
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
package net.md_5.bungee.api;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a configuration of a title. A title in Minecraft consists of a
|
||||||
|
* main title and a sub title. It will {@link #fadeIn(int)}, {@link #stay(int)},
|
||||||
|
* and {@link #fadeOut(int)} for a specified amount of time. In most cases you
|
||||||
|
* will want to {@link #reset()} the current title first so your title won't be
|
||||||
|
* affected by a previous one.
|
||||||
|
* <p>
|
||||||
|
* You can create a new configuration by calling
|
||||||
|
* {@link ProxyServer#createTitle()}.
|
||||||
|
*/
|
||||||
|
public interface Title
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the title to send to the player.
|
||||||
|
*
|
||||||
|
* @param text The text to use as the title.
|
||||||
|
* @return This title configuration.
|
||||||
|
*/
|
||||||
|
public Title title(BaseComponent text);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the title to send to the player.
|
||||||
|
*
|
||||||
|
* @param text The text to use as the title.
|
||||||
|
* @return This title configuration.
|
||||||
|
*/
|
||||||
|
public Title title(BaseComponent... text);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the subtitle to send to the player.
|
||||||
|
*
|
||||||
|
* @param text The text to use as the subtitle.
|
||||||
|
* @return This title configuration.
|
||||||
|
*/
|
||||||
|
public Title subTitle(BaseComponent text);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the subtitle to send to the player.
|
||||||
|
*
|
||||||
|
* @param text The text to use as the subtitle.
|
||||||
|
* @return This title configuration.
|
||||||
|
*/
|
||||||
|
public Title subTitle(BaseComponent... text);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the duration in ticks of the fade in effect of the title. Once this
|
||||||
|
* period of time is over the title will stay for the amount of time
|
||||||
|
* specified in {@link #stay(int)}. The default value for the official
|
||||||
|
* Minecraft version is 20 (1 second).
|
||||||
|
*
|
||||||
|
* @param ticks The amount of ticks (1/20 second) for the fade in effect.
|
||||||
|
* @return This title configuration.
|
||||||
|
*/
|
||||||
|
public Title fadeIn(int ticks);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the duration in ticks how long the title should stay on the screen.
|
||||||
|
* Once this period of time is over the title will fade out using the
|
||||||
|
* duration specified in {@link #fadeOut(int)}. The default value for the
|
||||||
|
* official Minecraft version is 60 (3 seconds).
|
||||||
|
*
|
||||||
|
* @param ticks The amount of ticks (1/20 second) for the fade in effect.
|
||||||
|
* @return This title configuration.
|
||||||
|
*/
|
||||||
|
public Title stay(int ticks);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the duration in ticks of the fade out effect of the title. The
|
||||||
|
* default value for the official Minecraft version is 20 (1 second).
|
||||||
|
*
|
||||||
|
* @param ticks The amount of ticks (1/20 second) for the fade out effect.
|
||||||
|
* @return This title configuration.
|
||||||
|
*/
|
||||||
|
public Title fadeOut(int ticks);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the currently displayed title from the player's screen. This will
|
||||||
|
* keep the currently used display times and will only remove the title.
|
||||||
|
*
|
||||||
|
* @return This title configuration.
|
||||||
|
*/
|
||||||
|
public Title clear();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the currently displayed title from the player's screen and set the
|
||||||
|
* configuration back to the default values.
|
||||||
|
*
|
||||||
|
* @return This title configuration.
|
||||||
|
*/
|
||||||
|
public Title reset();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send this title configuration to the specified player. This is the same
|
||||||
|
* as calling {@link ProxiedPlayer#sendTitle(Title)}.
|
||||||
|
*
|
||||||
|
* @param player The player to send the title to.
|
||||||
|
* @return This title configuration.
|
||||||
|
*/
|
||||||
|
public Title send(ProxiedPlayer player);
|
||||||
|
}
|
@@ -43,6 +43,15 @@ public interface ConfigurationAdapter
|
|||||||
*/
|
*/
|
||||||
public boolean getBoolean(String path, boolean def);
|
public boolean getBoolean(String path, boolean def);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list from the specified path.
|
||||||
|
*
|
||||||
|
* @param path the path to retrieve the list form.
|
||||||
|
* @param def the default value
|
||||||
|
* @return the retrieved list
|
||||||
|
*/
|
||||||
|
public Collection<?> getList(String path, Collection<?> def);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the configuration all servers which may be accessible via the proxy.
|
* Get the configuration all servers which may be accessible via the proxy.
|
||||||
*
|
*
|
||||||
|
@@ -3,7 +3,6 @@ package net.md_5.bungee.api.config;
|
|||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import net.md_5.bungee.api.tab.TabListHandler;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class representing the configuration of a server listener. Used for allowing
|
* Class representing the configuration of a server listener. Used for allowing
|
||||||
@@ -49,12 +48,24 @@ public class ListenerInfo
|
|||||||
*/
|
*/
|
||||||
private final Map<String, String> forcedHosts;
|
private final Map<String, String> forcedHosts;
|
||||||
/**
|
/**
|
||||||
* Get the texture pack used for servers connected to this proxy. May be
|
* The type of tab list to use
|
||||||
* null.
|
|
||||||
*/
|
*/
|
||||||
private final TexturePackInfo texturePack;
|
private final String tabListType;
|
||||||
/**
|
/**
|
||||||
* Class used to build tab lists for this player.
|
* Whether to set the local address when connecting to servers.
|
||||||
*/
|
*/
|
||||||
private final Class<? extends TabListHandler> tabList;
|
private final boolean setLocalAddress;
|
||||||
|
/**
|
||||||
|
* Whether to pass the ping through when we can reliably get the target
|
||||||
|
* server (force default server).
|
||||||
|
*/
|
||||||
|
private final boolean pingPassthrough;
|
||||||
|
/**
|
||||||
|
* What port to run udp query on.
|
||||||
|
*/
|
||||||
|
private final int queryPort;
|
||||||
|
/**
|
||||||
|
* Whether to enable udp query.
|
||||||
|
*/
|
||||||
|
private final boolean queryEnabled;
|
||||||
}
|
}
|
||||||
|
@@ -36,6 +36,13 @@ public interface ServerInfo
|
|||||||
*/
|
*/
|
||||||
Collection<ProxiedPlayer> getPlayers();
|
Collection<ProxiedPlayer> getPlayers();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the MOTD which should be used when this server is a forced host.
|
||||||
|
*
|
||||||
|
* @return the motd
|
||||||
|
*/
|
||||||
|
String getMotd();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the player can access this server. It will only return false when
|
* Whether the player can access this server. It will only return false when
|
||||||
* the player has no permission and this server is restricted.
|
* the player has no permission and this server is restricted.
|
||||||
@@ -46,13 +53,27 @@ public interface ServerInfo
|
|||||||
boolean canAccess(CommandSender sender);
|
boolean canAccess(CommandSender sender);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send data by any available means to this server.
|
* Send data by any available means to this server. This data may be queued
|
||||||
|
* and there is no guarantee of its timely arrival.
|
||||||
*
|
*
|
||||||
* @param channel the channel to send this data via
|
* @param channel the channel to send this data via
|
||||||
* @param data the data to send
|
* @param data the data to send
|
||||||
*/
|
*/
|
||||||
void sendData(String channel, byte[] data);
|
void sendData(String channel, byte[] data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send data by any available means to this server.
|
||||||
|
*
|
||||||
|
* @param channel the channel to send this data via
|
||||||
|
* @param data the data to send
|
||||||
|
* @param queue hold the message for later sending if it cannot be sent
|
||||||
|
* immediately.
|
||||||
|
* @return <code>true</code> if the message was sent immediately,
|
||||||
|
* <code>false</code> otherwise if queue is true, it has been queued, if it
|
||||||
|
* is false it has been discarded.
|
||||||
|
*/
|
||||||
|
boolean sendData(String channel, byte[] data, boolean queue);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asynchronously gets the current player count on this server.
|
* Asynchronously gets the current player count on this server.
|
||||||
*
|
*
|
||||||
|
@@ -1,17 +0,0 @@
|
|||||||
package net.md_5.bungee.api.config;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class TexturePackInfo
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The URL of the texture pack.
|
|
||||||
*/
|
|
||||||
private final String url;
|
|
||||||
/**
|
|
||||||
* The square dimension of this texture pack.
|
|
||||||
*/
|
|
||||||
private final int size;
|
|
||||||
}
|
|
@@ -1,7 +1,9 @@
|
|||||||
package net.md_5.bungee.api.connection;
|
package net.md_5.bungee.api.connection;
|
||||||
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import net.md_5.bungee.protocol.packet.DefinedPacket;
|
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
import net.md_5.bungee.protocol.DefinedPacket;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A proxy connection is defined as a connection directly connected to a socket.
|
* A proxy connection is defined as a connection directly connected to a socket.
|
||||||
@@ -26,8 +28,37 @@ public interface Connection
|
|||||||
* @param reason the reason shown to the player / sent to the server on
|
* @param reason the reason shown to the player / sent to the server on
|
||||||
* disconnect
|
* disconnect
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
void disconnect(String reason);
|
void disconnect(String reason);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disconnects this end of the connection for the specified reason. If this
|
||||||
|
* is an {@link ProxiedPlayer} the respective server connection will be
|
||||||
|
* closed too.
|
||||||
|
*
|
||||||
|
* @param reason the reason shown to the player / sent to the server on
|
||||||
|
* disconnect
|
||||||
|
*/
|
||||||
|
void disconnect(BaseComponent... reason);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disconnects this end of the connection for the specified reason. If this
|
||||||
|
* is an {@link ProxiedPlayer} the respective server connection will be
|
||||||
|
* closed too.
|
||||||
|
*
|
||||||
|
* @param reason the reason shown to the player / sent to the server on
|
||||||
|
* disconnect
|
||||||
|
*/
|
||||||
|
void disconnect(BaseComponent reason);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether this connection is currently open, ie: not disconnected, and
|
||||||
|
* able to send / receive data.
|
||||||
|
*
|
||||||
|
* @return current connection status
|
||||||
|
*/
|
||||||
|
boolean isConnected();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the unsafe methods of this class.
|
* Get the unsafe methods of this class.
|
||||||
*
|
*
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
package net.md_5.bungee.api.connection;
|
package net.md_5.bungee.api.connection;
|
||||||
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.UUID;
|
||||||
import net.md_5.bungee.api.config.ListenerInfo;
|
import net.md_5.bungee.api.config.ListenerInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -14,26 +15,67 @@ public interface PendingConnection extends Connection
|
|||||||
*
|
*
|
||||||
* @return the requested username, or null if not set
|
* @return the requested username, or null if not set
|
||||||
*/
|
*/
|
||||||
public String getName();
|
String getName();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the numerical client version of the player attempting to log in.
|
* Get the numerical client version of the player attempting to log in.
|
||||||
*
|
*
|
||||||
* @return the protocol version of the remote client
|
* @return the protocol version of the remote client
|
||||||
*/
|
*/
|
||||||
public byte getVersion();
|
int getVersion();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the requested virtual host that the client tried to connect to.
|
* Get the requested virtual host that the client tried to connect to.
|
||||||
*
|
*
|
||||||
* @return request virtual host or null if invalid / not specified.
|
* @return request virtual host or null if invalid / not specified.
|
||||||
*/
|
*/
|
||||||
public InetSocketAddress getVirtualHost();
|
InetSocketAddress getVirtualHost();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the listener that accepted this connection.
|
* Get the listener that accepted this connection.
|
||||||
*
|
*
|
||||||
* @return the accepting listener
|
* @return the accepting listener
|
||||||
*/
|
*/
|
||||||
public ListenerInfo getListener();
|
ListenerInfo getListener();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get this connection's UUID, if set.
|
||||||
|
*
|
||||||
|
* @return the UUID
|
||||||
|
* @deprecated In favour of {@link #getUniqueId()}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
String getUUID();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get this connection's UUID, if set.
|
||||||
|
*
|
||||||
|
* @return the UUID
|
||||||
|
*/
|
||||||
|
UUID getUniqueId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the connection's uuid
|
||||||
|
*/
|
||||||
|
void setUniqueId(UUID uuid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get this connection's online mode.
|
||||||
|
*
|
||||||
|
* @return the online mode
|
||||||
|
*/
|
||||||
|
boolean isOnlineMode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set this connection's online mode.
|
||||||
|
*/
|
||||||
|
void setOnlineMode(boolean onlineMode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the client is using the older unsupported Minecraft protocol
|
||||||
|
* used by Minecraft clients older than 1.7.
|
||||||
|
*
|
||||||
|
* @return Whether the client is using a legacy client.
|
||||||
|
*/
|
||||||
|
boolean isLegacy();
|
||||||
}
|
}
|
||||||
|
@@ -1,9 +1,14 @@
|
|||||||
package net.md_5.bungee.api.connection;
|
package net.md_5.bungee.api.connection;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import net.md_5.bungee.api.Callback;
|
||||||
|
import net.md_5.bungee.api.ChatMessageType;
|
||||||
import net.md_5.bungee.api.CommandSender;
|
import net.md_5.bungee.api.CommandSender;
|
||||||
|
import net.md_5.bungee.api.Title;
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
import net.md_5.bungee.api.config.ServerInfo;
|
import net.md_5.bungee.api.config.ServerInfo;
|
||||||
import net.md_5.bungee.api.config.TexturePackInfo;
|
|
||||||
import net.md_5.bungee.api.tab.TabListHandler;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a player who's connection is being connected to somewhere else,
|
* Represents a player who's connection is being connected to somewhere else,
|
||||||
@@ -27,6 +32,22 @@ public interface ProxiedPlayer extends Connection, CommandSender
|
|||||||
*/
|
*/
|
||||||
void setDisplayName(String name);
|
void setDisplayName(String name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a message to the specified screen position of this player.
|
||||||
|
*
|
||||||
|
* @param position the screen position
|
||||||
|
* @param message the message to send
|
||||||
|
*/
|
||||||
|
public void sendMessage(ChatMessageType position, BaseComponent... message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a message to the specified screen position of this player.
|
||||||
|
*
|
||||||
|
* @param position the screen position
|
||||||
|
* @param message the message to send
|
||||||
|
*/
|
||||||
|
public void sendMessage(ChatMessageType position, BaseComponent message);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connects / transfers this user to the specified connection, gracefully
|
* Connects / transfers this user to the specified connection, gracefully
|
||||||
* closing the current one. Depending on the implementation, this method
|
* closing the current one. Depending on the implementation, this method
|
||||||
@@ -36,6 +57,18 @@ public interface ProxiedPlayer extends Connection, CommandSender
|
|||||||
*/
|
*/
|
||||||
void connect(ServerInfo target);
|
void connect(ServerInfo target);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connects / transfers this user to the specified connection, gracefully
|
||||||
|
* closing the current one. Depending on the implementation, this method
|
||||||
|
* might return before the user has been connected.
|
||||||
|
*
|
||||||
|
* @param target the new server to connect to
|
||||||
|
* @param callback the method called when the connection is complete, or
|
||||||
|
* when an exception is encountered. The boolean parameter denotes success
|
||||||
|
* or failure.
|
||||||
|
*/
|
||||||
|
void connect(ServerInfo target, Callback<Boolean> callback);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the server this player is connected to.
|
* Gets the server this player is connected to.
|
||||||
*
|
*
|
||||||
@@ -73,24 +106,109 @@ public interface ProxiedPlayer extends Connection, CommandSender
|
|||||||
void chat(String message);
|
void chat(String message);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a request to change the players texture pack.
|
* Get the server which this player will be sent to next time the log in.
|
||||||
*
|
*
|
||||||
* @param pack the pack to request
|
* @return the server, or null if default
|
||||||
*/
|
*/
|
||||||
void setTexturePack(TexturePackInfo pack);
|
ServerInfo getReconnectServer();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the new tab list for the user. At this stage it is not advisable to
|
* Set the server which this player will be sent to next time the log in.
|
||||||
* change after the user has logged in!
|
|
||||||
*
|
*
|
||||||
* @param list the new list
|
* @param server the server to set
|
||||||
*/
|
*/
|
||||||
void setTabList(TabListHandler list);
|
void setReconnectServer(ServerInfo server);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the current tab list.
|
* Get this connection's UUID, if set.
|
||||||
*
|
*
|
||||||
* @return the tab list in use by this user
|
* @return the UUID
|
||||||
|
* @deprecated In favour of {@link #getUniqueId()}
|
||||||
*/
|
*/
|
||||||
TabListHandler getTabList();
|
@Deprecated
|
||||||
|
String getUUID();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get this connection's UUID, if set.
|
||||||
|
*
|
||||||
|
* @return the UUID
|
||||||
|
*/
|
||||||
|
UUID getUniqueId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets this player's locale.
|
||||||
|
*
|
||||||
|
* @return the locale
|
||||||
|
*/
|
||||||
|
Locale getLocale();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the header and footer displayed in the tab player list.
|
||||||
|
*
|
||||||
|
* @param header The header for the tab player list, null to clear it.
|
||||||
|
* @param footer The footer for the tab player list, null to clear it.
|
||||||
|
*/
|
||||||
|
void setTabHeader(BaseComponent header, BaseComponent footer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the header and footer displayed in the tab player list.
|
||||||
|
*
|
||||||
|
* @param header The header for the tab player list, null to clear it.
|
||||||
|
* @param footer The footer for the tab player list, null to clear it.
|
||||||
|
*/
|
||||||
|
void setTabHeader(BaseComponent[] header, BaseComponent[] footer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the header and footer displayed in the tab player list.
|
||||||
|
*/
|
||||||
|
void resetTabHeader();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a {@link Title} to this player. This is the same as calling
|
||||||
|
* {@link Title#send(ProxiedPlayer)}.
|
||||||
|
*
|
||||||
|
* @param title The title to send to the player.
|
||||||
|
* @see Title
|
||||||
|
*/
|
||||||
|
void sendTitle(Title title);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets whether this player is using a FML client.
|
||||||
|
* <p>
|
||||||
|
* This method is only reliable if BungeeCord links Minecraft 1.8 servers
|
||||||
|
* together, as Bungee can pick up whether a user is a Forge user with the
|
||||||
|
* initial handshake. If this is used for a 1.7 network, this might return
|
||||||
|
* <code>false</code> even if the user is a FML user, as Bungee can only
|
||||||
|
* determine this information if a handshake successfully completes.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @return <code>true</code> if it is known that the user is using a FML
|
||||||
|
* client, <code>false</code> otherwise.
|
||||||
|
*/
|
||||||
|
boolean isForgeUser();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets this player's Forge Mod List, if the player has sent this
|
||||||
|
* information during the lifetime of their connection to Bungee. There is
|
||||||
|
* no guarantee that information is available at any time, as it is only
|
||||||
|
* sent during a FML handshake. Therefore, this will only contain
|
||||||
|
* information for a user that has attempted joined a Forge server.
|
||||||
|
* <p>
|
||||||
|
* Consumers of this API should be aware that an empty mod list does
|
||||||
|
* <em>not</em> indicate that a user is not a Forge user, and so should not
|
||||||
|
* use this API to check for this. See the {@link #isForgeUser()
|
||||||
|
* isForgeUser} method instead.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* Calling this when handling a
|
||||||
|
* {@link net.md_5.bungee.api.event.ServerConnectedEvent} may be the best
|
||||||
|
* place to do so as this event occurs after a FML handshake has completed,
|
||||||
|
* if any has occurred.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @return A {@link Map} of mods, where the key is the name of the mod, and
|
||||||
|
* the value is the version. Returns an empty list if the FML handshake has
|
||||||
|
* not occurred for this {@link ProxiedPlayer} yet.
|
||||||
|
*/
|
||||||
|
Map<String, String> getModList();
|
||||||
}
|
}
|
||||||
|
@@ -33,11 +33,11 @@ public class AsyncEvent<T> extends Event
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void postCall()
|
public void postCall()
|
||||||
{
|
{
|
||||||
fired.set( true );
|
|
||||||
if ( latch.get() == 0 )
|
if ( latch.get() == 0 )
|
||||||
{
|
{
|
||||||
done.done( (T) this, null );
|
done.done( (T) this, null );
|
||||||
}
|
}
|
||||||
|
fired.set( true );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -67,9 +67,14 @@ public class AsyncEvent<T> extends Event
|
|||||||
{
|
{
|
||||||
Preconditions.checkState( intents.contains( plugin ), "Plugin %s has not registered intent for event %s", plugin, this );
|
Preconditions.checkState( intents.contains( plugin ), "Plugin %s has not registered intent for event %s", plugin, this );
|
||||||
intents.remove( plugin );
|
intents.remove( plugin );
|
||||||
if ( latch.decrementAndGet() == 0 && fired.get() )
|
if ( fired.get() )
|
||||||
{
|
{
|
||||||
done.done( (T) this, null );
|
if ( latch.decrementAndGet() == 0 )
|
||||||
|
{
|
||||||
|
done.done( (T) this, null );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
latch.decrementAndGet();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -7,8 +7,7 @@ import net.md_5.bungee.api.connection.Connection;
|
|||||||
import net.md_5.bungee.api.plugin.Cancellable;
|
import net.md_5.bungee.api.plugin.Cancellable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event called when a player sends a message to a server, or a server sends a
|
* Event called when a player sends a message to a server.
|
||||||
* message to a player.
|
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
|
@@ -0,0 +1,34 @@
|
|||||||
|
package net.md_5.bungee.api.event;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.ToString;
|
||||||
|
import net.md_5.bungee.api.connection.PendingConnection;
|
||||||
|
import net.md_5.bungee.api.plugin.Event;
|
||||||
|
import net.md_5.bungee.protocol.packet.Handshake;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event called to represent a player first making their presence and username
|
||||||
|
* known.
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ToString(callSuper = false)
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
public class PlayerHandshakeEvent extends Event
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connection attempting to login.
|
||||||
|
*/
|
||||||
|
private final PendingConnection connection;
|
||||||
|
/**
|
||||||
|
* The handshake.
|
||||||
|
*/
|
||||||
|
private final Handshake handshake;
|
||||||
|
|
||||||
|
public PlayerHandshakeEvent(PendingConnection connection, Handshake handshake)
|
||||||
|
{
|
||||||
|
this.connection = connection;
|
||||||
|
this.handshake = handshake;
|
||||||
|
}
|
||||||
|
}
|
@@ -7,8 +7,8 @@ import net.md_5.bungee.api.connection.ProxiedPlayer;
|
|||||||
import net.md_5.bungee.api.plugin.Event;
|
import net.md_5.bungee.api.plugin.Event;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event called as soon as a connection has an {@link ProxiedPlayer} and is
|
* Event called as soon as a connection has a {@link ProxiedPlayer} and is ready
|
||||||
* ready to be connected to a server.
|
* to be connected to a server.
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@ToString(callSuper = false)
|
@ToString(callSuper = false)
|
||||||
|
@@ -0,0 +1,42 @@
|
|||||||
|
package net.md_5.bungee.api.event;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.ToString;
|
||||||
|
import net.md_5.bungee.api.Callback;
|
||||||
|
import net.md_5.bungee.api.connection.PendingConnection;
|
||||||
|
import net.md_5.bungee.api.plugin.Cancellable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event called to represent a player first making their presence and username
|
||||||
|
* known.
|
||||||
|
*
|
||||||
|
* This will NOT contain many attributes relating to the player which are filled
|
||||||
|
* in after authentication with Mojang's servers. Examples of attributes which
|
||||||
|
* are not available include their UUID.
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ToString(callSuper = false)
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
public class PreLoginEvent extends AsyncEvent<PreLoginEvent> implements Cancellable
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancelled state.
|
||||||
|
*/
|
||||||
|
private boolean cancelled;
|
||||||
|
/**
|
||||||
|
* Message to use when kicking if this event is canceled.
|
||||||
|
*/
|
||||||
|
private String cancelReason;
|
||||||
|
/**
|
||||||
|
* Connection attempting to login.
|
||||||
|
*/
|
||||||
|
private final PendingConnection connection;
|
||||||
|
|
||||||
|
public PreLoginEvent(PendingConnection connection, Callback<PreLoginEvent> done)
|
||||||
|
{
|
||||||
|
super( done );
|
||||||
|
this.connection = connection;
|
||||||
|
}
|
||||||
|
}
|
@@ -1,9 +1,9 @@
|
|||||||
package net.md_5.bungee.api.event;
|
package net.md_5.bungee.api.event;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
import net.md_5.bungee.api.Callback;
|
||||||
import net.md_5.bungee.api.ServerPing;
|
import net.md_5.bungee.api.ServerPing;
|
||||||
import net.md_5.bungee.api.connection.PendingConnection;
|
import net.md_5.bungee.api.connection.PendingConnection;
|
||||||
import net.md_5.bungee.api.plugin.Event;
|
import net.md_5.bungee.api.plugin.Event;
|
||||||
@@ -12,10 +12,9 @@ import net.md_5.bungee.api.plugin.Event;
|
|||||||
* Called when the proxy is pinged with packet 0xFE from the server list.
|
* Called when the proxy is pinged with packet 0xFE from the server list.
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@AllArgsConstructor
|
|
||||||
@ToString(callSuper = false)
|
@ToString(callSuper = false)
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
public class ProxyPingEvent extends Event
|
public class ProxyPingEvent extends AsyncEvent<ProxyPingEvent>
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -26,4 +25,11 @@ public class ProxyPingEvent extends Event
|
|||||||
* The data to respond with.
|
* The data to respond with.
|
||||||
*/
|
*/
|
||||||
private ServerPing response;
|
private ServerPing response;
|
||||||
|
|
||||||
|
public ProxyPingEvent(PendingConnection connection, ServerPing response, Callback<ProxyPingEvent> done)
|
||||||
|
{
|
||||||
|
super( done );
|
||||||
|
this.connection = connection;
|
||||||
|
this.response = response;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,22 @@
|
|||||||
|
package net.md_5.bungee.api.event;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import net.md_5.bungee.api.CommandSender;
|
||||||
|
import net.md_5.bungee.api.plugin.Event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when somebody reloads BungeeCord
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
public class ProxyReloadEvent extends Event
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creator of the action.
|
||||||
|
*/
|
||||||
|
private final CommandSender sender;
|
||||||
|
}
|
@@ -2,12 +2,19 @@ package net.md_5.bungee.api.event;
|
|||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NonNull;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import net.md_5.bungee.api.config.ServerInfo;
|
import net.md_5.bungee.api.config.ServerInfo;
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
import net.md_5.bungee.api.plugin.Cancellable;
|
import net.md_5.bungee.api.plugin.Cancellable;
|
||||||
import net.md_5.bungee.api.plugin.Event;
|
import net.md_5.bungee.api.plugin.Event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when deciding to connect to a server. At the time when this event is
|
||||||
|
* called, no connection has actually been made. Cancelling the event will
|
||||||
|
* ensure that the connection does not proceed and can be useful to prevent
|
||||||
|
* certain players from accessing certain servers.
|
||||||
|
*/
|
||||||
@Data
|
@Data
|
||||||
@ToString(callSuper = false)
|
@ToString(callSuper = false)
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
@@ -21,6 +28,7 @@ public class ServerConnectEvent extends Event implements Cancellable
|
|||||||
/**
|
/**
|
||||||
* Server the player will be connected to.
|
* Server the player will be connected to.
|
||||||
*/
|
*/
|
||||||
|
@NonNull
|
||||||
private ServerInfo target;
|
private ServerInfo target;
|
||||||
/**
|
/**
|
||||||
* Cancelled state.
|
* Cancelled state.
|
||||||
|
@@ -0,0 +1,29 @@
|
|||||||
|
package net.md_5.bungee.api.event;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
import net.md_5.bungee.api.config.ServerInfo;
|
||||||
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
|
import net.md_5.bungee.api.plugin.Event;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@ToString(callSuper = false)
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
public class ServerDisconnectEvent extends Event
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Player disconnecting from a server.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
private final ProxiedPlayer player;
|
||||||
|
/**
|
||||||
|
* Server the player is disconnecting from.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
private final ServerInfo target;
|
||||||
|
}
|
@@ -3,6 +3,8 @@ package net.md_5.bungee.api.event;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
import net.md_5.bungee.api.config.ServerInfo;
|
import net.md_5.bungee.api.config.ServerInfo;
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
import net.md_5.bungee.api.plugin.Cancellable;
|
import net.md_5.bungee.api.plugin.Cancellable;
|
||||||
@@ -25,19 +27,60 @@ public class ServerKickEvent extends Event implements Cancellable
|
|||||||
* Player being kicked.
|
* Player being kicked.
|
||||||
*/
|
*/
|
||||||
private final ProxiedPlayer player;
|
private final ProxiedPlayer player;
|
||||||
|
/**
|
||||||
|
* The server the player was kicked from, should be used in preference to
|
||||||
|
* {@link ProxiedPlayer#getServer()}.
|
||||||
|
*/
|
||||||
|
private final ServerInfo kickedFrom;
|
||||||
/**
|
/**
|
||||||
* Kick reason.
|
* Kick reason.
|
||||||
*/
|
*/
|
||||||
private String kickReason;
|
private BaseComponent[] kickReasonComponent;
|
||||||
/**
|
/**
|
||||||
* Server to send player to if this event is cancelled.
|
* Server to send player to if this event is cancelled.
|
||||||
*/
|
*/
|
||||||
private ServerInfo cancelServer;
|
private ServerInfo cancelServer;
|
||||||
|
/**
|
||||||
|
* State in which the kick occured.
|
||||||
|
*/
|
||||||
|
private State state;
|
||||||
|
|
||||||
public ServerKickEvent(ProxiedPlayer player, String kickReason, ServerInfo cancelServer)
|
public enum State
|
||||||
|
{
|
||||||
|
|
||||||
|
CONNECTING, CONNECTED, UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public ServerKickEvent(ProxiedPlayer player, BaseComponent[] kickReasonComponent, ServerInfo cancelServer)
|
||||||
|
{
|
||||||
|
this( player, kickReasonComponent, cancelServer, State.UNKNOWN );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public ServerKickEvent(ProxiedPlayer player, BaseComponent[] kickReasonComponent, ServerInfo cancelServer, State state)
|
||||||
|
{
|
||||||
|
this( player, player.getServer().getInfo(), kickReasonComponent, cancelServer, state );
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerKickEvent(ProxiedPlayer player, ServerInfo kickedFrom, BaseComponent[] kickReasonComponent, ServerInfo cancelServer, State state)
|
||||||
{
|
{
|
||||||
this.player = player;
|
this.player = player;
|
||||||
this.kickReason = kickReason;
|
this.kickedFrom = kickedFrom;
|
||||||
|
this.kickReasonComponent = kickReasonComponent;
|
||||||
this.cancelServer = cancelServer;
|
this.cancelServer = cancelServer;
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public String getKickReason()
|
||||||
|
{
|
||||||
|
return BaseComponent.toLegacyText( kickReasonComponent );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public void setKickReason(String reason)
|
||||||
|
{
|
||||||
|
kickReasonComponent = TextComponent.fromLegacyText( reason );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,39 @@
|
|||||||
|
package net.md_5.bungee.api.event;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.ToString;
|
||||||
|
import net.md_5.bungee.api.connection.Connection;
|
||||||
|
import net.md_5.bungee.api.plugin.Cancellable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event called when a player uses tab completion.
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class TabCompleteEvent extends TargetedEvent implements Cancellable
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancelled state.
|
||||||
|
*/
|
||||||
|
private boolean cancelled;
|
||||||
|
/**
|
||||||
|
* The message the player has already entered.
|
||||||
|
*/
|
||||||
|
private final String cursor;
|
||||||
|
/**
|
||||||
|
* The suggestions that will be sent to the client. This list is mutable. If
|
||||||
|
* this list is empty, the request will be forwarded to the server.
|
||||||
|
*/
|
||||||
|
private final List<String> suggestions;
|
||||||
|
|
||||||
|
public TabCompleteEvent(Connection sender, Connection receiver, String cursor, List<String> suggestions)
|
||||||
|
{
|
||||||
|
super( sender, receiver );
|
||||||
|
this.cursor = cursor;
|
||||||
|
this.suggestions = suggestions;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,38 @@
|
|||||||
|
package net.md_5.bungee.api.event;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.ToString;
|
||||||
|
import net.md_5.bungee.api.connection.Connection;
|
||||||
|
import net.md_5.bungee.api.plugin.Cancellable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event called when a backend server sends a response to a player asking to
|
||||||
|
* tab-complete a chat message or command. Note that this is not called when
|
||||||
|
* BungeeCord or a plugin responds to a tab-complete request. Use
|
||||||
|
* {@link TabCompleteEvent} for that.
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class TabCompleteResponseEvent extends TargetedEvent implements Cancellable
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the event is cancelled.
|
||||||
|
*/
|
||||||
|
private boolean cancelled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutable list of suggestions sent back to the player. If this list is
|
||||||
|
* empty, an empty list is sent back to the client.
|
||||||
|
*/
|
||||||
|
private final List<String> suggestions;
|
||||||
|
|
||||||
|
public TabCompleteResponseEvent(Connection sender, Connection receiver, List<String> suggestions)
|
||||||
|
{
|
||||||
|
super( sender, receiver );
|
||||||
|
this.suggestions = suggestions;
|
||||||
|
}
|
||||||
|
}
|
@@ -1,11 +1,15 @@
|
|||||||
package net.md_5.bungee.api.plugin;
|
package net.md_5.bungee.api.plugin;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
import net.md_5.bungee.api.config.ConfigurationAdapter;
|
import net.md_5.bungee.api.config.ConfigurationAdapter;
|
||||||
|
import net.md_5.bungee.api.scheduler.GroupedThreadFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents any Plugin that may be loaded at runtime to enhance existing
|
* Represents any Plugin that may be loaded at runtime to enhance existing
|
||||||
@@ -83,4 +87,20 @@ public class Plugin
|
|||||||
this.file = description.getFile();
|
this.file = description.getFile();
|
||||||
this.logger = new PluginLogger( this );
|
this.logger = new PluginLogger( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
private ExecutorService service;
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public ExecutorService getExecutorService()
|
||||||
|
{
|
||||||
|
if ( service == null )
|
||||||
|
{
|
||||||
|
String name = ( getDescription() == null ) ? "unknown" : getDescription().getName();
|
||||||
|
service = Executors.newCachedThreadPool( new ThreadFactoryBuilder().setNameFormat( name + " Pool Thread #%1$d" )
|
||||||
|
.setThreadFactory( new GroupedThreadFactory( this, name ) ).build() );
|
||||||
|
}
|
||||||
|
return service;
|
||||||
|
}
|
||||||
|
//
|
||||||
}
|
}
|
||||||
|
@@ -2,13 +2,18 @@ package net.md_5.bungee.api.plugin;
|
|||||||
|
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLClassLoader;
|
import java.net.URLClassLoader;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
|
|
||||||
public class PluginClassloader extends URLClassLoader
|
public class PluginClassloader extends URLClassLoader
|
||||||
{
|
{
|
||||||
|
|
||||||
private static final Set<PluginClassloader> allLoaders = new HashSet<>();
|
private static final Set<PluginClassloader> allLoaders = new CopyOnWriteArraySet<>();
|
||||||
|
|
||||||
|
static
|
||||||
|
{
|
||||||
|
ClassLoader.registerAsParallelCapable();
|
||||||
|
}
|
||||||
|
|
||||||
public PluginClassloader(URL[] urls)
|
public PluginClassloader(URL[] urls)
|
||||||
{
|
{
|
||||||
|
@@ -36,8 +36,16 @@ public class PluginDescription
|
|||||||
* Plugin hard dependencies.
|
* Plugin hard dependencies.
|
||||||
*/
|
*/
|
||||||
private Set<String> depends = new HashSet<>();
|
private Set<String> depends = new HashSet<>();
|
||||||
|
/**
|
||||||
|
* Plugin soft dependencies.
|
||||||
|
*/
|
||||||
|
private Set<String> softDepends = new HashSet<>();
|
||||||
/**
|
/**
|
||||||
* File we were loaded from.
|
* File we were loaded from.
|
||||||
*/
|
*/
|
||||||
private File file = null;
|
private File file = null;
|
||||||
|
/**
|
||||||
|
* Optional description.
|
||||||
|
*/
|
||||||
|
private String description = null;
|
||||||
}
|
}
|
||||||
|
@@ -2,18 +2,17 @@ package net.md_5.bungee.api.plugin;
|
|||||||
|
|
||||||
import java.util.logging.LogRecord;
|
import java.util.logging.LogRecord;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
|
||||||
|
|
||||||
public class PluginLogger extends Logger
|
public class PluginLogger extends Logger
|
||||||
{
|
{
|
||||||
|
|
||||||
private String pluginName;
|
private final String pluginName;
|
||||||
|
|
||||||
protected PluginLogger(Plugin plugin)
|
protected PluginLogger(Plugin plugin)
|
||||||
{
|
{
|
||||||
super( plugin.getClass().getCanonicalName(), null );
|
super( plugin.getClass().getCanonicalName(), null );
|
||||||
pluginName = "[" + plugin.getDescription().getName() + "] ";
|
pluginName = "[" + plugin.getDescription().getName() + "] ";
|
||||||
setParent( ProxyServer.getInstance().getLogger() );
|
setParent( plugin.getProxy().getLogger() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
package net.md_5.bungee.api.plugin;
|
package net.md_5.bungee.api.plugin;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.google.common.collect.ArrayListMultimap;
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
import com.google.common.eventbus.Subscribe;
|
import com.google.common.eventbus.Subscribe;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@@ -10,8 +12,12 @@ import java.net.URLClassLoader;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
import java.util.jar.JarEntry;
|
import java.util.jar.JarEntry;
|
||||||
import java.util.jar.JarFile;
|
import java.util.jar.JarFile;
|
||||||
@@ -21,9 +27,12 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import net.md_5.bungee.api.CommandSender;
|
import net.md_5.bungee.api.CommandSender;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
import net.md_5.bungee.event.EventBus;
|
import net.md_5.bungee.event.EventBus;
|
||||||
import net.md_5.bungee.event.EventHandler;
|
import net.md_5.bungee.event.EventHandler;
|
||||||
import org.yaml.snakeyaml.Yaml;
|
import org.yaml.snakeyaml.Yaml;
|
||||||
|
import org.yaml.snakeyaml.constructor.Constructor;
|
||||||
|
import org.yaml.snakeyaml.introspector.PropertyUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to manage bridging between plugin duties and implementation duties, for
|
* Class to manage bridging between plugin duties and implementation duties, for
|
||||||
@@ -37,17 +46,27 @@ public class PluginManager
|
|||||||
/*========================================================================*/
|
/*========================================================================*/
|
||||||
private final ProxyServer proxy;
|
private final ProxyServer proxy;
|
||||||
/*========================================================================*/
|
/*========================================================================*/
|
||||||
private final Yaml yaml = new Yaml();
|
private final Yaml yaml;
|
||||||
private final EventBus eventBus;
|
private final EventBus eventBus;
|
||||||
private final Map<String, Plugin> plugins = new LinkedHashMap<>();
|
private final Map<String, Plugin> plugins = new LinkedHashMap<>();
|
||||||
private final Map<String, Command> commandMap = new HashMap<>();
|
private final Map<String, Command> commandMap = new HashMap<>();
|
||||||
private Map<String, PluginDescription> toLoad = new HashMap<>();
|
private Map<String, PluginDescription> toLoad = new HashMap<>();
|
||||||
|
private final Multimap<Plugin, Command> commandsByPlugin = ArrayListMultimap.create();
|
||||||
|
private final Multimap<Plugin, Listener> listenersByPlugin = ArrayListMultimap.create();
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public PluginManager(ProxyServer proxy)
|
public PluginManager(ProxyServer proxy)
|
||||||
{
|
{
|
||||||
this.proxy = proxy;
|
this.proxy = proxy;
|
||||||
eventBus = new EventBus( proxy.getLogger(), Subscribe.class, EventHandler.class );
|
|
||||||
|
// Ignore unknown entries in the plugin descriptions
|
||||||
|
Constructor yamlConstructor = new Constructor();
|
||||||
|
PropertyUtils propertyUtils = yamlConstructor.getPropertyUtils();
|
||||||
|
propertyUtils.setSkipMissingProperties( true );
|
||||||
|
yamlConstructor.setPropertyUtils( propertyUtils );
|
||||||
|
yaml = new Yaml( yamlConstructor );
|
||||||
|
|
||||||
|
eventBus = new EventBus( proxy.getLogger() );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -63,6 +82,7 @@ public class PluginManager
|
|||||||
{
|
{
|
||||||
commandMap.put( alias.toLowerCase(), command );
|
commandMap.put( alias.toLowerCase(), command );
|
||||||
}
|
}
|
||||||
|
commandsByPlugin.put( plugin, command );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -72,7 +92,28 @@ public class PluginManager
|
|||||||
*/
|
*/
|
||||||
public void unregisterCommand(Command command)
|
public void unregisterCommand(Command command)
|
||||||
{
|
{
|
||||||
commandMap.values().remove( command );
|
while ( commandMap.values().remove( command ) );
|
||||||
|
commandsByPlugin.values().remove( command );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregister all commands owned by a {@link Plugin}
|
||||||
|
*
|
||||||
|
* @param plugin the plugin to register the commands of
|
||||||
|
*/
|
||||||
|
public void unregisterCommands(Plugin plugin)
|
||||||
|
{
|
||||||
|
for ( Iterator<Command> it = commandsByPlugin.get( plugin ).iterator(); it.hasNext(); )
|
||||||
|
{
|
||||||
|
Command command = it.next();
|
||||||
|
while ( commandMap.values().remove( command ) );
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean dispatchCommand(CommandSender sender, String commandLine)
|
||||||
|
{
|
||||||
|
return dispatchCommand( sender, commandLine, null );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -83,10 +124,21 @@ public class PluginManager
|
|||||||
* arguments
|
* arguments
|
||||||
* @return whether the command was handled
|
* @return whether the command was handled
|
||||||
*/
|
*/
|
||||||
public boolean dispatchCommand(CommandSender sender, String commandLine)
|
public boolean dispatchCommand(CommandSender sender, String commandLine, List<String> tabResults)
|
||||||
{
|
{
|
||||||
String[] split = argsSplit.split( commandLine );
|
String[] split = argsSplit.split( commandLine, -1 );
|
||||||
Command command = commandMap.get( split[0].toLowerCase() );
|
// Check for chat that only contains " "
|
||||||
|
if ( split.length == 0 )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String commandName = split[0].toLowerCase();
|
||||||
|
if ( sender instanceof ProxiedPlayer && proxy.getDisabledCommands().contains( commandName ) )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Command command = commandMap.get( commandName );
|
||||||
if ( command == null )
|
if ( command == null )
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -95,14 +147,33 @@ public class PluginManager
|
|||||||
String permission = command.getPermission();
|
String permission = command.getPermission();
|
||||||
if ( permission != null && !permission.isEmpty() && !sender.hasPermission( permission ) )
|
if ( permission != null && !permission.isEmpty() && !sender.hasPermission( permission ) )
|
||||||
{
|
{
|
||||||
sender.sendMessage( proxy.getTranslation( "no_permission" ) );
|
if ( !( command instanceof TabExecutor ) || tabResults == null )
|
||||||
|
{
|
||||||
|
sender.sendMessage( proxy.getTranslation( "no_permission" ) );
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
String[] args = Arrays.copyOfRange( split, 1, split.length );
|
String[] args = Arrays.copyOfRange( split, 1, split.length );
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
command.execute( sender, args );
|
if ( tabResults == null )
|
||||||
|
{
|
||||||
|
if ( proxy.getConfig().isLogCommands() )
|
||||||
|
{
|
||||||
|
proxy.getLogger().log( Level.INFO, "{0} executed command: /{1}", new Object[]
|
||||||
|
{
|
||||||
|
sender.getName(), commandLine
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
command.execute( sender, args );
|
||||||
|
} else if ( commandLine.contains( " " ) && command instanceof TabExecutor )
|
||||||
|
{
|
||||||
|
for ( String s : ( (TabExecutor) command ).onTabComplete( sender, args ) )
|
||||||
|
{
|
||||||
|
tabResults.add( s );
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch ( Exception ex )
|
} catch ( Exception ex )
|
||||||
{
|
{
|
||||||
sender.sendMessage( ChatColor.RED + "An internal error occurred whilst executing this command, please check the console log for details." );
|
sender.sendMessage( ChatColor.RED + "An internal error occurred whilst executing this command, please check the console log for details." );
|
||||||
@@ -132,7 +203,7 @@ public class PluginManager
|
|||||||
return plugins.get( name );
|
return plugins.get( name );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadAndEnablePlugins()
|
public void loadPlugins()
|
||||||
{
|
{
|
||||||
Map<PluginDescription, Boolean> pluginStatuses = new HashMap<>();
|
Map<PluginDescription, Boolean> pluginStatuses = new HashMap<>();
|
||||||
for ( Map.Entry<String, PluginDescription> entry : toLoad.entrySet() )
|
for ( Map.Entry<String, PluginDescription> entry : toLoad.entrySet() )
|
||||||
@@ -140,12 +211,15 @@ public class PluginManager
|
|||||||
PluginDescription plugin = entry.getValue();
|
PluginDescription plugin = entry.getValue();
|
||||||
if ( !enablePlugin( pluginStatuses, new Stack<PluginDescription>(), plugin ) )
|
if ( !enablePlugin( pluginStatuses, new Stack<PluginDescription>(), plugin ) )
|
||||||
{
|
{
|
||||||
ProxyServer.getInstance().getLogger().warning( "Failed to enable " + entry.getKey() );
|
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Failed to enable {0}", entry.getKey() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
toLoad.clear();
|
toLoad.clear();
|
||||||
toLoad = null;
|
toLoad = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enablePlugins()
|
||||||
|
{
|
||||||
for ( Plugin plugin : plugins.values() )
|
for ( Plugin plugin : plugins.values() )
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -169,14 +243,19 @@ public class PluginManager
|
|||||||
return pluginStatuses.get( plugin );
|
return pluginStatuses.get( plugin );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// combine all dependencies for 'for loop'
|
||||||
|
Set<String> dependencies = new HashSet<>();
|
||||||
|
dependencies.addAll( plugin.getDepends() );
|
||||||
|
dependencies.addAll( plugin.getSoftDepends() );
|
||||||
|
|
||||||
// success status
|
// success status
|
||||||
boolean status = true;
|
boolean status = true;
|
||||||
|
|
||||||
// try to load dependencies first
|
// try to load dependencies first
|
||||||
for ( String dependName : plugin.getDepends() )
|
for ( String dependName : dependencies )
|
||||||
{
|
{
|
||||||
PluginDescription depend = toLoad.get( dependName );
|
PluginDescription depend = toLoad.get( dependName );
|
||||||
Boolean dependStatus = depend != null ? pluginStatuses.get( depend ) : Boolean.FALSE;
|
Boolean dependStatus = ( depend != null ) ? pluginStatuses.get( depend ) : Boolean.FALSE;
|
||||||
|
|
||||||
if ( dependStatus == null )
|
if ( dependStatus == null )
|
||||||
{
|
{
|
||||||
@@ -188,7 +267,7 @@ public class PluginManager
|
|||||||
dependencyGraph.append( element.getName() ).append( " -> " );
|
dependencyGraph.append( element.getName() ).append( " -> " );
|
||||||
}
|
}
|
||||||
dependencyGraph.append( plugin.getName() ).append( " -> " ).append( dependName );
|
dependencyGraph.append( plugin.getName() ).append( " -> " ).append( dependName );
|
||||||
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Circular dependency detected: " + dependencyGraph );
|
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Circular dependency detected: {0}", dependencyGraph );
|
||||||
status = false;
|
status = false;
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
@@ -198,11 +277,11 @@ public class PluginManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( dependStatus == Boolean.FALSE )
|
if ( dependStatus == Boolean.FALSE && plugin.getDepends().contains( dependName ) ) // only fail if this wasn't a soft dependency
|
||||||
{
|
{
|
||||||
ProxyServer.getInstance().getLogger().log( Level.WARNING, "{0} (required by {1}) is unavailable", new Object[]
|
ProxyServer.getInstance().getLogger().log( Level.WARNING, "{0} (required by {1}) is unavailable", new Object[]
|
||||||
{
|
{
|
||||||
depend.getName(), plugin.getName()
|
String.valueOf( dependName ), plugin.getName()
|
||||||
} );
|
} );
|
||||||
status = false;
|
status = false;
|
||||||
}
|
}
|
||||||
@@ -258,8 +337,12 @@ public class PluginManager
|
|||||||
{
|
{
|
||||||
try ( JarFile jar = new JarFile( file ) )
|
try ( JarFile jar = new JarFile( file ) )
|
||||||
{
|
{
|
||||||
JarEntry pdf = jar.getJarEntry( "plugin.yml" );
|
JarEntry pdf = jar.getJarEntry( "bungee.yml" );
|
||||||
Preconditions.checkNotNull( pdf, "Plugin must have a plugin.yml" );
|
if ( pdf == null )
|
||||||
|
{
|
||||||
|
pdf = jar.getJarEntry( "plugin.yml" );
|
||||||
|
}
|
||||||
|
Preconditions.checkNotNull( pdf, "Plugin must have a plugin.yml or bungee.yml" );
|
||||||
|
|
||||||
try ( InputStream in = jar.getInputStream( pdf ) )
|
try ( InputStream in = jar.getInputStream( pdf ) )
|
||||||
{
|
{
|
||||||
@@ -305,7 +388,7 @@ public class PluginManager
|
|||||||
/**
|
/**
|
||||||
* Register a {@link Listener} for receiving called events. Methods in this
|
* Register a {@link Listener} for receiving called events. Methods in this
|
||||||
* Object which wish to receive events must be annotated with the
|
* Object which wish to receive events must be annotated with the
|
||||||
* {@link Subscribe} annotation.
|
* {@link EventHandler} annotation.
|
||||||
*
|
*
|
||||||
* @param plugin the owning plugin
|
* @param plugin the owning plugin
|
||||||
* @param listener the listener to register events for
|
* @param listener the listener to register events for
|
||||||
@@ -314,14 +397,33 @@ public class PluginManager
|
|||||||
{
|
{
|
||||||
for ( Method method : listener.getClass().getDeclaredMethods() )
|
for ( Method method : listener.getClass().getDeclaredMethods() )
|
||||||
{
|
{
|
||||||
if ( method.isAnnotationPresent( Subscribe.class ) )
|
Preconditions.checkArgument( !method.isAnnotationPresent( Subscribe.class ),
|
||||||
{
|
"Listener %s has registered using deprecated subscribe annotation! Please update to @EventHandler.", listener );
|
||||||
proxy.getLogger().log( Level.WARNING, "Listener " + listener + " has registered using depreceated subscribe annotation!"
|
|
||||||
+ " Please advice author to update to @EventHandler."
|
|
||||||
+ " As a server owner you may safely ignore this.", new Exception() );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
eventBus.register( listener );
|
eventBus.register( listener );
|
||||||
|
listenersByPlugin.put( plugin, listener );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregister a {@link Listener} so that the events do not reach it anymore.
|
||||||
|
*
|
||||||
|
* @param listener the listener to unregister
|
||||||
|
*/
|
||||||
|
public void unregisterListener(Listener listener)
|
||||||
|
{
|
||||||
|
eventBus.unregister( listener );
|
||||||
|
listenersByPlugin.values().remove( listener );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregister all of a Plugin's listener.
|
||||||
|
*/
|
||||||
|
public void unregisterListeners(Plugin plugin)
|
||||||
|
{
|
||||||
|
for ( Iterator<Listener> it = listenersByPlugin.get( plugin ).iterator(); it.hasNext(); )
|
||||||
|
{
|
||||||
|
eventBus.unregister( it.next() );
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,9 @@
|
|||||||
|
package net.md_5.bungee.api.plugin;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.CommandSender;
|
||||||
|
|
||||||
|
public interface TabExecutor
|
||||||
|
{
|
||||||
|
|
||||||
|
public Iterable<String> onTabComplete(CommandSender sender, String[] args);
|
||||||
|
}
|
@@ -0,0 +1,34 @@
|
|||||||
|
package net.md_5.bungee.api.scheduler;
|
||||||
|
|
||||||
|
import java.util.concurrent.ThreadFactory;
|
||||||
|
import lombok.Data;
|
||||||
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Deprecated
|
||||||
|
public class GroupedThreadFactory implements ThreadFactory
|
||||||
|
{
|
||||||
|
|
||||||
|
private final ThreadGroup group;
|
||||||
|
|
||||||
|
public static class BungeeGroup extends ThreadGroup
|
||||||
|
{
|
||||||
|
|
||||||
|
private BungeeGroup(String name)
|
||||||
|
{
|
||||||
|
super( name );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public GroupedThreadFactory(Plugin plugin, String name)
|
||||||
|
{
|
||||||
|
this.group = new BungeeGroup( name );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Thread newThread(Runnable r)
|
||||||
|
{
|
||||||
|
return new Thread( group, r );
|
||||||
|
}
|
||||||
|
}
|
@@ -1,6 +1,5 @@
|
|||||||
package net.md_5.bungee.api.scheduler;
|
package net.md_5.bungee.api.scheduler;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import net.md_5.bungee.api.plugin.Plugin;
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,11 +30,7 @@ public interface ScheduledTask
|
|||||||
Runnable getTask();
|
Runnable getTask();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the delay in the specified unit before this task will next be
|
* Cancel this task to suppress subsequent executions.
|
||||||
* executed.
|
|
||||||
*
|
|
||||||
* @param unit the unit to get the delay in
|
|
||||||
* @return the time before the next execution of this task
|
|
||||||
*/
|
*/
|
||||||
long getDelay(TimeUnit unit);
|
void cancel();
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package net.md_5.bungee.api.scheduler;
|
package net.md_5.bungee.api.scheduler;
|
||||||
|
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import net.md_5.bungee.api.plugin.Plugin;
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
|
|
||||||
@@ -65,10 +66,28 @@ public interface TaskScheduler
|
|||||||
*
|
*
|
||||||
* @param owner the plugin owning this task
|
* @param owner the plugin owning this task
|
||||||
* @param task the task to run
|
* @param task the task to run
|
||||||
* @param delay the delay in milliseconds before this task will be executed
|
* @param delay the delay before this task will be executed
|
||||||
* @param period the interval before subsequent executions of this task
|
* @param period the interval before subsequent executions of this task
|
||||||
* @param unit the unit in which the delay and period will be measured
|
* @param unit the unit in which the delay and period will be measured
|
||||||
* @return the scheduled task
|
* @return the scheduled task
|
||||||
*/
|
*/
|
||||||
ScheduledTask schedule(Plugin owner, Runnable task, long delay, long period, TimeUnit unit);
|
ScheduledTask schedule(Plugin owner, Runnable task, long delay, long period, TimeUnit unit);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the unsafe methods of this class.
|
||||||
|
*
|
||||||
|
* @return the unsafe method interface
|
||||||
|
*/
|
||||||
|
Unsafe unsafe();
|
||||||
|
|
||||||
|
interface Unsafe
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An executor service which underlies this scheduler.
|
||||||
|
*
|
||||||
|
* @return the underlying executor service or compatible wrapper
|
||||||
|
*/
|
||||||
|
ExecutorService getExecutorService(Plugin plugin);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,11 +1,13 @@
|
|||||||
package net.md_5.bungee.api.score;
|
package net.md_5.bungee.api.score;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an objective entry.
|
* Represents an objective entry.
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
public class Objective
|
public class Objective
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -16,5 +18,9 @@ public class Objective
|
|||||||
/**
|
/**
|
||||||
* Value of the objective.
|
* Value of the objective.
|
||||||
*/
|
*/
|
||||||
private final String value; // displayName
|
private String value;
|
||||||
|
/**
|
||||||
|
* Type; integer or hearts
|
||||||
|
*/
|
||||||
|
private final String type;
|
||||||
}
|
}
|
||||||
|
@@ -6,5 +6,23 @@ package net.md_5.bungee.api.score;
|
|||||||
public enum Position
|
public enum Position
|
||||||
{
|
{
|
||||||
|
|
||||||
LIST, SIDEBAR, BELOW;
|
LIST,
|
||||||
|
SIDEBAR,
|
||||||
|
BELOW,
|
||||||
|
SIDEBAR_BLACK,
|
||||||
|
SIDEBAR_DARK_BLUE,
|
||||||
|
SIDEBAR_DARK_GREEN,
|
||||||
|
SIDEBAR_DARK_AQUA,
|
||||||
|
SIDEBAR_DARK_RED,
|
||||||
|
SIDEBAR_DARK_PURPLE,
|
||||||
|
SIDEBAR_GOLD,
|
||||||
|
SIDEBAR_GRAY,
|
||||||
|
SIDEBAR_DARK_GRAY,
|
||||||
|
SIDEBAR_BLUE,
|
||||||
|
SIDEBAR_GREEN,
|
||||||
|
SIDEBAR_AQUA,
|
||||||
|
SIDEBAR_RED,
|
||||||
|
SIDEBAR_LIGHT_PURPLE,
|
||||||
|
SIDEBAR_YELLOW,
|
||||||
|
SIDEBAR_WHITE;
|
||||||
}
|
}
|
||||||
|
@@ -74,6 +74,11 @@ public class Scoreboard
|
|||||||
return teams.get( name );
|
return teams.get( name );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Objective getObjective(String name)
|
||||||
|
{
|
||||||
|
return objectives.get( name );
|
||||||
|
}
|
||||||
|
|
||||||
public void removeObjective(String objectiveName)
|
public void removeObjective(String objectiveName)
|
||||||
{
|
{
|
||||||
objectives.remove( objectiveName );
|
objectives.remove( objectiveName );
|
||||||
|
@@ -16,7 +16,9 @@ public class Team
|
|||||||
private String displayName;
|
private String displayName;
|
||||||
private String prefix;
|
private String prefix;
|
||||||
private String suffix;
|
private String suffix;
|
||||||
private boolean friendlyFire;
|
private byte friendlyFire;
|
||||||
|
private String nameTagVisibility;
|
||||||
|
private byte color;
|
||||||
private Set<String> players = new HashSet<>();
|
private Set<String> players = new HashSet<>();
|
||||||
|
|
||||||
public Collection<String> getPlayers()
|
public Collection<String> getPlayers()
|
||||||
|
@@ -1,60 +0,0 @@
|
|||||||
package net.md_5.bungee.api.tab;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a custom tab list, which may have slots manipulated.
|
|
||||||
*/
|
|
||||||
public interface CustomTabList extends TabListHandler
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Blank out this tab list and update immediately.
|
|
||||||
*/
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the columns in this list.
|
|
||||||
*
|
|
||||||
* @return the width of this list
|
|
||||||
*/
|
|
||||||
int getColumns();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the rows in this list.
|
|
||||||
*
|
|
||||||
* @return the height of this list
|
|
||||||
*/
|
|
||||||
int getRows();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the total size of this list.
|
|
||||||
*
|
|
||||||
* @return {@link #getRows()} * {@link #getColumns()}
|
|
||||||
*/
|
|
||||||
int getSize();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the text in the specified slot and update immediately.
|
|
||||||
*
|
|
||||||
* @param row the row to set
|
|
||||||
* @param column the column to set
|
|
||||||
* @param text the text to set
|
|
||||||
* @return the padded text
|
|
||||||
*/
|
|
||||||
String setSlot(int row, int column, String text);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the text in the specified slot.
|
|
||||||
*
|
|
||||||
* @param row the row to set
|
|
||||||
* @param column the column to set
|
|
||||||
* @param text the text to set
|
|
||||||
* @param update whether or not to invoke {@link #update()} upon completion
|
|
||||||
* @return the padded text
|
|
||||||
*/
|
|
||||||
String setSlot(int row, int column, String text, boolean update);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flush all queued changes to the user.
|
|
||||||
*/
|
|
||||||
void update();
|
|
||||||
}
|
|
@@ -1,39 +0,0 @@
|
|||||||
package net.md_5.bungee.api.tab;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
|
||||||
|
|
||||||
@NoArgsConstructor
|
|
||||||
public abstract class TabListAdapter implements TabListHandler
|
|
||||||
{
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
private ProxiedPlayer player;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(ProxiedPlayer player)
|
|
||||||
{
|
|
||||||
this.player = player;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onConnect()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDisconnect()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onServerChange()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPingChange(int ping)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,55 +0,0 @@
|
|||||||
package net.md_5.bungee.api.tab;
|
|
||||||
|
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
|
||||||
|
|
||||||
public interface TabListHandler
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called so that this class may set member fields to keep track of its
|
|
||||||
* internal state. You should not do any packet sending or manipulation of
|
|
||||||
* the passed player, other than storing it.
|
|
||||||
*
|
|
||||||
* @param player the player to be associated with this list
|
|
||||||
*/
|
|
||||||
void init(ProxiedPlayer player);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when this player first connects to the proxy.
|
|
||||||
*/
|
|
||||||
void onConnect();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when a player first connects to the proxy.
|
|
||||||
*
|
|
||||||
* @param player the connecting player
|
|
||||||
*/
|
|
||||||
void onServerChange();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when a players ping changes. The new ping will have not updated in
|
|
||||||
* the player instance until this method returns.
|
|
||||||
*
|
|
||||||
* @param player the player who's ping changed
|
|
||||||
* @param ping the player's new ping.
|
|
||||||
*/
|
|
||||||
void onPingChange(int ping);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when a player disconnects.
|
|
||||||
*
|
|
||||||
* @param player the disconnected player
|
|
||||||
*/
|
|
||||||
void onDisconnect();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when a list update packet is sent from server to client.
|
|
||||||
*
|
|
||||||
* @param player receiving this packet
|
|
||||||
* @param name the player which this packet is relevant to
|
|
||||||
* @param online whether the subject player is online
|
|
||||||
* @param ping ping of the subject player
|
|
||||||
* @return whether to send the packet to the client
|
|
||||||
*/
|
|
||||||
boolean onListUpdate(String name, boolean online, int ping);
|
|
||||||
}
|
|
49
api/src/main/java/net/md_5/bungee/command/PlayerCommand.java
Normal file
49
api/src/main/java/net/md_5/bungee/command/PlayerCommand.java
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package net.md_5.bungee.command;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.base.Predicate;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
import net.md_5.bungee.api.CommandSender;
|
||||||
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
|
import net.md_5.bungee.api.plugin.Command;
|
||||||
|
import net.md_5.bungee.api.plugin.TabExecutor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated internal use only
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public abstract class PlayerCommand extends Command implements TabExecutor
|
||||||
|
{
|
||||||
|
|
||||||
|
public PlayerCommand(String name)
|
||||||
|
{
|
||||||
|
super( name );
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlayerCommand(String name, String permission, String... aliases)
|
||||||
|
{
|
||||||
|
super( name, permission, aliases );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterable<String> onTabComplete(CommandSender sender, String[] args)
|
||||||
|
{
|
||||||
|
final String lastArg = ( args.length > 0 ) ? args[args.length - 1].toLowerCase() : "";
|
||||||
|
return Iterables.transform( Iterables.filter( ProxyServer.getInstance().getPlayers(), new Predicate<ProxiedPlayer>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public boolean apply(ProxiedPlayer player)
|
||||||
|
{
|
||||||
|
return player.getName().toLowerCase().startsWith( lastArg );
|
||||||
|
}
|
||||||
|
} ), new Function<ProxiedPlayer, String>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public String apply(ProxiedPlayer player)
|
||||||
|
{
|
||||||
|
return player.getName();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
}
|
61
api/src/test/java/net/md_5/bungee/util/AddressParseTest.java
Normal file
61
api/src/test/java/net/md_5/bungee/util/AddressParseTest.java
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
package net.md_5.bungee.util;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import net.md_5.bungee.Util;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.Parameterized;
|
||||||
|
import org.junit.runners.Parameterized.Parameters;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RunWith(Parameterized.class)
|
||||||
|
public class AddressParseTest
|
||||||
|
{
|
||||||
|
|
||||||
|
@Parameters
|
||||||
|
public static Collection<Object[]> data()
|
||||||
|
{
|
||||||
|
return Arrays.asList( new Object[][]
|
||||||
|
{
|
||||||
|
{
|
||||||
|
"127.0.0.1", "127.0.0.1", Util.DEFAULT_PORT
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"127.0.0.1:1337", "127.0.0.1", 1337
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"[::1]", "0:0:0:0:0:0:0:1", Util.DEFAULT_PORT
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"[0:0:0:0::1]", "0:0:0:0:0:0:0:1", Util.DEFAULT_PORT
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"[0:0:0:0:0:0:0:1]", "0:0:0:0:0:0:0:1", Util.DEFAULT_PORT
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"[::1]:1337", "0:0:0:0:0:0:0:1", 1337
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"[0:0:0:0::1]:1337", "0:0:0:0:0:0:0:1", 1337
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"[0:0:0:0:0:0:0:1]:1337", "0:0:0:0:0:0:0:1", 1337
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
private final String line;
|
||||||
|
private final String host;
|
||||||
|
private final int port;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test()
|
||||||
|
{
|
||||||
|
InetSocketAddress parsed = Util.getAddr( line );
|
||||||
|
Assert.assertEquals( host, parsed.getHostString() );
|
||||||
|
Assert.assertEquals( port, parsed.getPort() );
|
||||||
|
}
|
||||||
|
}
|
31
bootstrap/nb-configuration.xml
Normal file
31
bootstrap/nb-configuration.xml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project-shared-configuration>
|
||||||
|
<!--
|
||||||
|
This file contains additional configuration written by modules in the NetBeans IDE.
|
||||||
|
The configuration is intended to be shared among all the users of project and
|
||||||
|
therefore it is assumed to be part of version control checkout.
|
||||||
|
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
|
||||||
|
-->
|
||||||
|
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
|
||||||
|
<!--
|
||||||
|
Properties that influence various parts of the IDE, especially code formatting and the like.
|
||||||
|
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
|
||||||
|
That way multiple projects can share the same settings (useful for formatting rules for example).
|
||||||
|
Any value defined here will override the pom.xml file value but is only applicable to the current project.
|
||||||
|
-->
|
||||||
|
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
|
||||||
|
</properties>
|
||||||
|
</project-shared-configuration>
|
94
bootstrap/pom.xml
Normal file
94
bootstrap/pom.xml
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
|
||||||
|
<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">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>net.md-5</groupId>
|
||||||
|
<artifactId>bungeecord-parent</artifactId>
|
||||||
|
<version>1.8-SNAPSHOT</version>
|
||||||
|
<relativePath>../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<groupId>net.md-5</groupId>
|
||||||
|
<artifactId>bungeecord-bootstrap</artifactId>
|
||||||
|
<version>1.8-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>BungeeCord-Bootstrap</name>
|
||||||
|
<description>Java 1.6 loader for BungeeCord</description>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>1.6</maven.compiler.source>
|
||||||
|
<maven.compiler.target>1.6</maven.compiler.target>
|
||||||
|
<maven.build.timestamp.format>yyyyMMdd</maven.build.timestamp.format>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.md-5</groupId>
|
||||||
|
<artifactId>bungeecord-proxy</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.sf.jopt-simple</groupId>
|
||||||
|
<artifactId>jopt-simple</artifactId>
|
||||||
|
<version>4.8</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<finalName>BungeeCord</finalName>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<!-- Don't deploy proxy to maven repo, only APIs -->
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<skip>true</skip>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<version>2.4</version>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifestEntries>
|
||||||
|
<Main-Class>net.md_5.bungee.Bootstrap</Main-Class>
|
||||||
|
<Implementation-Version>${describe}</Implementation-Version>
|
||||||
|
<Specification-Version>${maven.build.timestamp}</Specification-Version>
|
||||||
|
</manifestEntries>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
|
<version>2.1</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>shade</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<configuration>
|
||||||
|
<filters>
|
||||||
|
<filter>
|
||||||
|
<artifact>*:*</artifact>
|
||||||
|
<excludes>
|
||||||
|
<exclude>**/*.java</exclude>
|
||||||
|
<exclude>**/*.SF</exclude>
|
||||||
|
<exclude>**/*.DSA</exclude>
|
||||||
|
</excludes>
|
||||||
|
</filter>
|
||||||
|
</filters>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
17
bootstrap/src/main/java/net/md_5/bungee/Bootstrap.java
Normal file
17
bootstrap/src/main/java/net/md_5/bungee/Bootstrap.java
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package net.md_5.bungee;
|
||||||
|
|
||||||
|
public class Bootstrap
|
||||||
|
{
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception
|
||||||
|
{
|
||||||
|
if ( Float.parseFloat( System.getProperty( "java.class.version" ) ) < 51.0 )
|
||||||
|
{
|
||||||
|
System.err.println( "*** ERROR *** BungeeCord requires Java 7 or above to function! Please download and install it!" );
|
||||||
|
System.out.println( "You can check your Java version with the command: java -version" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BungeeCordLauncher.main( args );
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,69 @@
|
|||||||
|
package net.md_5.bungee;
|
||||||
|
|
||||||
|
import java.security.Security;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import joptsimple.OptionParser;
|
||||||
|
import joptsimple.OptionSet;
|
||||||
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
|
import net.md_5.bungee.command.ConsoleCommandSender;
|
||||||
|
|
||||||
|
public class BungeeCordLauncher
|
||||||
|
{
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception
|
||||||
|
{
|
||||||
|
Security.setProperty( "networkaddress.cache.ttl", "30" );
|
||||||
|
Security.setProperty( "networkaddress.cache.negative.ttl", "10" );
|
||||||
|
|
||||||
|
OptionParser parser = new OptionParser();
|
||||||
|
parser.allowsUnrecognizedOptions();
|
||||||
|
parser.acceptsAll( Arrays.asList( "v", "version" ) );
|
||||||
|
parser.acceptsAll( Arrays.asList( "noconsole" ) );
|
||||||
|
|
||||||
|
OptionSet options = parser.parse( args );
|
||||||
|
|
||||||
|
if ( options.has( "version" ) )
|
||||||
|
{
|
||||||
|
System.out.println( Bootstrap.class.getPackage().getImplementationVersion() );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( BungeeCord.class.getPackage().getSpecificationVersion() != null && System.getProperty( "IReallyKnowWhatIAmDoingISwear" ) == null )
|
||||||
|
{
|
||||||
|
Date buildDate = new SimpleDateFormat( "yyyyMMdd" ).parse( BungeeCord.class.getPackage().getSpecificationVersion() );
|
||||||
|
|
||||||
|
Calendar deadline = Calendar.getInstance();
|
||||||
|
deadline.add( Calendar.WEEK_OF_YEAR, -4 );
|
||||||
|
if ( buildDate.before( deadline.getTime() ) )
|
||||||
|
{
|
||||||
|
System.err.println( "*** Warning, this build is outdated ***" );
|
||||||
|
System.err.println( "*** Please download a new build from http://ci.md-5.net/job/BungeeCord ***" );
|
||||||
|
System.err.println( "*** You will get NO support regarding this build ***" );
|
||||||
|
System.err.println( "*** Server will start in 10 seconds ***" );
|
||||||
|
Thread.sleep( TimeUnit.SECONDS.toMillis( 10 ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BungeeCord bungee = new BungeeCord();
|
||||||
|
ProxyServer.setInstance( bungee );
|
||||||
|
bungee.getLogger().info( "Enabled BungeeCord version " + bungee.getVersion() );
|
||||||
|
bungee.start();
|
||||||
|
|
||||||
|
if ( !options.has( "noconsole" ) )
|
||||||
|
{
|
||||||
|
String line;
|
||||||
|
while ( bungee.isRunning && ( line = bungee.getConsoleReader().readLine( ">" ) ) != null )
|
||||||
|
{
|
||||||
|
if ( !bungee.getPluginManager().dispatchCommand( ConsoleCommandSender.getInstance(), line ) )
|
||||||
|
{
|
||||||
|
bungee.getConsole().sendMessage( ChatColor.RED + "Command not found" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
31
chat/nb-configuration.xml
Normal file
31
chat/nb-configuration.xml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project-shared-configuration>
|
||||||
|
<!--
|
||||||
|
This file contains additional configuration written by modules in the NetBeans IDE.
|
||||||
|
The configuration is intended to be shared among all the users of project and
|
||||||
|
therefore it is assumed to be part of version control checkout.
|
||||||
|
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
|
||||||
|
-->
|
||||||
|
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
|
||||||
|
<!--
|
||||||
|
Properties that influence various parts of the IDE, especially code formatting and the like.
|
||||||
|
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
|
||||||
|
That way multiple projects can share the same settings (useful for formatting rules for example).
|
||||||
|
Any value defined here will override the pom.xml file value but is only applicable to the current project.
|
||||||
|
-->
|
||||||
|
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
|
||||||
|
</properties>
|
||||||
|
</project-shared-configuration>
|
34
chat/pom.xml
Normal file
34
chat/pom.xml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
|
||||||
|
<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">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>net.md-5</groupId>
|
||||||
|
<artifactId>bungeecord-parent</artifactId>
|
||||||
|
<version>1.8-SNAPSHOT</version>
|
||||||
|
<relativePath>../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<groupId>net.md-5</groupId>
|
||||||
|
<artifactId>bungeecord-chat</artifactId>
|
||||||
|
<version>1.8-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>BungeeCord-Chat</name>
|
||||||
|
<description>Minecraft JSON chat API intended for use with BungeeCord</description>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>1.6</maven.compiler.source>
|
||||||
|
<maven.compiler.target>1.6</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.code.gson</groupId>
|
||||||
|
<artifactId>gson</artifactId>
|
||||||
|
<version>2.3.1</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
@@ -3,6 +3,7 @@ package net.md_5.bungee.api;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simplistic enumeration of all supported color values for chat.
|
* Simplistic enumeration of all supported color values for chat.
|
||||||
@@ -13,104 +14,105 @@ public enum ChatColor
|
|||||||
/**
|
/**
|
||||||
* Represents black.
|
* Represents black.
|
||||||
*/
|
*/
|
||||||
BLACK( '0' ),
|
BLACK( '0', "black" ),
|
||||||
/**
|
/**
|
||||||
* Represents dark blue.
|
* Represents dark blue.
|
||||||
*/
|
*/
|
||||||
DARK_BLUE( '1' ),
|
DARK_BLUE( '1', "dark_blue" ),
|
||||||
/**
|
/**
|
||||||
* Represents dark green.
|
* Represents dark green.
|
||||||
*/
|
*/
|
||||||
DARK_GREEN( '2' ),
|
DARK_GREEN( '2', "dark_green" ),
|
||||||
/**
|
/**
|
||||||
* Represents dark blue (aqua).
|
* Represents dark blue (aqua).
|
||||||
*/
|
*/
|
||||||
DARK_AQUA( '3' ),
|
DARK_AQUA( '3', "dark_aqua" ),
|
||||||
/**
|
/**
|
||||||
* Represents dark red.
|
* Represents dark red.
|
||||||
*/
|
*/
|
||||||
DARK_RED( '4' ),
|
DARK_RED( '4', "dark_red" ),
|
||||||
/**
|
/**
|
||||||
* Represents dark purple.
|
* Represents dark purple.
|
||||||
*/
|
*/
|
||||||
DARK_PURPLE( '5' ),
|
DARK_PURPLE( '5', "dark_purple" ),
|
||||||
/**
|
/**
|
||||||
* Represents gold.
|
* Represents gold.
|
||||||
*/
|
*/
|
||||||
GOLD( '6' ),
|
GOLD( '6', "gold" ),
|
||||||
/**
|
/**
|
||||||
* Represents gray.
|
* Represents gray.
|
||||||
*/
|
*/
|
||||||
GRAY( '7' ),
|
GRAY( '7', "gray" ),
|
||||||
/**
|
/**
|
||||||
* Represents dark gray.
|
* Represents dark gray.
|
||||||
*/
|
*/
|
||||||
DARK_GRAY( '8' ),
|
DARK_GRAY( '8', "dark_gray" ),
|
||||||
/**
|
/**
|
||||||
* Represents blue.
|
* Represents blue.
|
||||||
*/
|
*/
|
||||||
BLUE( '9' ),
|
BLUE( '9', "blue" ),
|
||||||
/**
|
/**
|
||||||
* Represents green.
|
* Represents green.
|
||||||
*/
|
*/
|
||||||
GREEN( 'a' ),
|
GREEN( 'a', "green" ),
|
||||||
/**
|
/**
|
||||||
* Represents aqua.
|
* Represents aqua.
|
||||||
*/
|
*/
|
||||||
AQUA( 'b' ),
|
AQUA( 'b', "aqua" ),
|
||||||
/**
|
/**
|
||||||
* Represents red.
|
* Represents red.
|
||||||
*/
|
*/
|
||||||
RED( 'c' ),
|
RED( 'c', "red" ),
|
||||||
/**
|
/**
|
||||||
* Represents light purple.
|
* Represents light purple.
|
||||||
*/
|
*/
|
||||||
LIGHT_PURPLE( 'd' ),
|
LIGHT_PURPLE( 'd', "light_purple" ),
|
||||||
/**
|
/**
|
||||||
* Represents yellow.
|
* Represents yellow.
|
||||||
*/
|
*/
|
||||||
YELLOW( 'e' ),
|
YELLOW( 'e', "yellow" ),
|
||||||
/**
|
/**
|
||||||
* Represents white.
|
* Represents white.
|
||||||
*/
|
*/
|
||||||
WHITE( 'f' ),
|
WHITE( 'f', "white" ),
|
||||||
/**
|
/**
|
||||||
* Represents magical characters that change around randomly.
|
* Represents magical characters that change around randomly.
|
||||||
*/
|
*/
|
||||||
MAGIC( 'k' ),
|
MAGIC( 'k', "obfuscated" ),
|
||||||
/**
|
/**
|
||||||
* Makes the text bold.
|
* Makes the text bold.
|
||||||
*/
|
*/
|
||||||
BOLD( 'l' ),
|
BOLD( 'l', "bold" ),
|
||||||
/**
|
/**
|
||||||
* Makes a line appear through the text.
|
* Makes a line appear through the text.
|
||||||
*/
|
*/
|
||||||
STRIKETHROUGH( 'm' ),
|
STRIKETHROUGH( 'm', "strikethrough" ),
|
||||||
/**
|
/**
|
||||||
* Makes the text appear underlined.
|
* Makes the text appear underlined.
|
||||||
*/
|
*/
|
||||||
UNDERLINE( 'n' ),
|
UNDERLINE( 'n', "underline" ),
|
||||||
/**
|
/**
|
||||||
* Makes the text italic.
|
* Makes the text italic.
|
||||||
*/
|
*/
|
||||||
ITALIC( 'o' ),
|
ITALIC( 'o', "italic" ),
|
||||||
/**
|
/**
|
||||||
* Resets all previous chat colors or formats.
|
* Resets all previous chat colors or formats.
|
||||||
*/
|
*/
|
||||||
RESET( 'r' );
|
RESET( 'r', "reset" );
|
||||||
/**
|
/**
|
||||||
* The special character which prefixes all chat colour codes. Use this if
|
* The special character which prefixes all chat colour codes. Use this if
|
||||||
* you need to dynamically convert colour codes from your custom format.
|
* you need to dynamically convert colour codes from your custom format.
|
||||||
*/
|
*/
|
||||||
public static final char COLOR_CHAR = '\u00A7';
|
public static final char COLOR_CHAR = '\u00A7';
|
||||||
|
public static final String ALL_CODES = "0123456789AaBbCcDdEeFfKkLlMmNnOoRr";
|
||||||
/**
|
/**
|
||||||
* Pattern to remove all colour codes.
|
* Pattern to remove all colour codes.
|
||||||
*/
|
*/
|
||||||
private static final Pattern STRIP_COLOR_PATTERN = Pattern.compile( "(?i)" + String.valueOf( COLOR_CHAR ) + "[0-9A-FK-OR]" );
|
public static final Pattern STRIP_COLOR_PATTERN = Pattern.compile( "(?i)" + String.valueOf( COLOR_CHAR ) + "[0-9A-FK-OR]" );
|
||||||
/**
|
/**
|
||||||
* Colour instances keyed by their active character.
|
* Colour instances keyed by their active character.
|
||||||
*/
|
*/
|
||||||
private static final Map<Character, ChatColor> BY_CHAR = new HashMap<>();
|
private static final Map<Character, ChatColor> BY_CHAR = new HashMap<Character, ChatColor>();
|
||||||
/**
|
/**
|
||||||
* The code appended to {@link #COLOR_CHAR} to make usable colour.
|
* The code appended to {@link #COLOR_CHAR} to make usable colour.
|
||||||
*/
|
*/
|
||||||
@@ -119,6 +121,8 @@ public enum ChatColor
|
|||||||
* This colour's colour char prefixed by the {@link #COLOR_CHAR}.
|
* This colour's colour char prefixed by the {@link #COLOR_CHAR}.
|
||||||
*/
|
*/
|
||||||
private final String toString;
|
private final String toString;
|
||||||
|
@Getter
|
||||||
|
private final String name;
|
||||||
|
|
||||||
static
|
static
|
||||||
{
|
{
|
||||||
@@ -128,9 +132,10 @@ public enum ChatColor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ChatColor(char code)
|
private ChatColor(char code, String name)
|
||||||
{
|
{
|
||||||
this.code = code;
|
this.code = code;
|
||||||
|
this.name = name;
|
||||||
this.toString = new String( new char[]
|
this.toString = new String( new char[]
|
||||||
{
|
{
|
||||||
COLOR_CHAR, code
|
COLOR_CHAR, code
|
||||||
@@ -164,7 +169,7 @@ public enum ChatColor
|
|||||||
char[] b = textToTranslate.toCharArray();
|
char[] b = textToTranslate.toCharArray();
|
||||||
for ( int i = 0; i < b.length - 1; i++ )
|
for ( int i = 0; i < b.length - 1; i++ )
|
||||||
{
|
{
|
||||||
if ( b[i] == altColorChar && "0123456789AaBbCcDdEeFfKkLlMmNnOoRr".indexOf( b[i + 1] ) > -1 )
|
if ( b[i] == altColorChar && ALL_CODES.indexOf( b[i + 1] ) > -1 )
|
||||||
{
|
{
|
||||||
b[i] = ChatColor.COLOR_CHAR;
|
b[i] = ChatColor.COLOR_CHAR;
|
||||||
b[i + 1] = Character.toLowerCase( b[i + 1] );
|
b[i + 1] = Character.toLowerCase( b[i + 1] );
|
12
chat/src/main/java/net/md_5/bungee/api/ChatMessageType.java
Normal file
12
chat/src/main/java/net/md_5/bungee/api/ChatMessageType.java
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package net.md_5.bungee.api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the position on the screen where a message will appear.
|
||||||
|
*/
|
||||||
|
public enum ChatMessageType
|
||||||
|
{
|
||||||
|
|
||||||
|
CHAT,
|
||||||
|
SYSTEM,
|
||||||
|
ACTION_BAR
|
||||||
|
}
|
398
chat/src/main/java/net/md_5/bungee/api/chat/BaseComponent.java
Normal file
398
chat/src/main/java/net/md_5/bungee/api/chat/BaseComponent.java
Normal file
@@ -0,0 +1,398 @@
|
|||||||
|
package net.md_5.bungee.api.chat;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@ToString(exclude = "parent")
|
||||||
|
@NoArgsConstructor
|
||||||
|
public abstract class BaseComponent
|
||||||
|
{
|
||||||
|
|
||||||
|
@Setter(AccessLevel.NONE)
|
||||||
|
BaseComponent parent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color of this component and any child components (unless overridden)
|
||||||
|
*/
|
||||||
|
private ChatColor color;
|
||||||
|
/**
|
||||||
|
* Whether this component and any child components (unless overridden) is
|
||||||
|
* bold
|
||||||
|
*/
|
||||||
|
private Boolean bold;
|
||||||
|
/**
|
||||||
|
* Whether this component and any child components (unless overridden) is
|
||||||
|
* italic
|
||||||
|
*/
|
||||||
|
private Boolean italic;
|
||||||
|
/**
|
||||||
|
* Whether this component and any child components (unless overridden) is
|
||||||
|
* underlined
|
||||||
|
*/
|
||||||
|
private Boolean underlined;
|
||||||
|
/**
|
||||||
|
* Whether this component and any child components (unless overridden) is
|
||||||
|
* strikethrough
|
||||||
|
*/
|
||||||
|
private Boolean strikethrough;
|
||||||
|
/**
|
||||||
|
* Whether this component and any child components (unless overridden) is
|
||||||
|
* obfuscated
|
||||||
|
*/
|
||||||
|
private Boolean obfuscated;
|
||||||
|
/**
|
||||||
|
* The text to insert into the chat when this component (and child
|
||||||
|
* components) are clicked while pressing the shift key
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
private String insertion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appended components that inherit this component's formatting and events
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
private List<BaseComponent> extra;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The action to preform when this component (and child components) are
|
||||||
|
* clicked
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
private ClickEvent clickEvent;
|
||||||
|
/**
|
||||||
|
* The action to preform when this component (and child components) are
|
||||||
|
* hovered over
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
private HoverEvent hoverEvent;
|
||||||
|
|
||||||
|
BaseComponent(BaseComponent old)
|
||||||
|
{
|
||||||
|
setColor( old.getColorRaw() );
|
||||||
|
setBold( old.isBoldRaw() );
|
||||||
|
setItalic( old.isItalicRaw() );
|
||||||
|
setUnderlined( old.isUnderlinedRaw() );
|
||||||
|
setStrikethrough( old.isStrikethroughRaw() );
|
||||||
|
setObfuscated( old.isObfuscatedRaw() );
|
||||||
|
setInsertion( old.getInsertion() );
|
||||||
|
setClickEvent( old.getClickEvent() );
|
||||||
|
setHoverEvent( old.getHoverEvent() );
|
||||||
|
if ( old.getExtra() != null )
|
||||||
|
{
|
||||||
|
for ( BaseComponent component : old.getExtra() )
|
||||||
|
{
|
||||||
|
addExtra( component.duplicate() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clones the BaseComponent and returns the clone.
|
||||||
|
*
|
||||||
|
* @return The duplicate of this BaseComponent
|
||||||
|
*/
|
||||||
|
public abstract BaseComponent duplicate();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the components to a string that uses the old formatting codes
|
||||||
|
* ({@link net.md_5.bungee.api.ChatColor#COLOR_CHAR}
|
||||||
|
*
|
||||||
|
* @param components the components to convert
|
||||||
|
* @return the string in the old format
|
||||||
|
*/
|
||||||
|
public static String toLegacyText(BaseComponent... components)
|
||||||
|
{
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
for ( BaseComponent msg : components )
|
||||||
|
{
|
||||||
|
builder.append( msg.toLegacyText() );
|
||||||
|
}
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the components into a string without any formatting
|
||||||
|
*
|
||||||
|
* @param components the components to convert
|
||||||
|
* @return the string as plain text
|
||||||
|
*/
|
||||||
|
public static String toPlainText(BaseComponent... components)
|
||||||
|
{
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
for ( BaseComponent msg : components )
|
||||||
|
{
|
||||||
|
builder.append( msg.toPlainText() );
|
||||||
|
}
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the color of this component. This uses the parent's color if this
|
||||||
|
* component doesn't have one. {@link net.md_5.bungee.api.ChatColor#WHITE}
|
||||||
|
* is returned if no color is found.
|
||||||
|
*
|
||||||
|
* @return the color of this component
|
||||||
|
*/
|
||||||
|
public ChatColor getColor()
|
||||||
|
{
|
||||||
|
if ( color == null )
|
||||||
|
{
|
||||||
|
if ( parent == null )
|
||||||
|
{
|
||||||
|
return ChatColor.WHITE;
|
||||||
|
}
|
||||||
|
return parent.getColor();
|
||||||
|
}
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the color of this component without checking the parents color.
|
||||||
|
* May return null
|
||||||
|
*
|
||||||
|
* @return the color of this component
|
||||||
|
*/
|
||||||
|
public ChatColor getColorRaw()
|
||||||
|
{
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether this component is bold. This uses the parent's setting if
|
||||||
|
* this component hasn't been set. false is returned if none of the parent
|
||||||
|
* chain has been set.
|
||||||
|
*
|
||||||
|
* @return whether the component is bold
|
||||||
|
*/
|
||||||
|
public boolean isBold()
|
||||||
|
{
|
||||||
|
if ( bold == null )
|
||||||
|
{
|
||||||
|
return parent != null && parent.isBold();
|
||||||
|
}
|
||||||
|
return bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether this component is bold without checking the parents
|
||||||
|
* setting. May return null
|
||||||
|
*
|
||||||
|
* @return whether the component is bold
|
||||||
|
*/
|
||||||
|
public Boolean isBoldRaw()
|
||||||
|
{
|
||||||
|
return bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether this component is italic. This uses the parent's setting
|
||||||
|
* if this component hasn't been set. false is returned if none of the
|
||||||
|
* parent chain has been set.
|
||||||
|
*
|
||||||
|
* @return whether the component is italic
|
||||||
|
*/
|
||||||
|
public boolean isItalic()
|
||||||
|
{
|
||||||
|
if ( italic == null )
|
||||||
|
{
|
||||||
|
return parent != null && parent.isItalic();
|
||||||
|
}
|
||||||
|
return italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether this component is italic without checking the parents
|
||||||
|
* setting. May return null
|
||||||
|
*
|
||||||
|
* @return whether the component is italic
|
||||||
|
*/
|
||||||
|
public Boolean isItalicRaw()
|
||||||
|
{
|
||||||
|
return italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether this component is underlined. This uses the parent's
|
||||||
|
* setting if this component hasn't been set. false is returned if none of
|
||||||
|
* the parent chain has been set.
|
||||||
|
*
|
||||||
|
* @return whether the component is underlined
|
||||||
|
*/
|
||||||
|
public boolean isUnderlined()
|
||||||
|
{
|
||||||
|
if ( underlined == null )
|
||||||
|
{
|
||||||
|
return parent != null && parent.isUnderlined();
|
||||||
|
}
|
||||||
|
return underlined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether this component is underlined without checking the parents
|
||||||
|
* setting. May return null
|
||||||
|
*
|
||||||
|
* @return whether the component is underlined
|
||||||
|
*/
|
||||||
|
public Boolean isUnderlinedRaw()
|
||||||
|
{
|
||||||
|
return underlined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether this component is strikethrough. This uses the parent's
|
||||||
|
* setting if this component hasn't been set. false is returned if none of
|
||||||
|
* the parent chain has been set.
|
||||||
|
*
|
||||||
|
* @return whether the component is strikethrough
|
||||||
|
*/
|
||||||
|
public boolean isStrikethrough()
|
||||||
|
{
|
||||||
|
if ( strikethrough == null )
|
||||||
|
{
|
||||||
|
return parent != null && parent.isStrikethrough();
|
||||||
|
}
|
||||||
|
return strikethrough;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether this component is strikethrough without checking the
|
||||||
|
* parents setting. May return null
|
||||||
|
*
|
||||||
|
* @return whether the component is strikethrough
|
||||||
|
*/
|
||||||
|
public Boolean isStrikethroughRaw()
|
||||||
|
{
|
||||||
|
return strikethrough;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether this component is obfuscated. This uses the parent's
|
||||||
|
* setting if this component hasn't been set. false is returned if none of
|
||||||
|
* the parent chain has been set.
|
||||||
|
*
|
||||||
|
* @return whether the component is obfuscated
|
||||||
|
*/
|
||||||
|
public boolean isObfuscated()
|
||||||
|
{
|
||||||
|
if ( obfuscated == null )
|
||||||
|
{
|
||||||
|
return parent != null && parent.isObfuscated();
|
||||||
|
}
|
||||||
|
return obfuscated;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether this component is obfuscated without checking the parents
|
||||||
|
* setting. May return null
|
||||||
|
*
|
||||||
|
* @return whether the component is obfuscated
|
||||||
|
*/
|
||||||
|
public Boolean isObfuscatedRaw()
|
||||||
|
{
|
||||||
|
return obfuscated;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExtra(List<BaseComponent> components)
|
||||||
|
{
|
||||||
|
for ( BaseComponent component : components )
|
||||||
|
{
|
||||||
|
component.parent = this;
|
||||||
|
}
|
||||||
|
extra = components;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends a text element to the component. The text will inherit this
|
||||||
|
* component's formatting
|
||||||
|
*
|
||||||
|
* @param text the text to append
|
||||||
|
*/
|
||||||
|
public void addExtra(String text)
|
||||||
|
{
|
||||||
|
addExtra( new TextComponent( text ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends a component to the component. The text will inherit this
|
||||||
|
* component's formatting
|
||||||
|
*
|
||||||
|
* @param component the component to append
|
||||||
|
*/
|
||||||
|
public void addExtra(BaseComponent component)
|
||||||
|
{
|
||||||
|
if ( extra == null )
|
||||||
|
{
|
||||||
|
extra = new ArrayList<BaseComponent>();
|
||||||
|
}
|
||||||
|
component.parent = this;
|
||||||
|
extra.add( component );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the component has any formatting or events applied to it
|
||||||
|
*
|
||||||
|
* @return Whether any formatting or events are applied
|
||||||
|
*/
|
||||||
|
public boolean hasFormatting()
|
||||||
|
{
|
||||||
|
return color != null || bold != null
|
||||||
|
|| italic != null || underlined != null
|
||||||
|
|| strikethrough != null || obfuscated != null
|
||||||
|
|| hoverEvent != null || clickEvent != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the component into a string without any formatting
|
||||||
|
*
|
||||||
|
* @return the string as plain text
|
||||||
|
*/
|
||||||
|
public String toPlainText()
|
||||||
|
{
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
toPlainText( builder );
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void toPlainText(StringBuilder builder)
|
||||||
|
{
|
||||||
|
if ( extra != null )
|
||||||
|
{
|
||||||
|
for ( BaseComponent e : extra )
|
||||||
|
{
|
||||||
|
e.toPlainText( builder );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the component to a string that uses the old formatting codes
|
||||||
|
* ({@link net.md_5.bungee.api.ChatColor#COLOR_CHAR}
|
||||||
|
*
|
||||||
|
* @return the string in the old format
|
||||||
|
*/
|
||||||
|
public String toLegacyText()
|
||||||
|
{
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
toLegacyText( builder );
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void toLegacyText(StringBuilder builder)
|
||||||
|
{
|
||||||
|
if ( extra != null )
|
||||||
|
{
|
||||||
|
for ( BaseComponent e : extra )
|
||||||
|
{
|
||||||
|
e.toLegacyText( builder );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
55
chat/src/main/java/net/md_5/bungee/api/chat/ClickEvent.java
Normal file
55
chat/src/main/java/net/md_5/bungee/api/chat/ClickEvent.java
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
package net.md_5.bungee.api.chat;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
import net.md_5.bungee.api.chat.ClickEvent.Action;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public final class ClickEvent
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of action to perform on click
|
||||||
|
*/
|
||||||
|
private final Action action;
|
||||||
|
/**
|
||||||
|
* Depends on action
|
||||||
|
*
|
||||||
|
* @see Action
|
||||||
|
*/
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
public enum Action
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a url at the path given by
|
||||||
|
* {@link net.md_5.bungee.api.chat.ClickEvent#value}
|
||||||
|
*/
|
||||||
|
OPEN_URL,
|
||||||
|
/**
|
||||||
|
* Open a file at the path given by
|
||||||
|
* {@link net.md_5.bungee.api.chat.ClickEvent#value}
|
||||||
|
*/
|
||||||
|
OPEN_FILE,
|
||||||
|
/**
|
||||||
|
* Run the command given by
|
||||||
|
* {@link net.md_5.bungee.api.chat.ClickEvent#value}
|
||||||
|
*/
|
||||||
|
RUN_COMMAND,
|
||||||
|
/**
|
||||||
|
* Inserts the string given by
|
||||||
|
* {@link net.md_5.bungee.api.chat.ClickEvent#value} into the players
|
||||||
|
* text box
|
||||||
|
*/
|
||||||
|
SUGGEST_COMMAND,
|
||||||
|
/**
|
||||||
|
* Change to the page number given by
|
||||||
|
* {@link net.md_5.bungee.api.chat.ClickEvent#value} in a book
|
||||||
|
*/
|
||||||
|
CHANGE_PAGE
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,269 @@
|
|||||||
|
package net.md_5.bungee.api.chat;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* ComponentBuilder simplifies creating basic messages by allowing the use of a
|
||||||
|
* chainable builder.
|
||||||
|
* </p>
|
||||||
|
* <pre>
|
||||||
|
* new ComponentBuilder("Hello ").color(ChatColor.RED).
|
||||||
|
* append("World").color(ChatColor.BLUE). append("!").bold(true).create();
|
||||||
|
* </pre>
|
||||||
|
* <p>
|
||||||
|
* All methods (excluding {@link #append(String)} and {@link #create()} work on
|
||||||
|
* the last part appended to the builder, so in the example above "Hello " would
|
||||||
|
* be {@link net.md_5.bungee.api.ChatColor#RED} and "World" would be
|
||||||
|
* {@link net.md_5.bungee.api.ChatColor#BLUE} but "!" would be bold and
|
||||||
|
* {@link net.md_5.bungee.api.ChatColor#BLUE} because append copies the previous
|
||||||
|
* part's formatting
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public class ComponentBuilder
|
||||||
|
{
|
||||||
|
|
||||||
|
private TextComponent current;
|
||||||
|
private final List<BaseComponent> parts = new ArrayList<BaseComponent>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a ComponentBuilder from the other given ComponentBuilder to clone
|
||||||
|
* it.
|
||||||
|
*
|
||||||
|
* @param original the original for the new ComponentBuilder.
|
||||||
|
*/
|
||||||
|
public ComponentBuilder(ComponentBuilder original)
|
||||||
|
{
|
||||||
|
current = new TextComponent( original.current );
|
||||||
|
for ( BaseComponent baseComponent : original.parts )
|
||||||
|
{
|
||||||
|
parts.add( baseComponent.duplicate() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a ComponentBuilder with the given text as the first part.
|
||||||
|
*
|
||||||
|
* @param text the first text element
|
||||||
|
*/
|
||||||
|
public ComponentBuilder(String text)
|
||||||
|
{
|
||||||
|
current = new TextComponent( text );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends the text to the builder and makes it the current target for
|
||||||
|
* formatting. The text will have all the formatting from the previous part.
|
||||||
|
*
|
||||||
|
* @param text the text to append
|
||||||
|
* @return this ComponentBuilder for chaining
|
||||||
|
*/
|
||||||
|
public ComponentBuilder append(String text)
|
||||||
|
{
|
||||||
|
return append( text, FormatRetention.ALL );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Appends the text to the builder and makes it the current target for
|
||||||
|
* formatting. You can specify the amount of formatting retained.
|
||||||
|
*
|
||||||
|
* @param text the text to append
|
||||||
|
* @param retention the formatting to retain
|
||||||
|
* @return this ComponentBuilder for chaining
|
||||||
|
*/
|
||||||
|
public ComponentBuilder append(String text, FormatRetention retention)
|
||||||
|
{
|
||||||
|
parts.add( current );
|
||||||
|
|
||||||
|
current = new TextComponent( current );
|
||||||
|
current.setText( text );
|
||||||
|
retain( retention );
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the color of the current part.
|
||||||
|
*
|
||||||
|
* @param color the new color
|
||||||
|
* @return this ComponentBuilder for chaining
|
||||||
|
*/
|
||||||
|
public ComponentBuilder color(ChatColor color)
|
||||||
|
{
|
||||||
|
current.setColor( color );
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether the current part is bold.
|
||||||
|
*
|
||||||
|
* @param bold whether this part is bold
|
||||||
|
* @return this ComponentBuilder for chaining
|
||||||
|
*/
|
||||||
|
public ComponentBuilder bold(boolean bold)
|
||||||
|
{
|
||||||
|
current.setBold( bold );
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether the current part is italic.
|
||||||
|
*
|
||||||
|
* @param italic whether this part is italic
|
||||||
|
* @return this ComponentBuilder for chaining
|
||||||
|
*/
|
||||||
|
public ComponentBuilder italic(boolean italic)
|
||||||
|
{
|
||||||
|
current.setItalic( italic );
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether the current part is underlined.
|
||||||
|
*
|
||||||
|
* @param underlined whether this part is underlined
|
||||||
|
* @return this ComponentBuilder for chaining
|
||||||
|
*/
|
||||||
|
public ComponentBuilder underlined(boolean underlined)
|
||||||
|
{
|
||||||
|
current.setUnderlined( underlined );
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether the current part is strikethrough.
|
||||||
|
*
|
||||||
|
* @param strikethrough whether this part is strikethrough
|
||||||
|
* @return this ComponentBuilder for chaining
|
||||||
|
*/
|
||||||
|
public ComponentBuilder strikethrough(boolean strikethrough)
|
||||||
|
{
|
||||||
|
current.setStrikethrough( strikethrough );
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether the current part is obfuscated.
|
||||||
|
*
|
||||||
|
* @param obfuscated whether this part is obfuscated
|
||||||
|
* @return this ComponentBuilder for chaining
|
||||||
|
*/
|
||||||
|
public ComponentBuilder obfuscated(boolean obfuscated)
|
||||||
|
{
|
||||||
|
current.setObfuscated( obfuscated );
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the insertion text for the current part.
|
||||||
|
*
|
||||||
|
* @param insertion the insertion text
|
||||||
|
* @return this ComponentBuilder for chaining
|
||||||
|
*/
|
||||||
|
public ComponentBuilder insertion(String insertion)
|
||||||
|
{
|
||||||
|
current.setInsertion( insertion );
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the click event for the current part.
|
||||||
|
*
|
||||||
|
* @param clickEvent the click event
|
||||||
|
* @return this ComponentBuilder for chaining
|
||||||
|
*/
|
||||||
|
public ComponentBuilder event(ClickEvent clickEvent)
|
||||||
|
{
|
||||||
|
current.setClickEvent( clickEvent );
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the hover event for the current part.
|
||||||
|
*
|
||||||
|
* @param hoverEvent the hover event
|
||||||
|
* @return this ComponentBuilder for chaining
|
||||||
|
*/
|
||||||
|
public ComponentBuilder event(HoverEvent hoverEvent)
|
||||||
|
{
|
||||||
|
current.setHoverEvent( hoverEvent );
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the current part back to normal settings. Only text is kept.
|
||||||
|
*
|
||||||
|
* @return this ComponentBuilder for chaining
|
||||||
|
*/
|
||||||
|
public ComponentBuilder reset()
|
||||||
|
{
|
||||||
|
return retain( FormatRetention.NONE );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retains only the specified formatting. Text is not modified.
|
||||||
|
*
|
||||||
|
* @param retention the formatting to retain
|
||||||
|
* @return this ComponentBuilder for chaining
|
||||||
|
*/
|
||||||
|
public ComponentBuilder retain(FormatRetention retention)
|
||||||
|
{
|
||||||
|
BaseComponent previous = current;
|
||||||
|
|
||||||
|
switch ( retention )
|
||||||
|
{
|
||||||
|
case NONE:
|
||||||
|
current = new TextComponent( current.getText() );
|
||||||
|
break;
|
||||||
|
case ALL:
|
||||||
|
// No changes are required
|
||||||
|
break;
|
||||||
|
case EVENTS:
|
||||||
|
current = new TextComponent( current.getText() );
|
||||||
|
current.setInsertion( previous.getInsertion() );
|
||||||
|
current.setClickEvent( previous.getClickEvent() );
|
||||||
|
current.setHoverEvent( previous.getHoverEvent() );
|
||||||
|
break;
|
||||||
|
case FORMATTING:
|
||||||
|
current.setClickEvent( null );
|
||||||
|
current.setHoverEvent( null );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the components needed to display the message created by this
|
||||||
|
* builder.
|
||||||
|
*
|
||||||
|
* @return the created components
|
||||||
|
*/
|
||||||
|
public BaseComponent[] create()
|
||||||
|
{
|
||||||
|
parts.add( current );
|
||||||
|
return parts.toArray( new BaseComponent[ parts.size() ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static enum FormatRetention
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify that we do not want to retain anything from the previous component.
|
||||||
|
*/
|
||||||
|
NONE,
|
||||||
|
/**
|
||||||
|
* Specify that we want the formatting retained from the previous component.
|
||||||
|
*/
|
||||||
|
FORMATTING,
|
||||||
|
/**
|
||||||
|
* Specify that we want the events retained from the previous component.
|
||||||
|
*/
|
||||||
|
EVENTS,
|
||||||
|
/**
|
||||||
|
* Specify that we want to retain everything from the previous component.
|
||||||
|
*/
|
||||||
|
ALL
|
||||||
|
}
|
||||||
|
}
|
24
chat/src/main/java/net/md_5/bungee/api/chat/HoverEvent.java
Normal file
24
chat/src/main/java/net/md_5/bungee/api/chat/HoverEvent.java
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package net.md_5.bungee.api.chat;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
final public class HoverEvent
|
||||||
|
{
|
||||||
|
|
||||||
|
private final Action action;
|
||||||
|
private final BaseComponent[] value;
|
||||||
|
|
||||||
|
public enum Action
|
||||||
|
{
|
||||||
|
|
||||||
|
SHOW_TEXT,
|
||||||
|
SHOW_ACHIEVEMENT,
|
||||||
|
SHOW_ITEM,
|
||||||
|
SHOW_ENTITY
|
||||||
|
}
|
||||||
|
}
|
213
chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java
Normal file
213
chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
package net.md_5.bungee.api.chat;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class TextComponent extends BaseComponent
|
||||||
|
{
|
||||||
|
|
||||||
|
private static final Pattern url = Pattern.compile( "^(?:(https?)://)?([-\\w_\\.]{2,}\\.[a-z]{2,4})(/\\S*)?$" );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the old formatting system that used
|
||||||
|
* {@link net.md_5.bungee.api.ChatColor#COLOR_CHAR} into the new json based
|
||||||
|
* system.
|
||||||
|
*
|
||||||
|
* @param message the text to convert
|
||||||
|
* @return the components needed to print the message to the client
|
||||||
|
*/
|
||||||
|
public static BaseComponent[] fromLegacyText(String message)
|
||||||
|
{
|
||||||
|
ArrayList<BaseComponent> components = new ArrayList<BaseComponent>();
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
TextComponent component = new TextComponent();
|
||||||
|
Matcher matcher = url.matcher( message );
|
||||||
|
|
||||||
|
for ( int i = 0; i < message.length(); i++ )
|
||||||
|
{
|
||||||
|
char c = message.charAt( i );
|
||||||
|
if ( c == ChatColor.COLOR_CHAR )
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
c = message.charAt( i );
|
||||||
|
if ( c >= 'A' && c <= 'Z' )
|
||||||
|
{
|
||||||
|
c += 32;
|
||||||
|
}
|
||||||
|
ChatColor format = ChatColor.getByChar( c );
|
||||||
|
if ( format == null )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ( builder.length() > 0 )
|
||||||
|
{
|
||||||
|
TextComponent old = component;
|
||||||
|
component = new TextComponent( old );
|
||||||
|
old.setText( builder.toString() );
|
||||||
|
builder = new StringBuilder();
|
||||||
|
components.add( old );
|
||||||
|
}
|
||||||
|
switch ( format )
|
||||||
|
{
|
||||||
|
case BOLD:
|
||||||
|
component.setBold( true );
|
||||||
|
break;
|
||||||
|
case ITALIC:
|
||||||
|
component.setItalic( true );
|
||||||
|
break;
|
||||||
|
case UNDERLINE:
|
||||||
|
component.setUnderlined( true );
|
||||||
|
break;
|
||||||
|
case STRIKETHROUGH:
|
||||||
|
component.setStrikethrough( true );
|
||||||
|
break;
|
||||||
|
case MAGIC:
|
||||||
|
component.setObfuscated( true );
|
||||||
|
break;
|
||||||
|
case RESET:
|
||||||
|
format = ChatColor.WHITE;
|
||||||
|
default:
|
||||||
|
component = new TextComponent();
|
||||||
|
component.setColor( format );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int pos = message.indexOf( ' ', i );
|
||||||
|
if ( pos == -1 )
|
||||||
|
{
|
||||||
|
pos = message.length();
|
||||||
|
}
|
||||||
|
if ( matcher.region( i, pos ).find() )
|
||||||
|
{ //Web link handling
|
||||||
|
|
||||||
|
if ( builder.length() > 0 )
|
||||||
|
{
|
||||||
|
TextComponent old = component;
|
||||||
|
component = new TextComponent( old );
|
||||||
|
old.setText( builder.toString() );
|
||||||
|
builder = new StringBuilder();
|
||||||
|
components.add( old );
|
||||||
|
}
|
||||||
|
|
||||||
|
TextComponent old = component;
|
||||||
|
component = new TextComponent( old );
|
||||||
|
String urlString = message.substring( i, pos );
|
||||||
|
component.setText( urlString );
|
||||||
|
component.setClickEvent( new ClickEvent( ClickEvent.Action.OPEN_URL,
|
||||||
|
urlString.startsWith( "http" ) ? urlString : "http://" + urlString ) );
|
||||||
|
components.add( component );
|
||||||
|
i += pos - i - 1;
|
||||||
|
component = old;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
builder.append( c );
|
||||||
|
}
|
||||||
|
if ( builder.length() > 0 )
|
||||||
|
{
|
||||||
|
component.setText( builder.toString() );
|
||||||
|
components.add( component );
|
||||||
|
}
|
||||||
|
|
||||||
|
// The client will crash if the array is empty
|
||||||
|
if ( components.isEmpty() )
|
||||||
|
{
|
||||||
|
components.add( new TextComponent( "" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return components.toArray( new BaseComponent[ components.size() ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The text of the component that will be displayed to the client
|
||||||
|
*/
|
||||||
|
private String text;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a TextComponent with formatting and text from the passed
|
||||||
|
* component
|
||||||
|
*
|
||||||
|
* @param textComponent the component to copy from
|
||||||
|
*/
|
||||||
|
public TextComponent(TextComponent textComponent)
|
||||||
|
{
|
||||||
|
super( textComponent );
|
||||||
|
setText( textComponent.getText() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a TextComponent with blank text and the extras set to the passed
|
||||||
|
* array
|
||||||
|
*
|
||||||
|
* @param extras the extras to set
|
||||||
|
*/
|
||||||
|
public TextComponent(BaseComponent... extras)
|
||||||
|
{
|
||||||
|
setText( "" );
|
||||||
|
setExtra( new ArrayList<BaseComponent>( Arrays.asList( extras ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a duplicate of this TextComponent.
|
||||||
|
*
|
||||||
|
* @return the duplicate of this TextComponent.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public BaseComponent duplicate()
|
||||||
|
{
|
||||||
|
return new TextComponent( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void toPlainText(StringBuilder builder)
|
||||||
|
{
|
||||||
|
builder.append( text );
|
||||||
|
super.toPlainText( builder );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void toLegacyText(StringBuilder builder)
|
||||||
|
{
|
||||||
|
builder.append( getColor() );
|
||||||
|
if ( isBold() )
|
||||||
|
{
|
||||||
|
builder.append( ChatColor.BOLD );
|
||||||
|
}
|
||||||
|
if ( isItalic() )
|
||||||
|
{
|
||||||
|
builder.append( ChatColor.ITALIC );
|
||||||
|
}
|
||||||
|
if ( isUnderlined() )
|
||||||
|
{
|
||||||
|
builder.append( ChatColor.UNDERLINE );
|
||||||
|
}
|
||||||
|
if ( isStrikethrough() )
|
||||||
|
{
|
||||||
|
builder.append( ChatColor.STRIKETHROUGH );
|
||||||
|
}
|
||||||
|
if ( isObfuscated() )
|
||||||
|
{
|
||||||
|
builder.append( ChatColor.MAGIC );
|
||||||
|
}
|
||||||
|
builder.append( text );
|
||||||
|
super.toLegacyText( builder );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return String.format( "TextComponent{text=%s, %s}", text, super.toString() );
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,250 @@
|
|||||||
|
package net.md_5.bungee.api.chat;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.MissingResourceException;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class TranslatableComponent extends BaseComponent
|
||||||
|
{
|
||||||
|
|
||||||
|
private final ResourceBundle locales = ResourceBundle.getBundle( "mojang-translations/en_US" );
|
||||||
|
private final Pattern format = Pattern.compile( "%(?:(\\d+)\\$)?([A-Za-z%]|$)" );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The key into the Minecraft locale files to use for the translation. The
|
||||||
|
* text depends on the client's locale setting. The console is always en_US
|
||||||
|
*/
|
||||||
|
private String translate;
|
||||||
|
/**
|
||||||
|
* The components to substitute into the translation
|
||||||
|
*/
|
||||||
|
private List<BaseComponent> with;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a translatable component from the original to clone it.
|
||||||
|
*
|
||||||
|
* @param original the original for the new translatable component.
|
||||||
|
*/
|
||||||
|
public TranslatableComponent(TranslatableComponent original)
|
||||||
|
{
|
||||||
|
super( original );
|
||||||
|
setTranslate( original.getTranslate() );
|
||||||
|
|
||||||
|
if ( original.getWith() != null )
|
||||||
|
{
|
||||||
|
List<BaseComponent> temp = new ArrayList<BaseComponent>();
|
||||||
|
for ( BaseComponent baseComponent : original.getWith() )
|
||||||
|
{
|
||||||
|
temp.add( baseComponent.duplicate() );
|
||||||
|
}
|
||||||
|
setWith( temp );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a translatable component with the passed substitutions
|
||||||
|
*
|
||||||
|
* @see #translate
|
||||||
|
* @see #setWith(java.util.List)
|
||||||
|
* @param translate the translation key
|
||||||
|
* @param with the {@link java.lang.String}s and
|
||||||
|
* {@link net.md_5.bungee.api.chat.BaseComponent}s to use into the
|
||||||
|
* translation
|
||||||
|
*/
|
||||||
|
public TranslatableComponent(String translate, Object... with)
|
||||||
|
{
|
||||||
|
setTranslate( translate );
|
||||||
|
List<BaseComponent> temp = new ArrayList<BaseComponent>();
|
||||||
|
for ( Object w : with )
|
||||||
|
{
|
||||||
|
if ( w instanceof String )
|
||||||
|
{
|
||||||
|
temp.add( new TextComponent( (String) w ) );
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
temp.add( (BaseComponent) w );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setWith( temp );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a duplicate of this TranslatableComponent.
|
||||||
|
*
|
||||||
|
* @return the duplicate of this TranslatableComponent.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public BaseComponent duplicate()
|
||||||
|
{
|
||||||
|
return new TranslatableComponent( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the translation substitutions to be used in this component. Removes
|
||||||
|
* any previously set substitutions
|
||||||
|
*
|
||||||
|
* @param components the components to substitute
|
||||||
|
*/
|
||||||
|
public void setWith(List<BaseComponent> components)
|
||||||
|
{
|
||||||
|
for ( BaseComponent component : components )
|
||||||
|
{
|
||||||
|
component.parent = this;
|
||||||
|
}
|
||||||
|
with = components;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a text substitution to the component. The text will inherit this
|
||||||
|
* component's formatting
|
||||||
|
*
|
||||||
|
* @param text the text to substitute
|
||||||
|
*/
|
||||||
|
public void addWith(String text)
|
||||||
|
{
|
||||||
|
addWith( new TextComponent( text ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a component substitution to the component. The text will inherit
|
||||||
|
* this component's formatting
|
||||||
|
*
|
||||||
|
* @param component the component to substitute
|
||||||
|
*/
|
||||||
|
public void addWith(BaseComponent component)
|
||||||
|
{
|
||||||
|
if ( with == null )
|
||||||
|
{
|
||||||
|
with = new ArrayList<BaseComponent>();
|
||||||
|
}
|
||||||
|
component.parent = this;
|
||||||
|
with.add( component );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void toPlainText(StringBuilder builder)
|
||||||
|
{
|
||||||
|
String trans;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
trans = locales.getString( translate );
|
||||||
|
} catch ( MissingResourceException e ) {
|
||||||
|
trans = translate;
|
||||||
|
}
|
||||||
|
|
||||||
|
Matcher matcher = format.matcher( trans );
|
||||||
|
int position = 0;
|
||||||
|
int i = 0;
|
||||||
|
while ( matcher.find( position ) )
|
||||||
|
{
|
||||||
|
int pos = matcher.start();
|
||||||
|
if ( pos != position )
|
||||||
|
{
|
||||||
|
builder.append( trans.substring( position, pos ) );
|
||||||
|
}
|
||||||
|
position = matcher.end();
|
||||||
|
|
||||||
|
String formatCode = matcher.group( 2 );
|
||||||
|
switch ( formatCode.charAt( 0 ) )
|
||||||
|
{
|
||||||
|
case 's':
|
||||||
|
case 'd':
|
||||||
|
String withIndex = matcher.group( 1 );
|
||||||
|
with.get( withIndex != null ? Integer.parseInt( withIndex ) - 1 : i++ ).toPlainText( builder );
|
||||||
|
break;
|
||||||
|
case '%':
|
||||||
|
builder.append( '%' );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( trans.length() != position )
|
||||||
|
{
|
||||||
|
builder.append( trans.substring( position, trans.length() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
super.toPlainText( builder );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void toLegacyText(StringBuilder builder)
|
||||||
|
{
|
||||||
|
String trans;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
trans = locales.getString( translate );
|
||||||
|
} catch ( MissingResourceException e ) {
|
||||||
|
trans = translate;
|
||||||
|
}
|
||||||
|
|
||||||
|
Matcher matcher = format.matcher( trans );
|
||||||
|
int position = 0;
|
||||||
|
int i = 0;
|
||||||
|
while ( matcher.find( position ) )
|
||||||
|
{
|
||||||
|
int pos = matcher.start();
|
||||||
|
if ( pos != position )
|
||||||
|
{
|
||||||
|
addFormat( builder );
|
||||||
|
builder.append( trans.substring( position, pos ) );
|
||||||
|
}
|
||||||
|
position = matcher.end();
|
||||||
|
|
||||||
|
String formatCode = matcher.group( 2 );
|
||||||
|
switch ( formatCode.charAt( 0 ) )
|
||||||
|
{
|
||||||
|
case 's':
|
||||||
|
case 'd':
|
||||||
|
String withIndex = matcher.group( 1 );
|
||||||
|
with.get( withIndex != null ? Integer.parseInt( withIndex ) - 1 : i++ ).toLegacyText( builder );
|
||||||
|
break;
|
||||||
|
case '%':
|
||||||
|
addFormat( builder );
|
||||||
|
builder.append( '%' );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( trans.length() != position )
|
||||||
|
{
|
||||||
|
addFormat( builder );
|
||||||
|
builder.append( trans.substring( position, trans.length() ) );
|
||||||
|
}
|
||||||
|
super.toLegacyText( builder );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addFormat(StringBuilder builder)
|
||||||
|
{
|
||||||
|
builder.append( getColor() );
|
||||||
|
if ( isBold() )
|
||||||
|
{
|
||||||
|
builder.append( ChatColor.BOLD );
|
||||||
|
}
|
||||||
|
if ( isItalic() )
|
||||||
|
{
|
||||||
|
builder.append( ChatColor.ITALIC );
|
||||||
|
}
|
||||||
|
if ( isUnderlined() )
|
||||||
|
{
|
||||||
|
builder.append( ChatColor.UNDERLINE );
|
||||||
|
}
|
||||||
|
if ( isStrikethrough() )
|
||||||
|
{
|
||||||
|
builder.append( ChatColor.STRIKETHROUGH );
|
||||||
|
}
|
||||||
|
if ( isObfuscated() )
|
||||||
|
{
|
||||||
|
builder.append( ChatColor.MAGIC );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,149 @@
|
|||||||
|
package net.md_5.bungee.chat;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.google.gson.JsonDeserializationContext;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonSerializationContext;
|
||||||
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
import net.md_5.bungee.api.chat.ClickEvent;
|
||||||
|
import net.md_5.bungee.api.chat.HoverEvent;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
public class BaseComponentSerializer
|
||||||
|
{
|
||||||
|
|
||||||
|
protected void deserialize(JsonObject object, BaseComponent component, JsonDeserializationContext context)
|
||||||
|
{
|
||||||
|
if ( object.has( "color" ) )
|
||||||
|
{
|
||||||
|
component.setColor( ChatColor.valueOf( object.get( "color" ).getAsString().toUpperCase() ) );
|
||||||
|
}
|
||||||
|
if ( object.has( "bold" ) )
|
||||||
|
{
|
||||||
|
component.setBold( object.get( "bold" ).getAsBoolean() );
|
||||||
|
}
|
||||||
|
if ( object.has( "italic" ) )
|
||||||
|
{
|
||||||
|
component.setItalic( object.get( "italic" ).getAsBoolean() );
|
||||||
|
}
|
||||||
|
if ( object.has( "underlined" ) )
|
||||||
|
{
|
||||||
|
component.setUnderlined( object.get( "underlined" ).getAsBoolean() );
|
||||||
|
}
|
||||||
|
if ( object.has( "strikethrough" ) )
|
||||||
|
{
|
||||||
|
component.setStrikethrough( object.get( "strikethrough" ).getAsBoolean() );
|
||||||
|
}
|
||||||
|
if ( object.has( "obfuscated" ) )
|
||||||
|
{
|
||||||
|
component.setObfuscated( object.get( "obfuscated" ).getAsBoolean() );
|
||||||
|
}
|
||||||
|
if ( object.has( "insertion" ) )
|
||||||
|
{
|
||||||
|
component.setInsertion( object.get( "insertion" ).getAsString() );
|
||||||
|
}
|
||||||
|
if ( object.has( "extra" ) )
|
||||||
|
{
|
||||||
|
component.setExtra( Arrays.<BaseComponent>asList( context.<BaseComponent[]>deserialize( object.get( "extra" ), BaseComponent[].class ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//Events
|
||||||
|
if ( object.has( "clickEvent" ) )
|
||||||
|
{
|
||||||
|
JsonObject event = object.getAsJsonObject( "clickEvent" );
|
||||||
|
component.setClickEvent( new ClickEvent(
|
||||||
|
ClickEvent.Action.valueOf( event.get( "action" ).getAsString().toUpperCase() ),
|
||||||
|
event.get( "value" ).getAsString() ) );
|
||||||
|
}
|
||||||
|
if ( object.has( "hoverEvent" ) )
|
||||||
|
{
|
||||||
|
JsonObject event = object.getAsJsonObject( "hoverEvent" );
|
||||||
|
BaseComponent[] res;
|
||||||
|
if ( event.get( "value" ).isJsonArray() )
|
||||||
|
{
|
||||||
|
res = context.deserialize( event.get( "value" ), BaseComponent[].class );
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
res = new BaseComponent[]
|
||||||
|
{
|
||||||
|
context.<BaseComponent>deserialize( event.get( "value" ), BaseComponent.class )
|
||||||
|
};
|
||||||
|
}
|
||||||
|
component.setHoverEvent( new HoverEvent( HoverEvent.Action.valueOf( event.get( "action" ).getAsString().toUpperCase() ), res ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void serialize(JsonObject object, BaseComponent component, JsonSerializationContext context)
|
||||||
|
{
|
||||||
|
boolean first = false;
|
||||||
|
if ( ComponentSerializer.serializedComponents.get() == null )
|
||||||
|
{
|
||||||
|
first = true;
|
||||||
|
ComponentSerializer.serializedComponents.set( new HashSet<BaseComponent>() );
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Preconditions.checkArgument( !ComponentSerializer.serializedComponents.get().contains( component ), "Component loop" );
|
||||||
|
ComponentSerializer.serializedComponents.get().add( component );
|
||||||
|
if ( component.getColorRaw() != null )
|
||||||
|
{
|
||||||
|
object.addProperty( "color", component.getColorRaw().getName() );
|
||||||
|
}
|
||||||
|
if ( component.isBoldRaw() != null )
|
||||||
|
{
|
||||||
|
object.addProperty( "bold", component.isBoldRaw() );
|
||||||
|
}
|
||||||
|
if ( component.isItalicRaw() != null )
|
||||||
|
{
|
||||||
|
object.addProperty( "italic", component.isItalicRaw() );
|
||||||
|
}
|
||||||
|
if ( component.isUnderlinedRaw() != null )
|
||||||
|
{
|
||||||
|
object.addProperty( "underlined", component.isUnderlinedRaw() );
|
||||||
|
}
|
||||||
|
if ( component.isStrikethroughRaw() != null )
|
||||||
|
{
|
||||||
|
object.addProperty( "strikethrough", component.isStrikethroughRaw() );
|
||||||
|
}
|
||||||
|
if ( component.isObfuscatedRaw() != null )
|
||||||
|
{
|
||||||
|
object.addProperty( "obfuscated", component.isObfuscatedRaw() );
|
||||||
|
}
|
||||||
|
if ( component.getInsertion() != null )
|
||||||
|
{
|
||||||
|
object.addProperty( "insertion", component.getInsertion() );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( component.getExtra() != null )
|
||||||
|
{
|
||||||
|
object.add( "extra", context.serialize( component.getExtra() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//Events
|
||||||
|
if ( component.getClickEvent() != null )
|
||||||
|
{
|
||||||
|
JsonObject clickEvent = new JsonObject();
|
||||||
|
clickEvent.addProperty( "action", component.getClickEvent().getAction().toString().toLowerCase() );
|
||||||
|
clickEvent.addProperty( "value", component.getClickEvent().getValue() );
|
||||||
|
object.add( "clickEvent", clickEvent );
|
||||||
|
}
|
||||||
|
if ( component.getHoverEvent() != null )
|
||||||
|
{
|
||||||
|
JsonObject hoverEvent = new JsonObject();
|
||||||
|
hoverEvent.addProperty( "action", component.getHoverEvent().getAction().toString().toLowerCase() );
|
||||||
|
hoverEvent.add( "value", context.serialize( component.getHoverEvent().getValue() ) );
|
||||||
|
object.add( "hoverEvent", hoverEvent );
|
||||||
|
}
|
||||||
|
} finally
|
||||||
|
{
|
||||||
|
ComponentSerializer.serializedComponents.get().remove( component );
|
||||||
|
if ( first )
|
||||||
|
{
|
||||||
|
ComponentSerializer.serializedComponents.set( null );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,64 @@
|
|||||||
|
package net.md_5.bungee.chat;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.google.gson.JsonDeserializationContext;
|
||||||
|
import com.google.gson.JsonDeserializer;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParseException;
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
|
import net.md_5.bungee.api.chat.TranslatableComponent;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
public class ComponentSerializer implements JsonDeserializer<BaseComponent>
|
||||||
|
{
|
||||||
|
|
||||||
|
private final static Gson gson = new GsonBuilder().
|
||||||
|
registerTypeAdapter( BaseComponent.class, new ComponentSerializer() ).
|
||||||
|
registerTypeAdapter( TextComponent.class, new TextComponentSerializer() ).
|
||||||
|
registerTypeAdapter( TranslatableComponent.class, new TranslatableComponentSerializer() ).
|
||||||
|
create();
|
||||||
|
|
||||||
|
public final static ThreadLocal<HashSet<BaseComponent>> serializedComponents = new ThreadLocal<HashSet<BaseComponent>>();
|
||||||
|
|
||||||
|
public static BaseComponent[] parse(String json)
|
||||||
|
{
|
||||||
|
if ( json.startsWith( "[" ) )
|
||||||
|
{ //Array
|
||||||
|
return gson.fromJson( json, BaseComponent[].class );
|
||||||
|
}
|
||||||
|
return new BaseComponent[]
|
||||||
|
{
|
||||||
|
gson.fromJson( json, BaseComponent.class )
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toString(BaseComponent component)
|
||||||
|
{
|
||||||
|
return gson.toJson( component );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toString(BaseComponent... components)
|
||||||
|
{
|
||||||
|
return gson.toJson( new TextComponent( components ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BaseComponent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
|
||||||
|
{
|
||||||
|
if ( json.isJsonPrimitive() )
|
||||||
|
{
|
||||||
|
return new TextComponent( json.getAsString() );
|
||||||
|
}
|
||||||
|
JsonObject object = json.getAsJsonObject();
|
||||||
|
if ( object.has( "translate" ) )
|
||||||
|
{
|
||||||
|
return context.deserialize( json, TranslatableComponent.class );
|
||||||
|
}
|
||||||
|
return context.deserialize( json, TextComponent.class );
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,43 @@
|
|||||||
|
package net.md_5.bungee.chat;
|
||||||
|
|
||||||
|
import com.google.gson.JsonDeserializationContext;
|
||||||
|
import com.google.gson.JsonDeserializer;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParseException;
|
||||||
|
import com.google.gson.JsonPrimitive;
|
||||||
|
import com.google.gson.JsonSerializationContext;
|
||||||
|
import com.google.gson.JsonSerializer;
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TextComponentSerializer extends BaseComponentSerializer implements JsonSerializer<TextComponent>, JsonDeserializer<TextComponent>
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TextComponent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
|
||||||
|
{
|
||||||
|
TextComponent component = new TextComponent();
|
||||||
|
JsonObject object = json.getAsJsonObject();
|
||||||
|
deserialize( object, component, context );
|
||||||
|
component.setText( object.get( "text" ).getAsString() );
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonElement serialize(TextComponent src, Type typeOfSrc, JsonSerializationContext context)
|
||||||
|
{
|
||||||
|
List<BaseComponent> extra = src.getExtra();
|
||||||
|
if ( !src.hasFormatting() && ( extra == null || extra.isEmpty() ) )
|
||||||
|
{
|
||||||
|
return new JsonPrimitive( src.getText() );
|
||||||
|
}
|
||||||
|
JsonObject object = new JsonObject();
|
||||||
|
serialize( object, src, context );
|
||||||
|
object.addProperty( "text", src.getText() );
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,45 @@
|
|||||||
|
package net.md_5.bungee.chat;
|
||||||
|
|
||||||
|
import com.google.gson.JsonDeserializationContext;
|
||||||
|
import com.google.gson.JsonDeserializer;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParseException;
|
||||||
|
import com.google.gson.JsonSerializationContext;
|
||||||
|
import com.google.gson.JsonSerializer;
|
||||||
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
import net.md_5.bungee.api.chat.TranslatableComponent;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class TranslatableComponentSerializer extends BaseComponentSerializer implements JsonSerializer<TranslatableComponent>, JsonDeserializer<TranslatableComponent>
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TranslatableComponent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException
|
||||||
|
{
|
||||||
|
TranslatableComponent component = new TranslatableComponent();
|
||||||
|
JsonObject object = json.getAsJsonObject();
|
||||||
|
deserialize( object, component, context );
|
||||||
|
component.setTranslate( object.get( "translate" ).getAsString() );
|
||||||
|
if ( object.has( "with" ) )
|
||||||
|
{
|
||||||
|
component.setWith( Arrays.asList( (BaseComponent[]) context.deserialize( object.get( "with" ), BaseComponent[].class ) ) );
|
||||||
|
}
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JsonElement serialize(TranslatableComponent src, Type typeOfSrc, JsonSerializationContext context)
|
||||||
|
{
|
||||||
|
JsonObject object = new JsonObject();
|
||||||
|
serialize( object, src, context );
|
||||||
|
object.addProperty( "translate", src.getTranslate() );
|
||||||
|
if ( src.getWith() != null )
|
||||||
|
{
|
||||||
|
object.add( "with", context.serialize( src.getWith() ) );
|
||||||
|
}
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
}
|
2647
chat/src/main/resources/mojang-translations/en_US.properties
Normal file
2647
chat/src/main/resources/mojang-translations/en_US.properties
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,16 @@
|
|||||||
|
package net.md_5.bungee.api.chat;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.chat.TranslatableComponent;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
public class TranslatableComponentTest {
|
||||||
|
@Test
|
||||||
|
public void testMissingPlaceholdersAdded()
|
||||||
|
{
|
||||||
|
TranslatableComponent testComponent = new TranslatableComponent( "Test string with %s placeholders: %s", "2", "aoeu" );
|
||||||
|
assertEquals( "Test string with 2 placeholders: aoeu", testComponent.toPlainText() );
|
||||||
|
assertEquals( "§fTest string with §f2§f placeholders: §faoeu", testComponent.toLegacyText() );
|
||||||
|
}
|
||||||
|
}
|
@@ -6,29 +6,24 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>net.md-5</groupId>
|
<groupId>net.md-5</groupId>
|
||||||
<artifactId>bungeecord-parent</artifactId>
|
<artifactId>bungeecord-parent</artifactId>
|
||||||
<version>1.4.7-SNAPSHOT</version>
|
<version>1.8-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<groupId>net.md-5</groupId>
|
<groupId>net.md-5</groupId>
|
||||||
<artifactId>bungeecord-config</artifactId>
|
<artifactId>bungeecord-config</artifactId>
|
||||||
<version>1.4.7-SNAPSHOT</version>
|
<version>1.8-SNAPSHOT</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>BungeeCord-Config</name>
|
<name>BungeeCord-Config</name>
|
||||||
<description>Generic java configuration API intended for use with BungeeCord</description>
|
<description>Generic java configuration API intended for use with BungeeCord</description>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
|
||||||
<groupId>junit</groupId>
|
|
||||||
<artifactId>junit</artifactId>
|
|
||||||
<version>4.11</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.yaml</groupId>
|
<groupId>org.yaml</groupId>
|
||||||
<artifactId>snakeyaml</artifactId>
|
<artifactId>snakeyaml</artifactId>
|
||||||
<version>1.11</version>
|
<version>1.14</version>
|
||||||
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
@@ -1,8 +1,10 @@
|
|||||||
package net.md_5.bungee.config;
|
package net.md_5.bungee.config;
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
@@ -13,58 +15,108 @@ public final class Configuration
|
|||||||
{
|
{
|
||||||
|
|
||||||
private static final char SEPARATOR = '.';
|
private static final char SEPARATOR = '.';
|
||||||
private final Map<String, Object> self;
|
final Map<String, Object> self;
|
||||||
private Map<String, Object> comments = new HashMap<>();
|
|
||||||
private final Configuration defaults;
|
private final Configuration defaults;
|
||||||
|
|
||||||
private Map<String, Object> getHolder(String path, Map<String, Object> parent, boolean create)
|
public Configuration()
|
||||||
{
|
{
|
||||||
return null;
|
this( null );
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object get(String path, Map<String, Object> holder)
|
public Configuration(Configuration defaults)
|
||||||
|
{
|
||||||
|
this( new LinkedHashMap<String, Object>(), defaults );
|
||||||
|
}
|
||||||
|
|
||||||
|
private Configuration getSectionFor(String path)
|
||||||
{
|
{
|
||||||
int index = path.indexOf( SEPARATOR );
|
int index = path.indexOf( SEPARATOR );
|
||||||
String first, second;
|
|
||||||
if ( index == -1 )
|
if ( index == -1 )
|
||||||
{
|
{
|
||||||
second = path;
|
return this;
|
||||||
} else
|
|
||||||
{
|
|
||||||
first = path.substring( 0, index );
|
|
||||||
second = path.substring( index + 1, path.length() );
|
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
|
String root = path.substring( 0, index );
|
||||||
|
Object section = self.get( root );
|
||||||
|
if ( section == null )
|
||||||
|
{
|
||||||
|
section = new LinkedHashMap<>();
|
||||||
|
self.put( root, section );
|
||||||
|
}
|
||||||
|
if ( section instanceof Configuration )
|
||||||
|
{
|
||||||
|
return (Configuration) section;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Configuration( (Map) section, ( defaults == null ) ? null : defaults.getSectionFor( path ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getChild(String path)
|
||||||
|
{
|
||||||
|
int index = path.indexOf( SEPARATOR );
|
||||||
|
return ( index == -1 ) ? path : path.substring( index + 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T> T get(String path, T def)
|
public <T> T get(String path, T def)
|
||||||
{
|
{
|
||||||
Object val = get( path, self );
|
Configuration section = getSectionFor( path );
|
||||||
return ( val != null && val.getClass().isInstance( def ) ) ? (T) val : (T) defaults.get( path );
|
Object val;
|
||||||
|
if ( section == this )
|
||||||
|
{
|
||||||
|
val = self.get( path );
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
val = section.get( getChild( path ), def );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( val != null ) ? (T) val : def;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object get(String path)
|
public Object get(String path)
|
||||||
{
|
{
|
||||||
return get( path, null );
|
return get( path, getDefault( path ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getDefault(String path)
|
public Object getDefault(String path)
|
||||||
{
|
{
|
||||||
return defaults.get( path );
|
return ( defaults == null ) ? null : defaults.get( path );
|
||||||
}
|
|
||||||
|
|
||||||
public void set(String path, Object value, String comment)
|
|
||||||
{
|
|
||||||
String child = path.substring( path.indexOf( SEPARATOR ) + 1 );
|
|
||||||
getHolder( path, self, true ).put( child, value );
|
|
||||||
getHolder( path, comments, true ).put( child, value );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void set(String path, Object value)
|
public void set(String path, Object value)
|
||||||
{
|
{
|
||||||
set( path, value, null );
|
Configuration section = getSectionFor( path );
|
||||||
|
if ( section == this )
|
||||||
|
{
|
||||||
|
if ( value == null )
|
||||||
|
{
|
||||||
|
self.remove( path );
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
self.put( path, value );
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
section.set( getChild( path ), value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------*/
|
||||||
|
public Configuration getSection(String path)
|
||||||
|
{
|
||||||
|
Object def = getDefault( path );
|
||||||
|
return new Configuration( (Map) ( get( path, ( def instanceof Map ) ? def : Collections.EMPTY_MAP ) ), ( defaults == null ) ? null : defaults.getSection( path ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets keys, not deep by default.
|
||||||
|
*
|
||||||
|
* @return top level keys for this section
|
||||||
|
*/
|
||||||
|
public Collection<String> getKeys()
|
||||||
|
{
|
||||||
|
return Sets.newLinkedHashSet( self.keySet() );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------*/
|
||||||
|
@@ -1,7 +1,10 @@
|
|||||||
package net.md_5.bungee.config;
|
package net.md_5.bungee.config;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
|
import java.io.Writer;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -15,15 +18,29 @@ public abstract class ConfigurationProvider
|
|||||||
providers.put( YamlConfiguration.class, new YamlConfiguration() );
|
providers.put( YamlConfiguration.class, new YamlConfiguration() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConfigurationProvider getProvider(Class<? extends ConfigurationProvider> provider)
|
public static ConfigurationProvider getProvider(Class<? extends ConfigurationProvider> provider)
|
||||||
{
|
{
|
||||||
return providers.get( provider );
|
return providers.get( provider );
|
||||||
}
|
}
|
||||||
/*------------------------------------------------------------------------*/
|
/*------------------------------------------------------------------------*/
|
||||||
|
|
||||||
public abstract Configuration load(File file);
|
public abstract void save(Configuration config, File file) throws IOException;
|
||||||
|
|
||||||
|
public abstract void save(Configuration config, Writer writer);
|
||||||
|
|
||||||
|
public abstract Configuration load(File file) throws IOException;
|
||||||
|
|
||||||
|
public abstract Configuration load(File file, Configuration defaults) throws IOException;
|
||||||
|
|
||||||
public abstract Configuration load(Reader reader);
|
public abstract Configuration load(Reader reader);
|
||||||
|
|
||||||
|
public abstract Configuration load(Reader reader, Configuration defaults);
|
||||||
|
|
||||||
|
public abstract Configuration load(InputStream is);
|
||||||
|
|
||||||
|
public abstract Configuration load(InputStream is, Configuration defaults);
|
||||||
|
|
||||||
public abstract Configuration load(String string);
|
public abstract Configuration load(String string);
|
||||||
|
|
||||||
|
public abstract Configuration load(String string, Configuration defaults);
|
||||||
}
|
}
|
||||||
|
@@ -1,14 +1,20 @@
|
|||||||
package net.md_5.bungee.config;
|
package net.md_5.bungee.config;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
|
import java.io.FileWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
import org.yaml.snakeyaml.DumperOptions;
|
import org.yaml.snakeyaml.DumperOptions;
|
||||||
import org.yaml.snakeyaml.Yaml;
|
import org.yaml.snakeyaml.Yaml;
|
||||||
|
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PACKAGE)
|
||||||
public class YamlConfiguration extends ConfigurationProvider
|
public class YamlConfiguration extends ConfigurationProvider
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -24,30 +30,86 @@ public class YamlConfiguration extends ConfigurationProvider
|
|||||||
};
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Configuration load(File file)
|
public void save(Configuration config, File file) throws IOException
|
||||||
{
|
{
|
||||||
try ( FileReader reader = new FileReader( file ) )
|
try ( FileWriter writer = new FileWriter( file ) )
|
||||||
{
|
{
|
||||||
return load( reader );
|
save( config, writer );
|
||||||
} catch ( IOException ex )
|
}
|
||||||
{
|
}
|
||||||
return null;
|
|
||||||
|
@Override
|
||||||
|
public void save(Configuration config, Writer writer)
|
||||||
|
{
|
||||||
|
yaml.get().dump( config.self, writer );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Configuration load(File file) throws IOException
|
||||||
|
{
|
||||||
|
return load( file, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Configuration load(File file, Configuration defaults) throws IOException
|
||||||
|
{
|
||||||
|
try ( FileReader reader = new FileReader( file ) )
|
||||||
|
{
|
||||||
|
return load( reader, defaults );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public Configuration load(Reader reader)
|
public Configuration load(Reader reader)
|
||||||
{
|
{
|
||||||
Configuration conf = new Configuration( (Map<String, Object>) yaml.get().loadAs( reader, Map.class ), null );
|
return load( reader, null );
|
||||||
return conf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
public Configuration load(Reader reader, Configuration defaults)
|
||||||
|
{
|
||||||
|
Map<String, Object> map = yaml.get().loadAs( reader, LinkedHashMap.class );
|
||||||
|
if ( map == null )
|
||||||
|
{
|
||||||
|
map = new LinkedHashMap<>();
|
||||||
|
}
|
||||||
|
return new Configuration( map, defaults );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Configuration load(InputStream is)
|
||||||
|
{
|
||||||
|
return load( is, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public Configuration load(InputStream is, Configuration defaults)
|
||||||
|
{
|
||||||
|
Map<String, Object> map = yaml.get().loadAs( is, LinkedHashMap.class );
|
||||||
|
if ( map == null )
|
||||||
|
{
|
||||||
|
map = new LinkedHashMap<>();
|
||||||
|
}
|
||||||
|
return new Configuration( map, defaults );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Configuration load(String string)
|
public Configuration load(String string)
|
||||||
{
|
{
|
||||||
Configuration conf = new Configuration( (Map<String, Object>) yaml.get().loadAs( string, Map.class ), null );
|
return load( string, null );
|
||||||
return conf;
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public Configuration load(String string, Configuration defaults)
|
||||||
|
{
|
||||||
|
Map<String, Object> map = yaml.get().loadAs( string, LinkedHashMap.class );
|
||||||
|
if ( map == null )
|
||||||
|
{
|
||||||
|
map = new LinkedHashMap<>();
|
||||||
|
}
|
||||||
|
return new Configuration( map, defaults );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,81 @@
|
|||||||
|
package net.md_5.bungee.config;
|
||||||
|
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class YamlConfigurationTest
|
||||||
|
{
|
||||||
|
|
||||||
|
private String document = ""
|
||||||
|
+ "receipt: Oz-Ware Purchase Invoice\n"
|
||||||
|
+ "date: 2012-08-06\n"
|
||||||
|
+ "customer:\n"
|
||||||
|
+ " given: Dorothy\n"
|
||||||
|
+ " family: Gale\n"
|
||||||
|
+ "\n"
|
||||||
|
+ "items:\n"
|
||||||
|
+ " - part_no: A4786\n"
|
||||||
|
+ " descrip: Water Bucket (Filled)\n"
|
||||||
|
+ " price: 1.47\n"
|
||||||
|
+ " quantity: 4\n"
|
||||||
|
+ "\n"
|
||||||
|
+ " - part_no: E1628\n"
|
||||||
|
+ " descrip: High Heeled \"Ruby\" Slippers\n"
|
||||||
|
+ " size: 8\n"
|
||||||
|
+ " price: 100.27\n"
|
||||||
|
+ " quantity: 1\n"
|
||||||
|
+ "\n"
|
||||||
|
+ "bill-to: &id001\n"
|
||||||
|
+ " street: |\n"
|
||||||
|
+ " 123 Tornado Alley\n"
|
||||||
|
+ " Suite 16\n"
|
||||||
|
+ " city: East Centerville\n"
|
||||||
|
+ " state: KS\n"
|
||||||
|
+ "\n"
|
||||||
|
+ "ship-to: *id001\n"
|
||||||
|
+ "\n"
|
||||||
|
+ "specialDelivery: >\n"
|
||||||
|
+ " Follow the Yellow Brick\n"
|
||||||
|
+ " Road to the Emerald City.\n"
|
||||||
|
+ " Pay no attention to the\n"
|
||||||
|
+ " man behind the curtain.";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConfig() throws Exception
|
||||||
|
{
|
||||||
|
Configuration conf = ConfigurationProvider.getProvider( YamlConfiguration.class ).load( document );
|
||||||
|
testSection( conf );
|
||||||
|
|
||||||
|
StringWriter sw = new StringWriter();
|
||||||
|
ConfigurationProvider.getProvider( YamlConfiguration.class ).save( conf, sw );
|
||||||
|
|
||||||
|
// Check nulls were saved, see #1094
|
||||||
|
Assert.assertFalse( "Config contains null", sw.toString().contains( "null" ) );
|
||||||
|
|
||||||
|
conf = ConfigurationProvider.getProvider( YamlConfiguration.class ).load( new StringReader( sw.toString() ) );
|
||||||
|
conf.set( "receipt", "Oz-Ware Purchase Invoice" ); // Add it back
|
||||||
|
testSection( conf );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testSection(Configuration conf)
|
||||||
|
{
|
||||||
|
Assert.assertEquals( "receipt", "Oz-Ware Purchase Invoice", conf.getString( "receipt" ) );
|
||||||
|
// Assert.assertEquals( "date", "2012-08-06", conf.get( "date" ).toString() );
|
||||||
|
|
||||||
|
Configuration customer = conf.getSection( "customer" );
|
||||||
|
Assert.assertEquals( "customer.given", "Dorothy", customer.getString( "given" ) );
|
||||||
|
Assert.assertEquals( "customer.given", "Dorothy", conf.getString( "customer.given" ) );
|
||||||
|
|
||||||
|
List items = conf.getList( "items" );
|
||||||
|
Map item = (Map) items.get( 0 );
|
||||||
|
Assert.assertEquals( "items[0].part_no", "A4786", item.get( "part_no" ) );
|
||||||
|
|
||||||
|
conf.set( "receipt", null );
|
||||||
|
Assert.assertEquals( null, conf.get( "receipt" ) );
|
||||||
|
Assert.assertEquals( "foo", conf.get( "receipt", "foo" ) );
|
||||||
|
}
|
||||||
|
}
|
@@ -6,24 +6,15 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>net.md-5</groupId>
|
<groupId>net.md-5</groupId>
|
||||||
<artifactId>bungeecord-parent</artifactId>
|
<artifactId>bungeecord-parent</artifactId>
|
||||||
<version>1.5-SNAPSHOT</version>
|
<version>1.8-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<groupId>net.md-5</groupId>
|
<groupId>net.md-5</groupId>
|
||||||
<artifactId>bungeecord-event</artifactId>
|
<artifactId>bungeecord-event</artifactId>
|
||||||
<version>1.5-SNAPSHOT</version>
|
<version>1.8-SNAPSHOT</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>BungeeCord-Event</name>
|
<name>BungeeCord-Event</name>
|
||||||
<description>Generic java event dispatching API intended for use with BungeeCord</description>
|
<description>Generic java event dispatching API intended for use with BungeeCord</description>
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>junit</groupId>
|
|
||||||
<artifactId>junit</artifactId>
|
|
||||||
<version>4.11</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
</project>
|
||||||
|
@@ -1,114 +1,93 @@
|
|||||||
package net.md_5.bungee.event;
|
package net.md_5.bungee.event;
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.locks.ReadWriteLock;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
public class EventBus
|
public class EventBus
|
||||||
{
|
{
|
||||||
|
|
||||||
private final Map<Class<?>, Map<Object, Method[]>> eventToHandler = new HashMap<>();
|
private final Map<Class<?>, Map<Byte, Map<Object, Method[]>>> byListenerAndPriority = new HashMap<>();
|
||||||
private final ReadWriteLock lock = new ReentrantReadWriteLock();
|
private final Map<Class<?>, EventHandlerMethod[]> byEventBaked = new ConcurrentHashMap<>();
|
||||||
|
private final Lock lock = new ReentrantLock();
|
||||||
private final Logger logger;
|
private final Logger logger;
|
||||||
private final Class<? extends Annotation>[] annotations;
|
|
||||||
|
|
||||||
public EventBus()
|
public EventBus()
|
||||||
{
|
{
|
||||||
this( null, (Class<? extends Annotation>[]) null );
|
this( null );
|
||||||
}
|
}
|
||||||
|
|
||||||
public EventBus(Logger logger)
|
public EventBus(Logger logger)
|
||||||
{
|
{
|
||||||
this( logger, (Class<? extends Annotation>[]) null );
|
this.logger = ( logger == null ) ? Logger.getLogger( Logger.GLOBAL_LOGGER_NAME ) : logger;
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public EventBus(Class<? extends Annotation>... annotations)
|
|
||||||
{
|
|
||||||
this( null, annotations );
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public EventBus(Logger logger, Class<? extends Annotation>... annotations)
|
|
||||||
{
|
|
||||||
this.logger = ( logger == null ) ? Logger.getGlobal() : logger;
|
|
||||||
this.annotations = ( annotations == null || annotations.length == 0 ) ? new Class[]
|
|
||||||
{
|
|
||||||
EventHandler.class
|
|
||||||
} : annotations;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void post(Object event)
|
public void post(Object event)
|
||||||
{
|
{
|
||||||
lock.readLock().lock();
|
EventHandlerMethod[] handlers = byEventBaked.get( event.getClass() );
|
||||||
try
|
|
||||||
|
if ( handlers != null )
|
||||||
{
|
{
|
||||||
Map<Object, Method[]> handlers = eventToHandler.get( event.getClass() );
|
for ( EventHandlerMethod method : handlers )
|
||||||
if ( handlers != null )
|
|
||||||
{
|
{
|
||||||
for ( Map.Entry<Object, Method[]> handler : handlers.entrySet() )
|
try
|
||||||
{
|
{
|
||||||
for ( Method method : handler.getValue() )
|
method.invoke( event );
|
||||||
{
|
} catch ( IllegalAccessException ex )
|
||||||
try
|
{
|
||||||
{
|
throw new Error( "Method became inaccessible: " + event, ex );
|
||||||
method.invoke( handler.getKey(), event );
|
} catch ( IllegalArgumentException ex )
|
||||||
} catch ( IllegalAccessException ex )
|
{
|
||||||
{
|
throw new Error( "Method rejected target/argument: " + event, ex );
|
||||||
throw new Error( "Method became inaccessible: " + event, ex );
|
} catch ( InvocationTargetException ex )
|
||||||
} catch ( IllegalArgumentException ex )
|
{
|
||||||
{
|
logger.log( Level.WARNING, MessageFormat.format( "Error dispatching event {0} to listener {1}", event, method.getListener() ), ex.getCause() );
|
||||||
throw new Error( "Method rejected target/argument: " + event, ex );
|
|
||||||
} catch ( InvocationTargetException ex )
|
|
||||||
{
|
|
||||||
logger.log( Level.WARNING, MessageFormat.format( "Error dispatching event {0} to listener {1}", event, handler.getKey() ), ex.getCause() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally
|
|
||||||
{
|
|
||||||
lock.readLock().unlock();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<Class<?>, Set<Method>> findHandlers(Object listener)
|
private Map<Class<?>, Map<Byte, Set<Method>>> findHandlers(Object listener)
|
||||||
{
|
{
|
||||||
Map<Class<?>, Set<Method>> handler = new HashMap<>();
|
Map<Class<?>, Map<Byte, Set<Method>>> handler = new HashMap<>();
|
||||||
for ( Method m : listener.getClass().getDeclaredMethods() )
|
for ( Method m : listener.getClass().getDeclaredMethods() )
|
||||||
{
|
{
|
||||||
for ( Class<? extends Annotation> annotation : annotations )
|
EventHandler annotation = m.getAnnotation( EventHandler.class );
|
||||||
|
if ( annotation != null )
|
||||||
{
|
{
|
||||||
if ( m.isAnnotationPresent( annotation ) )
|
Class<?>[] params = m.getParameterTypes();
|
||||||
|
if ( params.length != 1 )
|
||||||
{
|
{
|
||||||
Class<?>[] params = m.getParameterTypes();
|
logger.log( Level.INFO, "Method {0} in class {1} annotated with {2} does not have single argument", new Object[]
|
||||||
if ( params.length != 1 )
|
|
||||||
{
|
{
|
||||||
logger.log( Level.INFO, "Method {0} in class {1} annotated with {2} does not have single argument", new Object[]
|
m, listener.getClass(), annotation
|
||||||
{
|
} );
|
||||||
m, listener.getClass(), annotation
|
continue;
|
||||||
} );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<Method> existing = handler.get( params[0] );
|
|
||||||
if ( existing == null )
|
|
||||||
{
|
|
||||||
existing = new HashSet<>();
|
|
||||||
handler.put( params[0], existing );
|
|
||||||
}
|
|
||||||
existing.add( m );
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
Map<Byte, Set<Method>> prioritiesMap = handler.get( params[0] );
|
||||||
|
if ( prioritiesMap == null )
|
||||||
|
{
|
||||||
|
prioritiesMap = new HashMap<>();
|
||||||
|
handler.put( params[0], prioritiesMap );
|
||||||
|
}
|
||||||
|
Set<Method> priority = prioritiesMap.get( annotation.priority() );
|
||||||
|
if ( priority == null )
|
||||||
|
{
|
||||||
|
priority = new HashSet<>();
|
||||||
|
prioritiesMap.put( annotation.priority(), priority );
|
||||||
|
}
|
||||||
|
priority.add( m );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return handler;
|
return handler;
|
||||||
@@ -116,48 +95,107 @@ public class EventBus
|
|||||||
|
|
||||||
public void register(Object listener)
|
public void register(Object listener)
|
||||||
{
|
{
|
||||||
Map<Class<?>, Set<Method>> handler = findHandlers( listener );
|
Map<Class<?>, Map<Byte, Set<Method>>> handler = findHandlers( listener );
|
||||||
lock.writeLock().lock();
|
lock.lock();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
for ( Map.Entry<Class<?>, Set<Method>> e : handler.entrySet() )
|
for ( Map.Entry<Class<?>, Map<Byte, Set<Method>>> e : handler.entrySet() )
|
||||||
{
|
{
|
||||||
Map<Object, Method[]> a = eventToHandler.get( e.getKey() );
|
Map<Byte, Map<Object, Method[]>> prioritiesMap = byListenerAndPriority.get( e.getKey() );
|
||||||
if ( a == null )
|
if ( prioritiesMap == null )
|
||||||
{
|
{
|
||||||
a = new HashMap<>();
|
prioritiesMap = new HashMap<>();
|
||||||
eventToHandler.put( e.getKey(), a );
|
byListenerAndPriority.put( e.getKey(), prioritiesMap );
|
||||||
}
|
}
|
||||||
Method[] baked = new Method[ e.getValue().size() ];
|
for ( Map.Entry<Byte, Set<Method>> entry : e.getValue().entrySet() )
|
||||||
a.put( listener, e.getValue().toArray( baked ) );
|
{
|
||||||
|
Map<Object, Method[]> currentPriorityMap = prioritiesMap.get( entry.getKey() );
|
||||||
|
if ( currentPriorityMap == null )
|
||||||
|
{
|
||||||
|
currentPriorityMap = new HashMap<>();
|
||||||
|
prioritiesMap.put( entry.getKey(), currentPriorityMap );
|
||||||
|
}
|
||||||
|
Method[] baked = new Method[ entry.getValue().size() ];
|
||||||
|
currentPriorityMap.put( listener, entry.getValue().toArray( baked ) );
|
||||||
|
}
|
||||||
|
bakeHandlers( e.getKey() );
|
||||||
}
|
}
|
||||||
} finally
|
} finally
|
||||||
{
|
{
|
||||||
lock.writeLock().unlock();
|
lock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unregister(Object listener)
|
public void unregister(Object listener)
|
||||||
{
|
{
|
||||||
Map<Class<?>, Set<Method>> handler = findHandlers( listener );
|
Map<Class<?>, Map<Byte, Set<Method>>> handler = findHandlers( listener );
|
||||||
lock.writeLock().lock();
|
lock.lock();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
for ( Map.Entry<Class<?>, Set<Method>> e : handler.entrySet() )
|
for ( Map.Entry<Class<?>, Map<Byte, Set<Method>>> e : handler.entrySet() )
|
||||||
{
|
{
|
||||||
Map<Object, Method[]> a = eventToHandler.get( e.getKey() );
|
Map<Byte, Map<Object, Method[]>> prioritiesMap = byListenerAndPriority.get( e.getKey() );
|
||||||
if ( a != null )
|
if ( prioritiesMap != null )
|
||||||
{
|
{
|
||||||
a.remove( listener );
|
for ( Byte priority : e.getValue().keySet() )
|
||||||
if ( a.isEmpty() )
|
|
||||||
{
|
{
|
||||||
eventToHandler.remove( e.getKey() );
|
Map<Object, Method[]> currentPriority = prioritiesMap.get( priority );
|
||||||
|
if ( currentPriority != null )
|
||||||
|
{
|
||||||
|
currentPriority.remove( listener );
|
||||||
|
if ( currentPriority.isEmpty() )
|
||||||
|
{
|
||||||
|
prioritiesMap.remove( priority );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( prioritiesMap.isEmpty() )
|
||||||
|
{
|
||||||
|
byListenerAndPriority.remove( e.getKey() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
bakeHandlers( e.getKey() );
|
||||||
}
|
}
|
||||||
} finally
|
} finally
|
||||||
{
|
{
|
||||||
lock.writeLock().unlock();
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shouldn't be called without first locking the writeLock; intended for use
|
||||||
|
* only inside {@link #register(java.lang.Object) register(Object)} or
|
||||||
|
* {@link #unregister(java.lang.Object) unregister(Object)}.
|
||||||
|
*/
|
||||||
|
private void bakeHandlers(Class<?> eventClass)
|
||||||
|
{
|
||||||
|
Map<Byte, Map<Object, Method[]>> handlersByPriority = byListenerAndPriority.get( eventClass );
|
||||||
|
if ( handlersByPriority != null )
|
||||||
|
{
|
||||||
|
List<EventHandlerMethod> handlersList = new ArrayList<>( handlersByPriority.size() * 2 );
|
||||||
|
|
||||||
|
// Either I'm really tired, or the only way we can iterate between Byte.MIN_VALUE and Byte.MAX_VALUE inclusively,
|
||||||
|
// with only a byte on the stack is by using a do {} while() format loop.
|
||||||
|
byte value = Byte.MIN_VALUE;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Map<Object, Method[]> handlersByListener = handlersByPriority.get( value );
|
||||||
|
if ( handlersByListener != null )
|
||||||
|
{
|
||||||
|
for ( Map.Entry<Object, Method[]> listenerHandlers : handlersByListener.entrySet() )
|
||||||
|
{
|
||||||
|
for ( Method method : listenerHandlers.getValue() )
|
||||||
|
{
|
||||||
|
EventHandlerMethod ehm = new EventHandlerMethod( listenerHandlers.getKey(), method );
|
||||||
|
handlersList.add( ehm );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while ( value++ < Byte.MAX_VALUE );
|
||||||
|
byEventBaked.put( eventClass, handlersList.toArray( new EventHandlerMethod[ handlersList.size() ] ) );
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
byEventBaked.remove( eventClass );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -9,4 +9,18 @@ import java.lang.annotation.Target;
|
|||||||
@Target(ElementType.METHOD)
|
@Target(ElementType.METHOD)
|
||||||
public @interface EventHandler
|
public @interface EventHandler
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define the priority of the event handler.
|
||||||
|
* <p>
|
||||||
|
* Event handlers are called in order of priority:
|
||||||
|
* <ol>
|
||||||
|
* <li>LOWEST</li>
|
||||||
|
* <li>LOW</li>
|
||||||
|
* <li>NORMAL</li>
|
||||||
|
* <li>HIGH</li>
|
||||||
|
* <li>HIGHEST</li>
|
||||||
|
* </ol>
|
||||||
|
*/
|
||||||
|
byte priority() default EventPriority.NORMAL;
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,21 @@
|
|||||||
|
package net.md_5.bungee.event;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class EventHandlerMethod
|
||||||
|
{
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final Object listener;
|
||||||
|
@Getter
|
||||||
|
private final Method method;
|
||||||
|
|
||||||
|
public void invoke(Object event) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
|
||||||
|
{
|
||||||
|
method.invoke( listener, event );
|
||||||
|
}
|
||||||
|
}
|
19
event/src/main/java/net/md_5/bungee/event/EventPriority.java
Normal file
19
event/src/main/java/net/md_5/bungee/event/EventPriority.java
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package net.md_5.bungee.event;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Importance of the {@link EventHandler}. When executing an Event, the handlers
|
||||||
|
* are called in order of their Priority.
|
||||||
|
*/
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public class EventPriority
|
||||||
|
{
|
||||||
|
|
||||||
|
public static final byte LOWEST = -64;
|
||||||
|
public static final byte LOW = -32;
|
||||||
|
public static final byte NORMAL = 0;
|
||||||
|
public static final byte HIGH = 32;
|
||||||
|
public static final byte HIGHEST = 64;
|
||||||
|
}
|
@@ -15,14 +15,14 @@ public class EventBusTest
|
|||||||
{
|
{
|
||||||
bus.register( this );
|
bus.register( this );
|
||||||
bus.post( new FirstEvent() );
|
bus.post( new FirstEvent() );
|
||||||
Assert.assertEquals( latch.getCount(), 0 );
|
Assert.assertEquals( 0, latch.getCount() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void firstListener(FirstEvent event)
|
public void firstListener(FirstEvent event)
|
||||||
{
|
{
|
||||||
bus.post( new SecondEvent() );
|
bus.post( new SecondEvent() );
|
||||||
Assert.assertEquals( latch.getCount(), 1 );
|
Assert.assertEquals( 1, latch.getCount() );
|
||||||
latch.countDown();
|
latch.countDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -0,0 +1,78 @@
|
|||||||
|
package net.md_5.bungee.event;
|
||||||
|
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class EventPriorityTest
|
||||||
|
{
|
||||||
|
|
||||||
|
private final EventBus bus = new EventBus();
|
||||||
|
private final CountDownLatch latch = new CountDownLatch( 7 );
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPriority()
|
||||||
|
{
|
||||||
|
bus.register( this );
|
||||||
|
bus.register( new EventPriorityListenerPartner() );
|
||||||
|
bus.post( new PriorityTestEvent() );
|
||||||
|
Assert.assertEquals( 0, latch.getCount() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = Byte.MIN_VALUE)
|
||||||
|
public void onMinPriority(PriorityTestEvent event)
|
||||||
|
{
|
||||||
|
Assert.assertEquals( 7, latch.getCount() );
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
|
public void onLowestPriority(PriorityTestEvent event)
|
||||||
|
{
|
||||||
|
Assert.assertEquals( 6, latch.getCount() );
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onNormalPriority(PriorityTestEvent event)
|
||||||
|
{
|
||||||
|
Assert.assertEquals( 4, latch.getCount() );
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.HIGHEST)
|
||||||
|
public void onHighestPriority(PriorityTestEvent event)
|
||||||
|
{
|
||||||
|
Assert.assertEquals( 2, latch.getCount() );
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = Byte.MAX_VALUE)
|
||||||
|
public void onMaxPriority(PriorityTestEvent event)
|
||||||
|
{
|
||||||
|
Assert.assertEquals( 1, latch.getCount() );
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PriorityTestEvent
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EventPriorityListenerPartner
|
||||||
|
{
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.HIGH)
|
||||||
|
public void onHighPriority(PriorityTestEvent event)
|
||||||
|
{
|
||||||
|
Assert.assertEquals( 3, latch.getCount() );
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(priority = EventPriority.LOW)
|
||||||
|
public void onLowPriority(PriorityTestEvent event)
|
||||||
|
{
|
||||||
|
Assert.assertEquals( 5, latch.getCount() );
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,28 @@
|
|||||||
|
package net.md_5.bungee.event;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class UnregisteringListenerTest
|
||||||
|
{
|
||||||
|
|
||||||
|
private final EventBus bus = new EventBus();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPriority()
|
||||||
|
{
|
||||||
|
bus.register( this );
|
||||||
|
bus.unregister( this );
|
||||||
|
bus.post( new TestEvent() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onEvent(TestEvent evt)
|
||||||
|
{
|
||||||
|
Assert.fail( "Event listener wasn't unregistered" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TestEvent
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
31
module/cmd-alert/nb-configuration.xml
Normal file
31
module/cmd-alert/nb-configuration.xml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project-shared-configuration>
|
||||||
|
<!--
|
||||||
|
This file contains additional configuration written by modules in the NetBeans IDE.
|
||||||
|
The configuration is intended to be shared among all the users of project and
|
||||||
|
therefore it is assumed to be part of version control checkout.
|
||||||
|
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
|
||||||
|
-->
|
||||||
|
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
|
||||||
|
<!--
|
||||||
|
Properties that influence various parts of the IDE, especially code formatting and the like.
|
||||||
|
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
|
||||||
|
That way multiple projects can share the same settings (useful for formatting rules for example).
|
||||||
|
Any value defined here will override the pom.xml file value but is only applicable to the current project.
|
||||||
|
-->
|
||||||
|
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
|
||||||
|
</properties>
|
||||||
|
</project-shared-configuration>
|
20
module/cmd-alert/pom.xml
Normal file
20
module/cmd-alert/pom.xml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
<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">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>net.md-5</groupId>
|
||||||
|
<artifactId>bungeecord-module</artifactId>
|
||||||
|
<version>1.8-SNAPSHOT</version>
|
||||||
|
<relativePath>../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<groupId>net.md-5</groupId>
|
||||||
|
<artifactId>bungeecord-module-cmd-alert</artifactId>
|
||||||
|
<version>1.8-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>cmd_alert</name>
|
||||||
|
<description>Provides the alert and alertraw commands</description>
|
||||||
|
</project>
|
@@ -1,9 +1,8 @@
|
|||||||
package net.md_5.bungee.command;
|
package net.md_5.bungee.module.cmd.alert;
|
||||||
|
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import net.md_5.bungee.api.CommandSender;
|
import net.md_5.bungee.api.CommandSender;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
|
||||||
import net.md_5.bungee.api.plugin.Command;
|
import net.md_5.bungee.api.plugin.Command;
|
||||||
|
|
||||||
public class CommandAlert extends Command
|
public class CommandAlert extends Command
|
||||||
@@ -41,7 +40,6 @@ public class CommandAlert extends Command
|
|||||||
String message = builder.substring( 0, builder.length() - 1 );
|
String message = builder.substring( 0, builder.length() - 1 );
|
||||||
|
|
||||||
ProxyServer.getInstance().broadcast( message );
|
ProxyServer.getInstance().broadcast( message );
|
||||||
ProxyServer.getInstance().getConsole().sendMessage( message );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -0,0 +1,55 @@
|
|||||||
|
package net.md_5.bungee.module.cmd.alert;
|
||||||
|
|
||||||
|
import com.google.common.base.Joiner;
|
||||||
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
import net.md_5.bungee.api.CommandSender;
|
||||||
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
|
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||||
|
import net.md_5.bungee.api.chat.HoverEvent;
|
||||||
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
|
import net.md_5.bungee.api.plugin.Command;
|
||||||
|
import net.md_5.bungee.chat.ComponentSerializer;
|
||||||
|
|
||||||
|
public class CommandAlertRaw extends Command
|
||||||
|
{
|
||||||
|
|
||||||
|
public CommandAlertRaw()
|
||||||
|
{
|
||||||
|
super( "alertraw", "bungeecord.command.alert" );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(CommandSender sender, String[] args)
|
||||||
|
{
|
||||||
|
if ( args.length == 0 )
|
||||||
|
{
|
||||||
|
sender.sendMessage( ChatColor.RED + "You must supply a message." );
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
String message = Joiner.on( ' ' ).join( args );
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ProxyServer.getInstance().broadcast( ComponentSerializer.parse( message ) );
|
||||||
|
} catch ( Exception e )
|
||||||
|
{
|
||||||
|
Throwable error = e;
|
||||||
|
while ( error.getCause() != null )
|
||||||
|
{
|
||||||
|
error = error.getCause();
|
||||||
|
}
|
||||||
|
if ( sender instanceof ProxiedPlayer )
|
||||||
|
{
|
||||||
|
sender.sendMessage(
|
||||||
|
new ComponentBuilder( "An error occurred while parsing your message. (Hover for details)" ).
|
||||||
|
color( ChatColor.RED ).underlined( true ).
|
||||||
|
event( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( error.getMessage() ).color( ChatColor.RED ).create() ) ).
|
||||||
|
create() );
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
sender.sendMessage( new ComponentBuilder( "An error occurred while parsing your message: " ).color( ChatColor.RED ).append( error.getMessage() ).create() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,14 @@
|
|||||||
|
package net.md_5.bungee.module.cmd.alert;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
|
|
||||||
|
public class PluginAlert extends Plugin
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable()
|
||||||
|
{
|
||||||
|
getProxy().getPluginManager().registerCommand( this, new CommandAlert() );
|
||||||
|
getProxy().getPluginManager().registerCommand( this, new CommandAlertRaw() );
|
||||||
|
}
|
||||||
|
}
|
5
module/cmd-alert/src/main/resources/plugin.yml
Normal file
5
module/cmd-alert/src/main/resources/plugin.yml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
name: ${project.name}
|
||||||
|
main: net.md_5.bungee.module.cmd.alert.PluginAlert
|
||||||
|
version: ${describe}
|
||||||
|
description: ${project.description}
|
||||||
|
author: ${module.author}
|
31
module/cmd-find/nb-configuration.xml
Normal file
31
module/cmd-find/nb-configuration.xml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project-shared-configuration>
|
||||||
|
<!--
|
||||||
|
This file contains additional configuration written by modules in the NetBeans IDE.
|
||||||
|
The configuration is intended to be shared among all the users of project and
|
||||||
|
therefore it is assumed to be part of version control checkout.
|
||||||
|
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
|
||||||
|
-->
|
||||||
|
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
|
||||||
|
<!--
|
||||||
|
Properties that influence various parts of the IDE, especially code formatting and the like.
|
||||||
|
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
|
||||||
|
That way multiple projects can share the same settings (useful for formatting rules for example).
|
||||||
|
Any value defined here will override the pom.xml file value but is only applicable to the current project.
|
||||||
|
-->
|
||||||
|
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
|
||||||
|
</properties>
|
||||||
|
</project-shared-configuration>
|
20
module/cmd-find/pom.xml
Normal file
20
module/cmd-find/pom.xml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
<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">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>net.md-5</groupId>
|
||||||
|
<artifactId>bungeecord-module</artifactId>
|
||||||
|
<version>1.8-SNAPSHOT</version>
|
||||||
|
<relativePath>../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<groupId>net.md-5</groupId>
|
||||||
|
<artifactId>bungeecord-module-cmd-find</artifactId>
|
||||||
|
<version>1.8-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>cmd_find</name>
|
||||||
|
<description>Provides the find command</description>
|
||||||
|
</project>
|
@@ -1,12 +1,12 @@
|
|||||||
package net.md_5.bungee.command;
|
package net.md_5.bungee.module.cmd.find;
|
||||||
|
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import net.md_5.bungee.api.CommandSender;
|
import net.md_5.bungee.api.CommandSender;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.md_5.bungee.api.ProxyServer;
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||||
import net.md_5.bungee.api.plugin.Command;
|
import net.md_5.bungee.command.PlayerCommand;
|
||||||
|
|
||||||
public class CommandFind extends Command
|
public class CommandFind extends PlayerCommand
|
||||||
{
|
{
|
||||||
|
|
||||||
public CommandFind()
|
public CommandFind()
|
@@ -0,0 +1,13 @@
|
|||||||
|
package net.md_5.bungee.module.cmd.find;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
|
|
||||||
|
public class PluginFind extends Plugin
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable()
|
||||||
|
{
|
||||||
|
getProxy().getPluginManager().registerCommand( this, new CommandFind() );
|
||||||
|
}
|
||||||
|
}
|
5
module/cmd-find/src/main/resources/plugin.yml
Normal file
5
module/cmd-find/src/main/resources/plugin.yml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
name: ${project.name}
|
||||||
|
main: net.md_5.bungee.module.cmd.find.PluginFind
|
||||||
|
version: ${describe}
|
||||||
|
description: ${project.description}
|
||||||
|
author: ${module.author}
|
31
module/cmd-list/nb-configuration.xml
Normal file
31
module/cmd-list/nb-configuration.xml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project-shared-configuration>
|
||||||
|
<!--
|
||||||
|
This file contains additional configuration written by modules in the NetBeans IDE.
|
||||||
|
The configuration is intended to be shared among all the users of project and
|
||||||
|
therefore it is assumed to be part of version control checkout.
|
||||||
|
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
|
||||||
|
-->
|
||||||
|
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
|
||||||
|
<!--
|
||||||
|
Properties that influence various parts of the IDE, especially code formatting and the like.
|
||||||
|
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
|
||||||
|
That way multiple projects can share the same settings (useful for formatting rules for example).
|
||||||
|
Any value defined here will override the pom.xml file value but is only applicable to the current project.
|
||||||
|
-->
|
||||||
|
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
|
||||||
|
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
|
||||||
|
</properties>
|
||||||
|
</project-shared-configuration>
|
20
module/cmd-list/pom.xml
Normal file
20
module/cmd-list/pom.xml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
<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">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>net.md-5</groupId>
|
||||||
|
<artifactId>bungeecord-module</artifactId>
|
||||||
|
<version>1.8-SNAPSHOT</version>
|
||||||
|
<relativePath>../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<groupId>net.md-5</groupId>
|
||||||
|
<artifactId>bungeecord-module-cmd-list</artifactId>
|
||||||
|
<version>1.8-SNAPSHOT</version>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>cmd_list</name>
|
||||||
|
<description>Provides the glist command</description>
|
||||||
|
</project>
|
@@ -1,7 +1,6 @@
|
|||||||
package net.md_5.bungee.command;
|
package net.md_5.bungee.module.cmd.list;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import net.md_5.bungee.Util;
|
import net.md_5.bungee.Util;
|
||||||
@@ -33,31 +32,16 @@ public class CommandList extends Command
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection<ProxiedPlayer> serverPlayers = server.getPlayers();
|
|
||||||
|
|
||||||
StringBuilder message = new StringBuilder();
|
|
||||||
message.append( ChatColor.GREEN );
|
|
||||||
message.append( "[" );
|
|
||||||
message.append( server.getName() );
|
|
||||||
message.append( "] " );
|
|
||||||
message.append( ChatColor.YELLOW );
|
|
||||||
message.append( "(" );
|
|
||||||
message.append( serverPlayers.size() );
|
|
||||||
message.append( "): " );
|
|
||||||
message.append( ChatColor.RESET );
|
|
||||||
|
|
||||||
List<String> players = new ArrayList<>();
|
List<String> players = new ArrayList<>();
|
||||||
for ( ProxiedPlayer player : serverPlayers )
|
for ( ProxiedPlayer player : server.getPlayers() )
|
||||||
{
|
{
|
||||||
players.add( player.getDisplayName() );
|
players.add( player.getDisplayName() );
|
||||||
}
|
}
|
||||||
Collections.sort( players, String.CASE_INSENSITIVE_ORDER );
|
Collections.sort( players, String.CASE_INSENSITIVE_ORDER );
|
||||||
|
|
||||||
message.append( Util.format( players, ChatColor.RESET + ", " ) );
|
sender.sendMessage( ProxyServer.getInstance().getTranslation( "command_list", server.getName(), server.getPlayers().size(), Util.format( players, ChatColor.RESET + ", " ) ) );
|
||||||
|
|
||||||
sender.sendMessage( message.toString() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sender.sendMessage( ProxyServer.getInstance().getTranslation( "total_players" ) + ProxyServer.getInstance().getOnlineCount() );
|
sender.sendMessage( ProxyServer.getInstance().getTranslation( "total_players", ProxyServer.getInstance().getOnlineCount() ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -0,0 +1,13 @@
|
|||||||
|
package net.md_5.bungee.module.cmd.list;
|
||||||
|
|
||||||
|
import net.md_5.bungee.api.plugin.Plugin;
|
||||||
|
|
||||||
|
public class PluginList extends Plugin
|
||||||
|
{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable()
|
||||||
|
{
|
||||||
|
getProxy().getPluginManager().registerCommand( this, new CommandList() );
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user