mirror of
https://codeberg.org/Andre601/AdvancedServerList.git
synced 2026-11-05 17:02:34 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba311f42c4 | ||
|
|
1b5379d54b | ||
|
|
03a1908ca6 | ||
|
|
f9574d2f83 | ||
|
|
7e45439dfe | ||
|
|
2a8b4ed640 | ||
|
|
86c053e445 | ||
|
|
7eba04bb9a | ||
|
|
b4ac677f67 | ||
|
|
989d44cc5e | ||
|
|
9821875e7a | ||
|
|
07e3b6702b | ||
|
|
31889fbd9c | ||
|
|
87a089a0fa | ||
|
|
88b91e8859 | ||
|
|
f8097e3c72 | ||
|
|
e237c990d8 | ||
|
|
21c0ba975c | ||
|
|
642ce922c3 | ||
|
|
6e5466aacf | ||
|
|
e6635cd844 | ||
|
|
229ab60c57 | ||
|
|
483daee999 | ||
|
|
31ffcd7f7b | ||
|
|
e5139cc00d | ||
|
|
9b1b95b27a | ||
|
|
88d3ceeaf3 | ||
|
|
f74f2f337c | ||
|
|
87b35f240e | ||
|
|
fc861ea304 | ||
|
|
927971ca12 | ||
|
|
0ecb8383e3 | ||
|
|
9c3b2220d5 | ||
|
|
46e15441fd | ||
|
|
2d2a1ca805 | ||
|
|
c577264e1d | ||
|
|
27c3972ab0 | ||
|
|
e4c90730ba | ||
|
|
0694e08399 | ||
|
|
2fefa966dd | ||
|
|
a57cf3df17 | ||
|
|
1ae7260cf3 | ||
|
|
8459eee57d | ||
|
|
f5cebf42ab | ||
|
|
731bdeba7d | ||
|
|
d14cda243a | ||
|
|
0a98aad138 | ||
|
|
1249a08264 | ||
|
|
c0414a5962 | ||
|
|
9cc4d4bb36 | ||
|
|
338358a2ab | ||
|
|
805ba83bb6 | ||
|
|
0f646a8f8d | ||
|
|
2519f09f6f | ||
|
|
60bca9e3d7 | ||
|
|
da8f72fc50 | ||
|
|
c42d4b8967 | ||
|
|
0110854ae4 | ||
|
|
d6d5952cbc | ||
|
|
f9d961cae7 | ||
|
|
a387feea23 | ||
|
|
359c58163b | ||
|
|
0892f5cd1d | ||
|
|
452a7e6dcf | ||
|
|
162dd10a73 | ||
|
|
35120c5364 | ||
|
|
6c828171d2 | ||
|
|
dcc51f8458 | ||
|
|
1287ca62fe | ||
|
|
1ff439fa95 | ||
|
|
ed0f832b2f | ||
|
|
b8e6b2acc6 | ||
|
|
fba32c91c5 | ||
|
|
6505ded12b | ||
|
|
53088affcb | ||
|
|
9c030764fa | ||
|
|
d5d58f1eea | ||
|
|
7181092821 | ||
|
|
fc5ee4f242 | ||
|
|
6e74c4fb14 | ||
|
|
f6a27342e6 | ||
|
|
38b50df2c9 | ||
|
|
db93816e55 | ||
|
|
244c2440fc | ||
|
|
8e2c644669 | ||
|
|
a68809ab31 | ||
|
|
4b4fd80abe | ||
|
|
48ea128267 | ||
|
|
68e5795618 | ||
|
|
1aa20e4196 | ||
|
|
6db25c8f9c | ||
|
|
0ef3db752d | ||
|
|
1a26f5ad34 | ||
|
|
17a5574be7 | ||
|
|
c7bfb8a736 | ||
|
|
7a756c3b98 | ||
|
|
1539e1c3c0 | ||
|
|
a86872c021 | ||
|
|
7d12499f39 | ||
|
|
455434b5f3 | ||
|
|
b66251ab20 | ||
|
|
4a1dfa5cb4 | ||
|
|
1efd65e16c | ||
|
|
908da9cd32 | ||
|
|
e8a30c6ef7 | ||
|
|
df164c104f | ||
|
|
acdf6f6e9a | ||
|
|
f52a63a8f1 | ||
|
|
6a92cb3a16 | ||
|
|
1175451753 | ||
|
|
5c4130411b | ||
|
|
05727eeec5 | ||
|
|
10af949abc | ||
|
|
9851347e74 | ||
|
|
c3e01c8b9c | ||
|
|
a646d9e998 | ||
|
|
3c50a30d4a | ||
|
|
4328ad6b44 | ||
|
|
34b0555508 | ||
|
|
c92cd0058b | ||
|
|
2cfe8b8a27 | ||
|
|
6530fed704 | ||
|
|
7efb203e7b | ||
|
|
1a34376100 | ||
|
|
ec1aa5b393 | ||
|
|
9683d3c001 | ||
|
|
db60545fcc | ||
|
|
392495ef63 | ||
|
|
903764b234 | ||
|
|
72329ed1e4 | ||
|
|
c516b56053 | ||
|
|
5e4295fbfb | ||
|
|
b140c0aa32 | ||
|
|
8f7b293541 | ||
|
|
6f878164c5 | ||
|
|
a16801ff56 | ||
|
|
65a89cf762 | ||
|
|
27d4ada179 | ||
|
|
574edfb246 | ||
|
|
7b7aad9d4e | ||
|
|
c5c9ed8109 | ||
|
|
58fea4090d | ||
|
|
cd0aad6ec1 | ||
|
|
fa45844434 | ||
|
|
c4e2a144b5 | ||
|
|
7fe93c7021 | ||
|
|
1d413a5c2a | ||
|
|
51db52dbdd | ||
|
|
4ade528188 | ||
|
|
64ba48a7c7 | ||
|
|
ac4edb2b97 | ||
|
|
3ea000c98b | ||
|
|
746bef13e1 | ||
|
|
355ab73546 | ||
|
|
67170c70e0 | ||
|
|
f99c2df4e8 | ||
|
|
212ec04fb8 | ||
|
|
89c6089101 | ||
|
|
87bce39d9a | ||
|
|
18900547a0 | ||
|
|
5df2e05a14 | ||
|
|
d4e4173cc3 | ||
|
|
562ad481c5 | ||
|
|
a0ee2a4322 | ||
|
|
2c92efdb43 | ||
|
|
555dc9d6a5 | ||
|
|
27742c5e1b | ||
|
|
280aeb8d2e | ||
|
|
92a868f0fa | ||
|
|
189ac5e09b | ||
|
|
833cb81d65 | ||
|
|
ab09422da5 | ||
|
|
64cad6dc26 | ||
|
|
ce78b493f4 | ||
|
|
c43048ea3f | ||
|
|
6d4d1600ab | ||
|
|
f114e99b9b | ||
|
|
3d587bc86d | ||
|
|
bd8c6be7c6 | ||
|
|
b5d5d508e2 | ||
|
|
3001b65fe8 | ||
|
|
c82771db59 | ||
|
|
9880836c25 | ||
|
|
f12ae28722 | ||
|
|
42b0f0e94f | ||
|
|
0a4b872051 | ||
|
|
b1322105ed | ||
|
|
831ca57fbb | ||
|
|
6502639cd3 | ||
|
|
5059b80db2 | ||
|
|
ecdaf72963 | ||
|
|
28e2ca69ed | ||
|
|
9cad78b6e4 | ||
|
|
af8654666b | ||
|
|
6cd474b35d | ||
|
|
3802ab556c | ||
|
|
3a520eeaf0 | ||
|
|
204f43c112 | ||
|
|
fc8ed8e49e | ||
|
|
56082c308b | ||
|
|
205e563095 | ||
|
|
5b01940c60 | ||
|
|
cbb087e3d1 | ||
|
|
524b926244 | ||
|
|
4059bbfe93 | ||
|
|
9b0b69a4f4 | ||
|
|
10a82eb951 | ||
|
|
690f7dfaf0 | ||
|
|
6a22d20b3a | ||
|
|
b1072bb1fa | ||
|
|
d20da91bab | ||
|
|
17e9692028 | ||
|
|
45dc8a5fe6 | ||
|
|
a237ac1ce4 | ||
|
|
27e66a16b9 | ||
|
|
8f98846bc3 | ||
|
|
bbcab59845 | ||
|
|
3130e07070 | ||
|
|
7bc61ddf4d | ||
|
|
53d15a9011 | ||
|
|
8718e4a0ae | ||
|
|
06a49956af | ||
|
|
38ec131b69 | ||
|
|
1bdaa61dd9 | ||
|
|
080d5055c4 | ||
|
|
423b363964 | ||
|
|
6b9abfccfc | ||
|
|
f589a8da35 | ||
|
|
465581306f | ||
|
|
6b2919961b | ||
|
|
adb6e797b2 | ||
|
|
b410b9438f | ||
|
|
c1d5b4efa9 | ||
|
|
4785dd127e | ||
|
|
9e8e2f7e74 | ||
|
|
c14dfe0f3a | ||
|
|
ed92e7002c | ||
|
|
8f93d9732c | ||
|
|
96f8fa5860 | ||
|
|
bfb857bd5c | ||
|
|
5fe3b5811c | ||
|
|
2a7eff0092 | ||
|
|
1907f5d47e | ||
|
|
aa92350b52 | ||
|
|
869b9bd3b7 | ||
|
|
fe31dcf0a4 | ||
|
|
6b44438f52 | ||
|
|
6b0c654f41 | ||
|
|
c28ff3a891 | ||
|
|
f424b41c3b | ||
|
|
b5f901d8f5 | ||
|
|
29d52492fc | ||
|
|
2d6af20bdc | ||
|
|
59c913ecf8 | ||
|
|
4a50beb4e0 | ||
|
|
c099127272 | ||
|
|
15974b5c54 | ||
|
|
483afe63c4 | ||
|
|
f0cb458a34 | ||
|
|
2c547cd6d0 | ||
|
|
e7282b4a97 | ||
|
|
4fc0ad97fc | ||
|
|
3ae02167b9 | ||
|
|
e407b38565 | ||
|
|
c98d52ed46 | ||
|
|
266913e4b4 | ||
|
|
a3d4a009a5 | ||
|
|
18e00d082e | ||
|
|
6a3979743b | ||
|
|
3a29ad54ca | ||
|
|
987c520160 | ||
|
|
4b6197f6e0 | ||
|
|
01611d4130 | ||
|
|
531aa65fcc | ||
|
|
fb101c4a14 | ||
|
|
7bd97f5f5a | ||
|
|
52c3edd0ea | ||
|
|
368e544051 | ||
|
|
12b2f5a208 | ||
|
|
adc88a8640 | ||
|
|
817db44492 | ||
|
|
f74f7dfa6b | ||
|
|
e9c8730090 | ||
|
|
861ada0396 | ||
|
|
a2fb9c3d81 | ||
|
|
f747461018 | ||
|
|
f408146d57 | ||
|
|
c684001fcf | ||
|
|
6dc53c8c4f | ||
|
|
64ab958c67 | ||
|
|
7a66c9a0c9 | ||
|
|
0ff658632a | ||
|
|
ee32347bd0 | ||
|
|
9e11038e98 | ||
|
|
008ddbb98a | ||
|
|
f084c17d76 | ||
|
|
9dd73aec9d | ||
|
|
3ebf151f3a | ||
|
|
872c194a62 | ||
|
|
d122603c70 | ||
|
|
489fce2031 | ||
|
|
1651151f26 | ||
|
|
aa61ea826f | ||
|
|
0877eb4187 | ||
|
|
6e89cdb3cc | ||
|
|
1eb0b30356 | ||
|
|
417f5dc5d0 | ||
|
|
01a73b9ea3 | ||
|
|
c06788a55c | ||
|
|
fd924107bc | ||
|
|
dce90b91f0 | ||
|
|
aa968b7d25 | ||
|
|
137d089e4a | ||
|
|
bfa27f92e1 | ||
|
|
b405706b50 | ||
|
|
89f44d7bec | ||
|
|
28e9b6ed96 | ||
|
|
19b3eec401 | ||
|
|
c712b3b715 | ||
|
|
5c379c3b13 | ||
|
|
f6f48708d9 | ||
|
|
83890fa5cb | ||
|
|
d7653a6a6f | ||
|
|
676c4c8f1f | ||
|
|
b66870c942 | ||
|
|
af97a0dac2 | ||
|
|
d43ef090ef | ||
|
|
e7451ae567 | ||
|
|
cf4f095624 | ||
|
|
9280809ab0 | ||
|
|
875ae4d43d | ||
|
|
dbd45ac65e | ||
|
|
7c15778ebc | ||
|
|
2699856a75 | ||
|
|
b49c105620 | ||
|
|
2ffbfeec48 | ||
|
|
bd885e25e2 | ||
|
|
e2c6eb142c | ||
|
|
db11e42c6d | ||
|
|
36e5829943 | ||
|
|
7bbb2bbfa7 | ||
|
|
6acd536f43 | ||
|
|
64d1440ad2 | ||
|
|
6f1dd78aa7 | ||
|
|
4330978816 | ||
|
|
935603b852 | ||
|
|
9671938a66 | ||
|
|
5cc974eb9c | ||
|
|
e526cc6750 | ||
|
|
34fea78b01 | ||
|
|
072547005c | ||
|
|
cdb5852e8b | ||
|
|
050477c19f | ||
|
|
52b24bb3e9 | ||
|
|
df8a063369 | ||
|
|
3fc4a788b8 | ||
|
|
15e5108ec7 | ||
|
|
b8fa694e26 | ||
|
|
f1b55cba79 | ||
|
|
e76dd78cd5 | ||
|
|
09a668493b | ||
|
|
1ef466d2a4 | ||
|
|
e15ddbf2d4 | ||
|
|
1c0ce073e5 | ||
|
|
5964be18ed | ||
|
|
06ad4f106b | ||
|
|
adf343468f | ||
|
|
5a0bb3ce03 | ||
|
|
b3edb2833e | ||
|
|
83c2017544 | ||
|
|
42ecf8ec2a | ||
|
|
fe53c28f77 | ||
|
|
44e8b395f5 | ||
|
|
13828897a2 | ||
|
|
965a9898ca | ||
|
|
d3c9d1e7e2 | ||
|
|
ff3df14a90 | ||
|
|
374f477645 | ||
|
|
11bcbc7918 | ||
|
|
f91f77dba0 | ||
|
|
ac36bc7c6c | ||
|
|
184aa7cd83 | ||
|
|
e20a80b410 | ||
|
|
43f5cbdcf1 | ||
|
|
7c8d6067f5 | ||
|
|
5500239146 | ||
|
|
62844f3111 | ||
|
|
37df1c6376 | ||
|
|
abe1dea027 | ||
|
|
66500050fe | ||
|
|
2bc2f11fb1 | ||
|
|
4b88c78036 | ||
|
|
5a98301b7d | ||
|
|
2cf7fd4ffc | ||
|
|
83349e1c37 | ||
|
|
d928991ca5 | ||
|
|
8b3cd0fcee | ||
|
|
2afd7483df | ||
|
|
ae108d1bed | ||
|
|
37e343e92e | ||
|
|
8b01a12ef9 | ||
|
|
91ea80fbde | ||
|
|
deec676180 | ||
|
|
5fb22a505f | ||
|
|
539a1300d2 | ||
|
|
915fe7b134 | ||
|
|
da393a66c1 | ||
|
|
6563b93721 | ||
|
|
c8e51ab82e | ||
|
|
435fbe721d | ||
|
|
3677e90ad1 | ||
|
|
cd96a87028 | ||
|
|
3b1e5244e4 | ||
|
|
07a1baff36 | ||
|
|
c87f6d5a0d | ||
|
|
36f6c41059 | ||
|
|
fa0170fa16 | ||
|
|
c66936861f | ||
|
|
8933c39ce0 | ||
|
|
34865b5bb8 | ||
|
|
271ebed7b6 | ||
|
|
08e7eca34f | ||
|
|
0162bcdaaf | ||
|
|
39e76862d5 | ||
|
|
a7aeffa52a | ||
|
|
9f847ca1db | ||
|
|
6f4a429123 | ||
|
|
60db6eb445 | ||
|
|
5c06fec00a | ||
|
|
12eb80d4d7 | ||
|
|
c371bf323c | ||
|
|
8dca20c73d | ||
|
|
aabfb5273e | ||
|
|
a282382402 | ||
|
|
e86733052b | ||
|
|
a112036c2e | ||
|
|
6c07bfb5a3 | ||
|
|
7668a3e881 | ||
|
|
f53f2c724d | ||
|
|
5ea6f9307c | ||
|
|
8bdaa232ca | ||
|
|
1ad945a1a9 | ||
|
|
85d11e7896 | ||
|
|
bcd940d808 | ||
|
|
dd837b96e8 | ||
|
|
57295756fc | ||
|
|
9f1307f559 | ||
|
|
c489764b06 | ||
|
|
845b1b2022 | ||
|
|
3662a66ec9 | ||
|
|
e1e0083633 | ||
|
|
58e4624cf5 | ||
|
|
df069ebcdc | ||
|
|
82f2c476d8 | ||
|
|
3545cac908 | ||
|
|
cb95b833e6 | ||
|
|
e2c1c44537 | ||
|
|
aeb0587263 | ||
|
|
3471876687 | ||
|
|
82d58564ee | ||
|
|
d3918a487a | ||
|
|
a25232be6a | ||
|
|
bfa05f943a | ||
|
|
dc40a54999 | ||
|
|
682621e196 | ||
|
|
41fa678591 | ||
|
|
e7557da944 | ||
|
|
c7c9885e18 | ||
|
|
62c665a598 | ||
|
|
6d687d391d | ||
|
|
2ac6b89368 | ||
|
|
b8d4829e02 | ||
|
|
a9b4355ebf | ||
|
|
b7f3ecdc5d | ||
|
|
0428280480 | ||
|
|
31e7fb9a22 | ||
|
|
b3fc768ea7 | ||
|
|
7b990e798d | ||
|
|
7e1e00d246 | ||
|
|
15677e948d | ||
|
|
457f85d697 | ||
|
|
f3a3df648f | ||
|
|
000f3dd680 | ||
|
|
db3b0e39b5 | ||
|
|
e5a5cf9f7e | ||
|
|
0c3853de2b | ||
|
|
0146e594de | ||
|
|
1a790bca41 | ||
|
|
fc039ebe93 | ||
|
|
22561f6848 | ||
|
|
8a7ccc07ae | ||
|
|
b43f7b9f31 | ||
|
|
69b3086c65 | ||
|
|
e5b05b5859 | ||
|
|
a07994adb1 | ||
|
|
8d83b45657 | ||
|
|
22371715c5 | ||
|
|
8a7d042476 | ||
|
|
26205cdd67 | ||
|
|
ccb9cd5522 | ||
|
|
2383214b7e | ||
|
|
a82b6bf0e9 | ||
|
|
3e541e65ed | ||
|
|
314becdc45 | ||
|
|
8f662ced5c | ||
|
|
3ff782e128 | ||
|
|
6a6a708ee7 | ||
|
|
1751a77e6f | ||
|
|
3069244f21 | ||
|
|
99d4232304 | ||
|
|
ec408316bd | ||
|
|
eee5271966 | ||
|
|
34e4816517 | ||
|
|
7bde6dedb5 | ||
|
|
6864f57917 | ||
|
|
0b705ca897 | ||
|
|
4661d72f8c | ||
|
|
2b7053c724 | ||
|
|
8d81367354 | ||
|
|
facb358404 | ||
|
|
fd49e101ca | ||
|
|
a55e19bb4a | ||
|
|
07c1893895 | ||
|
|
eed3c37bcb | ||
|
|
42d9a54668 | ||
|
|
51811452fd | ||
|
|
0b21958826 | ||
|
|
f3fdc68dce | ||
|
|
3b76a2abdd | ||
|
|
87964d42a7 | ||
|
|
2529195097 | ||
|
|
62e54fe9ea | ||
|
|
ad49a0659e | ||
|
|
a703fba542 | ||
|
|
bc57b549d5 | ||
|
|
eed64e0f60 | ||
|
|
a673050489 | ||
|
|
d07890112d | ||
|
|
9cbd7fb6b7 | ||
|
|
5055c89cde | ||
|
|
eb04cab549 | ||
|
|
db2e56a382 | ||
|
|
71313afb01 | ||
|
|
039f2f7b8a | ||
|
|
b34c7b3cec | ||
|
|
40e1fb1f02 | ||
|
|
9292a46a86 | ||
|
|
fbb7e0f103 | ||
|
|
c6b6187fe8 | ||
|
|
937929c3c5 | ||
|
|
04534e18c3 | ||
|
|
6a3adee315 | ||
|
|
dddea9c022 | ||
|
|
a5029f22ad | ||
|
|
e425ae4ce3 | ||
|
|
48163610a4 | ||
|
|
78fc37c2d7 | ||
|
|
61aceb3fe8 | ||
|
|
2ccb2a470f | ||
|
|
849ea169a2 | ||
|
|
da7ae22535 | ||
|
|
fbd8d9fffa | ||
|
|
df10bdcc65 | ||
|
|
da1ada5a10 | ||
|
|
21f083dda1 | ||
|
|
e7882d1be8 | ||
|
|
81ed3a441f | ||
|
|
41381f498e | ||
|
|
e669a995a7 | ||
|
|
aad10a1146 | ||
|
|
eb4455797a | ||
|
|
02f1e68522 | ||
|
|
933d5f1e48 | ||
|
|
50e2fa95bf | ||
|
|
c908e6dc21 | ||
|
|
ccbe2afffb | ||
|
|
3d94259160 | ||
|
|
ee6d596493 | ||
|
|
8c608b60bd | ||
|
|
2b5e7d98c8 | ||
|
|
ee6e879c08 | ||
|
|
639084806a | ||
|
|
74a929d0ad | ||
|
|
5caffcb49a | ||
|
|
ce73d3c0e7 | ||
|
|
a0b59aecc8 | ||
|
|
3758a99ae2 | ||
|
|
1f45f5c3e5 | ||
|
|
937dc93366 | ||
|
|
b4dffedd09 | ||
|
|
ae1e16ca8b | ||
|
|
775482ea0f | ||
|
|
6fa848f730 | ||
|
|
6a1d720f08 | ||
|
|
7d72af0e44 | ||
|
|
ef1a34bdec | ||
|
|
c30334d2af | ||
|
|
da71fc0af9 | ||
|
|
f5ff4702e5 | ||
|
|
257031827d | ||
|
|
5e9c6f43fe | ||
|
|
bfc76290a7 | ||
|
|
4d8139bb3e | ||
|
|
77cc783855 | ||
|
|
d01605ee47 | ||
|
|
8128f3e4af | ||
|
|
10436a55bb | ||
|
|
740bf63afa | ||
|
|
9508f34cc2 | ||
|
|
10de3a42f4 | ||
|
|
407008284b | ||
|
|
e2fd877e91 | ||
|
|
ca16f618d8 | ||
|
|
80731117a3 | ||
|
|
dc62ef0989 | ||
|
|
13209e7a79 | ||
|
|
8edb7b194a | ||
|
|
354b5f83b2 | ||
|
|
5e568c68c4 | ||
|
|
5cc9678b5a | ||
|
|
ae5a5973aa | ||
|
|
5a589b2297 | ||
|
|
e6bc14fca5 | ||
|
|
95d67a270b | ||
|
|
559d5a2d9b | ||
|
|
a60bffa04d | ||
|
|
1a5dd75157 | ||
|
|
f5113d3d45 | ||
|
|
cddd2dbeb7 | ||
|
|
10da7c9eeb | ||
|
|
e50bbf4620 | ||
|
|
fe1b6dc0e5 | ||
|
|
a20acf5378 | ||
|
|
1d74640d67 | ||
|
|
20e3f908f9 | ||
|
|
8b2a499d20 | ||
|
|
d8ba5ffaea | ||
|
|
608c617b17 | ||
|
|
50d47a0c65 | ||
|
|
1d41072767 | ||
|
|
2ffd7f479b | ||
|
|
38f1e4f21d | ||
|
|
33f29b5694 | ||
|
|
4b6901467f | ||
|
|
62dc420d55 | ||
|
|
d7cb52d785 | ||
|
|
67bdd98a5b | ||
|
|
ffa0da8f1c | ||
|
|
abb2378bf2 | ||
|
|
d10c6ffb78 | ||
|
|
e2b4fdf72f | ||
|
|
993c665445 | ||
|
|
607b95b723 | ||
|
|
8476e72e9a | ||
|
|
57b782d7d7 | ||
|
|
2dd3b04dbe | ||
|
|
38d6ac3972 | ||
|
|
360b961221 | ||
|
|
ef22ede56d | ||
|
|
afa18b81fe | ||
|
|
ec9ea799cf | ||
|
|
99f762ff18 | ||
|
|
2bd59ff554 | ||
|
|
53157a7c06 | ||
|
|
bfc39ab172 | ||
|
|
fa44192bd3 | ||
|
|
53fc434bdd | ||
|
|
b6152372a8 | ||
|
|
5441d2bd96 | ||
|
|
2d358f76c0 | ||
|
|
d1cbaa3ef6 | ||
|
|
29513d953d | ||
|
|
365ec3d6f5 | ||
|
|
d4babddc31 | ||
|
|
648b656dd4 | ||
|
|
b2b71144d9 | ||
|
|
17357345ab | ||
|
|
f696fc2160 | ||
|
|
b9885c1249 | ||
|
|
e357f370e0 | ||
|
|
d777ac84f0 | ||
|
|
5da627b1b6 | ||
|
|
8ee063daec | ||
|
|
ad46149bb6 | ||
|
|
528226401f | ||
|
|
97a71958e1 | ||
|
|
b15d5f0633 | ||
|
|
b4e39ca985 | ||
|
|
5aae2cccdc | ||
|
|
c7ccd48037 | ||
|
|
2b6c904fbf | ||
|
|
eeefea3f6a | ||
|
|
2840c29a90 | ||
|
|
862e631405 | ||
|
|
f00737b0f0 | ||
|
|
2d4d1d3136 | ||
|
|
04d255bb54 | ||
|
|
f77db9c760 | ||
|
|
9cde35aa2f | ||
|
|
13ca53140c | ||
|
|
bc1d0722fa | ||
|
|
6201342ca7 | ||
|
|
801e0a2749 | ||
|
|
10718e6d03 | ||
|
|
03203345c0 | ||
|
|
3ade0952e2 | ||
|
|
f0e30d47dc | ||
|
|
bb94510858 | ||
|
|
c9d94619dd | ||
|
|
7ab8749421 | ||
|
|
a9216cc82c | ||
|
|
f14ef643b8 | ||
|
|
cc876d2f21 | ||
|
|
0f8693add2 | ||
|
|
dcc9d18dbe | ||
|
|
f579aa0088 | ||
|
|
579b945fbd | ||
|
|
664bea8109 | ||
|
|
73d94e99e4 | ||
|
|
389ed1df53 | ||
|
|
5f4a07cb71 | ||
|
|
b16f5e193c | ||
|
|
1c423e6cfa | ||
|
|
a27dcd5248 | ||
|
|
17bd1782fb | ||
|
|
96c44dafe2 | ||
|
|
d4d9a7e3c5 | ||
|
|
9f0f7297f0 | ||
|
|
691cb14c63 | ||
|
|
8670ea026e | ||
|
|
27c019c00d | ||
|
|
d34ea9c2ad | ||
|
|
74a61f2e09 | ||
|
|
5e550d5a7f | ||
|
|
b1180c0a8e | ||
|
|
fc4253acce | ||
|
|
a4e2cc29d5 | ||
|
|
95097a581a | ||
|
|
aff3aefb72 | ||
|
|
089e56be70 | ||
|
|
e7b8f1a0dc | ||
|
|
a2252f55c4 | ||
|
|
dcd6a1e867 | ||
|
|
24bf5193ff | ||
|
|
2e0068115d | ||
|
|
1accbfb5f0 | ||
|
|
f0f520d12b | ||
|
|
3edef1c2e4 | ||
|
|
0c835da51a | ||
|
|
1dc937e7b6 | ||
|
|
8d63d92ab0 | ||
|
|
2ade1c2506 | ||
|
|
c1b699aab7 | ||
|
|
6d5fc7a697 | ||
|
|
a5acd73482 | ||
|
|
f1afcc0fd8 | ||
|
|
9922485c34 | ||
|
|
9ee543fe28 | ||
|
|
da4eccdfcc | ||
|
|
89f5a45809 | ||
|
|
29664fde70 | ||
|
|
40f362f1de | ||
|
|
07cef34a37 | ||
|
|
afa80581e5 | ||
|
|
db2366e2ce | ||
|
|
b54151813f | ||
|
|
2be041a613 | ||
|
|
86411571ef | ||
|
|
d80236fef8 | ||
|
|
fe6fae58e3 | ||
|
|
b2e2b18d33 | ||
|
|
d8e54c7ff0 | ||
|
|
f0743d691f | ||
|
|
4b68253c7d | ||
|
|
d1cee68355 | ||
|
|
07d3ea088a | ||
|
|
912fb967fb | ||
|
|
d960644cc1 | ||
|
|
34908b4123 | ||
|
|
00466f1ffb | ||
|
|
d05527634d | ||
|
|
6e017219b4 | ||
|
|
8fa66867bc | ||
|
|
1df167b66a | ||
|
|
ffee02095f | ||
|
|
0fc7c7f047 | ||
|
|
c8ae03da16 | ||
|
|
dc4165465e | ||
|
|
05c32cd721 | ||
|
|
ccd326f036 | ||
|
|
e9117c8040 | ||
|
|
116714f9a4 | ||
|
|
06f025c50e | ||
|
|
25787e8c51 | ||
|
|
741ca73c62 | ||
|
|
50944717ea | ||
|
|
89d2d04c12 | ||
|
|
2aa53c556a | ||
|
|
7eb67c1571 | ||
|
|
e6ebf0964b | ||
|
|
2f7bbe8bae | ||
|
|
cc3e75f41b | ||
|
|
7706dd245f | ||
|
|
d4018ff666 | ||
|
|
4c7a2ca94d | ||
|
|
21632711ea | ||
|
|
e82ed84c11 | ||
|
|
1f44b34dd2 | ||
|
|
b7b6d8b82b | ||
|
|
53e270b183 | ||
|
|
f633bb393e | ||
|
|
41ac71e346 | ||
|
|
e04b9b4a09 | ||
|
|
42907c7f74 | ||
|
|
69bf90c20f | ||
|
|
b2f70b605c | ||
|
|
fb5e4b57bc | ||
|
|
49c17d941a | ||
|
|
ec6b852497 | ||
|
|
9bd2c4b8d5 | ||
|
|
57bb677578 | ||
|
|
40c4726fd6 | ||
|
|
c1eefbe114 | ||
|
|
082345fb66 | ||
|
|
1bedc472b3 | ||
|
|
aa9d6ff7d2 | ||
|
|
5e4fc3d69c | ||
|
|
b429e75797 | ||
|
|
c2eacf716f | ||
|
|
aca52b528d | ||
|
|
cd1469c554 | ||
|
|
ce4347ca1e | ||
|
|
acc59e0af7 | ||
|
|
099abcda67 | ||
|
|
2ced4db199 | ||
|
|
4f7c16ae5a | ||
|
|
06739bb68e | ||
|
|
d1c9ab5b82 | ||
|
|
d06f767e51 | ||
|
|
02e0821bd0 | ||
|
|
981d4e8146 | ||
|
|
05667c0f87 | ||
|
|
54f0f59925 | ||
|
|
de2c8a7547 | ||
|
|
50c31a3348 | ||
|
|
93e94aa9d3 | ||
|
|
1f71aeb7e5 | ||
|
|
5d01adfa49 | ||
|
|
da7e3eca09 | ||
|
|
66b305bbea | ||
|
|
3c1abf4f3a | ||
|
|
856be1e32e | ||
|
|
5303bb00a0 | ||
|
|
9b43428e5d | ||
|
|
d34d926f9a | ||
|
|
844279b32d | ||
|
|
5916e9b495 | ||
|
|
72384488d8 | ||
|
|
11a8b07f32 | ||
|
|
cd7dfc9c15 | ||
|
|
c715ed6163 | ||
|
|
5a35ebbef4 | ||
|
|
830eee5da3 | ||
|
|
09b845e86e | ||
|
|
a2bdd5c4e5 | ||
|
|
a72c0d326a | ||
|
|
40ef2e35d4 | ||
|
|
8422d6d2de | ||
|
|
4683dab513 | ||
|
|
d5947b20e5 | ||
|
|
147f01dd1b | ||
|
|
a6eddb3828 | ||
|
|
41e11f79cc | ||
|
|
66597ce7fa | ||
|
|
77f17b202c | ||
|
|
d3673a79af | ||
|
|
29c6930ce1 | ||
|
|
125e9c0918 | ||
|
|
2ac6931f26 | ||
|
|
e301ef38f0 | ||
|
|
3f6ada4599 | ||
|
|
45d3f17faa | ||
|
|
d8fca2ca03 | ||
|
|
730b2e3aa8 | ||
|
|
e4e3543b9b | ||
|
|
a955109db5 | ||
|
|
d399c7df63 | ||
|
|
973620925d | ||
|
|
697e9e265d | ||
|
|
cabed6aa65 | ||
|
|
b408658026 | ||
|
|
15f611445c | ||
|
|
a8d6fc48bf | ||
|
|
c964c942dc | ||
|
|
27c591d92c | ||
|
|
de2d43f01c | ||
|
|
3fde989eb5 | ||
|
|
c1fa8d0df1 | ||
|
|
f0446fe8f4 | ||
|
|
5509fb4380 | ||
|
|
d0f7bf9897 |
No files matched your search
@@ -0,0 +1,41 @@
|
||||
name: API support
|
||||
description: Ask for help with the API.
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |-
|
||||
## Before opening
|
||||
Please make sure you've checked the following things first:
|
||||
|
||||
- You're using the latest release of AdvancedServerList [[Download from Modrinth](https://modrinth.com/plugin/advancedserverlist)] and the right API version.
|
||||
- You're using a supported Proxy/Server version. As of right now is only 1.19+ supported.
|
||||
- The Feature you suggest hasn't been suggested before.
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Platforms
|
||||
description: On what platform(s) are you using the API?
|
||||
multiple: true
|
||||
options:
|
||||
- Proxy (BungeeCord, Waterfall, ...)
|
||||
- Proxy (Velocity)
|
||||
- Server (Spigot, Paper, ...)
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Description
|
||||
description: |-
|
||||
Give a detailed description of what exactly you try to do, what steps you did and what you need help with.
|
||||
placeholder: I tried to...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Code
|
||||
description: |-
|
||||
Provide code-snippets to help us better understand what you tried.
|
||||
The code is automatically parsed as Java Code.
|
||||
render: java
|
||||
validations:
|
||||
required: true
|
||||
@@ -9,7 +9,7 @@ body:
|
||||
Please make sure you've checked the following things first:
|
||||
|
||||
- You're using the latest release of AdvancedServerList [[Download from Modrinth](https://modrinth.com/plugin/advancedserverlist)]
|
||||
- You're using a supported Proxy/Server version. As of right now is only 1.19.x supported.
|
||||
- You're using a supported Proxy/Server version. As of right now is only 1.19+ supported.
|
||||
- The issue happens with just AdvancedServerList installed.
|
||||
- type: dropdown
|
||||
attributes:
|
||||
|
||||
@@ -5,4 +5,4 @@ contact_links:
|
||||
url: https://discord.gg/6dazXp6
|
||||
- name: Wiki
|
||||
about: Check the Wiki for explanations about the features and examples.
|
||||
url: https://github.com/Andre601/AdvancedServerList/wiki
|
||||
url: https://docs.andre601.ch/AdvancedServerList
|
||||
@@ -9,7 +9,7 @@ body:
|
||||
Please make sure you've checked the following things first:
|
||||
|
||||
- You're using the latest release of AdvancedServerList [[Download from Modrinth](https://modrinth.com/plugin/advancedserverlist)]
|
||||
- You're using a supported Proxy/Server version. As of right now is only 1.19.x supported.
|
||||
- You're using a supported Proxy/Server version. As of right now is only 1.19+ supported.
|
||||
- The Feature you suggest hasn't been suggested before.
|
||||
- type: dropdown
|
||||
attributes:
|
||||
|
||||
+30
-18
@@ -4,19 +4,19 @@ AdvancedServerList is a plugin that allowys you to customize your server's MOTD,
|
||||
## Supported Platforms
|
||||
|
||||
<a href="https://www.spigotmc.org" target="_blank">
|
||||
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/minimal/supported/spigot_vector.svg" width="64" alt="platform-spigot" title="Tested on Spigot">
|
||||
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact-minimal/supported/spigot_vector.svg&w=64 alt="platform-spigot" title="Tested on Spigot">
|
||||
</a>
|
||||
<a href="https://papermc.io" target="_blank">
|
||||
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/minimal/supported/paper_vector.svg" width="64" alt="platform-paper" title="Tested on Paper">
|
||||
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact-minimal/supported/paper_vector.svg&w=64 alt="platform-paper" title="Tested on Paper">
|
||||
</a>
|
||||
<a href="https://www.spigotmc.org" target="_blank">
|
||||
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/minimal/supported/bungeecord_vector.svg" width="64" alt="platform-bungeecord" title="Tested on BungeeCord">
|
||||
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact-minimal/supported/bungeecord_vector.svg&w=64 alt="platform-bungeecord" title="Tested on BungeeCord">
|
||||
</a>
|
||||
<a href="https://www.papermc.io" target="_blank">
|
||||
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/minimal/supported/waterfall_vector.svg" width="64" alt="platform-waterfall" title="Tested on Waterfall">
|
||||
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact-minimal/supported/waterfall_vector.svg&w=64 alt="platform-waterfall" title="Tested on Waterfall">
|
||||
</a>
|
||||
<a href="https://velocitypowered.com" target="_blank">
|
||||
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/minimal/supported/velocity_vector.svg" width="64" alt="platform-velocity" title="Tested on Velocity">
|
||||
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact-minimal/supported/velocity_vector.svg&w=64 alt="platform-velocity" title="Tested on Velocity">
|
||||
</a>
|
||||
|
||||
## What is a Server List Profile?
|
||||
@@ -24,12 +24,14 @@ A Server List Profile refers to a YAML file located in the plugin's `profiles` d
|
||||
It allows you to configure specific aspects of the server display in the MC-Client's multiplayer server list, such as the MOTD, player count text, player count hover or Favicon.
|
||||
|
||||
> [*Read More*][profiles]
|
||||
|
||||
### Conditions
|
||||
Thanks to conditions can you determine when a profile should be displayed in the player’s server list, to allow displaying specific text (i.e. a warning when they are using an outdated version).
|
||||
|
||||
When multiple profiles exist that have valid conditions will the one with the highest priority (Higher number = higher priority) be selected. Having no conditions makes the profile automatically return true.
|
||||
|
||||
> [*Read More*][conditions]
|
||||
|
||||
### Placeholders
|
||||
Placeholders can be used within conditions to further customize them. They can also be used in any other text option (motd, playerCount and players) to display their respective values.
|
||||
The format is `${<target> <identifier>}` which was adopted from BungeeTabListPlus. Depending on what platform you use the plugin on are only specific placeholders available.
|
||||
@@ -37,17 +39,20 @@ The format is `${<target> <identifier>}` which was adopted from BungeeTabListPlu
|
||||
When using the SpigotMC/PaperMC version can you also use placeholders from [PlaceholderAPI][placeholderapi] using its `%<identifier>_<values>%` placeholder format. PlaceholderAPI needs to be installed for that.
|
||||
|
||||
> [*Read More*][placeholders]
|
||||
|
||||
### Formatting
|
||||
The plugin uses the MiniMessage format for a consistent, easy way of formatting your text.
|
||||
Only certain options are usable for each option. As an example does motd support HEX colours and gradients, while the other options only support default colour codes.
|
||||
|
||||
> [*Read More*][minimessage]
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Dependency | Platforms | Required? |
|
||||
| ---------------- | ------------- | --------- |
|
||||
|------------------|---------------|-----------|
|
||||
| [ProtocolLib] | Spigot | Yes |
|
||||
| [PlaceholderAPI] | Spigot, Paper | No |
|
||||
| [ViaVersion] | Spigot, Paper | No |
|
||||
|
||||
## Statistics
|
||||
|
||||
@@ -58,35 +63,42 @@ You can disable this in the global bStats config file located in `/plugins/bstat
|
||||
- [Paper/Spigot][bstats-spigot]
|
||||
- [Velocity][bstats-velocity]
|
||||
|
||||
## Videos
|
||||
Do you have your own video to share? Contact me and I will add it to this section.
|
||||
|
||||
<details><summary>Click to Show/Hide Videos</summary>
|
||||
|
||||
Spanish Video by Ajneb97
|
||||
<iframe width="560" height="auto" src="https://www.youtube.com/embed/rIbljm_4HVI" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
|
||||
|
||||
</details>
|
||||
|
||||
## Screenshots
|
||||
|
||||
<a href="https://modrinth.com/plugin/advancedserverlist/gallery" target="_blank">
|
||||
<img src="https://raw.githubusercontent.com/intergrav/devins-badges/v2/assets/cozy/documentation/modrinth-gallery_vector.svg" width="208" alt="gallery" title="Check out the Gallery">
|
||||
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/cozy/documentation/modrinth-gallery_vector.svg&w=208" alt="gallery" title="Check out the Gallery">
|
||||
</a>
|
||||
|
||||
## Support
|
||||
<a href="https://discord.gg/6dazXp6" target="_blank">
|
||||
<img src="https://raw.githubusercontent.com/intergrav/devins-badges/v2/assets/minimal/social/discord-singular_vector.svg" width="64" alt="discord" title="Join my Discord Server">
|
||||
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact-minimal/social/discord-singular_vector.svg&w=64" alt="discord" title="Join my Discord Server">
|
||||
</a>
|
||||
<a href="https://app.revolt.chat/invite/74TpERXA" target="_blank">
|
||||
<img src="https://raw.githubusercontent.com/intergrav/devins-badges/v2/assets/minimal/social/revolt-singular_vector.svg" width="64" alt="revolt" title="Join my Revolt Server">
|
||||
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact-minimal/social/revolt-singular_vector.svg&w=64" alt="revolt" title="Join my Revolt Server">
|
||||
</a>
|
||||
<a href="https://blobfox.coffee/@andre_601" target="_blank">
|
||||
<img src="https://raw.githubusercontent.com/intergrav/devins-badges/v2/assets/minimal/social/mastodon-singular_vector.svg" width="64" alt="revolt" title="Chat with me on Mastodon">
|
||||
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact-minimal/social/mastodon-singular_vector.svg&w=64" alt="revolt" title="Chat with me on Mastodon">
|
||||
</a>
|
||||
|
||||
<!-- Links -->
|
||||
[profiles]: https://github.com/Andre601/AdvancedServerList/wiki/Profiles
|
||||
[conditions]: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#conditions
|
||||
[placeholders]: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#placeholders
|
||||
[minimessage]: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#minimessage
|
||||
|
||||
[placeholderapi]: https://www.spigotmc.org/resources/6245/
|
||||
|
||||
[modrinth]: https://modrinth.com/plugin/advancedserverlist
|
||||
[profiles]: https://docs.andre601.ch/AdvancedServerList/latest/profiles
|
||||
[conditions]: https://docs.andre601.ch/AdvancedServerList/latest/profiles/#conditions
|
||||
[placeholders]: https://docs.andre601.ch/AdvancedServerList/latest/profiles/placeholders
|
||||
[minimessage]: https://docs.andre601.ch/AdvancedServerList/latest/profiles/formatting
|
||||
|
||||
[protocollib]: https://www.spigotmc.org/resources/1997/
|
||||
[placeholderapi]: https://www.spigotmc.org/resources/6245/
|
||||
[viaversion]: https://www.spigotmc.org/resources/19254/
|
||||
|
||||
[bstats]: https://bstats.org
|
||||
[bstats-bungee]: https://bstats.org/plugin/bungeecord/AdvancedServerList/15585
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<!-- pr-build comment -->
|
||||
|
||||
![badge]
|
||||
|
||||
Building jar file from Pull request. Please wait...
|
||||
|
||||
[badge]: https://img.shields.io/badge/Building...-0d1117?style=for-the-badge&labelColor=7a8490&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiBmaWxsPSIjZmZmZmZmIj48cGF0aCBkPSJNNC43NSAyaDE0LjVhLjc1Ljc1IDAgMCAxIDAgMS41aC0uNzV2Mi45ODJhNC43NSA0Ljc1IDAgMCAxLTIuMjE1IDQuMDE3bC0yLjA0NCAxLjI5YS4yNS4yNSAwIDAgMCAwIC40MjJsMi4wNDQgMS4yOWE0Ljc1IDQuNzUgMCAwIDEgMi4yMTUgNC4wMTdWMjAuNWguNzVhLjc1Ljc1IDAgMCAxIDAgMS41SDQuNzVhLjc1Ljc1IDAgMCAxIDAtMS41aC43NXYtMi45ODJhNC43NSA0Ljc1IDAgMCAxIDIuMjE1LTQuMDE3bDIuMDQ0LTEuMjlhLjI1LjI1IDAgMCAwIDAtLjQyMmwtMi4wNDQtMS4yOUE0Ljc1IDQuNzUgMCAwIDEgNS41IDYuNDgyVjMuNWgtLjc1YS43NS43NSAwIDAgMSAwLTEuNVpNMTcgMy41SDd2Mi45ODJBMy4yNSAzLjI1IDAgMCAwIDguNTE2IDkuMjNsMi4wNDQgMS4yOWExLjc1IDEuNzUgMCAwIDEgMCAyLjk2bC0yLjA0NCAxLjI5QTMuMjUgMy4yNSAwIDAgMCA3IDE3LjUxOFYyMC41aDEwdi0yLjk4MmEzLjI1IDMuMjUgMCAwIDAtMS41MTYtMi43NDhsLTIuMDQ0LTEuMjlhMS43NSAxLjc1IDAgMCAxIDAtMi45NmwyLjA0NC0xLjI5QTMuMjUgMy4yNSAwIDAgMCAxNyA2LjQ4MloiPjwvcGF0aD48L3N2Zz4=
|
||||
@@ -0,0 +1,12 @@
|
||||
<!-- pr-build comment -->
|
||||
![badge]
|
||||
|
||||
**Compiling of jar files failed!**
|
||||
Please check the logs below for any errors.
|
||||
|
||||
| Name | Link |
|
||||
| ------ | -------------------------------- |
|
||||
| Commit | {{ .commit }} |
|
||||
| Logs | {{ .logs | mdlink "View Logs" }} |
|
||||
|
||||
[badge]: https://img.shields.io/badge/Build_Failure!-0d1117?style=for-the-badge&labelColor=f85149&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiBmaWxsPSIjZmZmZmZmIj48cGF0aCBkPSJNNS43MiA1LjcyYS43NS43NSAwIDAgMSAxLjA2IDBMMTIgMTAuOTRsNS4yMi01LjIyYS43NDkuNzQ5IDAgMCAxIDEuMjc1LjMyNi43NDkuNzQ5IDAgMCAxLS4yMTUuNzM0TDEzLjA2IDEybDUuMjIgNS4yMmEuNzQ5Ljc0OSAwIDAgMS0uMzI2IDEuMjc1Ljc0OS43NDkgMCAwIDEtLjczNC0uMjE1TDEyIDEzLjA2bC01LjIyIDUuMjJhLjc1MS43NTEgMCAwIDEtMS4wNDItLjAxOC43NTEuNzUxIDAgMCAxLS4wMTgtMS4wNDJMMTAuOTQgMTIgNS43MiA2Ljc4YS43NS43NSAwIDAgMSAwLTEuMDZaIj48L3BhdGg+PC9zdmc+
|
||||
@@ -0,0 +1,15 @@
|
||||
<!-- pr-build comment -->
|
||||
![badge]
|
||||
|
||||
The compiling of the jar files was successful!
|
||||
You can find a direct download for the artifact below.
|
||||
|
||||
File expires: `{{ .expire | date "02 Jan 2006 15:04 MST" }}`
|
||||
|
||||
| Name | Link |
|
||||
| -------- | -------------------------------------------- |
|
||||
| Commit | {{ .commit }} |
|
||||
| Logs | {{ .logs | mdlink "View Logs" }} |
|
||||
| Download | {{ .download | mdlink "Download Artifact" }} |
|
||||
|
||||
[badge]: https://img.shields.io/badge/Build_Success!-0d1117?style=for-the-badge&labelColor=3fb950&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiBmaWxsPSIjZmZmZmZmIj48cGF0aCBkPSJNMjEuMDMgNS43MmEuNzUuNzUgMCAwIDEgMCAxLjA2bC0xMS41IDExLjVhLjc0Ny43NDcgMCAwIDEtMS4wNzItLjAxMmwtNS41LTUuNzVhLjc1Ljc1IDAgMSAxIDEuMDg0LTEuMDM2bDQuOTcgNS4xOTVMMTkuOTcgNS43MmEuNzUuNzUgMCAwIDEgMS4wNiAwWiI+PC9wYXRoPjwvc3ZnPg==
|
||||
@@ -1,50 +0,0 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: maven
|
||||
directory: "/bungeecord"
|
||||
schedule:
|
||||
interval: daily
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- 'Type: Update Dependency'
|
||||
- 'Target: BungeeCord'
|
||||
- package-ecosystem: maven
|
||||
directory: "/core"
|
||||
schedule:
|
||||
interval: daily
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- 'Type: Update Dependency'
|
||||
- 'Target: Core'
|
||||
- package-ecosystem: maven
|
||||
directory: "/paper"
|
||||
schedule:
|
||||
interval: daily
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- 'Type: Update Dependency'
|
||||
- 'Target: PaperMC'
|
||||
- package-ecosystem: maven
|
||||
directory: "/spigot"
|
||||
schedule:
|
||||
interval: daily
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- 'Type: Update Dependency'
|
||||
- 'Target: Spigot'
|
||||
- package-ecosystem: maven
|
||||
directory: "/velocity"
|
||||
schedule:
|
||||
interval: daily
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- 'Type: Update Dependency'
|
||||
- 'Target: Velocity'
|
||||
- package-ecosystem: github-actions
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
open-pull-requests-limit: 10
|
||||
labels:
|
||||
- 'Type: Update Dependency'
|
||||
- 'Target: GitHub Action'
|
||||
@@ -0,0 +1,14 @@
|
||||
"Target: All":
|
||||
- all: ["bukkit/**", "bungeecord/**", "core/**", "velocity/**"]
|
||||
|
||||
"Target: Bukkit":
|
||||
- all: ["bukkit/**", "!bungeecord/**", "!core/**", "!velocity/**"]
|
||||
|
||||
"Target: BungeeCord":
|
||||
- all: ["!bukkit/**", "bungeecord/**", "!core/**", "!velocity/**"]
|
||||
|
||||
"Target: Core":
|
||||
- all: ["!bukkit/**", "!bungeecord/**", "core/**", "!velocity/**"]
|
||||
|
||||
"Target: Velocity":
|
||||
- all: ["!bukkit/**", "!bungeecord/**", "!core/**", "velocity/**"]
|
||||
@@ -0,0 +1,49 @@
|
||||
name: 'Deploy Site (Push)'
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
GITHUB_REPO_INSTANCE: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python 3.7
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.x
|
||||
- name: Create/Get Cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
key: ${{ github.ref }}
|
||||
path: .cache
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip setuptools
|
||||
python -m pip install -r requirements.txt
|
||||
- name: Build docs
|
||||
run: mkdocs build
|
||||
- name: Configure GitHub Pages
|
||||
uses: actions/configure-pages@v4
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: 'site/'
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
@@ -1,105 +0,0 @@
|
||||
#
|
||||
# Big thank you to @Kir-Antipov for providing this workflow file.
|
||||
# Check out his mc-publish action here: https://github.com/Kir-Antipov/mc-publish
|
||||
#
|
||||
|
||||
name: Publish Assets
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
|
||||
jobs:
|
||||
buildJars:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up JDK 1.16
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '16'
|
||||
cache: 'maven'
|
||||
- name: Build Jar files
|
||||
run: mvn clean install
|
||||
- name: Save BungeeCord Jar file
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: asl-bungeecord
|
||||
path: bungeecord/target/AdvancedServerList-*.jar
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
- name: Save Paper Jar file
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: asl-paper
|
||||
path: paper/target/AdvancedServerList-*.jar
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
- name: Save Spigot Jar file
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: asl-spigot
|
||||
path: spigot/target/AdvancedServerList-*.jar
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
- name: Save Velocity Jar file
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: asl-velocity
|
||||
path: velocity/target/AdvancedServerList-*.jar
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
publish:
|
||||
needs: [buildJars]
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- platforms: BungeeCord, Waterfall
|
||||
directory: bungeecord
|
||||
loaders: |
|
||||
bungeecord
|
||||
waterfall
|
||||
- platforms: Paper
|
||||
directory: paper
|
||||
loaders: paper
|
||||
- platforms: Spigot
|
||||
directory: spigot
|
||||
loaders: spigot
|
||||
- platforms: Velocity
|
||||
directory: velocity
|
||||
loaders: velocity
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Get Jar files
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: asl-${{ matrix.directory }}
|
||||
path: ${{ matrix.directory }}/target
|
||||
- name: Get Version
|
||||
id: github-release
|
||||
run: |
|
||||
version=$(echo ${{ github.event.release.tag_name }} | cut -d'v' -f2)
|
||||
echo "PLUGIN_RELEASE=$version" >> $GITHUB_OUTPUT
|
||||
- name: Upload AdvancedServerList (${{ matrix.loaders }}) to GitHub and Modrinth
|
||||
uses: Kir-Antipov/mc-publish@v3.2
|
||||
with:
|
||||
name: ${{ github.event.release.tag_name }} (${{ matrix.platforms }})
|
||||
version: ${{ steps.github-release.outputs.PLUGIN_RELEASE }}
|
||||
version-type: release
|
||||
files: ${{ matrix.directory}}/target/AdvancedServerList-*.jar
|
||||
files-secondary: ""
|
||||
loaders: ${{ matrix.loaders }}
|
||||
version-resolver: releases
|
||||
game-versions: |
|
||||
1.19
|
||||
1.19.1
|
||||
1.19.2
|
||||
1.19.3
|
||||
java: 16
|
||||
modrinth-id: xss83sOY
|
||||
modrinth-featured: false
|
||||
modrinth-token: ${{ secrets.MODRINTH_TOKEN }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -2,3 +2,4 @@
|
||||
/.idea/
|
||||
/**/dependency-reduced-pom.xml
|
||||
/**/target/
|
||||
/**/__pycache__/
|
||||
@@ -0,0 +1,36 @@
|
||||
when:
|
||||
- event: tag
|
||||
branch: master
|
||||
|
||||
steps:
|
||||
createFiles:
|
||||
image: maven:3.9.6-eclipse-temurin-17
|
||||
secrets:
|
||||
- source: cb_token
|
||||
target: codeberg_api_token
|
||||
- source: modrinth_api_token
|
||||
target: modrinth_api_token
|
||||
- source: hangar_api_token
|
||||
target: hangar_api_token
|
||||
- source: discord_webhook_url
|
||||
target: discord_webhook_url
|
||||
commands:
|
||||
# Create the jar files.
|
||||
- mvn clean install
|
||||
# Move VersionUploader jar file
|
||||
- cd version-uploader/target/
|
||||
- mv VersionUploader.jar ../../
|
||||
- cd ../../
|
||||
# Execute Jar file
|
||||
- java -jar VersionUploader.jar --all
|
||||
uploadToCodeberg:
|
||||
image: woodpeckerci/plugin-gitea-release
|
||||
settings:
|
||||
base_url: https://codeberg.org
|
||||
files:
|
||||
- "bungeecord/target/AdvancedServerList-*.jar"
|
||||
- "paper/target/AdvancedServerList-*.jar"
|
||||
- "velocity/target/AdvancedServerList-*.jar"
|
||||
- "addons/banplugins/target/AdvancedServerList-*.jar"
|
||||
api_key:
|
||||
from_secret: CB_TOKEN
|
||||
@@ -0,0 +1,36 @@
|
||||
when:
|
||||
- branch: master
|
||||
event: push
|
||||
path:
|
||||
include: ['requirements.txt', 'mkdocs.yml', 'docs/**']
|
||||
|
||||
variables:
|
||||
setup_git: &setup_git
|
||||
- apk add git
|
||||
- git config --global user.email "github@andre601.ch"
|
||||
- git config --global user.name "ASL Docs Builder"
|
||||
|
||||
steps:
|
||||
cloneTargetRepo:
|
||||
image: alpine:3.18.4
|
||||
commands:
|
||||
- chmod -R a+w .
|
||||
- <<: *setup_git
|
||||
- git clone -b pages https://codeberg.org/Andre601/AdvancedServerList.git site
|
||||
- chmod -R a+w site
|
||||
buildDocs:
|
||||
image: woodpeckerci/plugin-mkdocs:latest
|
||||
settings:
|
||||
pip_install_file: requirements.txt
|
||||
commitAndPush:
|
||||
image: alpine:3.18.4
|
||||
secrets:
|
||||
- cb_token
|
||||
commands:
|
||||
- <<: *setup_git
|
||||
- mv domains site/.domains
|
||||
- cd site
|
||||
- git remote set-url origin https://$CB_TOKEN@codeberg.org/Andre601/AdvancedServerList.git
|
||||
- git add --all
|
||||
- git commit -m "Update AdvancedServerList Docs ($( env TZ=Europe/Zurich date +"%d.%m.%Y %Z" )) [SKIP CI]"
|
||||
- git push
|
||||
@@ -1,50 +1,62 @@
|
||||
# AdvancedServerList
|
||||
<a href="https://modrinth.com/plugin/advancedserverlist" target="_blank">
|
||||
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/cozy/available/modrinth_vector.svg" height="64" align="right" alt="modrinth" title="Available on Modrinth">
|
||||
</a>
|
||||
|
||||
AdvancedServerList is a plugin that allowys you to customize your server's MOTD, favicon, Player count text and player count hover displayed in a player's multiplayer server list based on conditions and priorities.
|
||||
AdvancedServerList is a plugin that allows you to customize your server's MOTD, favicon, Player count text and player count hover displayed in a player's multiplayer server list based on conditions and priorities.
|
||||
|
||||
## Downloads
|
||||
|
||||
<a href="https://modrinth.com/plugin/advancedserverlist" target="_blank">
|
||||
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact/available/modrinth_vector.svg" height="46" alt="modrinth" title="Available on Modrinth">
|
||||
</a>
|
||||
<br>
|
||||
<!--
|
||||
<a href="https://hangar.papermc.io/Andre_601/AdvancedServerList" target="_blank">
|
||||
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact/available/hangar_vector.svg" height="46" alt="hangar" title="Available on Hangar">
|
||||
</a>
|
||||
-->
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
<a href="https://www.spigotmc.org" target="_blank">
|
||||
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/minimal/supported/spigot_vector.svg" height="64" alt="platform-spigot" title="Tested on Spigot">
|
||||
</a>
|
||||
<a href="https://papermc.io" target="_blank">
|
||||
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/minimal/supported/paper_vector.svg" height="64" alt="platform-paper" title="Tested on Paper">
|
||||
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact-minimal/supported/paper_vector.svg" height="64" alt="platform-paper" title="Tested on Paper">
|
||||
</a>
|
||||
<a href="https://www.spigotmc.org" target="_blank">
|
||||
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/minimal/supported/bungeecord_vector.svg" height="64" alt="platform-bungeecord" title="Tested on BungeeCord">
|
||||
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact-minimal/supported/bungeecord_vector.svg" height="64" alt="platform-bungeecord" title="Tested on BungeeCord">
|
||||
</a>
|
||||
<a href="https://www.papermc.io" target="_blank">
|
||||
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/minimal/supported/waterfall_vector.svg" height="64" alt="platform-waterfall" title="Tested on Waterfall">
|
||||
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact-minimal/supported/waterfall_vector.svg" height="64" alt="platform-waterfall" title="Tested on Waterfall">
|
||||
</a>
|
||||
<a href="https://velocitypowered.com" target="_blank">
|
||||
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/minimal/supported/velocity_vector.svg" height="64" alt="platform-velocity" title="Tested on Velocity">
|
||||
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact-minimal/supported/velocity_vector.svg" height="64" alt="platform-velocity" title="Tested on Velocity">
|
||||
</a>
|
||||
|
||||
## What is a Server List Profile?
|
||||
|
||||
A Server List Profile refers to a YAML file located in the plugin's `profiles` directory.
|
||||
It allows you to configure specific aspects of the server display in the MC-Client's multiplayer server list, such as the MOTD, player count text, player count hover or Favicon.
|
||||
|
||||
> [*Read More*][profiles]
|
||||
|
||||
### Conditions
|
||||
Thanks to conditions can you determine when a profile should be displayed in the player’s server list, to allow displaying specific text (i.e. a warning when they are using an outdated version).
|
||||
|
||||
When multiple profiles exist that have valid conditions will the one with the highest priority (Higher number = higher priority) be selected. Having no conditions makes the profile automatically return true.
|
||||
Thanks to conditions can you determine when a profile should be displayed in the player's server list, to allow displaying specific text (i.e. a warning when they are using an outdated version).
|
||||
|
||||
When multiple profiles exist that have valid conditions will the one with the highest priority (Higher number = higher priority) be selected. Having no conditions makes it automatically true.
|
||||
|
||||
> [*Read More*][conditions]
|
||||
|
||||
### Placeholders
|
||||
Placeholders can be used within conditions to further customize them. They can also be used in any other text option (motd, playerCount and players) to display their respective values.
|
||||
|
||||
Placeholders can be used within conditions to further customize them. They can also be used in any other text option to display their respective values.
|
||||
The format is `${<target> <identifier>}` which was adopted from BungeeTabListPlus. Depending on what platform you use the plugin on are only specific placeholders available.
|
||||
|
||||
When using the SpigotMC/PaperMC version can you also use placeholders from [PlaceholderAPI][placeholderapi] using its `%<identifier>_<values>%` placeholder format. PlaceholderAPI needs to be installed for that.
|
||||
When using the SpigotMC/PaperMC version, or while [PAPIProxyBridge][papiproxybridge] is installed on your proxy, can you also use placeholders from [PlaceholderAPI][placeholderapi] using its `%<identifier>_<values>%` placeholder format. PlaceholderAPI needs to be installed on the server (not proxy) for that.
|
||||
|
||||
If you're a plugin dev can you even add your own custom placeholders through AdvancedServerList's own API.
|
||||
|
||||
> [*Read More*][placeholders]
|
||||
|
||||
### Formatting
|
||||
|
||||
The plugin uses the MiniMessage format for a consistent, easy way of formatting your text.
|
||||
Only certain options are usable for each option. As an example does motd support HEX colours and gradients, while the other options only support default colour codes.
|
||||
|
||||
@@ -52,10 +64,14 @@ Only certain options are usable for each option. As an example does motd support
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Dependency | Platforms | Required? |
|
||||
| ---------------- | ------------- | --------- |
|
||||
| [ProtocolLib] | Spigot | Yes |
|
||||
| [PlaceholderAPI] | Spigot, Paper | No |
|
||||
All listed dependencies are optional.
|
||||
|
||||
| Dependency | Platforms |
|
||||
|-------------------|----------------------|
|
||||
| [PlaceholderAPI] | Paper |
|
||||
| [ViaVersion] | Paper |
|
||||
| [PAPIProxyBridge] | BungeeCord, Velocity |
|
||||
| [Maintenance] | All |
|
||||
|
||||
## Statistics
|
||||
|
||||
@@ -69,32 +85,33 @@ You can disable this in the global bStats config file located in `/plugins/bstat
|
||||
## Screenshots
|
||||
|
||||
<a href="https://modrinth.com/plugin/advancedserverlist/gallery" target="_blank">
|
||||
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/cozy/documentation/modrinth-gallery_vector.svg" height="64" alt="gallery" title="Check out the Gallery">
|
||||
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/cozy/documentation/modrinth-gallery_vector.svg" height="64" alt="gallery" title="Check out the Gallery">
|
||||
</a>
|
||||
|
||||
## Support
|
||||
|
||||
<a href="https://discord.gg/6dazXp6" target="_blank">
|
||||
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/minimal/social/discord-singular_vector.svg" height="64" alt="discord" title="Join my Discord Server">
|
||||
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact-minimal/social/discord-singular_vector.svg" height="64" alt="discord" title="Join my Discord Server">
|
||||
</a>
|
||||
<a href="https://app.revolt.chat/invite/74TpERXA" target="_blank">
|
||||
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/minimal/social/revolt-singular_vector.svg" height="64" alt="revolt" title="Join my Revolt Server">
|
||||
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact-minimal/social/revolt-singular_vector.svg" height="64" alt="revolt" title="Join my Revolt Server">
|
||||
</a>
|
||||
<a href="https://blobfox.coffee/@andre_601" target="_blank">
|
||||
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/minimal/social/mastodon-singular_vector.svg" height="64" alt="mastodon" title="Chat with me on Mastodon">
|
||||
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact-minimal/social/mastodon-singular_vector.svg" height="64" alt="mastodon" title="Chat with me on Mastodon">
|
||||
</a>
|
||||
|
||||
<!-- Links -->
|
||||
[profiles]: https://github.com/Andre601/AdvancedServerList/wiki/Profiles
|
||||
[conditions]: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#conditions
|
||||
[placeholders]: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#placeholders
|
||||
[minimessage]: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#minimessage
|
||||
|
||||
[placeholderapi]: https://www.spigotmc.org/resources/6245/
|
||||
[profiles]: https://asl.andre601.ch/profiles/
|
||||
[conditions]: https://asl.andre601.ch/profiles/#condition
|
||||
[placeholders]: https://asl.andre601.ch/profiles/placeholders/
|
||||
[minimessage]: https://asl.andre601.ch/profiles/formatting/
|
||||
|
||||
[modrinth]: https://modrinth.com/plugin/advancedserverlist
|
||||
|
||||
[protocollib]: https://www.spigotmc.org/resources/1997/
|
||||
[placeholderapi]: https://www.spigotmc.org/resources/6245/
|
||||
[placeholderapi]: https://hangar.papermc.io/HelpChat/PlaceholderAPI
|
||||
[viaversion]: https://hangar.papermc.io/ViaVersion/ViaVersion
|
||||
[papiproxybridge]: https://hangar.papermc.io/William278/PAPIProxyBridge
|
||||
[maintenance]: https://hangar.papermc.io/kennytv/Maintenance
|
||||
|
||||
[bstats]: https://bstats.org
|
||||
[bstats-bungee]: https://bstats.org/plugin/bungeecord/AdvancedServerList/15585
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ MIT License
|
||||
~
|
||||
~ Copyright (c) 2022-2024 Andre_601
|
||||
~
|
||||
~ Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
~ of this software and associated documentation files (the "Software"), to deal
|
||||
~ in the Software without restriction, including without limitation the rights
|
||||
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
~ copies of the Software, and to permit persons to whom the Software is
|
||||
~ furnished to do so, subject to the following conditions:
|
||||
~
|
||||
~ The above copyright notice and this permission notice shall be included in all
|
||||
~ copies or substantial portions of the Software.
|
||||
~
|
||||
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
~ SOFTWARE.
|
||||
~
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>parent</artifactId>
|
||||
<groupId>ch.andre601.advancedserverlist</groupId>
|
||||
<version>parent</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>banplugins</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>${plugin.version}</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>16</maven.compiler.source>
|
||||
<maven.compiler.target>16</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>sonatype</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>papermc</id>
|
||||
<url>https://papermc.io/repo/repository/maven-public/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<!-- Proxy/Server -->
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>1.20-R0.2</version>
|
||||
<type>jar</type>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>1.20-R0.2</version>
|
||||
<type>javadoc</type>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.papermc.paper</groupId>
|
||||
<artifactId>paper-api</artifactId>
|
||||
<version>1.20-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Plugin APIs -->
|
||||
<dependency>
|
||||
<groupId>com.github.DevLeoko</groupId>
|
||||
<artifactId>AdvancedBan</artifactId>
|
||||
<version>v2.3.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.andre601.asl-api</groupId>
|
||||
<artifactId>api</artifactId>
|
||||
<version>${api.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>AdvancedServerList-BanPlugins-Addon-${plugin.version}</finalName>
|
||||
<resources>
|
||||
<resource>
|
||||
<filtering>true</filtering>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.12.1</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.banplugins.bungeecord;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.banplugins.placeholders.AdvancedBanPlaceholders;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public enum BungeeCordBanPlugins{
|
||||
|
||||
ADVANCED_BAN("AdvancedBan", new AdvancedBanPlaceholders());
|
||||
|
||||
private final String plugin;
|
||||
private final PlaceholderProvider placeholderProvider;
|
||||
|
||||
BungeeCordBanPlugins(String plugin, PlaceholderProvider placeholderProvider){
|
||||
this.plugin = plugin;
|
||||
this.placeholderProvider = placeholderProvider;
|
||||
}
|
||||
|
||||
public static Map<String, PlaceholderProvider> getBanPlugins(){
|
||||
Map<String, PlaceholderProvider> content = new HashMap<>();
|
||||
|
||||
for(BungeeCordBanPlugins bungeeCordBanPlugins : BungeeCordBanPlugins.values()){
|
||||
content.put(bungeeCordBanPlugins.plugin, bungeeCordBanPlugins.placeholderProvider);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.banplugins.bungeecord;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.AdvancedServerListAPI;
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class BungeeCordBanPluginsAddon extends Plugin{
|
||||
|
||||
@Override
|
||||
public void onEnable(){
|
||||
if(getProxy().getPluginManager().getPlugin("AdvancedServerList") == null){
|
||||
getLogger().warning("AdvancedServerList is not enabled. This plugin requires it to function!");
|
||||
return;
|
||||
}
|
||||
|
||||
int loadedPlaceholders = loadPlaceholderProviders();
|
||||
if(loadedPlaceholders == 0){
|
||||
getLogger().warning("No compatible Ban plugin was found to register placeholders for.");
|
||||
}else{
|
||||
getLogger().info("Loaded " + loadedPlaceholders + " Placeholder Set(s) for AdvancedServerList!");
|
||||
}
|
||||
}
|
||||
|
||||
private int loadPlaceholderProviders(){
|
||||
int loaded = 0;
|
||||
Map<String, PlaceholderProvider> banPlugins = BungeeCordBanPlugins.getBanPlugins();
|
||||
AdvancedServerListAPI api = AdvancedServerListAPI.get();
|
||||
|
||||
for(Map.Entry<String, PlaceholderProvider> entry : banPlugins.entrySet()){
|
||||
if(getProxy().getPluginManager().getPlugin(entry.getKey()) != null){
|
||||
getLogger().info("Registering Placeholders for " + entry.getKey() + "...");
|
||||
api.addPlaceholderProvider(entry.getValue());
|
||||
getLogger().info("Placeholder successfully registered!");
|
||||
|
||||
loaded++;
|
||||
}
|
||||
}
|
||||
|
||||
return loaded;
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.banplugins.paper;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.banplugins.placeholders.AdvancedBanPlaceholders;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public enum PaperBanPlugins{
|
||||
|
||||
ADVANCED_BAN("AdvancedBan", new AdvancedBanPlaceholders());
|
||||
|
||||
private final String plugin;
|
||||
private final PlaceholderProvider placeholderProvider;
|
||||
|
||||
PaperBanPlugins(String plugin, PlaceholderProvider placeholderProvider){
|
||||
this.plugin = plugin;
|
||||
this.placeholderProvider = placeholderProvider;
|
||||
}
|
||||
|
||||
public static Map<String, PlaceholderProvider> getBanPlugins(){
|
||||
Map<String, PlaceholderProvider> content = new HashMap<>();
|
||||
|
||||
for(PaperBanPlugins paperBanPlugins : PaperBanPlugins.values()){
|
||||
content.put(paperBanPlugins.plugin, paperBanPlugins.placeholderProvider);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.banplugins.paper;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.AdvancedServerListAPI;
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class PaperBanPluginsAddon extends JavaPlugin{
|
||||
|
||||
@Override
|
||||
public void onEnable(){
|
||||
if(!getServer().getPluginManager().isPluginEnabled("AdvancedServerList")){
|
||||
getLogger().warning("AdvancedServerList is not enabled. This plugin requires it to function!");
|
||||
getServer().getPluginManager().disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
|
||||
int loadedPlaceholders = loadPlaceholderProviders();
|
||||
if(loadedPlaceholders == 0){
|
||||
getLogger().warning("No compatible Ban plugin was found to register placeholders for. Disabling plugin...");
|
||||
|
||||
getServer().getPluginManager().disablePlugin(this);
|
||||
}else{
|
||||
getLogger().info("Loaded " + loadedPlaceholders + " Placeholder Set(s) for AdvancedServerList!");
|
||||
}
|
||||
}
|
||||
|
||||
private int loadPlaceholderProviders(){
|
||||
int loaded = 0;
|
||||
Map<String, PlaceholderProvider> banPlugins = PaperBanPlugins.getBanPlugins();
|
||||
AdvancedServerListAPI api = AdvancedServerListAPI.get();
|
||||
|
||||
for(Map.Entry<String, PlaceholderProvider> entry : banPlugins.entrySet()){
|
||||
if(getServer().getPluginManager().isPluginEnabled(entry.getKey())){
|
||||
getLogger().info("Registering Placeholders for " + entry.getKey() + "...");
|
||||
api.addPlaceholderProvider(entry.getValue());
|
||||
getLogger().info("Placeholder successfully registered!");
|
||||
|
||||
loaded++;
|
||||
}
|
||||
}
|
||||
|
||||
return loaded;
|
||||
}
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.banplugins.placeholders;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.banplugins.providers.AdvancedBanProvider;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class AdvancedBanPlaceholders extends PlaceholderProvider{
|
||||
|
||||
private final AdvancedBanProvider provider = new AdvancedBanProvider();
|
||||
|
||||
public AdvancedBanPlaceholders(){
|
||||
super("advancedban");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
|
||||
String[] args = placeholder.split("\\s");
|
||||
|
||||
return switch(args[0]) {
|
||||
// Mute-related placeholders
|
||||
case "isMuted" -> String.valueOf(provider.muted(player));
|
||||
case "muteReason" -> provider.muteReason(player);
|
||||
case "muteDuration" -> {
|
||||
if(args.length == 1)
|
||||
yield provider.muteDuration(player);
|
||||
|
||||
if(args.length > 2)
|
||||
yield null;
|
||||
|
||||
boolean fromStart = Boolean.getBoolean(args[1]);
|
||||
yield provider.muteDuration(player, fromStart);
|
||||
}
|
||||
case "muteExpiration" -> {
|
||||
if(args.length == 1)
|
||||
yield provider.muteExpirationDate(player);
|
||||
|
||||
String pattern = String.join(" ", Arrays.copyOfRange(args, 1, args.length));
|
||||
|
||||
yield provider.banExpirationDate(player, pattern);
|
||||
}
|
||||
|
||||
// Ban-related placeholders
|
||||
case "isBanned" -> String.valueOf(provider.banned(player));
|
||||
case "banReason" -> provider.banReason(player);
|
||||
case "banDuration" -> {
|
||||
if(args.length == 1)
|
||||
yield provider.banDuration(player);
|
||||
|
||||
if(args.length > 2)
|
||||
yield null;
|
||||
|
||||
boolean fromStart = Boolean.getBoolean(args[1]);
|
||||
yield provider.banDuration(player, fromStart);
|
||||
}
|
||||
case "banExpiration" -> {
|
||||
if(args.length == 1)
|
||||
yield provider.banExpirationDate(player);
|
||||
|
||||
String pattern = String.join(" ", Arrays.copyOfRange(args, 1, args.length));
|
||||
|
||||
yield provider.banExpirationDate(player, pattern);
|
||||
}
|
||||
|
||||
// Unknown/Invalid placeholder.
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
}
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.banplugins.providers;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.primitives.UnsignedLongs;
|
||||
import me.leoko.advancedban.manager.PunishmentManager;
|
||||
import me.leoko.advancedban.utils.Punishment;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
public class AdvancedBanProvider implements PunishmentProvider{
|
||||
|
||||
private static PunishmentManager getAPI(){
|
||||
return PunishmentManager.get();
|
||||
}
|
||||
|
||||
private static String noDashesUUID(UUID uuid){
|
||||
return hexString(uuid.getMostSignificantBits()) + hexString(uuid.getLeastSignificantBits());
|
||||
}
|
||||
|
||||
private static Punishment mute(GenericPlayer player){
|
||||
return getAPI().getMute(noDashesUUID(player.getUUID()));
|
||||
}
|
||||
|
||||
private static Punishment ban(GenericPlayer player){
|
||||
return getAPI().getBan(noDashesUUID(player.getUUID()));
|
||||
}
|
||||
|
||||
private static String hexString(long unsigned){
|
||||
return Strings.padStart(UnsignedLongs.toString(unsigned, 16), 16, '0');
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean muted(GenericPlayer player){
|
||||
return getAPI().isMuted(noDashesUUID(player.getUUID()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean banned(GenericPlayer player){
|
||||
return getAPI().isBanned(noDashesUUID(player.getUUID()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String muteReason(GenericPlayer player){
|
||||
Punishment mute = mute(player);
|
||||
if(mute == null)
|
||||
return null;
|
||||
|
||||
return mute.getReason();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String banReason(GenericPlayer player){
|
||||
Punishment ban = ban(player);
|
||||
if(ban == null)
|
||||
return null;
|
||||
|
||||
return ban.getReason();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String muteDuration(GenericPlayer player){
|
||||
return muteDuration(player, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String banDuration(GenericPlayer player){
|
||||
return banDuration(player, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String muteExpirationDate(GenericPlayer player, String pattern){
|
||||
Punishment mute = mute(player);
|
||||
if(mute == null)
|
||||
return null;
|
||||
|
||||
long end = mute.getEnd();
|
||||
if(end < 0L)
|
||||
return "never";
|
||||
|
||||
Date date = new Date(end);
|
||||
return new SimpleDateFormat(pattern).format(date);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String banExpirationDate(GenericPlayer player, String pattern){
|
||||
Punishment ban = ban(player);
|
||||
if(ban == null)
|
||||
return null;
|
||||
|
||||
long end = ban.getEnd();
|
||||
if(end < 0L)
|
||||
return "never";
|
||||
|
||||
Date date = new Date(end);
|
||||
return new SimpleDateFormat(pattern).format(date);
|
||||
}
|
||||
|
||||
public String muteDuration(GenericPlayer player, boolean fromStart){
|
||||
Punishment mute = mute(player);
|
||||
if(mute == null)
|
||||
return null;
|
||||
|
||||
return mute.getDuration(fromStart);
|
||||
}
|
||||
|
||||
public String banDuration(GenericPlayer player, boolean fromStart){
|
||||
Punishment ban = ban(player);
|
||||
if(ban == null)
|
||||
return null;
|
||||
|
||||
return ban.getDuration(fromStart);
|
||||
}
|
||||
}
|
||||
+23
-20
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -23,31 +23,34 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.objects;
|
||||
package ch.andre601.advancedserverlist.banplugins.providers;
|
||||
|
||||
/*
|
||||
* A simple class to allow having a nullable boolean without having to deal with possible NPEs
|
||||
* when trying to get Boolean.getValue() while it is null...
|
||||
*
|
||||
* Here, it simply checks if the value is null and if it is, returns a default. Otherwise, it gives
|
||||
* the value.
|
||||
*/
|
||||
public class NullBool{
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
|
||||
public interface PunishmentProvider{
|
||||
|
||||
public static final NullBool FALSE = new NullBool(false);
|
||||
public static final NullBool NULL = new NullBool(null);
|
||||
boolean muted(GenericPlayer player);
|
||||
|
||||
private final Boolean value;
|
||||
boolean banned(GenericPlayer player);
|
||||
|
||||
public NullBool(Boolean value){
|
||||
this.value = value;
|
||||
String muteReason(GenericPlayer player);
|
||||
|
||||
String banReason(GenericPlayer player);
|
||||
|
||||
String muteDuration(GenericPlayer player);
|
||||
|
||||
String banDuration(GenericPlayer player);
|
||||
|
||||
default String muteExpirationDate(GenericPlayer player){
|
||||
return muteExpirationDate(player, "dd, MMM yyyy HH:mm:ss");
|
||||
}
|
||||
|
||||
public boolean isNull(){
|
||||
return value == null;
|
||||
String muteExpirationDate(GenericPlayer player, String pattern);
|
||||
|
||||
default String banExpirationDate(GenericPlayer player){
|
||||
return banExpirationDate(player, "dd, MMM yyyy HH:mm:ss");
|
||||
}
|
||||
|
||||
public boolean getValue(boolean def){
|
||||
return isNull() ? def : value;
|
||||
}
|
||||
String banExpirationDate(GenericPlayer player, String pattern);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
name: 'ASLBanPluginsAddon'
|
||||
author: 'Andre_601'
|
||||
version: '${plugin.version}'
|
||||
description: 'AdvancedBan Add-on for AdvancedServerList to add placeholders to use.'
|
||||
|
||||
softDepends:
|
||||
- AdvancedServerList
|
||||
- AdvancedBan
|
||||
|
||||
main: 'ch.andre601.advancedserverlist.banplugins.bungeecord.BungeeCordBanPluginsAddon'
|
||||
@@ -0,0 +1,16 @@
|
||||
name: 'ASLBanPluginsAddon'
|
||||
author: 'Andre_601'
|
||||
version: '${plugin.version}'
|
||||
|
||||
main: 'ch.andre601.advancedserverlist.banplugins.paper.AdvancedBanPlaceholders'
|
||||
|
||||
api-version: '1.19'
|
||||
|
||||
dependencies:
|
||||
server:
|
||||
AdvancedServerList:
|
||||
required: false
|
||||
load: BEFORE
|
||||
AdvancedBans:
|
||||
required: false
|
||||
load: BEFORE
|
||||
+30
-14
@@ -58,30 +58,54 @@
|
||||
<version>${plugin.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.andre601.asl-api</groupId>
|
||||
<artifactId>platform-bungeecord</artifactId>
|
||||
<version>${api.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>1.19-R0.1-SNAPSHOT</version>
|
||||
<version>1.20-R0.2</version>
|
||||
<type>jar</type>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>1.19-R0.1-SNAPSHOT</version>
|
||||
<version>1.20-R0.2</version>
|
||||
<type>javadoc</type>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-api</artifactId>
|
||||
<version>4.16.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-text-minimessage</artifactId>
|
||||
<version>4.16.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-platform-bungeecord</artifactId>
|
||||
<version>4.1.2</version>
|
||||
<version>4.3.2</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bstats</groupId>
|
||||
<artifactId>bstats-bungeecord</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.0.2</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spongepowered</groupId>
|
||||
<artifactId>configurate-yaml</artifactId>
|
||||
<version>4.1.2</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
@@ -98,12 +122,12 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.10.1</version>
|
||||
<version>3.12.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.4.1</version>
|
||||
<version>3.5.2</version>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<relocations>
|
||||
@@ -119,14 +143,6 @@
|
||||
<pattern>org.bstats</pattern>
|
||||
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.bstats</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>com.github.benmanes.caffeine</pattern>
|
||||
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.caffeine</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>okhttp3</pattern>
|
||||
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.okhttp3</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
<filters>
|
||||
<filter>
|
||||
|
||||
+19
-28
@@ -26,35 +26,32 @@
|
||||
package ch.andre601.advancedserverlist.bungeecord;
|
||||
|
||||
import ch.andre601.advancedserverlist.bungeecord.commands.CmdAdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.bungeecord.events.JoinEvent;
|
||||
import ch.andre601.advancedserverlist.bungeecord.events.PingEvent;
|
||||
import ch.andre601.advancedserverlist.bungeecord.listeners.JoinEvent;
|
||||
import ch.andre601.advancedserverlist.bungeecord.listeners.PingEvent;
|
||||
import ch.andre601.advancedserverlist.bungeecord.logging.BungeeLogger;
|
||||
import ch.andre601.advancedserverlist.bungeecord.objects.BungeePlayerPlaceholders;
|
||||
import ch.andre601.advancedserverlist.bungeecord.objects.BungeeServerPlaceholders;
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.core.ProxyCore;
|
||||
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
|
||||
import ch.andre601.advancedserverlist.core.profiles.favicon.FaviconHandler;
|
||||
import ch.andre601.advancedserverlist.core.profiles.replacer.placeholders.Placeholders;
|
||||
import net.md_5.bungee.api.Favicon;
|
||||
import net.md_5.bungee.api.ServerPing;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
import org.bstats.bungeecord.Metrics;
|
||||
import org.bstats.charts.SimplePie;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class BungeeCordCore extends Plugin implements ProxyCore<Favicon, ServerPing.PlayerInfo>{
|
||||
public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
|
||||
|
||||
private AdvancedServerList core;
|
||||
private AdvancedServerList<Favicon> core;
|
||||
private FaviconHandler<Favicon> faviconHandler = null;
|
||||
private final PluginLogger logger = new BungeeLogger(getLogger());
|
||||
private final PluginLogger logger = new BungeeLogger(this);
|
||||
|
||||
@Override
|
||||
public void onEnable(){
|
||||
this.core = new AdvancedServerList(this);
|
||||
this.core = AdvancedServerList.init(this, BungeePlayerPlaceholders.init(), BungeeServerPlaceholders.init());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -81,16 +78,21 @@ public class BungeeCordCore extends Plugin implements ProxyCore<Favicon, ServerP
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadFaviconHandler(AdvancedServerList<Favicon> core){
|
||||
faviconHandler = new FaviconHandler<>(core);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearFaviconCache(){
|
||||
if(faviconHandler == null)
|
||||
return;
|
||||
|
||||
faviconHandler.clearCache();
|
||||
faviconHandler.cleanCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdvancedServerList getCore(){
|
||||
public AdvancedServerList<Favicon> getCore(){
|
||||
return core;
|
||||
}
|
||||
|
||||
@@ -128,18 +130,7 @@ public class BungeeCordCore extends Plugin implements ProxyCore<Favicon, ServerP
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ServerPing.PlayerInfo> createPlayers(List<String> lines, Placeholders... placeholders){
|
||||
List<ServerPing.PlayerInfo> players = new ArrayList<>(lines.size());
|
||||
|
||||
for(String line : lines){
|
||||
String parsed = ComponentParser.text(line)
|
||||
.replacements(placeholders[0])
|
||||
.replacements(placeholders[1])
|
||||
.toString();
|
||||
|
||||
players.add(new ServerPing.PlayerInfo(parsed, UUID.randomUUID()));
|
||||
}
|
||||
|
||||
return players;
|
||||
public Favicon createFavicon(BufferedImage image) throws IllegalArgumentException{
|
||||
return Favicon.create(image);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.bungeecord.commands;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.interfaces.CmdSender;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
|
||||
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
|
||||
import net.kyori.adventure.platform.bungeecord.BungeeAudiences;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
|
||||
+69
-19
@@ -23,29 +23,35 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.bungeecord.events;
|
||||
package ch.andre601.advancedserverlist.bungeecord.listeners;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.events.GenericServerListEvent;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
|
||||
import ch.andre601.advancedserverlist.bungeecord.BungeePlayer;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.events.GenericEventWrapper;
|
||||
import ch.andre601.advancedserverlist.bungeecord.objects.BungeePlayerImpl;
|
||||
import ch.andre601.advancedserverlist.bungeecord.objects.BungeeProxyImpl;
|
||||
import ch.andre601.advancedserverlist.core.events.PingEventHandler;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.events.GenericEventWrapper;
|
||||
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.players.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.replacer.placeholders.PlayerPlaceholders;
|
||||
import ch.andre601.advancedserverlist.core.profiles.replacer.placeholders.ServerPlaceholders;
|
||||
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
|
||||
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer;
|
||||
import net.md_5.bungee.api.Favicon;
|
||||
import net.md_5.bungee.api.ServerPing;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.ProxyPingEvent;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class BungeeEventWrapper implements GenericEventWrapper<ProxiedPlayer, Favicon>{
|
||||
public class BungeeEventWrapper implements GenericEventWrapper<Favicon, BungeePlayerImpl>{
|
||||
|
||||
private final BungeeCordCore plugin;
|
||||
private final ProxyPingEvent event;
|
||||
@@ -59,6 +65,14 @@ public class BungeeEventWrapper implements GenericEventWrapper<ProxiedPlayer, Fa
|
||||
this.ping = event.getResponse();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GenericServerListEvent callEvent(ProfileEntry entry){
|
||||
PreServerListSetEventImpl event = new PreServerListSetEventImpl(entry);
|
||||
plugin.getProxy().getPluginManager().callEvent(event);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxPlayers(int maxPlayers){
|
||||
ping.getPlayers().setMax(maxPlayers);
|
||||
@@ -81,12 +95,20 @@ public class BungeeEventWrapper implements GenericEventWrapper<ProxiedPlayer, Fa
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayers(List<String> players, GenericPlayer<ProxiedPlayer> player, PlayerPlaceholders playerPlaceholders, ServerPlaceholders serverPlaceholders){
|
||||
ServerPing.PlayerInfo[] playerInfos = plugin.createPlayers(players, playerPlaceholders, serverPlaceholders)
|
||||
.toArray(new ServerPing.PlayerInfo[0]);
|
||||
public void setPlayers(List<String> lines, BungeePlayerImpl player, GenericServer server){
|
||||
ServerPing.PlayerInfo[] players = new ServerPing.PlayerInfo[lines.size()];
|
||||
|
||||
if(playerInfos.length > 0)
|
||||
ping.getPlayers().setSample(playerInfos);
|
||||
for(int i = 0; i < players.length; i++){
|
||||
String parsed = ComponentParser.text(lines.get(i))
|
||||
.modifyText(text -> StringReplacer.replace(text, player, server))
|
||||
.toString();
|
||||
|
||||
ServerPing.PlayerInfo pi = new ServerPing.PlayerInfo(parsed, UUID.randomUUID());
|
||||
players[i] = pi;
|
||||
}
|
||||
|
||||
if(players.length > 0)
|
||||
ping.getPlayers().setSample(players);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -110,6 +132,14 @@ public class BungeeEventWrapper implements GenericEventWrapper<ProxiedPlayer, Fa
|
||||
return protocol == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMaintenanceModeActive(){
|
||||
if(plugin.getProxy().getPluginManager().getPlugin("Maintenance") == null)
|
||||
return false;
|
||||
|
||||
return PingEventHandler.getMaintenanceUtil().isMaintenanceEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtocolVersion(){
|
||||
return this.protocol.getProtocol();
|
||||
@@ -131,8 +161,26 @@ public class BungeeEventWrapper implements GenericEventWrapper<ProxiedPlayer, Fa
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parsePAPIPlaceholders(String text, GenericPlayer<ProxiedPlayer> player){
|
||||
return text;
|
||||
public String parsePAPIPlaceholders(String text, BungeePlayerImpl player){
|
||||
if(plugin.getProxy().getPluginManager().getPlugin("PAPIProxyBridge") == null)
|
||||
return text;
|
||||
|
||||
if(!PingEventHandler.getPAPIUtil().isCompatible())
|
||||
return text;
|
||||
|
||||
String server = PingEventHandler.getPAPIUtil().getServer();
|
||||
if(server == null || server.isEmpty())
|
||||
return text;
|
||||
|
||||
ServerInfo serverInfo = plugin.getProxy().getServerInfo(server);
|
||||
if(serverInfo == null || serverInfo.getPlayers().isEmpty())
|
||||
return text;
|
||||
|
||||
ProxiedPlayer carrier = PingEventHandler.getPAPIUtil().getPlayer(serverInfo.getPlayers());
|
||||
if(carrier == null)
|
||||
return text;
|
||||
|
||||
return PingEventHandler.getPAPIUtil().parse(text, carrier.getUniqueId(), player.getUUID());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -146,12 +194,14 @@ public class BungeeEventWrapper implements GenericEventWrapper<ProxiedPlayer, Fa
|
||||
}
|
||||
|
||||
@Override
|
||||
public GenericPlayer<ProxiedPlayer> createPlayer(CachedPlayer player, int protocol){
|
||||
return new BungeePlayer(player, protocol);
|
||||
public BungeePlayerImpl createPlayer(CachedPlayer player, int protocol){
|
||||
return new BungeePlayerImpl(player, protocol);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Favicon createFavicon(BufferedImage image) throws IllegalArgumentException{
|
||||
return Favicon.create(image);
|
||||
public GenericServer createGenericServer(int playersOnline, int playersMax, String host){
|
||||
Map<String, ServerInfo> servers = plugin.getProxy().getServers();
|
||||
|
||||
return new BungeeProxyImpl(servers, playersOnline, playersMax, host);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -23,7 +23,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.bungeecord.events;
|
||||
package ch.andre601.advancedserverlist.bungeecord.listeners;
|
||||
|
||||
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
+1
-1
@@ -23,7 +23,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.bungeecord.events;
|
||||
package ch.andre601.advancedserverlist.bungeecord.listeners;
|
||||
|
||||
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
|
||||
import ch.andre601.advancedserverlist.core.events.PingEventHandler;
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.bungeecord.listeners;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.bungeecord.events.PreServerListSetEvent;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
|
||||
public class PreServerListSetEventImpl extends PreServerListSetEvent{
|
||||
|
||||
public PreServerListSetEventImpl(ProfileEntry entry){
|
||||
super(entry);
|
||||
}
|
||||
}
|
||||
+17
-2
@@ -25,6 +25,7 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.bungeecord.logging;
|
||||
|
||||
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
|
||||
import java.util.logging.Level;
|
||||
@@ -32,10 +33,24 @@ import java.util.logging.Logger;
|
||||
|
||||
public class BungeeLogger implements PluginLogger{
|
||||
|
||||
private final BungeeCordCore plugin;
|
||||
private final Logger logger;
|
||||
|
||||
public BungeeLogger(Logger logger){
|
||||
this.logger = logger;
|
||||
public BungeeLogger(BungeeCordCore plugin){
|
||||
this.plugin = plugin;
|
||||
this.logger = plugin.getLogger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Class<?> clazz, String msg, Object... args){
|
||||
if(plugin.isDebugEnabled())
|
||||
info("[DEBUG] [" + clazz.getSimpleName() + "] " + msg, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debugWarn(Class<?> clazz, String msg, Object... args){
|
||||
if(plugin.isDebugEnabled())
|
||||
warn("[DEBUG] [" + clazz.getSimpleName() + "] " + msg, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+4
-5
@@ -23,15 +23,14 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.bungeecord;
|
||||
package ch.andre601.advancedserverlist.bungeecord.objects;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.players.GenericPlayer;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.players.GenericPlayerImpl;
|
||||
|
||||
public class BungeePlayer extends GenericPlayer<ProxiedPlayer>{
|
||||
public class BungeePlayerImpl extends GenericPlayerImpl{
|
||||
|
||||
public BungeePlayer(CachedPlayer player, int protocol){
|
||||
public BungeePlayerImpl(CachedPlayer player, int protocol){
|
||||
this.name = player.getName();
|
||||
this.protocol = protocol;
|
||||
this.uuid = player.getUuid();
|
||||
+19
-17
@@ -23,29 +23,31 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.spigot.commands;
|
||||
package ch.andre601.advancedserverlist.bungeecord.objects;
|
||||
|
||||
import ch.andre601.advancedserverlist.spigot.SpigotCore;
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
|
||||
public class CmdAdvancedServerList implements CommandExecutor{
|
||||
import java.util.Locale;
|
||||
|
||||
public class BungeePlayerPlaceholders extends PlaceholderProvider{
|
||||
|
||||
SpigotCore plugin;
|
||||
BukkitAudiences bukkitAudiences;
|
||||
private BungeePlayerPlaceholders(){
|
||||
super("player");
|
||||
}
|
||||
|
||||
public CmdAdvancedServerList(SpigotCore plugin){
|
||||
this.plugin = plugin;
|
||||
bukkitAudiences = BukkitAudiences.create(plugin);
|
||||
public static BungeePlayerPlaceholders init(){
|
||||
return new BungeePlayerPlaceholders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command cmd, @NotNull String label, @NotNull String[] args){
|
||||
plugin.getCore().getCommandHandler().handle(new SpigotCmdSender(sender, bukkitAudiences), args);
|
||||
|
||||
return true;
|
||||
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
|
||||
return switch(placeholder.toLowerCase(Locale.ROOT)){
|
||||
case "name" -> player.getName();
|
||||
case "protocol" -> String.valueOf(player.getProtocol());
|
||||
case "uuid" -> String.valueOf(player.getUUID());
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.bungeecord.objects;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.bungeecord.objects.BungeeProxy;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public record BungeeProxyImpl(Map<String, ServerInfo> servers, int playersOnline, int playersMax, String host) implements BungeeProxy{
|
||||
@Override
|
||||
public Map<String, ServerInfo> getServers(){
|
||||
return servers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPlayersOnline(){
|
||||
return playersOnline;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPlayersMax(){
|
||||
return playersMax;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHost(){
|
||||
return host;
|
||||
}
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.bungeecord.objects;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.api.bungeecord.objects.BungeeProxy;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
public class BungeeServerPlaceholders extends PlaceholderProvider{
|
||||
|
||||
private BungeeServerPlaceholders(){
|
||||
super("server");
|
||||
}
|
||||
|
||||
public static BungeeServerPlaceholders init(){
|
||||
return new BungeeServerPlaceholders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
|
||||
if(!(server instanceof BungeeProxy proxy))
|
||||
return null;
|
||||
|
||||
String[] args = placeholder.split("\\s", 2);
|
||||
|
||||
return switch(args[0]){
|
||||
case "playersOnline" -> {
|
||||
if(args.length >= 2){
|
||||
String[] servers = args[1].split(",");
|
||||
|
||||
int players = 0;
|
||||
for(String serverName : servers){
|
||||
if(serverName.isEmpty())
|
||||
continue;
|
||||
|
||||
ServerInfo info = proxy.getServers().get(serverName.strip());
|
||||
if(info == null)
|
||||
continue;
|
||||
|
||||
players += info.getPlayers().size();
|
||||
}
|
||||
|
||||
yield String.valueOf(players);
|
||||
}
|
||||
|
||||
yield String.valueOf(proxy.getPlayersOnline());
|
||||
}
|
||||
case "playersMax" -> {
|
||||
// ServerInfo doesn't provide the max players that could join, so we won't allow an extra argument
|
||||
if(args.length >= 2)
|
||||
yield null;
|
||||
|
||||
yield String.valueOf(proxy.getPlayersMax());
|
||||
}
|
||||
case "host" -> {
|
||||
if(args.length > 2)
|
||||
yield null;
|
||||
|
||||
if(args.length == 2){
|
||||
ServerInfo info = proxy.getServers().get(args[1]);
|
||||
if(info == null)
|
||||
yield null;
|
||||
|
||||
yield String.valueOf(((InetSocketAddress)info.getSocketAddress()).getHostString());
|
||||
}
|
||||
|
||||
yield proxy.getHost();
|
||||
}
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -3,4 +3,8 @@ author: 'Andre_601'
|
||||
version: '${plugin.version}'
|
||||
description: '${plugin.description}'
|
||||
|
||||
softDepends:
|
||||
- PAPIProxyBridge
|
||||
- Maintenance
|
||||
|
||||
main: 'ch.andre601.advancedserverlist.bungeecord.BungeeCordCore'
|
||||
+62
-20
@@ -41,6 +41,7 @@
|
||||
<properties>
|
||||
<maven.compiler.source>16</maven.compiler.source>
|
||||
<maven.compiler.target>16</maven.compiler.target>
|
||||
<plugin.config.version>4</plugin.config.version>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
@@ -48,56 +49,93 @@
|
||||
<id>flexver-repo</id>
|
||||
<url>https://repo.sleeping.town/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>papiproxybridge-repo</id>
|
||||
<url>https://repo.william278.net/releases/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>sonatype</id>
|
||||
<url>https://s01.oss.sonatype.org/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>ch.andre601.asl-api</groupId>
|
||||
<artifactId>api</artifactId>
|
||||
<version>${api.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.andre601</groupId>
|
||||
<artifactId>ExpressionParser</artifactId>
|
||||
<version>v1.2.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spongepowered</groupId>
|
||||
<artifactId>configurate-yaml</artifactId>
|
||||
<version>4.1.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- MiniMessage -->
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-api</artifactId>
|
||||
<version>4.12.0</version>
|
||||
<version>4.16.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-text-minimessage</artifactId>
|
||||
<version>4.12.0</version>
|
||||
<version>4.16.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-text-serializer-legacy</artifactId>
|
||||
<version>4.12.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
<version>3.1.2</version>
|
||||
<scope>compile</scope>
|
||||
<version>4.16.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.10.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>4.10.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.unascribed</groupId>
|
||||
<artifactId>flexver-java</artifactId>
|
||||
<version>1.0.2</version>
|
||||
<version>1.1.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>33.0.0-jre</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Plugins -->
|
||||
<dependency>
|
||||
<groupId>net.william278</groupId>
|
||||
<artifactId>papiproxybridge</artifactId>
|
||||
<version>1.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>eu.kennytv.maintenance</groupId>
|
||||
<artifactId>maintenance-api</artifactId>
|
||||
<version>4.2.0-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Test dependencies -->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.13.2</version>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>5.10.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
@@ -114,12 +152,12 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.10.1</version>
|
||||
<version>3.12.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.4.1</version>
|
||||
<version>3.5.2</version>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<filters>
|
||||
@@ -136,6 +174,10 @@
|
||||
<pattern>com.unascribed</pattern>
|
||||
<shadedPattern>ch.andre601.advancedserverlist.core.depends.flexver</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>ch.andre601.expressionparser</pattern>
|
||||
<shadedPattern>ch.andre601.advancedserverlist.core.depends.expressionparser</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
<executions>
|
||||
|
||||
@@ -25,38 +25,50 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.core;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.AdvancedServerListAPI;
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.core.check.UpdateChecker;
|
||||
import ch.andre601.advancedserverlist.core.commands.CommandHandler;
|
||||
import ch.andre601.advancedserverlist.core.file.FileHandler;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.ProfileConditionParser;
|
||||
import ch.andre601.advancedserverlist.core.profiles.players.PlayerHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
public class AdvancedServerList{
|
||||
public class AdvancedServerList<F>{
|
||||
|
||||
private final PluginCore<?> plugin;
|
||||
private final PluginCore<F> plugin;
|
||||
private final FileHandler fileHandler;
|
||||
private final CommandHandler commandHandler;
|
||||
private final PlayerHandler playerHandler;
|
||||
private final AdvancedServerListAPI api = AdvancedServerListAPI.get();
|
||||
private final ProfileConditionParser parser = ProfileConditionParser.create();
|
||||
|
||||
private UpdateChecker updateChecker;
|
||||
|
||||
private String version;
|
||||
|
||||
public AdvancedServerList(PluginCore<?> plugin){
|
||||
private AdvancedServerList(PluginCore<F> plugin, List<PlaceholderProvider> placeholders){
|
||||
this.plugin = plugin;
|
||||
this.fileHandler = new FileHandler(this);
|
||||
this.commandHandler = new CommandHandler(this);
|
||||
this.playerHandler = new PlayerHandler(this);
|
||||
|
||||
placeholders.forEach(this.api::addPlaceholderProvider);
|
||||
|
||||
load();
|
||||
}
|
||||
|
||||
public PluginCore<?> getPlugin(){
|
||||
public static <F> AdvancedServerList<F> init(PluginCore<F> plugin, PlaceholderProvider... placeholders){
|
||||
return new AdvancedServerList<>(plugin, Arrays.asList(placeholders));
|
||||
}
|
||||
|
||||
public PluginCore<F> getPlugin(){
|
||||
return plugin;
|
||||
}
|
||||
|
||||
@@ -76,6 +88,14 @@ public class AdvancedServerList{
|
||||
return version;
|
||||
}
|
||||
|
||||
public AdvancedServerListAPI getApi(){
|
||||
return api;
|
||||
}
|
||||
|
||||
public ProfileConditionParser getParser(){
|
||||
return parser;
|
||||
}
|
||||
|
||||
public void disable(){
|
||||
getPlugin().getPluginLogger().info("Saving playercache.json file...");
|
||||
getPlayerHandler().save();
|
||||
@@ -92,6 +112,10 @@ public class AdvancedServerList{
|
||||
plugin.clearFaviconCache();
|
||||
}
|
||||
|
||||
public void clearPlayerCache(){
|
||||
getPlayerHandler().clearCache();
|
||||
}
|
||||
|
||||
private void load(){
|
||||
printBanner();
|
||||
resolveVersion();
|
||||
@@ -106,16 +130,24 @@ public class AdvancedServerList{
|
||||
return;
|
||||
}
|
||||
|
||||
if(getFileHandler().isOldConfig()){
|
||||
getPlugin().getPluginLogger().info("Detected old config.yml. Attempting to migrate...");
|
||||
if(getFileHandler().migrateConfig()){
|
||||
getPlugin().getPluginLogger().info("Migration completed successfully!");
|
||||
}else{
|
||||
getPlugin().getPluginLogger().warn("Couldn't migrate config.yml! Check previous lines for errors.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(getFileHandler().loadProfiles()){
|
||||
getPlugin().getPluginLogger().info("Successfully loaded " + getFileHandler().getProfiles().size() + " profiles!");
|
||||
getPlugin().getPluginLogger().info("Successfully loaded %d profile(s)!", getFileHandler().getProfiles().size());
|
||||
}else{
|
||||
getPlugin().getPluginLogger().warn("Unable to load profiles! Check previous lines for errors.");
|
||||
return;
|
||||
}
|
||||
|
||||
Path folder = getPlugin().getFolderPath().resolve("favicons");
|
||||
if(!folder.toFile().exists() && folder.toFile().mkdirs())
|
||||
getPlugin().getPluginLogger().info("Successfully created favicons folder.");
|
||||
getPlugin().loadFaviconHandler(this);
|
||||
|
||||
getPlugin().getPluginLogger().info("Loading Commands...");
|
||||
plugin.loadCommands();
|
||||
@@ -134,12 +166,11 @@ public class AdvancedServerList{
|
||||
|
||||
getPlugin().getPluginLogger().info("AdvancedServerList is ready!");
|
||||
|
||||
if(getFileHandler().getBoolean("check_updates"))
|
||||
if(getFileHandler().getBoolean("checkUpdates"))
|
||||
this.updateChecker = new UpdateChecker(this);
|
||||
}
|
||||
|
||||
private void printBanner(){
|
||||
getPlugin().getPluginLogger().info("");
|
||||
getPlugin().getPluginLogger().info(" _____ _");
|
||||
getPlugin().getPluginLogger().info(" /\\ / ____| |");
|
||||
getPlugin().getPluginLogger().info(" / \\ | (___ | |");
|
||||
|
||||
@@ -32,6 +32,8 @@ import java.util.concurrent.ThreadFactory;
|
||||
public class UpdateCheckThread implements ThreadFactory{
|
||||
@Override
|
||||
public Thread newThread(@NotNull Runnable r){
|
||||
return new Thread(r, "AdvancedServerList Update-Thread");
|
||||
Thread t = new Thread(r, "AdvancedServerList-UpdateThread");
|
||||
t.setDaemon(true);
|
||||
return t;
|
||||
}
|
||||
}
|
||||
@@ -30,18 +30,17 @@ import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import com.google.gson.FieldNamingPolicy;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.unascribed.flexver.FlexVerComparator;
|
||||
import io.leangen.geantyref.TypeToken;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
@@ -49,12 +48,10 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class UpdateChecker{
|
||||
|
||||
private final String url = "https://api.modrinth.com/v2/project/advancedserverlist/version?loaders=[\"%s\"]";
|
||||
private final OkHttpClient client = new OkHttpClient();
|
||||
|
||||
private final AdvancedServerList core;
|
||||
private final PluginLogger logger;
|
||||
private final String loader;
|
||||
@SuppressWarnings("FieldCanBeLocal")
|
||||
// 'https://api.modrinth.com/v2/project/advancedserverlist/version?loaders=["%s"]' URL encoded.
|
||||
private final String url = "https://api.modrinth.com/v2/project/advancedserverlist/version?loaders=%%5B%%22%s%%22%%5D";
|
||||
private final HttpClient client = HttpClient.newHttpClient();
|
||||
|
||||
private final Type listType = new TypeToken<ArrayList<ModrinthVersion>>(){}.getType();
|
||||
private final Gson gson = new GsonBuilder()
|
||||
@@ -65,7 +62,11 @@ public class UpdateChecker{
|
||||
|
||||
private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(new UpdateCheckThread());
|
||||
|
||||
public UpdateChecker(AdvancedServerList core){
|
||||
private final AdvancedServerList<?> core;
|
||||
private final PluginLogger logger;
|
||||
private final String loader;
|
||||
|
||||
public UpdateChecker(AdvancedServerList<?> core){
|
||||
this.core = core;
|
||||
this.logger = core.getPlugin().getPluginLogger();
|
||||
this.loader = core.getPlugin().getLoader();
|
||||
@@ -73,42 +74,13 @@ public class UpdateChecker{
|
||||
startUpdateChecker();
|
||||
}
|
||||
|
||||
public void startUpdateChecker(){
|
||||
executor.scheduleAtFixedRate(() -> {
|
||||
logger.info("Checking for a new update...");
|
||||
checkUpdate().whenComplete((version, throwable) -> {
|
||||
if(version == null || throwable != null){
|
||||
logger.warn("Failed to look for any updates. See previous messages for reasons.");
|
||||
return;
|
||||
}
|
||||
|
||||
int result = version.compare(core.getVersion());
|
||||
switch(result){
|
||||
case -1 -> printUpdateBanner(version.getVersionNumber(), version.getId(), version.isRelease());
|
||||
case 0 -> logger.info("No new update found. You're running the latest version!");
|
||||
case 1 -> logger.info(
|
||||
"Your version (%s) is higher than the latest release (%s). Are you running a dev build?",
|
||||
core.getVersion(), version.getVersionNumber()
|
||||
);
|
||||
}
|
||||
});
|
||||
}, 0L, 12L, TimeUnit.HOURS);
|
||||
}
|
||||
|
||||
public void disable(){
|
||||
executor.shutdown();
|
||||
client.dispatcher().executorService().shutdown();
|
||||
try{
|
||||
if(!executor.awaitTermination(1, TimeUnit.SECONDS)){
|
||||
executor.shutdownNow();
|
||||
if(!executor.awaitTermination(1, TimeUnit.SECONDS))
|
||||
logger.warn("Scheduler didn't terminate in time!");
|
||||
}
|
||||
|
||||
if(!client.dispatcher().executorService().awaitTermination(1, TimeUnit.SECONDS)){
|
||||
client.dispatcher().executorService().shutdownNow();
|
||||
if(!client.dispatcher().executorService().awaitTermination(1, TimeUnit.SECONDS))
|
||||
logger.warn("OkHttp's Scheduler didn't terminate in time!");
|
||||
logger.warn("Scheduler did not terminate in time!");
|
||||
}
|
||||
}catch(InterruptedException ex){
|
||||
executor.shutdownNow();
|
||||
@@ -116,108 +88,93 @@ public class UpdateChecker{
|
||||
}
|
||||
}
|
||||
|
||||
private CompletableFuture<ModrinthVersion> checkUpdate(){
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
PluginLogger logger = core.getPlugin().getPluginLogger();
|
||||
if(core.getVersion().equals("UNKNOWN")){
|
||||
logger.warn("Cannot perform Update check! Plugin version couldn't be parsed.");
|
||||
return null;
|
||||
}
|
||||
private void startUpdateChecker(){
|
||||
executor.scheduleAtFixedRate(() -> {
|
||||
logger.info("Looking for an update...");
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.url(String.format(url, loader))
|
||||
.header("User-Agent", "AdvancedServerList-" + loader + "/" + core.getVersion())
|
||||
.build();
|
||||
|
||||
try(Response response = client.newCall(request).execute()){
|
||||
if(!response.isSuccessful()){
|
||||
logger.warn("Encountered a non-successful response from Modrinth! Code: %d", response.code());
|
||||
return null;
|
||||
}
|
||||
|
||||
ResponseBody body = response.body();
|
||||
if(body == null){
|
||||
logger.warn("Received an empty Response body from Modrinth!");
|
||||
return null;
|
||||
performUpdateCheck().whenComplete((version, throwable) -> {
|
||||
if(version == null || throwable != null){
|
||||
logger.warn("Failed to look for any updates. Check previous messages for causes.");
|
||||
return;
|
||||
}
|
||||
|
||||
String responseString = body.string();
|
||||
if(responseString.isEmpty()){
|
||||
logger.warn("Received an empty Response body from Modrinth!");
|
||||
return null;
|
||||
logger.debug(UpdateChecker.class, "Comparing versions...");
|
||||
|
||||
int result = version.compare(core.getVersion());
|
||||
switch(result){
|
||||
case -1 -> printUpdateBanner(version);
|
||||
case 0 -> logger.info("You are running the latest version!");
|
||||
case 1 -> logger.info(
|
||||
"Your version (%s) seems to be newer than the latest release (%s). Are you running a dev build?",
|
||||
core.getVersion(), version.versionNumber()
|
||||
);
|
||||
}
|
||||
|
||||
List<ModrinthVersion> list = gson.fromJson(responseString, listType);
|
||||
if(list == null || list.isEmpty()){
|
||||
logger.warn("Couldn't convert JSON Array into a valid list.");
|
||||
return null;
|
||||
}
|
||||
|
||||
ModrinthVersion version = list.get(0);
|
||||
|
||||
if(version.getVersionNumber() == null || version.getVersionNumber().isEmpty()){
|
||||
logger.warn("Cannot check latest version. Received version number was null/empty.");
|
||||
return null;
|
||||
}
|
||||
|
||||
return version;
|
||||
}catch(JsonSyntaxException ex){
|
||||
logger.warn("Encountered invalid JSON from Response body!", ex);
|
||||
return null;
|
||||
}catch(IOException ex){
|
||||
logger.warn("Encountered Exception while checking for an update!", ex);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
});
|
||||
}, 0L, 12L, TimeUnit.HOURS);
|
||||
}
|
||||
|
||||
private void printUpdateBanner(String version, String versionId, boolean isRelease){
|
||||
private CompletableFuture<ModrinthVersion> performUpdateCheck(){
|
||||
String finalUrl = String.format(url, loader);
|
||||
|
||||
logger.debug(UpdateChecker.class, "Checking '%s' for updates...", finalUrl);
|
||||
|
||||
if(core.getVersion().equals("UNKNOWN")){
|
||||
logger.warn("Cannot perform update check. Plugin version is 'UNKNOWN'!");
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
HttpRequest request;
|
||||
try{
|
||||
request = HttpRequest.newBuilder()
|
||||
.uri(new URI(finalUrl))
|
||||
.header("User-Agent", "AdvancedServerList-" + loader + "/" + core.getVersion())
|
||||
.build();
|
||||
}catch(URISyntaxException ex){
|
||||
logger.warn("Cannot perform update check. URL '%s' is not a valid URI.", ex, finalUrl);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
return client.sendAsync(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8))
|
||||
.thenApply(response -> new ArrayList<ModrinthVersion>(gson.fromJson(response.body(), listType)))
|
||||
.thenApply(list -> list.get(0))
|
||||
.exceptionally((throwable) -> {
|
||||
logger.warn("Encountered exception while performing update check!", throwable);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private void printUpdateBanner(ModrinthVersion version){
|
||||
logger.info("==================================================================");
|
||||
logger.info("You are running an outdated version of AdvancedServerList!");
|
||||
logger.info("");
|
||||
logger.info("Your version: %s", core.getVersion());
|
||||
logger.info("Modrinth version: %s", version);
|
||||
logger.info("Modrinth: %s", version.versionNumber());
|
||||
logger.info("");
|
||||
|
||||
if(!isRelease){
|
||||
logger.info("WARNING: This release is an Alpha/Beta! It may contain");
|
||||
logger.info(" breaking changes!");
|
||||
if(!version.isRelease()){
|
||||
logger.info("WARNING!");
|
||||
logger.info("This is a %s version and may contain breaking changes and/or bugs!", version.versionType());
|
||||
logger.info("");
|
||||
}
|
||||
|
||||
logger.info("You can download the latest release from here:");
|
||||
logger.info("https://modrinth.com/plugin/advancedserverlist/version/%s", versionId);
|
||||
logger.info("Download the latest version from here:");
|
||||
logger.info("https://modrinth.com/plugin/advancedserverlist/version/%s", version.id());
|
||||
logger.info("==================================================================");
|
||||
}
|
||||
|
||||
public static class ModrinthVersion{
|
||||
@SuppressWarnings("FieldMayBeFinal")
|
||||
private String id;
|
||||
@SuppressWarnings("FieldMayBeFinal")
|
||||
private String versionNumber;
|
||||
@SuppressWarnings("FieldMayBeFinal")
|
||||
private String versionType;
|
||||
|
||||
public ModrinthVersion(String id, String versionNumber, String versionType){
|
||||
this.id = id;
|
||||
this.versionNumber = versionNumber;
|
||||
this.versionType = versionType;
|
||||
}
|
||||
|
||||
public String getId(){
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getVersionNumber(){
|
||||
return versionNumber;
|
||||
}
|
||||
public record ModrinthVersion(String id, String versionNumber, String versionType){
|
||||
|
||||
public boolean isRelease(){
|
||||
return versionType.equals("release");
|
||||
return versionType().equals("release");
|
||||
}
|
||||
|
||||
public int compare(String version){
|
||||
return FlexVerComparator.compare(version, versionNumber);
|
||||
return FlexVerComparator.compare(version, versionNumber());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
return String.format("ModrinthVersion{id=%s,versionNumber=%s,versionType=%s}", id, versionNumber, versionType);
|
||||
}
|
||||
}
|
||||
}
|
||||
+98
-39
@@ -26,56 +26,115 @@
|
||||
package ch.andre601.advancedserverlist.core.commands;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.CmdSender;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.PluginCommand;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class CommandHandler{
|
||||
|
||||
private final AdvancedServerList core;
|
||||
private final List<PluginCommand> subCommands = new ArrayList<>();
|
||||
|
||||
public CommandHandler(AdvancedServerList core){
|
||||
this.core = core;
|
||||
public CommandHandler(AdvancedServerList<?> core){
|
||||
subCommands.add(new Help());
|
||||
subCommands.add(new Reload(core));
|
||||
subCommands.add(new ClearCache(core));
|
||||
}
|
||||
|
||||
public void handle(CmdSender sender, String[] args){
|
||||
String errorPrefix = "<grey>[<gradient:dark_red:red>AdvancedServerList</gradient>]";
|
||||
String prefix = "<grey>[<gradient:aqua:white>AdvancedServerList</gradient>]";
|
||||
if(args.length == 0){
|
||||
sender.sendErrorMsg("<red>Too few arguments! Use <grey>/asl help</grey> for a list of commands.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(args.length == 0 || args[0].equalsIgnoreCase("help")){
|
||||
if(sender.hasPermission("advancedserverlist.command.help")){
|
||||
sender.sendMsg("%s - Commands", prefix);
|
||||
sender.sendMsg();
|
||||
sender.sendMsg("<gradient:aqua:white>/asl help</gradient> <grey>- Shows this Help");
|
||||
sender.sendMsg();
|
||||
sender.sendMsg("<gradient:aqua:white>/asl reload</gradient> <grey>- Reloads the plugin");
|
||||
}else{
|
||||
sender.sendMsg("%s <red>You do not have permissions to execute this command!", errorPrefix);
|
||||
}
|
||||
}else
|
||||
if(args[0].equalsIgnoreCase("reload")){
|
||||
if(sender.hasPermission("advancedserverlist.command.reload")){
|
||||
sender.sendMsg("%s Reloading plugin...", prefix);
|
||||
|
||||
if(core.getFileHandler().reloadConfig()){
|
||||
sender.sendMsg("%s <green>Reloaded <grey>config.yml</grey>!", prefix);
|
||||
}else{
|
||||
sender.sendMsg("%s <red>Error while reloading the <grey>config.yml</grey>!", errorPrefix);
|
||||
for(PluginCommand subCommand : subCommands){
|
||||
if(subCommand.getArgument().equalsIgnoreCase(args[0])){
|
||||
if(!sender.hasPermission(subCommand.getPermission())){
|
||||
sender.sendErrorMsg(
|
||||
"<red>You do not have the permission <grey>%s</grey> to execute this command.",
|
||||
subCommand.getPermission()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if(core.getFileHandler().reloadProfiles()){
|
||||
sender.sendMsg("%s <green>Loaded <grey>%d Profile(s)</grey>!", prefix, core.getFileHandler().getProfiles().size());
|
||||
}else{
|
||||
sender.sendMsg("%s <red>Cannot load Profiles!", errorPrefix);
|
||||
}
|
||||
|
||||
core.clearFaviconCache();
|
||||
sender.sendMsg("%s <green>Successfully cleared Favicon cache!", prefix);
|
||||
|
||||
sender.sendMsg("%s <green>Reload complete!", prefix);
|
||||
}else{
|
||||
sender.sendMsg("%s <red>You do not have permissions to execute this command!", errorPrefix);
|
||||
subCommand.handle(sender);
|
||||
return;
|
||||
}
|
||||
}else{
|
||||
sender.sendMsg("%s <red>Unknown subcommand <grey>%s</grey>. Use <grey>/asl help</grey> for a list of commands.", prefix, args[0]);
|
||||
}
|
||||
|
||||
sender.sendErrorMsg("<red>Unknown subcommand <grey>%s</grey>. Use <grey>/asl help</grey> for a list of commands.", args[0]);
|
||||
}
|
||||
|
||||
private static class Help extends PluginCommand{
|
||||
|
||||
public Help(){
|
||||
super("help");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(CmdSender sender){
|
||||
sender.sendPrefixedMsg("- Commands");
|
||||
sender.sendMsg();
|
||||
sender.sendMsg("<aqua>/asl <white>help <grey>- Shows this help");
|
||||
sender.sendMsg();
|
||||
sender.sendMsg("<aqua>/asl <white>reload <grey>- Reloads the config.yml and profiles");
|
||||
sender.sendMsg();
|
||||
sender.sendMsg("<aqua>/asl <white>clearCache <grey>- Clears the Player and Favicon cache");
|
||||
}
|
||||
}
|
||||
|
||||
private static class Reload extends PluginCommand{
|
||||
|
||||
private final AdvancedServerList<?> core;
|
||||
|
||||
public Reload(AdvancedServerList<?> core){
|
||||
super("reload");
|
||||
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(CmdSender sender){
|
||||
sender.sendPrefixedMsg("Reloading plugin...");
|
||||
|
||||
if(core.getFileHandler().reloadConfig()){
|
||||
sender.sendPrefixedMsg("<green>Reloaded <grey>config.yml</grey>!");
|
||||
}else{
|
||||
sender.sendErrorMsg("<red>Error while reloading <grey>config.yml</grey>!");
|
||||
}
|
||||
|
||||
if(core.getFileHandler().reloadProfiles()){
|
||||
sender.sendPrefixedMsg("<green>Loaded <grey>%d profile(s)</grey>!", core.getFileHandler().getProfiles().size());
|
||||
}else{
|
||||
sender.sendErrorMsg("<red>Error while loading profile(s)!");
|
||||
}
|
||||
|
||||
sender.sendPrefixedMsg("<green>Reload complete!");
|
||||
}
|
||||
}
|
||||
|
||||
private static class ClearCache extends PluginCommand{
|
||||
|
||||
private final AdvancedServerList<?> core;
|
||||
|
||||
public ClearCache(AdvancedServerList<?> core){
|
||||
super("clearCache");
|
||||
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(CmdSender sender){
|
||||
sender.sendPrefixedMsg("Clearing caches...");
|
||||
|
||||
core.clearFaviconCache();
|
||||
sender.sendPrefixedMsg("<green>Successfully cleared Favicon Cache!");
|
||||
|
||||
core.clearPlayerCache();
|
||||
sender.sendPrefixedMsg("<green>Successfully cleared Player Cache!");
|
||||
|
||||
sender.sendPrefixedMsg("<green>Cache clearing complete!");
|
||||
}
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.compat.maintenance;
|
||||
|
||||
import eu.kennytv.maintenance.api.Maintenance;
|
||||
import eu.kennytv.maintenance.api.MaintenanceProvider;
|
||||
|
||||
public class MaintenanceUtil{
|
||||
|
||||
private final Maintenance api;
|
||||
|
||||
public MaintenanceUtil(){
|
||||
this.api = MaintenanceProvider.get();
|
||||
}
|
||||
|
||||
public boolean isMaintenanceEnabled(){
|
||||
return api.isMaintenance();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.compat.papi;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class PAPICache{
|
||||
|
||||
private CacheValue cache = null;
|
||||
|
||||
public PAPICache(){}
|
||||
|
||||
public String get(Supplier<String> supplier){
|
||||
if(cache == null || cache.isExpired())
|
||||
cache = new CacheValue(supplier.get(), System.currentTimeMillis());
|
||||
|
||||
return cache.server();
|
||||
}
|
||||
|
||||
private record CacheValue(String server, long timestamp){
|
||||
// Consider the cache expired if it is older than 5 seconds.
|
||||
public boolean isExpired(){
|
||||
return (timestamp < 0L) || System.currentTimeMillis() - timestamp >= 5000L;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.compat.papi;
|
||||
|
||||
import net.william278.papiproxybridge.api.PlaceholderAPI;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
|
||||
public class PAPIUtil{
|
||||
|
||||
private final PlaceholderAPI papi;
|
||||
|
||||
private final PAPICache cache = new PAPICache();
|
||||
|
||||
public PAPIUtil(){
|
||||
this.papi = PlaceholderAPI.createInstance();
|
||||
}
|
||||
|
||||
// Make sure the version of PAPIProxyBridge we get has the required methods we need...
|
||||
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||
public boolean isCompatible(){
|
||||
try{
|
||||
papi.getClass().getMethod("findServers");
|
||||
return true;
|
||||
}catch(NoSuchMethodException ex){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public String getServer(){
|
||||
return cache.get(() -> {
|
||||
List<String> servers;
|
||||
try{
|
||||
servers = papi.findServers().getNow(Collections.emptyList());
|
||||
}catch(CancellationException | CompletionException ex){
|
||||
return null;
|
||||
}
|
||||
|
||||
if(servers == null || servers.isEmpty())
|
||||
return null;
|
||||
|
||||
return servers.get(0);
|
||||
});
|
||||
}
|
||||
|
||||
public <P> P getPlayer(Collection<P> players){
|
||||
if(players.isEmpty())
|
||||
return null;
|
||||
|
||||
return List.copyOf(players).get(0);
|
||||
}
|
||||
|
||||
public String parse(String text, UUID carrier, UUID player){
|
||||
try{
|
||||
CompletableFuture<String> future = papi.formatPlaceholders(text, carrier, player);
|
||||
return future.getNow(text);
|
||||
}catch(IllegalArgumentException | CancellationException | CompletionException ex){
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
||||
+105
-49
@@ -25,103 +25,159 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.core.events;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.events.GenericServerListEvent;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.core.compat.maintenance.MaintenanceUtil;
|
||||
import ch.andre601.advancedserverlist.core.compat.papi.PAPIUtil;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.events.GenericEventWrapper;
|
||||
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
|
||||
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileManager;
|
||||
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
|
||||
import ch.andre601.advancedserverlist.core.profiles.players.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileManager;
|
||||
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.replacer.placeholders.PlayerPlaceholders;
|
||||
import ch.andre601.advancedserverlist.core.profiles.replacer.placeholders.ServerPlaceholders;
|
||||
|
||||
public class PingEventHandler{
|
||||
|
||||
public static <P, F> void handleEvent(GenericEventWrapper<P, F> event){
|
||||
if(event.isInvalidProtocol())
|
||||
private static PAPIUtil papiUtil = null;
|
||||
private static MaintenanceUtil maintenanceUtil = null;
|
||||
|
||||
public static <F, P extends GenericPlayer> void handleEvent(GenericEventWrapper<F, P> event){
|
||||
event.getPlugin().getPluginLogger().debug(PingEventHandler.class, "Received ping event. Handling it...");
|
||||
if(event.isInvalidProtocol() || event.isMaintenanceModeActive()){
|
||||
event.getPlugin().getPluginLogger().debug(PingEventHandler.class, "Not handling event. Either protocol was invalid of Maintenance is enabled.");
|
||||
return;
|
||||
}
|
||||
|
||||
PluginCore<F> plugin = event.getPlugin();
|
||||
|
||||
GenericPlayer<P> player = event.createPlayer(
|
||||
plugin.getCore().getPlayerHandler().getCachedPlayer(event.getPlayerIP()),
|
||||
event.getProtocolVersion()
|
||||
);
|
||||
String host = event.getVirtualHost();
|
||||
PluginLogger logger = plugin.getPluginLogger();
|
||||
|
||||
logger.debug(PingEventHandler.class, "Protocol valid. Continue handling...");
|
||||
|
||||
int online = event.getOnlinePlayers();
|
||||
int max = event.getMaxPlayers();
|
||||
|
||||
PlayerPlaceholders playerPlaceholders = new PlayerPlaceholders(player);
|
||||
ServerPlaceholders serverPlaceholders = new ServerPlaceholders(online, max, host);
|
||||
|
||||
ServerListProfile profile = ProfileManager.get(plugin.getCore())
|
||||
.replacements(playerPlaceholders)
|
||||
.replacements(serverPlaceholders)
|
||||
.getProfile();
|
||||
|
||||
if(profile == null)
|
||||
P player = event.createPlayer(
|
||||
plugin.getCore().getPlayerHandler().getCachedPlayer(event.getPlayerIP()),
|
||||
event.getProtocolVersion()
|
||||
);
|
||||
GenericServer server = event.createGenericServer(online, max, host);
|
||||
|
||||
ServerListProfile profile = ProfileManager.resolveProfile(plugin.getCore(), player, server);
|
||||
|
||||
if(profile == null){
|
||||
logger.debugWarn(PingEventHandler.class, "Server List Profile couldn't be resolved properly. Cancelling event handling...");
|
||||
return;
|
||||
|
||||
ProfileEntry entry = ProfileManager.merge(profile);
|
||||
}
|
||||
|
||||
if(entry.isExtraPlayersEnabled().getValue(false)){
|
||||
max = online + (entry.getExtraPlayersCount() == null ? 0 : entry.getExtraPlayersCount());
|
||||
logger.debug(PingEventHandler.class, "Received valid Server List Profile. Calling PreServerListSetEvent...");
|
||||
|
||||
GenericServerListEvent e = event.callEvent(ProfileManager.merge(profile));
|
||||
if(e == null || e.isCancelled()){
|
||||
logger.debug(PingEventHandler.class, "PreServerListSetEvent was cancelled. Stopping ping handling...");
|
||||
return;
|
||||
}
|
||||
|
||||
logger.debug(PingEventHandler.class, "PreServerListSetEvent completed. Proceeding with ping handling...");
|
||||
|
||||
ProfileEntry entry = e.getEntry();
|
||||
if(entry.isInvalid()){
|
||||
logger.debugWarn(PingEventHandler.class, "No valid ProfileEntry retrieved. Cancelling ping handling...");
|
||||
return;
|
||||
}
|
||||
|
||||
boolean extraPlayers = ProfileManager.checkOption(entry.extraPlayersEnabled());
|
||||
|
||||
if(extraPlayers){
|
||||
max = online + (entry.extraPlayersCount() == null ? 0 : entry.extraPlayersCount());
|
||||
|
||||
logger.debug(PingEventHandler.class, "Extra Players enabled. Applying '%d' as max player count...", max);
|
||||
|
||||
event.setMaxPlayers(max);
|
||||
}
|
||||
|
||||
serverPlaceholders = new ServerPlaceholders(online, max, host);
|
||||
if(ProfileManager.checkOption(entry.maxPlayersEnabled()) && !extraPlayers){
|
||||
max = (entry.maxPlayersCount() == null) ? 0 : entry.maxPlayersCount();
|
||||
|
||||
logger.debug(PingEventHandler.class, "Max Players enabled. Applying '%d' as max player count...", max);
|
||||
|
||||
event.setMaxPlayers(max);
|
||||
}
|
||||
|
||||
if(!entry.getMOTD().isEmpty()){
|
||||
GenericServer finalServer = event.createGenericServer(online, max, host);
|
||||
|
||||
if(ProfileManager.checkOption(entry.motd())){
|
||||
logger.debug(PingEventHandler.class, "MOTD set. Applying '%s'...", String.join("\\n", entry.motd()));
|
||||
|
||||
event.setMotd(
|
||||
ComponentParser.list(entry.getMOTD())
|
||||
.replacements(playerPlaceholders)
|
||||
.replacements(serverPlaceholders)
|
||||
ComponentParser.list(entry.motd())
|
||||
.modifyText(text -> StringReplacer.replace(text, player, finalServer))
|
||||
.modifyText(text -> event.parsePAPIPlaceholders(text, player))
|
||||
.toComponent()
|
||||
);
|
||||
}
|
||||
|
||||
boolean hidePlayers = entry.isHidePlayersEnabled().getValue(false);
|
||||
boolean hidePlayers = ProfileManager.checkOption(entry.hidePlayersEnabled());
|
||||
|
||||
if(hidePlayers){
|
||||
logger.debug(PingEventHandler.class, "Hide Players enabled. Hiding player count...");
|
||||
|
||||
event.hidePlayers();
|
||||
}
|
||||
|
||||
if(!entry.getPlayerCountText().isEmpty() && !hidePlayers){
|
||||
if(ProfileManager.checkOption(entry.playerCountText()) && !hidePlayers){
|
||||
logger.debug(PingEventHandler.class, "Player Count Text set. Applying '%s'...", entry.playerCountText());
|
||||
|
||||
event.setPlayerCount(
|
||||
ComponentParser.text(entry.getPlayerCountText())
|
||||
.replacements(playerPlaceholders)
|
||||
.replacements(serverPlaceholders)
|
||||
ComponentParser.text(entry.playerCountText())
|
||||
.modifyText(text -> StringReplacer.replace(text, player, finalServer))
|
||||
.modifyText(text -> event.parsePAPIPlaceholders(text, player))
|
||||
.toString()
|
||||
);
|
||||
}
|
||||
|
||||
if(!entry.getPlayers().isEmpty() && !hidePlayers){
|
||||
event.setPlayers(entry.getPlayers(), player, playerPlaceholders, serverPlaceholders);
|
||||
if(ProfileManager.checkOption(entry.players()) && !hidePlayers){
|
||||
logger.debug(PingEventHandler.class, "Player Count Hover set. Applying '%s'...", String.join("\\n", entry.players()));
|
||||
|
||||
event.setPlayers(entry.players(), player, server);
|
||||
}
|
||||
|
||||
if(!entry.getFavicon().isEmpty()){
|
||||
String favicon = StringReplacer.replace(entry.getFavicon(), playerPlaceholders.getReplacements());
|
||||
if(ProfileManager.checkOption(entry.favicon())){
|
||||
logger.debug(PingEventHandler.class, "Favicon set. Resolving '%s'...", entry.favicon());
|
||||
|
||||
F fav = plugin.getFaviconHandler().getFavicon(favicon, image -> {
|
||||
try{
|
||||
return event.createFavicon(image);
|
||||
}catch(Exception ex){
|
||||
plugin.getPluginLogger().warn("Encountered an Exception while creating Favicon!", ex);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
String faviconString = StringReplacer.replace(entry.favicon(), player, server);
|
||||
|
||||
if(fav == null){
|
||||
F favicon = plugin.getFaviconHandler().getFavicon(faviconString);
|
||||
|
||||
if(favicon == null){
|
||||
logger.debugWarn(PingEventHandler.class, "Favicon was invalid or not yet resolved! Using default favicon of Server/Proxy...");
|
||||
|
||||
event.setDefaultFavicon();
|
||||
}else{
|
||||
event.setFavicon(fav);
|
||||
logger.debug(PingEventHandler.class, "Applying favicon...");
|
||||
|
||||
event.setFavicon(favicon);
|
||||
}
|
||||
}
|
||||
|
||||
logger.debug(PingEventHandler.class, "Event handling completed. Updating Ping data...");
|
||||
event.updateEvent();
|
||||
}
|
||||
|
||||
public static PAPIUtil getPAPIUtil(){
|
||||
if(papiUtil != null)
|
||||
return papiUtil;
|
||||
|
||||
return (papiUtil = new PAPIUtil());
|
||||
}
|
||||
|
||||
public static MaintenanceUtil getMaintenanceUtil(){
|
||||
if(maintenanceUtil != null)
|
||||
return maintenanceUtil;
|
||||
|
||||
return (maintenanceUtil = new MaintenanceUtil());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.file;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import org.spongepowered.configurate.ConfigurateException;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.NodePath;
|
||||
import org.spongepowered.configurate.transformation.ConfigurationTransformation;
|
||||
import org.spongepowered.configurate.transformation.TransformAction;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
|
||||
public class ConfigMigrator{
|
||||
|
||||
public static final int LATEST = resolveConfigVersion();
|
||||
|
||||
private ConfigMigrator(){}
|
||||
|
||||
public static ConfigurationTransformation.Versioned create(){
|
||||
return ConfigurationTransformation.versionedBuilder()
|
||||
.versionKey("configVersion")
|
||||
.addVersion(LATEST, threeToFour())
|
||||
.addVersion(3, twoToThree())
|
||||
.addVersion(2, oneToTwo())
|
||||
.build();
|
||||
}
|
||||
|
||||
public static ConfigurationTransformation threeToFour(){
|
||||
return ConfigurationTransformation.builder()
|
||||
.addAction(NodePath.path(), (path, value) -> {
|
||||
value.node("faviconCacheTime").set(1);
|
||||
|
||||
return null;
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
public static ConfigurationTransformation twoToThree(){
|
||||
return ConfigurationTransformation.builder()
|
||||
.addAction(NodePath.path(), (path, value) -> {
|
||||
value.node("debug").set(false);
|
||||
|
||||
return null;
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
public static ConfigurationTransformation oneToTwo(){
|
||||
return ConfigurationTransformation.builder()
|
||||
.addAction(NodePath.path("unknown_player"), (path, value) -> new Object[]{"unknownPlayer", "name"})
|
||||
.addAction(NodePath.path("unknown_player_uuid"), (path, value) -> new Object[]{"unknownPlayer", "uuid"})
|
||||
.addAction(NodePath.path("disable_cache"), TransformAction.rename("disableCache"))
|
||||
.addAction(NodePath.path("check_updates"), TransformAction.rename("checkUpdates"))
|
||||
.addAction(NodePath.path("send_statistics"), TransformAction.rename("sendStatistics"))
|
||||
.addAction(NodePath.path(), (path, value) -> {
|
||||
value.node("configVersion").set(LATEST);
|
||||
|
||||
return null;
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
public static <N extends ConfigurationNode> N updateNode(final N node, PluginLogger logger) throws ConfigurateException{
|
||||
if(!node.virtual()){
|
||||
final ConfigurationTransformation.Versioned versioned = create();
|
||||
final int startVersion = versioned.version(node);
|
||||
versioned.apply(node);
|
||||
final int endVersion = versioned.version(node);
|
||||
if(startVersion < endVersion)
|
||||
logger.info("Migrated config.yml from v" + startVersion + " to v" + endVersion);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
private static int resolveConfigVersion(){
|
||||
try(InputStream is = AdvancedServerList.class.getResourceAsStream("/version.properties")){
|
||||
Properties properties = new Properties();
|
||||
|
||||
properties.load(is);
|
||||
|
||||
return Integer.parseInt(properties.getProperty("config-version"));
|
||||
}catch(IOException | NumberFormatException ex){
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,12 +25,14 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.core.file;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
|
||||
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileSerializer;
|
||||
import org.spongepowered.configurate.ConfigurateException;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.yaml.NodeStyle;
|
||||
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
|
||||
|
||||
import java.io.File;
|
||||
@@ -38,13 +40,16 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
public class FileHandler{
|
||||
|
||||
private final AdvancedServerList plugin;
|
||||
private final AdvancedServerList<?> plugin;
|
||||
private final PluginLogger logger;
|
||||
|
||||
private final Path config;
|
||||
@@ -54,7 +59,7 @@ public class FileHandler{
|
||||
|
||||
private ConfigurationNode node = null;
|
||||
|
||||
public FileHandler(AdvancedServerList core){
|
||||
public FileHandler(AdvancedServerList<?> core){
|
||||
this.plugin = core;
|
||||
this.logger = core.getPlugin().getPluginLogger();
|
||||
|
||||
@@ -68,7 +73,7 @@ public class FileHandler{
|
||||
|
||||
public boolean loadConfig(){
|
||||
logger.info("Loading config.yml...");
|
||||
File folder = config.toFile().getParentFile();
|
||||
File folder = plugin.getPlugin().getFolderPath().toFile();
|
||||
if(!folder.exists() && !folder.mkdirs()){
|
||||
logger.warn("Couldn't create folder for plugin. Is it missing Write permissions?");
|
||||
return false;
|
||||
@@ -82,6 +87,7 @@ public class FileHandler{
|
||||
}
|
||||
|
||||
Files.copy(stream, config);
|
||||
logger.info("Created new config.yml!");
|
||||
}catch(IOException ex){
|
||||
logger.warn("Cannot create config.yml for plugin.", ex);
|
||||
return false;
|
||||
@@ -112,6 +118,26 @@ public class FileHandler{
|
||||
return reloadProfiles();
|
||||
}
|
||||
|
||||
public boolean migrateConfig(){
|
||||
YamlConfigurationLoader loader = YamlConfigurationLoader.builder()
|
||||
.path(config)
|
||||
.nodeStyle(NodeStyle.BLOCK)
|
||||
.build();
|
||||
|
||||
if(!makeBackup())
|
||||
return false;
|
||||
|
||||
try{
|
||||
node = ConfigMigrator.updateNode(loader.load(), logger);
|
||||
loader.save(node);
|
||||
|
||||
return true;
|
||||
}catch(ConfigurateException ex){
|
||||
logger.warn("Error while trying to migrate config.yml.", ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean reloadConfig(){
|
||||
return (node = getConfigurationNode(config)) != null;
|
||||
}
|
||||
@@ -131,7 +157,7 @@ public class FileHandler{
|
||||
continue;
|
||||
|
||||
profiles.add(ServerListProfile.Builder.resolve(file.getName(), tmp, logger).build());
|
||||
logger.info("Loaded " + file.getName());
|
||||
logger.info("Loaded '%s'!", file.getName());
|
||||
}
|
||||
|
||||
if(profiles.isEmpty()){
|
||||
@@ -139,7 +165,7 @@ public class FileHandler{
|
||||
return false;
|
||||
}
|
||||
|
||||
profiles.sort(Comparator.comparing(ServerListProfile::getPriority).reversed());
|
||||
profiles.sort(Comparator.comparing(ServerListProfile::priority).reversed());
|
||||
return !profiles.isEmpty();
|
||||
}
|
||||
|
||||
@@ -152,7 +178,7 @@ public class FileHandler{
|
||||
try{
|
||||
return loader.load();
|
||||
}catch(IOException ex){
|
||||
logger.warn("Cannot load " + path.toFile().getName() + " due to an IOException!", ex);
|
||||
logger.warn("Cannot load '%s' due to an IOException!", ex, path.toFile().getName());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -164,4 +190,41 @@ public class FileHandler{
|
||||
public boolean getBoolean(Object... path){
|
||||
return node.node(path).getBoolean();
|
||||
}
|
||||
|
||||
public long getLong(long def, long limit, Object... path){
|
||||
long value = node.node(path).getLong(def);
|
||||
return Math.max(value, limit);
|
||||
}
|
||||
|
||||
public boolean isOldConfig(){
|
||||
return node.node("configVersion").virtual() || node.node("configVersion").getInt(0) < ConfigMigrator.LATEST;
|
||||
}
|
||||
|
||||
private boolean makeBackup(){
|
||||
logger.info("Making backup of old config.yml...");
|
||||
|
||||
File backups = plugin.getPlugin().getFolderPath().resolve("backups").toFile();
|
||||
if(!backups.exists() && !backups.mkdirs()){
|
||||
logger.warn("Cannot create backups folder for migration!");
|
||||
return false;
|
||||
}
|
||||
|
||||
String date = DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.now());
|
||||
|
||||
File configBackup = new File(backups, "config_" + date.replace(":", "_") + ".yml");
|
||||
try{
|
||||
if(!configBackup.exists() && !configBackup.createNewFile()){
|
||||
logger.warn("Cannot create backup file for config.yml!");
|
||||
return false;
|
||||
}
|
||||
|
||||
Files.copy(config, configBackup.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
logger.info("Saved backup as '%s'!", configBackup.getName());
|
||||
|
||||
return true;
|
||||
}catch(IOException ex){
|
||||
logger.warn("Encountered IOException while trying to create a backup.", ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,10 @@ package ch.andre601.advancedserverlist.core.interfaces;
|
||||
|
||||
public interface PluginLogger{
|
||||
|
||||
void debug(Class<?> clazz, String msg, Object... args);
|
||||
|
||||
void debugWarn(Class<?> clazz, String msg, Object... args);
|
||||
|
||||
void info(String msg, Object... args);
|
||||
|
||||
void warn(String msg, Object... args);
|
||||
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.interfaces.commands;
|
||||
|
||||
public interface CmdSender{
|
||||
|
||||
String prefix = "<grey>[<gradient:aqua:white>AdvancedServerList</gradient>] ";
|
||||
String errorPrefix = "<grey>[<gradient:dark_red:red>AdvancedServerList</gradient>] ";
|
||||
|
||||
boolean hasPermission(String permission);
|
||||
|
||||
void sendMsg(String msg, Object... args);
|
||||
|
||||
default void sendMsg(){
|
||||
sendMsg("");
|
||||
}
|
||||
|
||||
default void sendPrefixedMsg(String msg, Object... args){
|
||||
sendMsg(prefix + msg, args);
|
||||
}
|
||||
|
||||
default void sendErrorMsg(String msg, Object... args){
|
||||
sendMsg(errorPrefix + msg, args);
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.interfaces.commands;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public abstract class PluginCommand{
|
||||
|
||||
private final String argument;
|
||||
|
||||
public PluginCommand(String argument){
|
||||
this.argument = argument;
|
||||
}
|
||||
|
||||
public String getArgument(){
|
||||
return argument;
|
||||
}
|
||||
|
||||
public String getPermission(){
|
||||
return "advancedserverlist.command." + getArgument().toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
public abstract void handle(CmdSender sender);
|
||||
}
|
||||
+13
-1
@@ -29,6 +29,7 @@ import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import ch.andre601.advancedserverlist.core.profiles.favicon.FaviconHandler;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public interface PluginCore<F>{
|
||||
@@ -39,9 +40,11 @@ public interface PluginCore<F>{
|
||||
|
||||
void loadMetrics();
|
||||
|
||||
void loadFaviconHandler(AdvancedServerList<F> core);
|
||||
|
||||
void clearFaviconCache();
|
||||
|
||||
AdvancedServerList getCore();
|
||||
AdvancedServerList<F> getCore();
|
||||
|
||||
Path getFolderPath();
|
||||
|
||||
@@ -54,4 +57,13 @@ public interface PluginCore<F>{
|
||||
String getPlatformVersion();
|
||||
|
||||
String getLoader();
|
||||
|
||||
F createFavicon(BufferedImage image) throws Exception;
|
||||
|
||||
default boolean isDebugEnabled(){
|
||||
if(getCore() == null)
|
||||
return false;
|
||||
|
||||
return getCore().getFileHandler().getBoolean("debug");
|
||||
}
|
||||
}
|
||||
+13
-9
@@ -25,18 +25,20 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.core.interfaces.events;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.events.GenericServerListEvent;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
|
||||
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.players.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.replacer.placeholders.PlayerPlaceholders;
|
||||
import ch.andre601.advancedserverlist.core.profiles.replacer.placeholders.ServerPlaceholders;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.List;
|
||||
|
||||
public interface GenericEventWrapper<P, F>{
|
||||
public interface GenericEventWrapper<F, P extends GenericPlayer>{
|
||||
|
||||
GenericServerListEvent callEvent(ProfileEntry entry);
|
||||
|
||||
void setMaxPlayers(int maxPlayers);
|
||||
|
||||
@@ -46,7 +48,7 @@ public interface GenericEventWrapper<P, F>{
|
||||
|
||||
void setPlayerCount(String name);
|
||||
|
||||
void setPlayers(List<String> players, GenericPlayer<P> player, PlayerPlaceholders playerPlaceholders, ServerPlaceholders serverPlaceholders);
|
||||
void setPlayers(List<String> players, P player, GenericServer server);
|
||||
|
||||
void setFavicon(F favicon);
|
||||
|
||||
@@ -56,6 +58,8 @@ public interface GenericEventWrapper<P, F>{
|
||||
|
||||
boolean isInvalidProtocol();
|
||||
|
||||
boolean isMaintenanceModeActive();
|
||||
|
||||
int getProtocolVersion();
|
||||
|
||||
int getOnlinePlayers();
|
||||
@@ -64,15 +68,15 @@ public interface GenericEventWrapper<P, F>{
|
||||
|
||||
String getPlayerIP();
|
||||
|
||||
String parsePAPIPlaceholders(String text, GenericPlayer<P> player);
|
||||
String parsePAPIPlaceholders(String text, P player);
|
||||
|
||||
String getVirtualHost();
|
||||
|
||||
PluginCore<F> getPlugin();
|
||||
|
||||
GenericPlayer<P> createPlayer(CachedPlayer player, int protocol);
|
||||
P createPlayer(CachedPlayer player, int protocol);
|
||||
|
||||
F createFavicon(BufferedImage image) throws Exception;
|
||||
GenericServer createGenericServer(int playersOnline, int playersMax, String host);
|
||||
|
||||
default String resolveHost(InetSocketAddress address){
|
||||
return address == null ? null : address.getHostString();
|
||||
|
||||
@@ -25,8 +25,6 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.core.parsing;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.replacer.placeholders.Placeholders;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
@@ -58,11 +56,6 @@ public class ComponentParser{
|
||||
return new ComponentParser(String.join("\n", lines));
|
||||
}
|
||||
|
||||
public ComponentParser replacements(Placeholders placeholders){
|
||||
text = StringReplacer.replace(text, placeholders.getReplacements());
|
||||
return this;
|
||||
}
|
||||
|
||||
public ComponentParser modifyText(Function<String, String> function){
|
||||
this.text = function.apply(text);
|
||||
return this;
|
||||
|
||||
+39
-62
@@ -25,48 +25,46 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.Expression;
|
||||
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.ProfileConditionParser;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
import ch.andre601.expressionparser.templates.ExpressionTemplate;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
public class ServerListProfile{
|
||||
public record ServerListProfile(int priority, String condition, ProfileEntry defaultProfile, List<ProfileEntry> profiles){
|
||||
private static final Random random = new Random();
|
||||
|
||||
private final int priority;
|
||||
private final List<Expression> expressions;
|
||||
private final ProfileEntry defaultProfile;
|
||||
|
||||
private final List<ProfileEntry> profiles;
|
||||
|
||||
private final Random random = new Random();
|
||||
|
||||
public ServerListProfile(int priority, List<Expression> expressions, List<ProfileEntry> profiles, ProfileEntry defaultProfile){
|
||||
this.priority = priority;
|
||||
this.expressions = expressions;
|
||||
this.profiles = profiles;
|
||||
this.defaultProfile = defaultProfile;
|
||||
}
|
||||
|
||||
public int getPriority(){
|
||||
return priority;
|
||||
}
|
||||
|
||||
public boolean evaluateConditions(Map<String, Object> replacements){
|
||||
if(expressions.isEmpty())
|
||||
public boolean evalConditions(ProfileConditionParser parser, PluginLogger logger, GenericPlayer player, GenericServer server){
|
||||
if(condition == null || condition.isEmpty())
|
||||
return true;
|
||||
|
||||
for(Expression expression : expressions){
|
||||
if(!expression.evaluate(replacements))
|
||||
return false;
|
||||
ParseWarnCollector collector = new ParseWarnCollector(condition);
|
||||
ExpressionTemplate template = parser.compile(condition, player, server, collector);
|
||||
|
||||
if(collector.hasWarnings()){
|
||||
logger.warn("Encountered %d Error(s) while parsing condition '%s':", collector.getWarnings().size(), condition);
|
||||
|
||||
for(ParseWarnCollector.Context context : collector.getWarnings()){
|
||||
if(context.position() <= -1){
|
||||
logger.warn(" - %s", context.message());
|
||||
}else{
|
||||
logger.warn(" - At Position %d: %s", context.position(), context.message());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
if(template == null)
|
||||
return false;
|
||||
|
||||
return template.returnBooleanExpression().evaluate();
|
||||
}
|
||||
|
||||
public ProfileEntry getRandomProfile(){
|
||||
@@ -82,10 +80,6 @@ public class ServerListProfile{
|
||||
}
|
||||
}
|
||||
|
||||
public ProfileEntry getDefaultProfile(){
|
||||
return defaultProfile;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if the Profile...
|
||||
* ...doesn't have any valid MOTD set AND
|
||||
@@ -94,20 +88,20 @@ public class ServerListProfile{
|
||||
* ...doesn't have a favicon set.
|
||||
*/
|
||||
public boolean isInvalidProfile(){
|
||||
if(profiles.isEmpty())
|
||||
return defaultProfile.isInvalidProfile();
|
||||
if(profiles().isEmpty())
|
||||
return defaultProfile().isInvalid();
|
||||
|
||||
boolean profilesValid = false;
|
||||
|
||||
for(ProfileEntry profile : profiles){
|
||||
if(profile.isInvalidProfile())
|
||||
for(ProfileEntry profile : profiles()){
|
||||
if(profile.isInvalid())
|
||||
continue;
|
||||
|
||||
profilesValid = true;
|
||||
break;
|
||||
}
|
||||
|
||||
return !profilesValid && defaultProfile.isInvalidProfile();
|
||||
return !profilesValid && defaultProfile.isInvalid();
|
||||
}
|
||||
|
||||
public static class Builder{
|
||||
@@ -115,10 +109,10 @@ public class ServerListProfile{
|
||||
private final String fileName;
|
||||
private final ConfigurationNode node;
|
||||
private final int priority;
|
||||
private final List<Expression> expressions = new ArrayList<>();
|
||||
|
||||
private final PluginLogger logger;
|
||||
|
||||
private String condition = null;
|
||||
private List<ProfileEntry> profiles = new ArrayList<>();
|
||||
private ProfileEntry defaultProfile = ProfileEntry.empty();
|
||||
|
||||
@@ -131,34 +125,17 @@ public class ServerListProfile{
|
||||
|
||||
public static Builder resolve(String fileName, ConfigurationNode node, PluginLogger logger){
|
||||
return new Builder(fileName, node, logger)
|
||||
.resolveExpressions()
|
||||
.resolveCondition()
|
||||
.resolveProfiles()
|
||||
.resolveDefaultProfile();
|
||||
}
|
||||
|
||||
private Builder resolveExpressions(){
|
||||
List<String> temp;
|
||||
try{
|
||||
temp = node.node("conditions").getList(String.class);
|
||||
}catch(SerializationException ex){
|
||||
logger.warn("Encountered a SerializationException while resolving conditions for %s", ex, fileName);
|
||||
return this;
|
||||
}
|
||||
|
||||
if(temp == null || temp.isEmpty())
|
||||
private Builder resolveCondition(){
|
||||
String condition = node.node("condition").getString();
|
||||
if(condition == null || condition.isEmpty())
|
||||
return this;
|
||||
|
||||
for(String str : temp){
|
||||
Expression expr = new Expression(str);
|
||||
|
||||
if(expr.getResult() != Expression.ExpressionResult.VALID){
|
||||
logger.warn("Found invalid expression in condition '%s'! Reason: %s", str, expr.getResult().getMessage());
|
||||
continue;
|
||||
}
|
||||
|
||||
this.expressions.add(expr);
|
||||
}
|
||||
|
||||
this.condition = condition;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -182,7 +159,7 @@ public class ServerListProfile{
|
||||
}
|
||||
|
||||
public ServerListProfile build(){
|
||||
return new ServerListProfile(this.priority, this.expressions, this.profiles, this.defaultProfile);
|
||||
return new ServerListProfile(this.priority, this.condition, this.defaultProfile, this.profiles);
|
||||
}
|
||||
}
|
||||
}
|
||||
-208
@@ -1,208 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class Expression{
|
||||
|
||||
private ExpressionResult result = ExpressionResult.VALID;
|
||||
|
||||
private String left;
|
||||
private Operator operator = Operator.UNKNOWN;
|
||||
private String right;
|
||||
|
||||
public Expression(String expression){
|
||||
resolveExpression(expression);
|
||||
}
|
||||
|
||||
public boolean evaluate(Map<String, Object> replacements){
|
||||
String newLeft = StringReplacer.replace(left, replacements).trim();
|
||||
String newRight = StringReplacer.replace(right, replacements).trim();
|
||||
|
||||
return operator.evaluate(newLeft, newRight);
|
||||
}
|
||||
|
||||
public ExpressionResult getResult(){
|
||||
return result;
|
||||
}
|
||||
|
||||
private void resolveExpression(String expression){
|
||||
if(expression == null || expression.isEmpty()){
|
||||
result = ExpressionResult.INVALID_NO_EXPRESSION;
|
||||
return;
|
||||
}
|
||||
|
||||
char[] chars = expression.toCharArray();
|
||||
|
||||
StringBuilder left = new StringBuilder();
|
||||
StringBuilder right = new StringBuilder();
|
||||
|
||||
boolean foundOperator = false;
|
||||
|
||||
for(int i = 0; i < chars.length; i++){
|
||||
char c = chars[i];
|
||||
char next = (i == (chars.length - 1)) ? '\0' : chars[i + 1];
|
||||
|
||||
Operator tmp = Operator.getOperand(c, next);
|
||||
if(tmp != Operator.UNKNOWN && !foundOperator){
|
||||
operator = tmp;
|
||||
foundOperator = true;
|
||||
|
||||
if(tmp.hasSecond())
|
||||
i++; // Skip next character if operator has 2
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if(foundOperator){
|
||||
right.append(c);
|
||||
}else{
|
||||
left.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
if(left.isEmpty() || right.isEmpty()){
|
||||
result = ExpressionResult.INVALID_EMPTY_PARTS;
|
||||
return;
|
||||
}
|
||||
|
||||
this.left = left.toString();
|
||||
this.right = right.toString();
|
||||
}
|
||||
|
||||
public enum Operator{
|
||||
LESS('<', '\0'){
|
||||
@Override
|
||||
public boolean evaluate(String left, String right){
|
||||
int leftInt = Operator.getInt(left);
|
||||
int rightInt = Operator.getInt(right);
|
||||
|
||||
return leftInt < rightInt;
|
||||
}
|
||||
},
|
||||
LESS_OR_EQUAL('<', '='){
|
||||
@Override
|
||||
public boolean evaluate(String left, String right){
|
||||
int leftInt = Operator.getInt(left);
|
||||
int rightInt = Operator.getInt(right);
|
||||
|
||||
return leftInt <= rightInt;
|
||||
}
|
||||
},
|
||||
EQUAL('=', '\0'){
|
||||
@Override
|
||||
public boolean evaluate(String left, String right){
|
||||
return left.equals(right);
|
||||
}
|
||||
},
|
||||
NOT_EQUAL('!', '='){
|
||||
@Override
|
||||
public boolean evaluate(String left, String right){
|
||||
return !left.equals(right);
|
||||
}
|
||||
},
|
||||
GREATER('>', '\0'){
|
||||
@Override
|
||||
public boolean evaluate(String left, String right){
|
||||
int leftInt = Operator.getInt(left);
|
||||
int rightInt = Operator.getInt(right);
|
||||
|
||||
return leftInt > rightInt;
|
||||
}
|
||||
},
|
||||
GREATER_OR_EQUAL('>', '='){
|
||||
@Override
|
||||
public boolean evaluate(String left, String right){
|
||||
int leftInt = Operator.getInt(left);
|
||||
int rightInt = Operator.getInt(right);
|
||||
|
||||
return leftInt >= rightInt;
|
||||
}
|
||||
},
|
||||
|
||||
UNKNOWN('\0', '\0'){
|
||||
@Override
|
||||
public boolean evaluate(String left, String right){
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
private static final Operator[] VALUES = values();
|
||||
|
||||
private final char first;
|
||||
private final char second;
|
||||
|
||||
Operator(char first, char second){
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
|
||||
public static Operator getOperand(char first, char second){
|
||||
for(Operator operator : VALUES){
|
||||
if(operator.first == first){
|
||||
if((!operator.hasSecond() && second != '=') || operator.second == second)
|
||||
return operator;
|
||||
}
|
||||
}
|
||||
|
||||
return Operator.UNKNOWN;
|
||||
}
|
||||
|
||||
public boolean hasSecond(){
|
||||
return second != '\0';
|
||||
}
|
||||
|
||||
public abstract boolean evaluate(String left, String right);
|
||||
|
||||
private static int getInt(String text){
|
||||
try{
|
||||
return Integer.parseInt(text);
|
||||
}catch(NumberFormatException ex){
|
||||
return text.length();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum ExpressionResult{
|
||||
VALID(null),
|
||||
|
||||
INVALID_NO_EXPRESSION("Received empty condition which isn't allowed!"),
|
||||
INVALID_EMPTY_PARTS ("Received condition with either left or right part being empty.");
|
||||
|
||||
private final String message;
|
||||
|
||||
ExpressionResult(String message){
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getMessage(){
|
||||
return message;
|
||||
}
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.reader.PlaceholderTokenReader;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.reader.PlaceholderValueReader;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens.CustomExpressionTokenizer;
|
||||
import ch.andre601.expressionparser.ExpressionParserEngine;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
import ch.andre601.expressionparser.operator.Operator;
|
||||
import ch.andre601.expressionparser.parsers.ExpressionTemplateParser;
|
||||
import ch.andre601.expressionparser.parsers.ValueReader;
|
||||
import ch.andre601.expressionparser.templates.ExpressionTemplate;
|
||||
import ch.andre601.expressionparser.tokens.Token;
|
||||
import ch.andre601.expressionparser.tokens.readers.TokenReader;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ProfileConditionParser implements ExpressionParserEngine{
|
||||
|
||||
private final CustomExpressionTokenizer tokenizer;
|
||||
private final ExpressionTemplateParser parser;
|
||||
|
||||
private ProfileConditionParser(List<TokenReader> tokenReaders, ImmutableMap<Token, Operator> operators, ImmutableList<ValueReader> valueReaders){
|
||||
this.tokenizer = new CustomExpressionTokenizer(tokenReaders);
|
||||
this.parser = new ExpressionTemplateParser(operators, valueReaders);
|
||||
}
|
||||
|
||||
public static ProfileConditionParser create(){
|
||||
return new ProfileConditionParserBuilder().createDefault()
|
||||
.addTokenReader(new PlaceholderTokenReader(-20))
|
||||
.addValueReader(new PlaceholderValueReader())
|
||||
.build();
|
||||
}
|
||||
|
||||
public ExpressionTemplate compile(String text, GenericPlayer player, GenericServer server, ParseWarnCollector collector){
|
||||
return parser.parse(tokenizer.parse(text, player, server, collector), collector);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionTemplate compile(String s, ParseWarnCollector parseWarnCollector){
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class ProfileConditionParserBuilder extends ExpressionParserEngine.Builder<ProfileConditionParser>{
|
||||
@Override
|
||||
public ProfileConditionParser build(){
|
||||
return new ProfileConditionParser(this.getTokenReaders(), ImmutableMap.copyOf(this.getOperators()), ImmutableList.copyOf(this.getValueReaders()));
|
||||
}
|
||||
}
|
||||
}
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions.placeholders;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.AdvancedServerListAPI;
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens.PlaceholderToken;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
|
||||
import java.text.ParsePosition;
|
||||
|
||||
public class PlaceholderParser{
|
||||
|
||||
public static PlaceholderToken.Placeholder parse(String text, ParsePosition position, GenericPlayer player, GenericServer server, ParseWarnCollector collector){
|
||||
AdvancedServerListAPI api = AdvancedServerListAPI.get();
|
||||
|
||||
// We want to point to the start of a placeholder in the ParseWarnCollector.
|
||||
// Since the PlaceholderTokenReader updates the index by 2 are we reverting this here.
|
||||
int placeholderStart = position.getIndex() - 2;
|
||||
int index = position.getIndex();
|
||||
|
||||
StringBuilder identifier = new StringBuilder();
|
||||
StringBuilder values = new StringBuilder();
|
||||
|
||||
boolean identified = false;
|
||||
boolean invalid = true;
|
||||
|
||||
char[] chars = text.substring(index).toCharArray();
|
||||
for(final char c : chars){
|
||||
index++;
|
||||
|
||||
if(c == '}'){
|
||||
invalid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if(c == ' ' && !identified){
|
||||
identified = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(identified){
|
||||
values.append(c);
|
||||
}else{
|
||||
identifier.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
String identifierStr = identifier.toString();
|
||||
String valuesStr = values.toString();
|
||||
|
||||
StringBuilder raw = new StringBuilder();
|
||||
|
||||
// Skipping whatever character we currently were on (i.e. })
|
||||
position.setIndex(index + 1);
|
||||
|
||||
if(invalid){
|
||||
raw.append("${").append(identifierStr);
|
||||
|
||||
if(identified)
|
||||
raw.append(' ').append(valuesStr);
|
||||
|
||||
collector.appendWarningFormatted(placeholderStart, "Placeholder '%s' does not have a closing bracket (}).", raw.toString());
|
||||
return new PlaceholderToken.Placeholder(raw.toString());
|
||||
}
|
||||
|
||||
PlaceholderProvider provider = api.retrievePlaceholderProvider(identifierStr);
|
||||
if(provider == null){
|
||||
raw.append("${").append(identifierStr);
|
||||
|
||||
if(identified)
|
||||
raw.append(' ').append(valuesStr);
|
||||
|
||||
raw.append('}');
|
||||
|
||||
collector.appendWarningFormatted(placeholderStart, "Placeholder '%s' does not have any available PlaceholderProvider", raw.toString());
|
||||
return new PlaceholderToken.Placeholder(raw.toString());
|
||||
}
|
||||
|
||||
String replacement = provider.parsePlaceholder(valuesStr, player, server);
|
||||
if(replacement == null){
|
||||
raw.append("${").append(identifierStr);
|
||||
|
||||
if(identified)
|
||||
raw.append(' ').append(valuesStr);
|
||||
|
||||
raw.append('}');
|
||||
|
||||
collector.appendWarningFormatted(placeholderStart, "Placeholder '%s' has an invalid value String '%s'.", raw.toString(), valuesStr);
|
||||
return new PlaceholderToken.Placeholder(raw.toString());
|
||||
}
|
||||
|
||||
return new PlaceholderToken.Placeholder(replacement);
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.reader;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
import ch.andre601.expressionparser.tokens.Token;
|
||||
import ch.andre601.expressionparser.tokens.readers.TokenReader;
|
||||
|
||||
import java.text.ParsePosition;
|
||||
|
||||
public abstract class CustomTokenReader extends TokenReader{
|
||||
|
||||
public CustomTokenReader(int priority){
|
||||
super(priority);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Token read(String text, ParsePosition position, ParseWarnCollector collector){
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract Token read(String text, ParsePosition position, GenericPlayer player, GenericServer server, ParseWarnCollector collector);
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.reader;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.PlaceholderParser;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens.PlaceholderToken;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
import ch.andre601.expressionparser.tokens.Token;
|
||||
|
||||
import java.text.ParsePosition;
|
||||
|
||||
public class PlaceholderTokenReader extends CustomTokenReader{
|
||||
|
||||
public PlaceholderTokenReader(int priority){
|
||||
super(priority);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Token read(String text, ParsePosition position, GenericPlayer player, GenericServer server, ParseWarnCollector collector){
|
||||
if(position.getIndex() + 1 < text.length() && text.charAt(position.getIndex()) == '$' && text.charAt(position.getIndex() + 1) == '{'){
|
||||
position.setIndex(position.getIndex() + 2);
|
||||
return new PlaceholderToken(PlaceholderParser.parse(text, position, player, server, collector));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.reader;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens.PlaceholderToken;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
import ch.andre601.expressionparser.parsers.ExpressionTemplateParser;
|
||||
import ch.andre601.expressionparser.parsers.ValueReader;
|
||||
import ch.andre601.expressionparser.templates.ExpressionTemplate;
|
||||
import ch.andre601.expressionparser.tokens.Token;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PlaceholderValueReader extends ValueReader{
|
||||
@Override
|
||||
public ExpressionTemplate read(ExpressionTemplateParser parser, List<Token> tokens, ParseWarnCollector collector){
|
||||
if(tokens.get(0) instanceof PlaceholderToken){
|
||||
PlaceholderToken token = (PlaceholderToken)tokens.remove(0);
|
||||
return token.getValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.reader.CustomTokenReader;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
import ch.andre601.expressionparser.tokens.Token;
|
||||
import ch.andre601.expressionparser.tokens.readers.TokenReader;
|
||||
import com.google.common.collect.Ordering;
|
||||
|
||||
import java.text.ParsePosition;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class CustomExpressionTokenizer{
|
||||
|
||||
private static final Ordering<TokenReader> TOKEN_READER_ORDERING = Ordering.from(Comparator.comparingInt(TokenReader::getPriority)).reverse();
|
||||
|
||||
private final List<TokenReader> tokenReaders;
|
||||
|
||||
public CustomExpressionTokenizer(Iterable<TokenReader> tokenReaders){
|
||||
this.tokenReaders = TOKEN_READER_ORDERING.immutableSortedCopy(tokenReaders);
|
||||
}
|
||||
|
||||
public List<Token> parse(String text, GenericPlayer player, GenericServer server, ParseWarnCollector collector){
|
||||
ParsePosition position = new ParsePosition(0);
|
||||
|
||||
List<Token> tokens = new LinkedList<>();
|
||||
|
||||
next_token:
|
||||
while(true){
|
||||
while(position.getIndex() < text.length() && Character.isWhitespace(text.charAt(position.getIndex())))
|
||||
position.setIndex(position.getIndex() + 1);
|
||||
|
||||
if(position.getIndex() >= text.length())
|
||||
break;
|
||||
|
||||
for(TokenReader tokenReader : tokenReaders){
|
||||
Token token;
|
||||
if(tokenReader instanceof CustomTokenReader customTokenReader){
|
||||
if(null != (token = customTokenReader.read(text, position, player, server, collector))){
|
||||
tokens.add(token);
|
||||
continue next_token;
|
||||
}
|
||||
}else{
|
||||
if(null != (token = tokenReader.read(text, position, collector))){
|
||||
tokens.add(token);
|
||||
continue next_token;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
collector.appendWarningFormatted(position.getIndex(), "Illegal Token '%c'.", text.charAt(position.getIndex()));
|
||||
break;
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens;
|
||||
|
||||
import ch.andre601.expressionparser.expressions.ToBooleanExpression;
|
||||
import ch.andre601.expressionparser.expressions.ToDoubleExpression;
|
||||
import ch.andre601.expressionparser.expressions.ToStringExpression;
|
||||
import ch.andre601.expressionparser.templates.ExpressionTemplate;
|
||||
import ch.andre601.expressionparser.tokens.Token;
|
||||
|
||||
public class PlaceholderToken extends Token{
|
||||
|
||||
private final Placeholder value;
|
||||
|
||||
public PlaceholderToken(Placeholder value){
|
||||
super("PLACEHOLDER");
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Placeholder getValue(){
|
||||
return value;
|
||||
}
|
||||
|
||||
public static class Placeholder implements ExpressionTemplate{
|
||||
|
||||
private final ToBooleanExpression toBooleanExpression;
|
||||
private final ToDoubleExpression toDoubleExpression;
|
||||
private final ToStringExpression toStringExpression;
|
||||
|
||||
public Placeholder(String value){
|
||||
double doubleValue;
|
||||
try{
|
||||
doubleValue = Double.parseDouble(value);
|
||||
}catch(NumberFormatException ex){
|
||||
doubleValue = value.length();
|
||||
}
|
||||
|
||||
this.toBooleanExpression = ToBooleanExpression.literal(Boolean.parseBoolean(value));
|
||||
this.toDoubleExpression = ToDoubleExpression.literal(doubleValue);
|
||||
this.toStringExpression = ToStringExpression.literal(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ToBooleanExpression returnBooleanExpression(){
|
||||
return toBooleanExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ToDoubleExpression returnDoubleExpression(){
|
||||
return toDoubleExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ToStringExpression returnStringExpression(){
|
||||
return toStringExpression;
|
||||
}
|
||||
}
|
||||
}
|
||||
+139
-76
@@ -26,113 +26,176 @@
|
||||
package ch.andre601.advancedserverlist.core.profiles.favicon;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class FaviconHandler<F>{
|
||||
|
||||
private final Cache<String, F> favicons = Caffeine.newBuilder()
|
||||
.expireAfterWrite(5, TimeUnit.MINUTES)
|
||||
.build();
|
||||
private final AdvancedServerList<F> core;
|
||||
private final PluginLogger logger;
|
||||
private final ThreadPoolExecutor faviconThreadPool;
|
||||
private final Cache<String, CompletableFuture<F>> faviconCache;
|
||||
|
||||
private final AdvancedServerList core;
|
||||
private final Map<String, F> localFavicons = new HashMap<>();
|
||||
private final HttpClient client = HttpClient.newHttpClient();
|
||||
|
||||
public FaviconHandler(AdvancedServerList core){
|
||||
public FaviconHandler(AdvancedServerList<F> core){
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
public F getFavicon(String input, Function<BufferedImage, F> function){
|
||||
return favicons.get(input, k -> {
|
||||
BufferedImage image = resolveImage(core, input);
|
||||
if(image == null)
|
||||
return null;
|
||||
|
||||
return function.apply(image);
|
||||
});
|
||||
}
|
||||
|
||||
public void clearCache(){
|
||||
favicons.invalidateAll();
|
||||
}
|
||||
|
||||
private BufferedImage resolveImage(AdvancedServerList core, String input){
|
||||
InputStream stream;
|
||||
this.logger = core.getPlugin().getPluginLogger();
|
||||
this.faviconThreadPool = createFaviconThreadPool();
|
||||
this.faviconCache = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(core.getFileHandler().getLong(1, 1, "faviconCacheTime"), TimeUnit.MINUTES)
|
||||
.build();
|
||||
|
||||
loadLocalFavicons();
|
||||
}
|
||||
|
||||
public F getFavicon(String input){
|
||||
if(localFavicons.containsKey(input.toLowerCase(Locale.ROOT).split("\\.")[0])){
|
||||
return localFavicons.get(input.toLowerCase(Locale.ROOT).split("\\.")[0]);
|
||||
}
|
||||
|
||||
try{
|
||||
return faviconCache.get(input, () -> getFuture(input)).getNow(null);
|
||||
}catch(ExecutionException ex){
|
||||
logger.warn("Received ExecutionException while retrieving Favicon for '%s'.", ex, input);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void cleanCache(){
|
||||
faviconCache.invalidateAll();
|
||||
loadLocalFavicons();
|
||||
}
|
||||
|
||||
private CompletableFuture<F> getFuture(String input){
|
||||
if(input.toLowerCase(Locale.ROOT).startsWith("https://")){
|
||||
stream = getFromUrl(core, input);
|
||||
logger.debug(FaviconHandler.class, "Resolving URL '%s'...", input);
|
||||
return CompletableFuture.supplyAsync(() -> fromURL(core, input), this.faviconThreadPool);
|
||||
}else
|
||||
if(input.toLowerCase(Locale.ROOT).endsWith(".png")){
|
||||
File folder = core.getPlugin().getFolderPath().resolve("favicons").toFile();
|
||||
if(!folder.exists()){
|
||||
core.getPlugin().getPluginLogger().warn("Cannot get Favicon %s from favicons folder. Folder doesn't exist!", input);
|
||||
return null;
|
||||
}
|
||||
|
||||
File file = new File(folder, input);
|
||||
|
||||
try{
|
||||
stream = new FileInputStream(file);
|
||||
}catch(IOException ex){
|
||||
core.getPlugin().getPluginLogger().warn("Cannot create Favicon from File %s.", input);
|
||||
core.getPlugin().getPluginLogger().warn("Cause: %s", ex.getMessage());
|
||||
return null;
|
||||
}
|
||||
logger.debug(FaviconHandler.class, "Resolving image file '%s'...", input);
|
||||
return CompletableFuture.completedFuture(localFavicons.get(input.toLowerCase(Locale.ROOT).split("\\.")[0]));
|
||||
}else{
|
||||
stream = getFromUrl(core, "https://mc-heads.net/avatar/" + input + "/64");
|
||||
logger.debug(FaviconHandler.class, "Resolving Name/UUID as https://mc-heads.net/avatar/%s/64...", input);
|
||||
return CompletableFuture.supplyAsync(() -> fromURL(core, "https://mc-heads.net/avatar/" + input + "/64"), this.faviconThreadPool);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadLocalFavicons(){
|
||||
this.localFavicons.clear();
|
||||
|
||||
logger.info("Loading local image files as Favicons...");
|
||||
|
||||
Path folder = core.getPlugin().getFolderPath().resolve("favicons");
|
||||
if(!Files.exists(folder)){
|
||||
try{
|
||||
Files.createDirectories(folder);
|
||||
logger.info("Created favicons folder.");
|
||||
}catch(IOException ex){
|
||||
logger.warn("Cannot create favicons folder. Encountered an IOException.", ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(stream == null){
|
||||
core.getPlugin().getPluginLogger().warn("Cannot create Favicon. InputStream was null.");
|
||||
return null;
|
||||
try(Stream<Path> pathStream = Files.list(folder)){
|
||||
pathStream.filter(Files::isRegularFile)
|
||||
.filter(file -> file.getFileName().toString().endsWith(".png"))
|
||||
.forEach(this::loadFile);
|
||||
}catch(IOException ex){
|
||||
logger.warn("Cannot load files from Favicons folder.", ex);
|
||||
}
|
||||
|
||||
try{
|
||||
BufferedImage original = ImageIO.read(stream);
|
||||
if(original == null){
|
||||
core.getPlugin().getPluginLogger().warn("Cannot create Favicon. Unable to create BufferedImage.");
|
||||
return null;
|
||||
}
|
||||
|
||||
private void loadFile(Path path){
|
||||
try(InputStream stream = Files.newInputStream(path)){
|
||||
F favicon = createFavicon(stream);
|
||||
if(favicon == null){
|
||||
logger.warn("Cannot create Favicon from file '%s'. Received Favicon was null.", path.getFileName().toString());
|
||||
return;
|
||||
}
|
||||
|
||||
BufferedImage favicon = new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D img = favicon.createGraphics();
|
||||
|
||||
// Resize original image to 64x64 and apply to favicon.
|
||||
img.drawImage(original, 0, 0, 64, 64, null);
|
||||
img.dispose();
|
||||
|
||||
return favicon;
|
||||
localFavicons.put(path.getFileName().toString().split("\\.")[0], favicon);
|
||||
logger.info("Loaded file '%s' as Favicon.", path.getFileName().toString());
|
||||
}catch(IOException ex){
|
||||
core.getPlugin().getPluginLogger().warn("Unable to create Favicon. Encountered IOException during creation.");
|
||||
core.getPlugin().getPluginLogger().warn("Cause: %s", ex.getMessage());
|
||||
logger.warn("Cannot create Favicon from file '%s'. Encountered IOException.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private F fromURL(AdvancedServerList<F> core, String url){
|
||||
try{
|
||||
logger.debug(FaviconHandler.class, "Creating Request for URL '%s'...", url);
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(new URI(url))
|
||||
.header("User-Agent", "AdvancedServerList-" + core.getPlugin().getLoader() + "/" + core.getVersion())
|
||||
.build();
|
||||
|
||||
try(InputStream stream = client.send(request, HttpResponse.BodyHandlers.ofInputStream()).body()){
|
||||
return createFavicon(stream);
|
||||
}catch(InterruptedException | IOException ex){
|
||||
logger.warn("Cannot create Favicon from URL '%s'. Encountered an Exception.", ex, url);
|
||||
return null;
|
||||
}
|
||||
}catch(URISyntaxException ex){
|
||||
logger.warn("Cannot create Favicon from URL '%s'. Encountered an IOException.", ex, url);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private InputStream getFromUrl(AdvancedServerList core, String url){
|
||||
private F createFavicon(InputStream stream){
|
||||
try{
|
||||
URL faviconUrl = new URL(url);
|
||||
URLConnection connection = faviconUrl.openConnection();
|
||||
connection.setRequestProperty("User-Agent", "AdvancedServerList/" + core.getVersion());
|
||||
connection.connect();
|
||||
logger.debug(FaviconHandler.class, "Creating BufferedImage from InputStream...");
|
||||
BufferedImage original = ImageIO.read(stream);
|
||||
if(original == null){
|
||||
logger.warn("Cannot create Favicon. Received null BufferedImage.");
|
||||
return null;
|
||||
}
|
||||
|
||||
return connection.getInputStream();
|
||||
}catch(IOException ex){
|
||||
core.getPlugin().getPluginLogger().warn("Error while connecting to %s for Favicon creation.", url);
|
||||
core.getPlugin().getPluginLogger().warn("Cause: %s", ex.getMessage());
|
||||
// Don't waste resources resizing images already having right size.
|
||||
if(original.getWidth() == 64 && original.getHeight() == 64){
|
||||
logger.debug(FaviconHandler.class, "BufferedImage is 64x64 pixels. No resizing needed.");
|
||||
return core.getPlugin().createFavicon(original);
|
||||
}
|
||||
|
||||
logger.debug(FaviconHandler.class, "Resizing image to 64x64 pixels...");
|
||||
BufferedImage image = new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D graphics2D = image.createGraphics();
|
||||
|
||||
graphics2D.drawImage(original, 0, 0, 64, 64, null);
|
||||
graphics2D.dispose();
|
||||
|
||||
logger.debug(FaviconHandler.class, "Image resized! Returning Favicon...");
|
||||
return core.getPlugin().createFavicon(image);
|
||||
}catch(Exception ex){
|
||||
logger.warn("Unable to create Favicon. Received Exception.", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private ThreadPoolExecutor createFaviconThreadPool(){
|
||||
return new ThreadPoolExecutor(3, 3, 60L, TimeUnit.SECONDS, new LinkedBlockingDeque<>(1024), r -> {
|
||||
Thread t = new Thread(r, "AdvancedServerList-FaviconThread");
|
||||
t.setDaemon(true);
|
||||
return t;
|
||||
});
|
||||
}
|
||||
}
|
||||
+8
-28
@@ -25,48 +25,28 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.players;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public abstract class GenericPlayer<T>{
|
||||
public abstract class GenericPlayerImpl implements GenericPlayer{
|
||||
|
||||
protected T player = null;
|
||||
protected String name = null;
|
||||
protected String version = null;
|
||||
protected int protocol = -1;
|
||||
protected boolean playedBefore = false;
|
||||
protected boolean banned = false;
|
||||
protected boolean whitelisted = false;
|
||||
protected int protocol = 0;
|
||||
protected UUID uuid = null;
|
||||
|
||||
public T getPlayer(){
|
||||
return player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName(){
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtocol(){
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public String getVersion(){
|
||||
return version;
|
||||
}
|
||||
|
||||
public boolean hasPlayedBefore(){
|
||||
return playedBefore;
|
||||
}
|
||||
|
||||
public boolean isBanned(){
|
||||
return banned;
|
||||
}
|
||||
|
||||
public boolean isWhitelisted(){
|
||||
return whitelisted;
|
||||
}
|
||||
|
||||
public UUID getUniqueId(){
|
||||
@Override
|
||||
public UUID getUUID(){
|
||||
return uuid;
|
||||
}
|
||||
}
|
||||
+38
-14
@@ -31,31 +31,33 @@ import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
|
||||
import com.google.gson.Gson;
|
||||
import io.leangen.geantyref.TypeToken;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PlayerHandler{
|
||||
|
||||
private final AdvancedServerList core;
|
||||
private final AdvancedServerList<?> core;
|
||||
private final PluginLogger logger;
|
||||
private final Path cache;
|
||||
private List<CachedPlayer> cachedPlayers = new ArrayList<>();
|
||||
|
||||
private final Type listType = new TypeToken<ArrayList<CachedPlayer>>(){}.getType();
|
||||
private final Gson gson = new Gson();
|
||||
|
||||
// UUID of MHF_Question
|
||||
private final String defaultUUID = "606e2ff0-ed77-4842-9d6c-e1d3321c7838";
|
||||
private final UUID defaultUUID = UUID.fromString("606e2ff0-ed77-4842-9d6c-e1d3321c7838");
|
||||
|
||||
private List<CachedPlayer> cachedPlayers = new ArrayList<>();
|
||||
private CachedPlayer defaultPlayer = null;
|
||||
|
||||
public PlayerHandler(AdvancedServerList core){
|
||||
public PlayerHandler(AdvancedServerList<?> core){
|
||||
this.core = core;
|
||||
this.logger = core.getPlugin().getPluginLogger();
|
||||
this.cache = core.getPlugin().getFolderPath().resolve("playercache.json");
|
||||
@@ -67,13 +69,13 @@ public class PlayerHandler{
|
||||
return;
|
||||
}
|
||||
|
||||
if(core.getFileHandler().getBoolean("disable_cache")){
|
||||
if(core.getFileHandler().getBoolean("disableCache")){
|
||||
logger.info("'disable_cache' is set to true. Skipping playercache.json loading...");
|
||||
return;
|
||||
}
|
||||
|
||||
try{
|
||||
Reader reader = Files.newBufferedReader(cache);
|
||||
BufferedReader reader = Files.newBufferedReader(cache);
|
||||
|
||||
cachedPlayers = gson.fromJson(reader, listType);
|
||||
|
||||
@@ -83,6 +85,14 @@ public class PlayerHandler{
|
||||
return;
|
||||
}
|
||||
|
||||
// In case Gson messes up... I guess.
|
||||
if(cachedPlayers == null){
|
||||
logger.warn("Couldn't load players from playercache.json file. Is the JSON valid?");
|
||||
// Create new ArrayList instance to avoid further issues.
|
||||
cachedPlayers = new ArrayList<>();
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info("Loaded %d players into cache!", cachedPlayers.size());
|
||||
}
|
||||
|
||||
@@ -92,7 +102,7 @@ public class PlayerHandler{
|
||||
return;
|
||||
}
|
||||
|
||||
if(core.getFileHandler().getBoolean("disable_cache")){
|
||||
if(core.getFileHandler().getBoolean("disableCache")){
|
||||
logger.info("'disable_cache' is set to true. Skipping saving of cached players...");
|
||||
return;
|
||||
}
|
||||
@@ -108,14 +118,14 @@ public class PlayerHandler{
|
||||
}
|
||||
|
||||
public void addPlayer(String ip, String name, UUID uuid){
|
||||
if(contains(ip) || core.getFileHandler().getBoolean("disable_cache"))
|
||||
if(contains(ip) || core.getFileHandler().getBoolean("disableCache"))
|
||||
return;
|
||||
|
||||
cachedPlayers.add(new CachedPlayer(ip, name, uuid));
|
||||
}
|
||||
|
||||
public CachedPlayer getCachedPlayer(String key){
|
||||
if(!contains(key) || core.getFileHandler().getBoolean("disable_cache"))
|
||||
if(!contains(key) || core.getFileHandler().getBoolean("disableCache"))
|
||||
return getDefaultPlayer();
|
||||
|
||||
for(CachedPlayer player : cachedPlayers){
|
||||
@@ -126,6 +136,20 @@ public class PlayerHandler{
|
||||
return getDefaultPlayer();
|
||||
}
|
||||
|
||||
public CachedPlayer getCachedPlayer(UUID uuid){
|
||||
for(CachedPlayer player : cachedPlayers){
|
||||
if(player.getUuid().equals(uuid))
|
||||
return player;
|
||||
}
|
||||
|
||||
return getDefaultPlayer();
|
||||
}
|
||||
|
||||
public void clearCache(){
|
||||
cachedPlayers.clear();
|
||||
defaultPlayer = null;
|
||||
}
|
||||
|
||||
private boolean contains(String ip){
|
||||
for(CachedPlayer player : cachedPlayers){
|
||||
if(player.getIp().equals(ip))
|
||||
@@ -141,8 +165,8 @@ public class PlayerHandler{
|
||||
|
||||
return (defaultPlayer = new CachedPlayer(
|
||||
"0.0.0.0",
|
||||
core.getFileHandler().getString("Anonymous", "unknown_player"),
|
||||
convertToUUID(core.getFileHandler().getString(defaultUUID, "unknown_player_uuid"))
|
||||
core.getFileHandler().getString("Anonymous", "unknownPlayer", "name"),
|
||||
convertToUUID(core.getFileHandler().getString(defaultUUID.toString(), "unknownPlayer", "uuid"))
|
||||
));
|
||||
}
|
||||
|
||||
@@ -151,7 +175,7 @@ public class PlayerHandler{
|
||||
return UUID.fromString(uuid);
|
||||
}catch(IllegalArgumentException ex){
|
||||
// This is always a valid UUID.
|
||||
return UUID.fromString(defaultUUID);
|
||||
return defaultUUID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-194
@@ -1,194 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.profile;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.objects.NullBool;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class ProfileEntry{
|
||||
|
||||
private final List<String> motd;
|
||||
private final List<String> players;
|
||||
private final String playerCountText;
|
||||
private final String favicon;
|
||||
private final NullBool hidePlayersEnabled;
|
||||
private final NullBool extraPlayersEnabled;
|
||||
private final Integer extraPlayersCount;
|
||||
|
||||
public ProfileEntry(List<String> motd, List<String> players,
|
||||
String playerCountText, String favicon, NullBool hidePlayersEnabled,
|
||||
NullBool extraPlayersEnabled, Integer extraPlayersCount){
|
||||
this.motd = motd;
|
||||
this.players = players;
|
||||
this.playerCountText = playerCountText;
|
||||
this.favicon = favicon;
|
||||
this.hidePlayersEnabled = hidePlayersEnabled;
|
||||
this.extraPlayersEnabled = extraPlayersEnabled;
|
||||
this.extraPlayersCount = extraPlayersCount;
|
||||
}
|
||||
|
||||
public static ProfileEntry empty(){
|
||||
return new ProfileEntry(Collections.emptyList(), Collections.emptyList(), "", "",
|
||||
NullBool.FALSE, NullBool.FALSE, 0);
|
||||
}
|
||||
|
||||
public List<String> getMOTD(){
|
||||
return motd;
|
||||
}
|
||||
|
||||
public List<String> getPlayers(){
|
||||
return players;
|
||||
}
|
||||
|
||||
public String getPlayerCountText(){
|
||||
return playerCountText;
|
||||
}
|
||||
|
||||
public String getFavicon(){
|
||||
return favicon;
|
||||
}
|
||||
|
||||
public NullBool isHidePlayersEnabled(){
|
||||
return hidePlayersEnabled;
|
||||
}
|
||||
|
||||
public NullBool isExtraPlayersEnabled(){
|
||||
return extraPlayersEnabled;
|
||||
}
|
||||
|
||||
public Integer getExtraPlayersCount(){
|
||||
return extraPlayersCount;
|
||||
}
|
||||
|
||||
public boolean isInvalidProfile(){
|
||||
return getMOTD().isEmpty() &&
|
||||
getPlayers().isEmpty() &&
|
||||
(getPlayerCountText().isEmpty() && !isHidePlayersEnabled().getValue(false)) &&
|
||||
getFavicon().isEmpty();
|
||||
}
|
||||
|
||||
public static class Builder{
|
||||
|
||||
private final ConfigurationNode node;
|
||||
|
||||
private List<String> motd = new ArrayList<>();
|
||||
private List<String> players = new ArrayList<>();
|
||||
private String playerCountText = null;
|
||||
private String favicon = null;
|
||||
private NullBool hidePlayersEnabled = NullBool.FALSE;
|
||||
private NullBool extraPlayersEnabled = NullBool.FALSE;
|
||||
private Integer extraPlayersCount = 0;
|
||||
|
||||
private Builder(ConfigurationNode node){
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
public static Builder resolve(ConfigurationNode node){
|
||||
return new Builder(node)
|
||||
.resolveMOTD()
|
||||
.resolvePlayers()
|
||||
.resolvePlayerCountText()
|
||||
.resolveFavicon()
|
||||
.resolveHidePlayersEnabled()
|
||||
.resolveExtraPlayersEnabled()
|
||||
.resolveExtraPlayersCount();
|
||||
}
|
||||
|
||||
public Builder resolveMOTD(){
|
||||
List<String> motd = resolveList(node, "motd");
|
||||
if(motd.size() <= 2){
|
||||
this.motd = motd;
|
||||
return this;
|
||||
}
|
||||
|
||||
this.motd = motd.subList(0, 2);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder resolvePlayers(){
|
||||
this.players = this.resolveList(node, "playerCount", "hover");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder resolvePlayerCountText(){
|
||||
this.playerCountText = node.node("playerCount", "text").getString("");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder resolveFavicon(){
|
||||
this.favicon = node.node("favicon").getString("");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder resolveHidePlayersEnabled(){
|
||||
if(node.node("playerCount", "hidePlayers").virtual()){
|
||||
this.hidePlayersEnabled = NullBool.NULL;
|
||||
return this;
|
||||
}
|
||||
|
||||
this.hidePlayersEnabled = new NullBool(node.node("playerCount", "hidePlayers").getBoolean());
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder resolveExtraPlayersEnabled(){
|
||||
if(node.node("playerCount", "extraPlayers", "enabled").virtual()){
|
||||
this.extraPlayersEnabled = NullBool.NULL;
|
||||
return this;
|
||||
}
|
||||
|
||||
this.extraPlayersEnabled = new NullBool(node.node("playerCount", "extraPlayers", "enabled").getBoolean());
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder resolveExtraPlayersCount(){
|
||||
if(node.node("playerCount", "extraPlayers", "amount").virtual()){
|
||||
this.extraPlayersCount = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
this.extraPlayersCount = node.node("playerCount", "extraPlayers", "amount").getInt();
|
||||
return this;
|
||||
}
|
||||
|
||||
public ProfileEntry build(){
|
||||
return new ProfileEntry(this.motd, this.players, this.playerCountText,
|
||||
this.favicon, this.hidePlayersEnabled, this.extraPlayersEnabled, this.extraPlayersCount);
|
||||
}
|
||||
|
||||
private List<String> resolveList(ConfigurationNode node, Object... path){
|
||||
try{
|
||||
return node.node(path).getList(String.class);
|
||||
}catch(SerializationException ex){
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+121
-56
@@ -25,53 +25,27 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.profile;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.api.objects.NullBool;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.objects.NullBool;
|
||||
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
|
||||
import ch.andre601.advancedserverlist.core.profiles.replacer.placeholders.Placeholders;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ProfileManager{
|
||||
|
||||
private final AdvancedServerList core;
|
||||
|
||||
private final Map<String, Object> replacements = new HashMap<>();
|
||||
|
||||
private ProfileManager(AdvancedServerList core){
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
public static ProfileManager get(AdvancedServerList core){
|
||||
return new ProfileManager(core);
|
||||
}
|
||||
|
||||
public ProfileManager replacements(Placeholders placeholders){
|
||||
this.replacements.putAll(placeholders.getReplacements());
|
||||
return this;
|
||||
}
|
||||
|
||||
public ServerListProfile getProfile(){
|
||||
for(ServerListProfile profile : core.getFileHandler().getProfiles()){
|
||||
if(profile.isInvalidProfile())
|
||||
continue;
|
||||
|
||||
if(profile.evaluateConditions(replacements))
|
||||
return profile;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convenience method to get a ProfileEntry instance with values merged.
|
||||
* If the random profile's value is not null will it be used instead of the default one.
|
||||
*/
|
||||
public static ProfileEntry merge(ServerListProfile profile){
|
||||
ProfileEntry entry = profile.getRandomProfile();
|
||||
ProfileEntry defEntry = profile.getDefaultProfile();
|
||||
ProfileEntry defEntry = profile.defaultProfile();
|
||||
|
||||
List<String> motd = resolveMOTD(entry, defEntry);
|
||||
List<String> players = resolvePlayers(entry, defEntry);
|
||||
@@ -79,59 +53,150 @@ public class ProfileManager{
|
||||
String favicon = resolveFavicon(entry, defEntry);
|
||||
boolean isHidePlayersEnabled = resolveHidePlayersEnabled(entry, defEntry);
|
||||
boolean isExtraPlayersEnabled = resolveExtraPlayersEnabled(entry, defEntry);
|
||||
boolean isMaxPlayersEnabled = resolveMaxPlayersEnabled(entry, defEntry);
|
||||
Integer extraPlayersCount = resolveExtraPlayersCount(entry, defEntry);
|
||||
Integer maxPlayersCount = resolveMaxPlayersCount(entry, defEntry);
|
||||
|
||||
return new ProfileEntry(motd, players, playerCountText, favicon,
|
||||
new NullBool(isHidePlayersEnabled), new NullBool(isExtraPlayersEnabled), extraPlayersCount);
|
||||
NullBool.resolve(isHidePlayersEnabled), NullBool.resolve(isExtraPlayersEnabled), NullBool.resolve(isMaxPlayersEnabled),
|
||||
extraPlayersCount, maxPlayersCount);
|
||||
}
|
||||
|
||||
public static ServerListProfile resolveProfile(AdvancedServerList<?> core, GenericPlayer player, GenericServer server){
|
||||
for(ServerListProfile profile : core.getFileHandler().getProfiles()){
|
||||
if(profile.isInvalidProfile())
|
||||
continue;
|
||||
|
||||
if(profile.evalConditions(core.getParser(), core.getPlugin().getPluginLogger(), player, server))
|
||||
return profile;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ProfileEntry retrieveProfileEntry(ConfigurationNode node){
|
||||
List<String> motd = resolveList(node, "motd");
|
||||
List<String> players = resolveList(node, "playerCount", "hover");
|
||||
String playerCountText = node.node("playerCount", "text").getString("");
|
||||
String favicon = node.node("favicon").getString("");
|
||||
NullBool hidePlayers = resolveNullBool(node, "playerCount", "hidePlayers");
|
||||
NullBool extraPlayersEnabled = resolveNullBool(node, "playerCount", "extraPlayers", "enabled");
|
||||
NullBool maxPlayersEnabled = resolveNullBool(node, "playerCount", "maxPlayers", "enabled");
|
||||
Integer extraPlayers = resolveNullableInt(node, "playerCount", "extraPlayers", "amount");
|
||||
Integer maxPlayers = resolveNullableInt(node, "playerCount", "maxPlayers", "amount");
|
||||
|
||||
return new ProfileEntry.Builder()
|
||||
.setMotd(motd)
|
||||
.setPlayers(players)
|
||||
.setPlayerCountText(playerCountText)
|
||||
.setFavicon(favicon)
|
||||
.setHidePlayersEnabled(hidePlayers)
|
||||
.setExtraPlayersEnabled(extraPlayersEnabled)
|
||||
.setMaxPlayersEnabled(maxPlayersEnabled)
|
||||
.setExtraPlayersCount(extraPlayers)
|
||||
.setMaxPlayersCount(maxPlayers)
|
||||
.build();
|
||||
}
|
||||
|
||||
public static boolean checkOption(Object obj){
|
||||
if(obj == null)
|
||||
return false;
|
||||
|
||||
if(obj instanceof List<?> list){
|
||||
return !list.isEmpty(); // Check if list isn't empty
|
||||
}else
|
||||
if(obj instanceof String str){
|
||||
return !str.isEmpty(); // Check if String is not empty
|
||||
}else
|
||||
if(obj instanceof NullBool nb){
|
||||
return nb.getOrDefault(false); // Return NullBool's value
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static List<String> resolveMOTD(ProfileEntry profile, ProfileEntry defaultProfile){
|
||||
if(profile == null || profile.getMOTD().isEmpty())
|
||||
return defaultProfile.getMOTD();
|
||||
if(profile == null || !checkOption(profile.motd()))
|
||||
return defaultProfile.motd();
|
||||
|
||||
return profile.getMOTD();
|
||||
return profile.motd();
|
||||
}
|
||||
|
||||
private static List<String> resolvePlayers(ProfileEntry profile, ProfileEntry defaultProfile){
|
||||
if(profile == null || profile.getPlayers().isEmpty())
|
||||
return defaultProfile.getPlayers();
|
||||
if(profile == null || !checkOption(profile.players()))
|
||||
return defaultProfile.players();
|
||||
|
||||
return profile.getPlayers();
|
||||
return profile.players();
|
||||
}
|
||||
|
||||
private static String resolvePlayerCountText(ProfileEntry profile, ProfileEntry defaultProfile){
|
||||
if(profile == null || profile.getPlayerCountText().isEmpty())
|
||||
return defaultProfile.getPlayerCountText();
|
||||
if(profile == null || !checkOption(profile.playerCountText()))
|
||||
return defaultProfile.playerCountText();
|
||||
|
||||
return profile.getPlayerCountText();
|
||||
return profile.playerCountText();
|
||||
}
|
||||
|
||||
private static String resolveFavicon(ProfileEntry profile, ProfileEntry defaultProfile){
|
||||
if(profile == null || profile.getFavicon().isEmpty())
|
||||
return defaultProfile.getFavicon();
|
||||
if(profile == null || !checkOption(profile.favicon()))
|
||||
return defaultProfile.favicon();
|
||||
|
||||
return profile.getFavicon();
|
||||
return profile.favicon();
|
||||
}
|
||||
|
||||
private static boolean resolveHidePlayersEnabled(ProfileEntry profile, ProfileEntry defaultProfile){
|
||||
if(profile == null || profile.isHidePlayersEnabled().isNull())
|
||||
return defaultProfile.isHidePlayersEnabled().getValue(false);
|
||||
if(profile == null || !checkOption(profile.hidePlayersEnabled()))
|
||||
return defaultProfile.hidePlayersEnabled().getOrDefault(false);
|
||||
|
||||
return profile.isHidePlayersEnabled().getValue(false);
|
||||
return profile.hidePlayersEnabled().getOrDefault(false);
|
||||
}
|
||||
|
||||
private static boolean resolveExtraPlayersEnabled(ProfileEntry profile, ProfileEntry defaultProfile){
|
||||
if(profile == null || profile.isExtraPlayersEnabled().isNull())
|
||||
return defaultProfile.isExtraPlayersEnabled().getValue(false);
|
||||
if(profile == null || !checkOption(profile.extraPlayersEnabled()))
|
||||
return defaultProfile.extraPlayersEnabled().getOrDefault(false);
|
||||
|
||||
return profile.isExtraPlayersEnabled().getValue(false);
|
||||
return profile.extraPlayersEnabled().getOrDefault(false);
|
||||
}
|
||||
|
||||
private static boolean resolveMaxPlayersEnabled(ProfileEntry profile, ProfileEntry defaultProfile){
|
||||
if(profile == null || !checkOption(profile.maxPlayersEnabled()))
|
||||
return defaultProfile.maxPlayersEnabled().getOrDefault(false);
|
||||
|
||||
return profile.maxPlayersEnabled().getOrDefault(false);
|
||||
}
|
||||
|
||||
private static Integer resolveExtraPlayersCount(ProfileEntry profile, ProfileEntry defaultProfile){
|
||||
if(profile == null || profile.getExtraPlayersCount() == null)
|
||||
return defaultProfile.getExtraPlayersCount() == null ? 0 : defaultProfile.getExtraPlayersCount();
|
||||
if(profile == null || profile.extraPlayersCount() == null)
|
||||
return defaultProfile.extraPlayersCount() == null ? 0 : defaultProfile.extraPlayersCount();
|
||||
|
||||
return profile.getExtraPlayersCount();
|
||||
return profile.extraPlayersCount();
|
||||
}
|
||||
|
||||
private static Integer resolveMaxPlayersCount(ProfileEntry profile, ProfileEntry defaultProfile){
|
||||
if(profile == null || profile.maxPlayersCount() == null)
|
||||
return defaultProfile.maxPlayersCount() == null ? 0 : defaultProfile.maxPlayersCount();
|
||||
|
||||
return profile.maxPlayersCount();
|
||||
}
|
||||
|
||||
private static List<String> resolveList(ConfigurationNode node, Object... path){
|
||||
try{
|
||||
return node.node(path).getList(String.class);
|
||||
}catch(SerializationException ex){
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
private static NullBool resolveNullBool(ConfigurationNode node, Object... path){
|
||||
if(node.node(path).virtual())
|
||||
return NullBool.NOT_SET;
|
||||
|
||||
return NullBool.resolve(node.node(path).getBoolean());
|
||||
}
|
||||
|
||||
private static Integer resolveNullableInt(ConfigurationNode node, Object... path){
|
||||
if(node.node(path).virtual())
|
||||
return null;
|
||||
|
||||
return node.node(path).getInt();
|
||||
}
|
||||
}
|
||||
+11
-8
@@ -25,6 +25,7 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.profile;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
@@ -37,7 +38,7 @@ public class ProfileSerializer implements TypeSerializer<ProfileEntry>{
|
||||
|
||||
@Override
|
||||
public ProfileEntry deserialize(Type type, ConfigurationNode node){
|
||||
return ProfileEntry.Builder.resolve(node).build();
|
||||
return ProfileManager.retrieveProfileEntry(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -47,12 +48,14 @@ public class ProfileSerializer implements TypeSerializer<ProfileEntry>{
|
||||
return;
|
||||
}
|
||||
|
||||
node.node("motd").set(profile.getMOTD());
|
||||
node.node("playerCount", "hover").set(profile.getPlayers());
|
||||
node.node("playerCount", "text").set(profile.getPlayerCountText());
|
||||
node.node("favicon").set(profile.getFavicon());
|
||||
node.node("playerCount", "hidePlayers").set(profile.isHidePlayersEnabled());
|
||||
node.node("playerCount", "extraPlayers", "enabled").set(profile.isExtraPlayersEnabled());
|
||||
node.node("playerCount", "extraPlayers", "amount").set(profile.getExtraPlayersCount());
|
||||
node.node("motd").set(profile.motd());
|
||||
node.node("playerCount", "hover").set(profile.players());
|
||||
node.node("playerCount", "text").set(profile.playerCountText());
|
||||
node.node("favicon").set(profile.favicon());
|
||||
node.node("playerCount", "hidePlayers").set(profile.hidePlayersEnabled().getOrDefault(false));
|
||||
node.node("playerCount", "extraPlayers", "enabled").set(profile.extraPlayersEnabled().getOrDefault(false));
|
||||
node.node("playerCount", "extraPlayers", "amount").set((profile.extraPlayersCount() == null) ? 0 : profile.extraPlayersCount());
|
||||
node.node("playerCount", "maxPlayers", "enabled").set(profile.maxPlayersEnabled().getOrDefault(false));
|
||||
node.node("playerCount", "maxPlayers", "amount").set((profile.maxPlayersCount() == null) ? 0 : profile.maxPlayersCount());
|
||||
}
|
||||
}
|
||||
+100
-10
@@ -25,20 +25,110 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.replacer;
|
||||
|
||||
import java.util.Map;
|
||||
import ch.andre601.advancedserverlist.api.AdvancedServerListAPI;
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
|
||||
public class StringReplacer{
|
||||
|
||||
public static String replace(String input, Map<String, Object> replacements){
|
||||
StringBuilder output = new StringBuilder(input);
|
||||
int index;
|
||||
for(Map.Entry<String, Object> entry : replacements.entrySet()){
|
||||
index = 0;
|
||||
while((index = output.indexOf(entry.getKey(), index)) != -1){
|
||||
output.replace(index, index + entry.getKey().length(), String.valueOf(entry.getValue()));
|
||||
index += String.valueOf(entry.getValue()).length();
|
||||
public static String replace(String input, GenericPlayer player, GenericServer server){
|
||||
if(input == null)
|
||||
return null;
|
||||
|
||||
char[] chars = input.toCharArray();
|
||||
StringBuilder builder = new StringBuilder(input.length());
|
||||
|
||||
StringBuilder identifier = new StringBuilder();
|
||||
StringBuilder placeholder = new StringBuilder();
|
||||
|
||||
AdvancedServerListAPI api = AdvancedServerListAPI.get();
|
||||
|
||||
for(int i = 0; i < chars.length; i++){
|
||||
char c = chars[i];
|
||||
char next = (i == (chars.length - 1)) ? '\0' : chars[i + 1];
|
||||
|
||||
if(c != '$' || i + 2 >= chars.length){
|
||||
builder.append(c);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(next != '{'){
|
||||
if(next == '\0')
|
||||
continue;
|
||||
|
||||
builder.append(next);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
boolean identified = false;
|
||||
boolean invalid = true;
|
||||
|
||||
while(++i < chars.length){
|
||||
final char id = chars[i];
|
||||
|
||||
if(id == '}'){
|
||||
invalid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if(id == ' ' && !identified){
|
||||
identified = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(identified){
|
||||
placeholder.append(id);
|
||||
}else{
|
||||
identifier.append(id);
|
||||
}
|
||||
}
|
||||
|
||||
String identifierString = identifier.toString();
|
||||
String placeholderString = placeholder.toString();
|
||||
|
||||
identifier.setLength(0);
|
||||
placeholder.setLength(0);
|
||||
|
||||
if(invalid){
|
||||
builder.append("${").append(identifierString);
|
||||
|
||||
if(identified){
|
||||
builder.append(' ').append(placeholderString);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
PlaceholderProvider provider = api.retrievePlaceholderProvider(identifierString);
|
||||
if(provider == null){
|
||||
builder.append("${").append(identifierString);
|
||||
|
||||
if(identified){
|
||||
builder.append(' ').append(placeholderString);
|
||||
}
|
||||
|
||||
builder.append('}');
|
||||
continue;
|
||||
}
|
||||
|
||||
String replacement = provider.parsePlaceholder(placeholderString, player, server);
|
||||
if(replacement == null){
|
||||
builder.append("${").append(identifierString);
|
||||
|
||||
if(identified){
|
||||
builder.append(' ').append(placeholderString);
|
||||
}
|
||||
|
||||
builder.append('}');
|
||||
continue;
|
||||
}
|
||||
|
||||
builder.append(replacement);
|
||||
}
|
||||
return output.toString();
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,25 @@
|
||||
#
|
||||
# Used for when AdvancedServerList doesn't have a cached player to use for ${player name}
|
||||
# Used for when AdvancedServerList doesn't have a cached player to use for player placeholders.
|
||||
#
|
||||
# Defaults to 'Anonymous' when not present.
|
||||
#
|
||||
unknown_player: "Anonymous"
|
||||
|
||||
#
|
||||
# UUID used for when AdvancedServerList doesn't have a cached player to use for the ${player uuid}
|
||||
# placeholder.
|
||||
#
|
||||
# Defaults to the UUID of MHF_Question (606e2ff0-ed77-4842-9d6c-e1d3321c7838) when not present.
|
||||
#
|
||||
unknown_player_uuid: "606e2ff0-ed77-4842-9d6c-e1d3321c7838"
|
||||
unknownPlayer:
|
||||
#
|
||||
# The name to use. Defaults to Anonymous.
|
||||
#
|
||||
name: "Anonymous"
|
||||
#
|
||||
# The UUID to use. Defaults to 606e2ff0-ed77-4842-9d6c-e1d3321c7838 (UUID of MHF_Question).
|
||||
#
|
||||
uuid: "606e2ff0-ed77-4842-9d6c-e1d3321c7838"
|
||||
|
||||
#
|
||||
# Should the Caching of players be disabled?
|
||||
#
|
||||
# When set to true will AdvancedServerList not load any players from the cache.data file (if present) nor save any to it.
|
||||
# Placeholders that rely on the player being cached (such as ${player isWhitelisted}) will not work while this option is enabled.
|
||||
# Placeholders that rely on the player being cached (such as ${player name}) will not work while this option is enabled.
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
#
|
||||
disable_cache: false
|
||||
disableCache: false
|
||||
|
||||
#
|
||||
# Should AdvancedServerList check for new versions?
|
||||
@@ -31,4 +29,31 @@ disable_cache: false
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
#
|
||||
check_updates: true
|
||||
checkUpdates: true
|
||||
|
||||
#
|
||||
# Should debug mode be enabled?
|
||||
#
|
||||
# When set to true will AdvancedServerList print additional messages to the console prefixed with "[DEBUG]".
|
||||
# It is recommended to only enable this when having problems or when being told to by the plugin dev, as it could
|
||||
# otherwise cause significant spam in your console.
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
#
|
||||
debug: false
|
||||
|
||||
#
|
||||
# Sets the time in minutes for favicons to be cached.
|
||||
# The number cannot be less than 1.
|
||||
#
|
||||
# Defaults to 1 if not set.
|
||||
#
|
||||
faviconCacheTime: 1
|
||||
|
||||
#
|
||||
# DO NOT EDIT!
|
||||
#
|
||||
# This is used internally to determine if the config needs to be migrated.
|
||||
# Changing or even removing this option could result in your config being broken.
|
||||
#
|
||||
config-version: ${plugin.config.version}
|
||||
@@ -2,15 +2,24 @@
|
||||
# Set the priority of this profile.
|
||||
# Higher number = Higher priority.
|
||||
#
|
||||
# Read more: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#priority
|
||||
# Read more: https://asl.andre601.ch/profiles/#priority
|
||||
#
|
||||
priority: 0
|
||||
|
||||
#
|
||||
# Set conditions that need to me met to show this profile.
|
||||
# You can use keywords 'and' or 'or' (Or alternatively '&&' or `||`) to make more complex condition sets.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#condition
|
||||
#
|
||||
# condition: '${player protocol} < 759'
|
||||
#
|
||||
|
||||
#
|
||||
# Set conditions that needs to be met.
|
||||
# Only when all conditions return true will the profile be shown (Given no profile with higher priority is used).
|
||||
#
|
||||
# Read more: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#conditions
|
||||
# Read more: https://asl.andre601.ch/profiles/#conditions
|
||||
#
|
||||
#conditions:
|
||||
# - '{playerVersion} < 759'
|
||||
@@ -25,7 +34,7 @@ priority: 0
|
||||
#
|
||||
# Remove this option or set it to profiles: [] to use the global options of this file.
|
||||
#
|
||||
# Read more: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#profiles
|
||||
# Read more: https://asl.andre601.ch/profiles/#profiles
|
||||
#
|
||||
#profiles:
|
||||
# - motd:
|
||||
@@ -49,7 +58,7 @@ priority: 0
|
||||
#
|
||||
# Remove this option or set it to motd: [] to not alter the MOTD.
|
||||
#
|
||||
# Read more: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#motds
|
||||
# Read more: https://asl.andre601.ch/profiles/#motd
|
||||
#
|
||||
motd:
|
||||
- '<grey>Line 1'
|
||||
@@ -64,14 +73,14 @@ motd:
|
||||
#
|
||||
# Remove this option or set to favicon: '' to not replace the Favicon.
|
||||
#
|
||||
# Read more: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#favicon
|
||||
# Read more: https://asl.andre601.ch/profiles/#favicon
|
||||
#
|
||||
favicon: ''
|
||||
|
||||
#
|
||||
# Contains various options to manipulate the player count (Text displaying online and max players allowed).
|
||||
#
|
||||
# Read more: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#playercount
|
||||
# Read more: https://asl.andre601.ch/profiles/#playercount
|
||||
#
|
||||
playerCount:
|
||||
#
|
||||
@@ -82,7 +91,7 @@ playerCount:
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
#
|
||||
# Read more: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#hideplayers
|
||||
# Read more: https://asl.andre601.ch/profiles/#hideplayers
|
||||
#
|
||||
hidePlayers: false
|
||||
#
|
||||
@@ -90,7 +99,7 @@ playerCount:
|
||||
#
|
||||
# Remove this option or set it to hover: [] to not modify the player samples on the player count.
|
||||
#
|
||||
# Read more: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#hover
|
||||
# Read more: https://asl.andre601.ch/profiles/#hover
|
||||
#
|
||||
hover:
|
||||
- '<grey>Line 1'
|
||||
@@ -104,24 +113,24 @@ playerCount:
|
||||
#
|
||||
# Remove this option or set it to text: '' to not modify the player count text.
|
||||
#
|
||||
# Read more: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#text
|
||||
# Read more: https://asl.andre601.ch/profiles/#text
|
||||
#
|
||||
text: ''
|
||||
#
|
||||
# Allows you to modify the max player count displayed.
|
||||
# Note that this will affect ${server playersMax} (Except for when used in conditions).
|
||||
#
|
||||
# Read more: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#extraPlayers
|
||||
# Read more: https://asl.andre601.ch/profiles/#extraplayers
|
||||
#
|
||||
extraPlayers:
|
||||
#
|
||||
# Enables/Disables the extraPlayers option.
|
||||
# When enabled will the total amount of players allowed be modified to the current
|
||||
# When enabled will the total amount of players allowed to join be modified to the current
|
||||
# number of online players + 'amount'
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
#
|
||||
# Read more: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#enabled
|
||||
# Read more: https://asl.andre601.ch/profiles/#extraplayers-enabled
|
||||
#
|
||||
enabled: false
|
||||
#
|
||||
@@ -134,6 +143,35 @@ playerCount:
|
||||
#
|
||||
# Defaults to 0 when not present.
|
||||
#
|
||||
# Read more: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#amount
|
||||
# Read more: https://asl.andre601.ch/profiles/#extraplayers-amount
|
||||
#
|
||||
amount: 0
|
||||
#
|
||||
# Allows you to set the max players that could join your server.
|
||||
# Note that this option influences the '${server playersMax}' placeholder.
|
||||
#
|
||||
# The settings of this option have no effect should 'extraPlayers' be enabled
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#maxplayers
|
||||
#
|
||||
maxPlayers:
|
||||
#
|
||||
# Enables/Disables the maxPlayers option.
|
||||
# When enabled will the total amount of players allowed to join be changed to what 'amount' is set to.
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#maxplayers-enabled
|
||||
#
|
||||
enabled: false
|
||||
#
|
||||
# Sets the number to display for the max number of players allowed to join your server.
|
||||
#
|
||||
# Example:
|
||||
# Setting this option to 0 (Default) while 1 player is online would display '1/0'
|
||||
#
|
||||
# Defaults to 0 if not set.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#maxplayers-amount
|
||||
#
|
||||
amount: 0
|
||||
@@ -23,4 +23,5 @@
|
||||
#
|
||||
#
|
||||
|
||||
version=${plugin.version}
|
||||
version=${plugin.version}
|
||||
config-version=${plugin.config.version}
|
||||
+14
-14
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -23,38 +23,38 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.spigot.logging;
|
||||
package ch.andre601.advancedserverlist.test;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class SpigotLogger implements PluginLogger{
|
||||
public class DummyPluginLogger implements PluginLogger{
|
||||
@Override
|
||||
public void debug(Class<?> clazz, String msg, Object... args){
|
||||
info("[DEBUG] [" + clazz.getSimpleName() + "] " + msg, args);
|
||||
}
|
||||
|
||||
private final Logger logger;
|
||||
|
||||
public SpigotLogger(Logger logger){
|
||||
this.logger = logger;
|
||||
@Override
|
||||
public void debugWarn(Class<?> clazz, String msg, Object... args){
|
||||
warn("[DEBUG] [" + clazz.getSimpleName() + "] " + msg, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String msg, Object... args){
|
||||
logger.info(String.format(msg, args));
|
||||
System.out.printf((msg) + "%n", args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Object... args){
|
||||
logger.warning(String.format(msg, args));
|
||||
System.out.printf((msg) + "%n", args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Throwable throwable){
|
||||
logger.log(Level.WARNING, msg, throwable);
|
||||
System.out.printf((msg) + "%n", throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Throwable throwable, Object... args){
|
||||
logger.log(Level.WARNING, String.format(msg, args), throwable);
|
||||
System.out.printf((msg) + "%n", args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.test;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.ProfileConditionParser;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
import ch.andre601.expressionparser.templates.ExpressionTemplate;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class ExpressionParserTests{
|
||||
|
||||
private final ProfileConditionParser parser = ProfileConditionParser.create();
|
||||
private final DummyPluginLogger logger = new DummyPluginLogger();
|
||||
private final Map<String, Boolean> testValuesMap = getTestMap();
|
||||
|
||||
@Test
|
||||
public void testBasicExpressionResults(){
|
||||
for(Map.Entry<String, Boolean> values : testValuesMap.entrySet()){
|
||||
logger.info("TEST[expression=\"%s\", expected=%b]", values.getKey(), values.getValue());
|
||||
|
||||
ParseWarnCollector collector = new ParseWarnCollector(values.getKey());
|
||||
ExpressionTemplate template = parser.compile(values.getKey(), null, null, collector);
|
||||
boolean result;
|
||||
if(template == null){
|
||||
result = false;
|
||||
}else{
|
||||
result = template.returnBooleanExpression().evaluate();
|
||||
}
|
||||
|
||||
logger.info("Result (output, isExpected): " + result + ", " + (result == values.getValue()));
|
||||
assertEquals(result, values.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Boolean> getTestMap(){
|
||||
return Map.of(
|
||||
"20 > 10", true,
|
||||
"10 > 20", false,
|
||||
"10 = 10", true,
|
||||
"10 = 20", false,
|
||||
"(10 - 5) > (1 + 1)", true,
|
||||
"(10 - 10) > (1 + 1)", false,
|
||||
"100 > 50 and 50 < 100", true,
|
||||
"100 < 50 and 50 > 100", false,
|
||||
"true or 100 > 10", true,
|
||||
"false or 100 < 10", false
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,9 @@
|
||||
package ch.andre601.advancedserverlist.test;
|
||||
|
||||
import com.unascribed.flexver.FlexVerComparator;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class FlexVerTests{
|
||||
|
||||
@@ -286,7 +288,9 @@ public class FlexVerTests{
|
||||
|
||||
private void compare(String version1, String comparator, String version2, int expected){
|
||||
String expression = version1 + " " + comparator + " " + version2 + "?";
|
||||
int result = FlexVerComparator.compare(version1, version2);
|
||||
|
||||
System.out.printf("│ %-24s %5b │\n", expression, FlexVerComparator.compare(version1, version2) == expected);
|
||||
assertEquals(result, expected);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
#
|
||||
# Modified version of Squidfunk's shortcodes.py file for Material for MkDocs.
|
||||
#
|
||||
# It was altered to create compact admonition-like boxes to display in the documentation.
|
||||
#
|
||||
# Original shortcodes.py file:
|
||||
# https://github.com/squidfunk/mkdocs-material/blob/56b96b4d799174d48d36613d70ffac9b964171cc/material/overrides/hooks/shortcodes.py
|
||||
#
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
|
||||
from mkdocs.config.defaults import MkDocsConfig
|
||||
from mkdocs.structure.files import File, Files
|
||||
from mkdocs.structure.pages import Page
|
||||
from re import Match
|
||||
|
||||
def on_page_markdown(
|
||||
markdown: str, *, page: Page, config: MkDocsConfig, files: Files
|
||||
):
|
||||
|
||||
# Replace callback
|
||||
def replace(match: Match):
|
||||
type, args = match.groups()
|
||||
args = args.strip()
|
||||
if type == "abstract": return _admo(text = args, type = "abstract")
|
||||
elif type == "info": return _admo(text = args, type = "info")
|
||||
elif type == "tip": return _admo(text = args, type = "tip")
|
||||
elif type == "success": return _admo(text = args, type = "success")
|
||||
elif type == "question": return _admo(text = args, type = "question")
|
||||
elif type == "warning": return _admo(text = args, type = "warning")
|
||||
elif type == "failure": return _admo(text = args, type = "failure")
|
||||
elif type == "danger": return _admo(text = args, type = "danger")
|
||||
elif type == "bug": return _admo(text = args, type = "bug")
|
||||
elif type == "example": return _admo(text = args, type = "example")
|
||||
elif type == "quote": return _admo(text = args, type = "quote")
|
||||
elif type == "deprecated": return _admo(text = args, type = "deprecated")
|
||||
else: return _admo(text = args)
|
||||
|
||||
# Find and replace all external asset URLs in current page
|
||||
return re.sub(
|
||||
r"<!-- admo:(\w+)(.*?) -->",
|
||||
replace, markdown, flags = re.I | re.M
|
||||
)
|
||||
|
||||
def _admo(text: str = "", type: str = ""):
|
||||
classes = f"mdx-grid-wrapper mdx-admo--{type}" if type else "mdx-grid-wrapper"
|
||||
return "".join([
|
||||
f"<div class=\"{classes}\">",
|
||||
f"<div class=\"mdx-grid-child mdx-grid-child--icon\"></div>",
|
||||
f"<div class=\"mdx-grid-child\">{text}</div>"
|
||||
"</div>",
|
||||
])
|
||||
@@ -0,0 +1,26 @@
|
||||
#
|
||||
# A simple hook that replaces any appearances of \| with just |.
|
||||
#
|
||||
# There is an inconsistency between GitHub flavourited Markdown and Python Markdown
|
||||
# where the former treats | as part of a table, even if it is inside inline code
|
||||
# causing unwanted table rendering.
|
||||
#
|
||||
# The only way to prevent this is to escape it by prefixing it with a back slash (\).
|
||||
# Unfortunately does this cause issues on Python-Markdown, as it renders inline code
|
||||
# content as-is without special treatments whatsoever, meaning that `\|` will be
|
||||
# rendered as <code>\|</code> in the end.
|
||||
#
|
||||
# Using this hook, `\|` is being turned into `|` before further processing, resulting
|
||||
# in <code>|</code> being rendered in the end, while preserving proper table rendering
|
||||
# on GitHub and co.
|
||||
#
|
||||
import re
|
||||
|
||||
from mkdocs.config.defaults import MkDocsConfig
|
||||
from mkdocs.structure.files import File, Files
|
||||
from mkdocs.structure.pages import Page
|
||||
|
||||
def on_page_markdown(
|
||||
markdown: str, *, page: Page, config: MkDocsConfig, files: Files
|
||||
):
|
||||
return re.sub(r"\\\|","|",markdown)
|
||||
@@ -0,0 +1,35 @@
|
||||
{% extends "base.html" %}
|
||||
{% import "api-objects/info-template.html" as info %}
|
||||
|
||||
{% block content %}
|
||||
{% include "partials/content.html" %}
|
||||
{% if page.meta %}
|
||||
<!--
|
||||
Object summaries
|
||||
-->
|
||||
{% if page.meta.constructors %}
|
||||
{{ info.summary('Constructor Summary', page.meta.constructors, details_type='constructor') }}
|
||||
{% endif %}
|
||||
{% if page.meta.classes %}
|
||||
{{ info.summary('Class Summary', page.meta.classes, details_type='class') }}
|
||||
{% endif %}
|
||||
{% if page.meta.enums %}
|
||||
{{ info.summary('Enum Constant Summary', page.meta.enums, details_type='enum') }}
|
||||
{% endif %}
|
||||
{% if page.meta.methods or page.meta.inherits %}
|
||||
{{ info.summary('Method Summary', page.meta.methods, page.meta.inherits, details_type='method') }}
|
||||
{% endif %}
|
||||
<!--
|
||||
Detailed object info
|
||||
-->
|
||||
{% if page.meta.constructors %}
|
||||
{{ info.info('Constructor Detail', page.meta.constructors) }}
|
||||
{% endif %}
|
||||
{% if page.meta.enums %}
|
||||
{{ info.info('Enum Constant Detail', page.meta.enums, true) }}
|
||||
{% endif %}
|
||||
{% if page.meta.methods %}
|
||||
{{ info.info('Method Detail', page.meta.methods)}}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,218 @@
|
||||
{% macro summary(title, summaries, inherits, details_type = 'unknown') -%}
|
||||
<h2 id="{{ title | lower() | replace(' ', '-') | e}}">
|
||||
{{ title }}
|
||||
</h2>
|
||||
<div class="md-typeset__scrollwrap">
|
||||
<div class="md-typeset__table">
|
||||
{% if summaries %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
{% if details_type and details_type == "method" %}
|
||||
<th>Modifier and Type</th>
|
||||
{% endif %}
|
||||
<th>{{ details_type | capitalize() }}</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for summary in summaries %}
|
||||
<tr>
|
||||
{% set modifiers = namespace(name = "") %}
|
||||
{% for attribute in summary.attributes %}
|
||||
{% set modifiers.name = modifiers.name ~ attribute %}
|
||||
{% if loop.revindex > 0 %}{% set modifiers.name = modifiers.name ~ " " %}{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if modifiers.name %}{% set modifiers.name = modifiers.name ~ " " %}{% endif %}
|
||||
|
||||
{% if summary.type and summary.type.name %}
|
||||
{% set modifiers.name = modifiers.name ~ summary.type.name %}
|
||||
{% else %}
|
||||
{% set modifiers.name = modifiers.name ~ "void" %}
|
||||
{% endif %}
|
||||
|
||||
{% set desc = "" %}
|
||||
{% if summary.deprecated %}
|
||||
{% set desc = "<api__deprecated></api__deprecated><br>" ~ summary.deprecated.split("<br>")[0] %}
|
||||
{% elif summary.description %}
|
||||
{% set desc = summary.description.split("<br>")[0] %}
|
||||
{% endif %}
|
||||
|
||||
{% set final_name = namespace(name = "") %}
|
||||
{% if details_type and details_type == "enum" %}
|
||||
{% set final_name.name = summary.name | upper() %}
|
||||
{% else %}
|
||||
{% set final_name.name = summary.name ~ "(" %}
|
||||
{% endif %}
|
||||
|
||||
{% for parameter in summary.parameters %}
|
||||
{% set final_name.name = final_name.name ~ parameter.type %}
|
||||
{% if loop.revindex > 1 %}{% set final_name.name = final_name.name ~ ", " %}{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if details_type != "enum" %}
|
||||
{% set final_name.name = final_name.name ~ ")" %}
|
||||
{% endif %}
|
||||
|
||||
{% if details_type and details_type == "method" %}
|
||||
{% if modifiers.name %}
|
||||
<td><code>{{ modifiers.name }}</code></td>
|
||||
{% else %}
|
||||
<td></td>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<td>
|
||||
{% if summary.link %}
|
||||
<a href="{{ summary.link }}"><code>{{ final_name.name | e}}</code></a>
|
||||
{% else %}
|
||||
<a href="#{{ final_name.name | lower() | replace(' ', '-') | e }}"><code>{{ final_name.name | e}}</code></a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ desc }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
|
||||
{% if inherits %}
|
||||
{% for classpath, inherit in inherits.items() %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Methods inherited from <a href="{{ inherit.link }}"><code>{{ classpath }}</code></a></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
{% for inh in inherit.list %}
|
||||
<a href="{{ inherit.link }}#{{ inh | lower() | replace(' ', '-') | e }}">
|
||||
<code>{{- inh | e -}}</code>
|
||||
</a>
|
||||
{%- if loop.revindex > 1 %}, {% endif -%}
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro info(title, details, enum = false) -%}
|
||||
<h2 id="{{ title | lower() | replace(' ', '-') | e}}">
|
||||
{{ title }}
|
||||
</h2>
|
||||
{% for detail in details %}
|
||||
<div class="api-detail">
|
||||
{% set final_name = namespace(name = "") %}
|
||||
{% if enum %}
|
||||
{% set final_name.name = detail.name | upper() %}
|
||||
{% else %}
|
||||
{% set final_name.name = detail.name ~ "(" %}
|
||||
{% endif %}
|
||||
|
||||
{% for parameter in detail.parameters %}
|
||||
{% set final_name.name = final_name.name ~ parameter.type %}
|
||||
{% if loop.revindex > 1 %}{% set final_name.name = final_name.name ~ ", " %}{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if not enum %}
|
||||
{% set final_name.name = final_name.name ~ ")" %}
|
||||
{% endif %}
|
||||
|
||||
<h3 id="{{ final_name.name | lower() | replace(' ', '-') | e }}">
|
||||
{% if detail.deprecated %}
|
||||
<api__deprecated></api__deprecated>
|
||||
{% endif %}
|
||||
|
||||
{% for attribute in detail.attributes %}
|
||||
<api__{{- attribute -}}></api__{{- attribute -}}>
|
||||
{% endfor %}
|
||||
|
||||
{% if enum %}
|
||||
<api__static></api__static> <api__final></api__final>
|
||||
{% endif %}
|
||||
|
||||
{% if detail.type %}
|
||||
{% if detail.type.link %}
|
||||
<a href="{{ detail.type.link }}" class="api-type__{{- detail.type.type | default('primitive') -}}">{{ detail.type.name | default('void') | e }}</a>
|
||||
{% else %}
|
||||
<span class="api-type__{{- detail.type.type | default('primitive') -}}">{{ detail.type.name | default('void') | e }}</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<code>{{ final_name.name | e }}</code><a href="#{{ final_name.name | lower() | replace(' ', '-') | e }}" class="headerlink" title="Permanent link">¶</a>
|
||||
</h3>
|
||||
|
||||
{% if detail.deprecated %}
|
||||
<div class="admonition deprecated">
|
||||
<div class="admonition-title">Deprecation Warning</div>
|
||||
<p>
|
||||
{{ detail.deprecated }}
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if detail.description %}
|
||||
<p class="api-detail__description">
|
||||
{{ detail.description }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{% if detail.parameters %}
|
||||
<h4 id="{{ detail.name | lower() | replace(' ', '-') | e }}-parameters">
|
||||
Parameters:<a href="#{{ detail.name | lower() | replace(' ', '-') | e }}-parameters" class="headerlink" title="Permanent link">¶</a>
|
||||
</h4>
|
||||
<ul>
|
||||
{% for parameter in detail.parameters %}
|
||||
<li>
|
||||
{% for attribute in parameter.attribute %}
|
||||
<api__{{- attribute -}}></api__{{- attribute -}}>
|
||||
{% endfor %}
|
||||
<code>{{ parameter.type | e }}: {{ parameter.name }}</code>{% if parameter.description %} - {{ parameter.description }}{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
{% if detail.returns %}
|
||||
<h4 id="{{ detail.name | lower() | replace(' ', '-') | e }}-returns">
|
||||
Returns:<a href="#{{ detail.name | lower() | replace(' ', '-') | e }}-returns" class="headerlink" title="Permanent link">¶</a>
|
||||
</h4>
|
||||
<p class="api-detail__description">
|
||||
{{ detail.returns }}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{% if detail.throws %}
|
||||
<h4 id="{{ detail.name | lower() | replace(' ', '-') | e }}-throws">
|
||||
Throws:<a href="#{{ detail.name | lower() | replace(' ', '-') | e }}-throws" class="headerlink" title="Permanent link">¶</a>
|
||||
</h4>
|
||||
<ul>
|
||||
{% for throw in detail.throws %}
|
||||
<li>
|
||||
<code>{{ throw.name }}</code>{% if throw.description %} - {{ throw.description }}{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
{% if seealso %}
|
||||
<h4 id="{{ detail.name | lower() | replace(' ', '-') | e }}-see-also">
|
||||
See also:<a href="#{{ detail.name | lower() | replace(' ', '-') | e }}-see-also" class="headerlink" title="Permanent link">¶</a>
|
||||
</h4>
|
||||
<ul>
|
||||
{% for see in detail.seealso %}
|
||||
<li>
|
||||
<a href="{{ see.link }}"><code>{{ see.name }}</code></a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{%- endmacro %}
|
||||
@@ -0,0 +1,42 @@
|
||||
<!-- Tags -->
|
||||
{% if "material/tags" in config.plugins and tags %}
|
||||
{% include "partials/tags.html" %}
|
||||
{% endif %}
|
||||
|
||||
<!-- Actions -->
|
||||
{% include "partials/actions.html" %}
|
||||
|
||||
{% if config.extra.github_repository %}
|
||||
<div class="admonition info">
|
||||
<p class="admonition-title">Moved</p>
|
||||
<p>
|
||||
The documenation has been moved and can now be found at <a href="https://asl.andre601.ch" target="_blank" rel="noreferral nofollow noopener"><strong>asl.andre601.ch</strong></a>.<br>
|
||||
This page in particular can be found at <a href="https://asl.andre601.ch/{{ page.url }}" target="_blank" rel="noreferral nofollow noopener"><strong>asl.andre601.ch/{{ page.url }}</strong></a>.
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!--
|
||||
Hack: check whether the content contains a h1 headline. If it doesn't, the
|
||||
page title (or respectively site name) is used as the main headline.
|
||||
-->
|
||||
{% if "\x3ch1" not in page.content %}
|
||||
<h1>{{ page.title | d(config.site_name, true)}}</h1>
|
||||
{% endif %}
|
||||
|
||||
<!-- Page content -->
|
||||
{{ page.content }}
|
||||
|
||||
<!-- Source file information -->
|
||||
{% if page.meta and (
|
||||
page.meta.git_revision_date_localized or
|
||||
page.meta.revision_date
|
||||
) %}
|
||||
{% include "partials/source-file.html" %}
|
||||
{% endif %}
|
||||
|
||||
<!-- Was this page helpful? -->
|
||||
{% include "partials/feedback.html" %}
|
||||
|
||||
<!-- Comment system -->
|
||||
{% include "partials/comments.html" %}
|
||||
@@ -0,0 +1,10 @@
|
||||
nav:
|
||||
- Home: index.md
|
||||
- getting-started
|
||||
- commands
|
||||
- profiles
|
||||
- examples
|
||||
- migration
|
||||
- api
|
||||
- addons
|
||||
- PlaceholderAPI: placeholderapi
|
||||
@@ -0,0 +1 @@
|
||||
<div class="mdx-badge"><span class="mdx-badge__icon">[:octicons-tag-24:](changelog.md#v3.1.0 'View latest Release Changelog')</span><span class="mdx-badge__text">[v3.1.0](changelog.md#v3.1.0 'View latest Release Changelog')</span></div>
|
||||
@@ -0,0 +1 @@
|
||||
<div class="mdx-badge"><span class="mdx-badge__icon" >[:octicons-alert-24:](changelog.md)</span><span class="mdx-badge__text">[v3.1.0](changelog.md#v3.1.0 'View latest Release Changelog')</span></div>
|
||||
@@ -0,0 +1,44 @@
|
||||
# BanPlugins Addon
|
||||
|
||||
The BanPlugins Addon was made to provide placeholders for different punishment plugins to use in AdvancedServerList.
|
||||
|
||||
## Placeholders
|
||||
|
||||
### AdvancedBan
|
||||
|
||||
Placeholders for the plugin [AdvancedBan](https://www.spigotmc.org/resources/8695/){ target="_blank" rel="nofollow" } are available to use.
|
||||
|
||||
| Placeholder | Description |
|
||||
|---------------------------------|-------------------------------------------------------------------------------------------|
|
||||
| `${advancedban isMuted}` | Whether the player is muted or not. |
|
||||
| `${advancedban muteReason}` | The reason for why the player was muted. Returns invalid placeholder if no mute was set. |
|
||||
| `${advancedban muteDuration}` | Relative time until the mute expires.[^1] Returns invalid placeholder if no mute was set. |
|
||||
| `${advancedban muteExpiration}` | Date on when the mute will expire.[^2] |
|
||||
| `${advancedban isBanned}` | Whether the player is banned or not. |
|
||||
| `${advancedban banReason}` | The reason for why the player was banned. Returns invalid placeholder if no ban was set. |
|
||||
| `${advancedban banDuration}` | Relative time until the ban expires.[^3] Returns invalid placeholder if no ban was set. |
|
||||
| `${advancedban banExpiration}` | Date on when the ban will expire.[^4] |
|
||||
|
||||
[^1]:
|
||||
An optional boolean can be added to set whether the duration should be from the start or not. `false` is the default.
|
||||
Example: `${advancedban muteDuration true}`
|
||||
[^2]:
|
||||
An optional Date and time Pattern can be set to change the displayed output. The default is `dd, MMM yyyy HH:mm:ss`.
|
||||
Example: `${advancedban muteExpiration yyyy-MM-dd HH:mm:ss}`
|
||||
[^3]:
|
||||
An optional boolean can be added to set whether the duration should be from the start or not. `false` is the default.
|
||||
Example: `${advancedban banDuration true}`
|
||||
[^4]:
|
||||
An optional Date and time Pattern can be set to change the displayed output. The default is `dd, MMM yyyy HH:mm:ss`.
|
||||
Example: `${advancedban banExpiration yyyy-MM-dd HH:mm:ss}`
|
||||
|
||||
## Example
|
||||
|
||||
```yaml title="banned.yml"
|
||||
priority: 1
|
||||
condition: '${advancedban isBanned}'
|
||||
|
||||
motd:
|
||||
- '<red>You were <bold>BANNED</bold>!'
|
||||
- '<red>Expires: <grey>${advancedban banExpiration}'
|
||||
```
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
icon: octicons/plus-circle-24
|
||||
---
|
||||
|
||||
# Addons
|
||||
|
||||
This section contains a curated list of add-ons for AdvancedServerList which can be used to enhance the plugin in different ways.
|
||||
Do you have a plugin that hooks into AdvancedServerList that is not listed here? Contact Andre601 on Discord and it will be added!
|
||||
|
||||
## First-party Addons
|
||||
|
||||
These Addons are made by Andre601 and available together with the plugin downloads.
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- [**BanPlugins**](banplugins.md)
|
||||
|
||||
----
|
||||
|
||||
Addon for different Punishment plugins such as AdvancedBan, that add new placeholders to use in AdvancedServerList.
|
||||
|
||||
</div>
|
||||
|
||||
## Third-party
|
||||
|
||||
Third-party addons made by other people not working on AdvancedServerList.
|
||||
|
||||
*Currently no entries*
|
||||
@@ -0,0 +1,2 @@
|
||||
nav:
|
||||
- ...
|
||||
@@ -0,0 +1,116 @@
|
||||
---
|
||||
icon: octicons/log-24
|
||||
---
|
||||
|
||||
# Changelog
|
||||
|
||||
This page lists the recent changes made towards the AdvancedServerListAPI.
|
||||
They are ordered newest to oldest.
|
||||
|
||||
## v3.1.0 { #v3.1.0 }
|
||||
|
||||
### :octicons-plus-circle-24:{ .changelog-added title="Added" } Added { #v3.1.0-added }
|
||||
|
||||
- New getters in [`ProfileEntry`][profileentry]:
|
||||
- [`maxPlayersEnabled()`][maxplayersenabled] - Returns the value for `playerCount -> maxPlayers -> enabled` as `NullBool`
|
||||
- [`maxPlayersCount()`][maxplayerscount] - Returns the value of `playerCount -> maxPlayers -> amount` as nullable `Integer`
|
||||
- New setters in [`ProfileEntry.Builder`][profileentry.builder]:
|
||||
- [`setMaxPlayersEnabled(NullBool)`][setmaxplayersenabled] - Sets whether the max players feature is enabled or not.
|
||||
- [`setMaxPlayersCount(Integer)`][setmaxplayerscount] - Sets the number to use for the max players count.
|
||||
- [`setExtraPlayersCount(Integer)`][setextraplayersecount] - Replacement for [deprecated `setExtraPlayerCount(Integer)` method](#v3.1.0-deprecated).
|
||||
|
||||
### :octicons-zap-24:{ .changelog-breaking title="Deprecated" } Deprecated { #v3.1.0-deprecated }
|
||||
|
||||
- `setExtraPlayerEnabled(Integer)` in `ProfileEntry.Builder` - Typo in method name.
|
||||
|
||||
[profileentry]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/index.md
|
||||
[maxplayersenabled]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/index.md#maxplayersenabled()
|
||||
[maxplayerscount]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/index.md#maxplayerscount()
|
||||
|
||||
[profileentry.builder]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md
|
||||
[setmaxplayersenabled]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#setmaxplayersenabled(nullbool)
|
||||
[setmaxplayerscount]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#setmaxplayerscount(integer)
|
||||
[setextraplayersecount]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#setextraplayerscount(integer)
|
||||
|
||||
----
|
||||
|
||||
## v3.0.0 { #v3.0.0 }
|
||||
|
||||
### :octicons-alert-24:{ .changelog-breaking title="Breaking Changes" } Breaking Changes { #v3-breaking }
|
||||
|
||||
- Removed `platform-spigot` API in favour of a more generic sounding `platform-bukkit`
|
||||
- Renamed all platform-specific packages from `ch.andre601.advancedserverlist.<platform>` to `ch.andre601.advancedserverlist.api.<platform>`
|
||||
|
||||
### :octicons-plus-circle-24:{ .changelog-added title="Added" } Added { #v3-added }
|
||||
|
||||
- New platform-specific `GenericServer` instances with their own methods to use.
|
||||
- `BukkitServer` - Contains a `getWorlds()` method that returns a `Map<String, World>` of all loaded worlds in the server.
|
||||
- `BungeeProxy` - Contains a `getServers()` method that returns a `Map<String, ServerInfo>` of all known Servers for BungeeCord.
|
||||
- `VelocityProxy` - Contains a `getServers()` method that returns a `Map<String, RegisteredServer>` of all known Servers for Velocity.
|
||||
|
||||
### :octicons-trash-24:{ .changelog-removed title="Removed" } Removed { #v3-removed }
|
||||
|
||||
- All previously deprecated `getX()` methods from the `ProfileEntry` record
|
||||
|
||||
----
|
||||
|
||||
## v2.1.0 { #v2.1.0 }
|
||||
|
||||
### :octicons-pencil-24:{ .changelog-changed title="Changed" } Changed { #v2.1.0-changed }
|
||||
|
||||
- Turned `ProfileEntry` class into a record
|
||||
- Former `getX()` methods are now deprecated in favour of the record's own `x()` methods (i.e. `getMotd()` -> `motd()`)
|
||||
|
||||
----
|
||||
|
||||
## v2.0.0 { #v2.0.0 }
|
||||
|
||||
### :octicons-alert-24:{ .changelog-breaking title="Breaking Changes" } Breaking Changes { #v2-breaking }
|
||||
|
||||
- `platform-paper` has been removed. It used the same code as `platform-spigot` and was therefore considered duplicate code and useless.
|
||||
- `core` has been removed. The `CachedPlayer` is no longer needed in the platform-specific APIs.
|
||||
|
||||
### :octicons-plus-circle-24:{ .changelog-added title="Added" } Added { #v2-added }
|
||||
|
||||
- `PreServerListSetEvent` to the different platform-specific APIs.
|
||||
- Called before AdvancedServerList alters the server list.
|
||||
- Allows to override the `ProfileEntry` used or even cancel the event.
|
||||
- `ProfileEntry`
|
||||
- Used for setting the different values of the server list.
|
||||
- Own instances can be made using the nested `Builder` class.
|
||||
- Has methods to create a Builder instance from itself, or make a copy from another ProfileEntry-instance.
|
||||
|
||||
### :octicons-pencil-24:{ .changelog-changed title="Changed" } Changed { #v2-changed }
|
||||
|
||||
- Converted `GenericPlayer`, `GenericServer`, `BungeePlayer`, `SpigotPlayer` and `VelocityPlayer` into interfaces.
|
||||
- `GenericPlayer` no longer has `getVersion()`, `hasPlayedBefore()`, `isBanned()` and `isWhitelisted()`. They have been moved to `VelocityPlayer` (Only `getVersion()`) and `SpigotPlayer` respectively.
|
||||
- Converted `NullBool` from a class to an enum.
|
||||
- Contains `TRUE`, `FALSE` and `NOT_SET`.
|
||||
- `isNull()` is now `isNotSet()`.
|
||||
|
||||
### :octicons-trash-24:{ .changelog-removed title="Removed" } Removed { #v2-removed }
|
||||
|
||||
- `UnsupportedAPIAccessException` as it is no longer used in the API itself.
|
||||
|
||||
----
|
||||
|
||||
## v1.0.0 { #v1.0.0 }
|
||||
|
||||
### :octicons-plus-circle-24:{ .changelog-added title="Added" } Added { #v1-added }
|
||||
|
||||
- `AdvancedServerListAPI`
|
||||
- Main class used to add your own `PlaceholderProvider` instances.
|
||||
- `PlaceholderProvider`
|
||||
- Abstract class used to add your own placeholders to parse in AdvancedServerList.
|
||||
|
||||
<!--
|
||||
|
||||
Templates for changelog
|
||||
|
||||
### :octicons-alert-24:{ .changelog-breaking title="Breaking Changes" } Breaking Changes { #v-breaking }
|
||||
### :octicons-plus-circle-24:{ .changelog-added title="Added" } Added { #v-added }
|
||||
### :octicons-pencil-24:{ .changelog-changed title="Changed" } Changed { #v-changed }
|
||||
### :octicons-trash-24:{ .changelog-removed title="Removed" } Removed { #v-removed }
|
||||
### :octicons-zap-24:{ .changelog-deprecated title="Deprecated" } Deprecated { #v-deprecated }
|
||||
|
||||
-->
|
||||
@@ -0,0 +1,395 @@
|
||||
---
|
||||
icon: octicons/command-palette-24
|
||||
---
|
||||
|
||||
# API
|
||||
|
||||
AdvancedServerList v2 introduced a new API that plugins can hook into to use.
|
||||
It provides a way for your plugin to provide its own placeholders that should be parsed by AdvancedServerList and also an event to modify the server list.
|
||||
|
||||
## Add dependency
|
||||
|
||||
Add the following to your `pom.xml`, `build.gradle` or `build.gradle.kts` depending on what you use:
|
||||
|
||||
/// tab | :simple-apachemaven: Maven
|
||||
```xml title="pom.xml"
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>jitpack</id>
|
||||
<url>https://jitpack.io/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>ch.andre601.asl-api</groupId>
|
||||
<artifactId>api</artifactId>
|
||||
<version>{apiVersion}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Optional platform dependencies -->
|
||||
<dependency>
|
||||
<groupId>ch.andre601.asl-api</groupId>
|
||||
<artifactId>platform-bukkit</artifactId>
|
||||
<version>{apiVersion}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.andre601.asl-api</groupId>
|
||||
<artifactId>platform-bungeecord</artifactId>
|
||||
<version>{apiVersion}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.andre601.asl-api</groupId>
|
||||
<artifactId>platform-velocity</artifactId>
|
||||
<version>{apiVersion}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
```
|
||||
///
|
||||
|
||||
/// tab | :simple-gradle: Gradle
|
||||
```groovy title="build.gradle"
|
||||
repositorories {
|
||||
maven { url = 'https://jitpack.io/' }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly 'ch.andre601.asl-api:api:{apiVersion}'
|
||||
|
||||
// Optional platform dependencies
|
||||
compileOnly 'ch.andre601.asl-api:platform-bukkit:{apiVersion}'
|
||||
compileOnly 'ch.andre601.asl-api:platform-bungeecord:{apiVersion}'
|
||||
compileOnly 'ch.andre601.asl-api:platform-velocity:{apiVersion}'
|
||||
}
|
||||
```
|
||||
///
|
||||
|
||||
/// tab | :simple-gradle: Gradle (KTS)
|
||||
```kotlin title="build.gradle.kts"
|
||||
repositories {
|
||||
maven("https://jitpack.io")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("ch.andre601.asl-api:api:{apiVersion}")
|
||||
|
||||
// Optional platform dependencies
|
||||
compileOnly("ch.andre601.asl-api:platform-bukkit:{apiVersion}")
|
||||
compileOnly("ch.andre601.asl-api:platform-bungeecord:{apiVersion}")
|
||||
compileOnly("ch.andre601.asl-api:platform-velocity:{apiVersion}")
|
||||
}
|
||||
```
|
||||
///
|
||||
|
||||
## Adding your own Placeholders
|
||||
|
||||
<!-- admo:info This requires the main api module -->
|
||||
|
||||
The API allows you to add your own placeholders which would be available through the `${<identifier> <values>}` placeholder Pattern in a Server List profile.
|
||||
|
||||
To add your own placeholders, follow these steps:
|
||||
|
||||
### 1. Create a Placeholder class
|
||||
|
||||
You should first create a new class and make it extend the abstract [`PlaceholderProvider`][placeholderprovider]. This class includes a constructor and a method you need to add, so do that:
|
||||
|
||||
```java
|
||||
public class MyPlaceholders extends PlaceholderProvider {
|
||||
|
||||
public MyPlaceholders(String identifier) {
|
||||
super(identifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
/// tip
|
||||
You can replace the Constructor with a String argument with a no-args constructor and set the identifier directly in the `super`:
|
||||
```java
|
||||
public MyPlaceholders() {
|
||||
super("myplaceholders");
|
||||
}
|
||||
```
|
||||
///
|
||||
|
||||
The [`parsePlaceholder(String, GenericPlayer, GenericServer)`][parseplaceholder] method is used by AdvancedServerList to replace a matching placeholder with a value.
|
||||
What you return is completely up to you. Just keep in mind that returning `null` will be treated as an invalid placeholder by AdvancedServerList, resulting in the placeholder being returned as-is without any changes.
|
||||
|
||||
[placeholderprovider]: reference/api/ch.andre601.advancedserverlist.api/placeholderprovider.md
|
||||
[parseplaceholder]: reference/api/ch.andre601.advancedserverlist.api/placeholderprovider.md#parseplaceholder(string,-genericplayer,-genericserver)
|
||||
|
||||
/// details | Example of final class
|
||||
type: example
|
||||
|
||||
```java
|
||||
public class MyPlaceholders extends PlaceholderProvider {
|
||||
|
||||
public MyPlaceholders() {
|
||||
super("myplaceholders");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server) {
|
||||
if(placeholder.equalsIgnoreCase("hello"))
|
||||
return "Hello " + player.getName();
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
```
|
||||
///
|
||||
|
||||
### 2. Register the Placeholders
|
||||
|
||||
Next step should be to register the placeholder. To achieve this, first obtain an instance of the [`AdvancedServerListAPI`][advancedserverlistapi] by using the static [`get()`][get] method. After that call [`addPlaceholderProvider(PlaceholderProvider placeholderProvider)`][addplaceholderprovider].
|
||||
Your code may look similar to this:
|
||||
|
||||
```java title="Registering PlaceholderProvider class"
|
||||
public class MyPlugin extends JavaPlugin {
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
AdvancedServerListAPI api = AdvancedServerListAPI.get();
|
||||
|
||||
api.addPlaceholderProvider(new MyPlaceholders());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
[advancedserverlistapi]: reference/api/ch.andre601.advancedserverlist.api/advancedserverlistapi.md
|
||||
[get]: reference/api/ch.andre601.advancedserverlist.api/advancedserverlistapi.md#get()
|
||||
[addplaceholderprovider]: reference/api/ch.andre601.advancedserverlist.api/advancedserverlistapi.md#addplaceholderprovider(placeholderprovider)
|
||||
|
||||
This should register your PlaceholderExpansion as long as it is valid, meaning that the identifier...
|
||||
|
||||
- ...is not `null`
|
||||
- ...is not containing spaces
|
||||
- ...is not using a name already registered in the API
|
||||
|
||||
### 3. Declare AdvancedServerList as (soft)depend
|
||||
|
||||
The final thing you should make sure is to define AdvancedServerList as a depend or soft-depend for your plugin, to make sure it loads after AdvancedServerList.
|
||||
|
||||
Below are example setups for Spigot, Paper, BungeeCord and Velocity:
|
||||
|
||||
/// tab | :simple-spigotmc: Spigot
|
||||
//// tab | Softdepend
|
||||
```yaml title="plugin.yml"
|
||||
name: "MyPlugin"
|
||||
author: "author"
|
||||
version: "1.0.0"
|
||||
|
||||
main: "com.example.plugin.ExamplePlugin"
|
||||
|
||||
softdepend:
|
||||
- AdvancedServerList
|
||||
```
|
||||
////
|
||||
|
||||
//// tab | Depend
|
||||
```yaml title="plugin.yml"
|
||||
name: "MyPlugin"
|
||||
author: "author"
|
||||
version: "1.0.0"
|
||||
|
||||
main: "com.example.plugin.ExamplePlugin"
|
||||
|
||||
depend:
|
||||
- AdvancedServerList
|
||||
```
|
||||
////
|
||||
///
|
||||
|
||||
/// tab | :fontawesome-solid-paper-plane: Paper
|
||||
//// tab | Softdepend
|
||||
```yaml title="paper-plugin.yml"
|
||||
name: "MyPlugin"
|
||||
author: "author"
|
||||
version: "1.0.0"
|
||||
|
||||
main: "com.example.plugin.ExamplePlugin"
|
||||
|
||||
dependencies:
|
||||
server:
|
||||
AdvancedServerList:
|
||||
load: BEFORE
|
||||
required: false # Default, not required
|
||||
```
|
||||
////
|
||||
|
||||
//// tab | Depend
|
||||
```yaml title="paper-plugin.yml"
|
||||
name: "MyPlugin"
|
||||
author: "author"
|
||||
version: "1.0.0"
|
||||
|
||||
main: "com.example.plugin.ExamplePlugin"
|
||||
|
||||
dependencies:
|
||||
server:
|
||||
AdvancedServerList:
|
||||
load: BEFORE
|
||||
required: true
|
||||
```
|
||||
////
|
||||
///
|
||||
|
||||
/// tab | :octicons-git-merge-24: BungeeCord
|
||||
//// tab | Softdepend
|
||||
```yaml title="bungee.yml"
|
||||
name: "MyPlugin"
|
||||
author: "author"
|
||||
version: "1.0.0"
|
||||
|
||||
main: "com.example.plugin.ExamplePlugin"
|
||||
|
||||
softDepends:
|
||||
- AdvancedServerList
|
||||
```
|
||||
////
|
||||
|
||||
//// tab | Depend
|
||||
```yaml title="bungee.yml"
|
||||
name: "MyPlugin"
|
||||
author: "author"
|
||||
version: "1.0.0"
|
||||
|
||||
main: "com.example.plugin.ExamplePlugin"
|
||||
|
||||
depends:
|
||||
- AdvancedServerList
|
||||
```
|
||||
////
|
||||
///
|
||||
|
||||
/// tab | :octicons-git-merge-24: Velocity
|
||||
//// tab | Softdepend (File)
|
||||
```json title="velocity-plugin.json"
|
||||
{
|
||||
"id": "myplugin",
|
||||
"name": "MyPlugin",
|
||||
"version": "1.0.0",
|
||||
"authors": [
|
||||
"author"
|
||||
],
|
||||
"main": "com.example.plugin.ExamplePlugin",
|
||||
"dependencies": [
|
||||
{
|
||||
"id": "advancedserverlist",
|
||||
"optional": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
////
|
||||
|
||||
//// tab | Depend (File)
|
||||
```json title="velocity-plugin.json"
|
||||
{
|
||||
"id": "myplugin",
|
||||
"name": "MyPlugin",
|
||||
"version": "1.0.0",
|
||||
"authors": [
|
||||
"author"
|
||||
],
|
||||
"main": "com.example.plugin.ExamplePlugin",
|
||||
"dependencies": [
|
||||
{
|
||||
"id": "advancedserverlist",
|
||||
"optional": false // Default, not required
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
////
|
||||
|
||||
//// tab | Softdepend (Annotation)
|
||||
```java title="MyPlugin.java"
|
||||
@Plugin(
|
||||
id = "myplugin",
|
||||
name = "MyPlugin",
|
||||
version = "1.0.0",
|
||||
authors = {"author"},
|
||||
dependencies = {
|
||||
@Dependency(
|
||||
id = "advancedserverlist",
|
||||
optional = true
|
||||
)
|
||||
}
|
||||
)
|
||||
public class MyPlugin {
|
||||
|
||||
// ...
|
||||
|
||||
}
|
||||
```
|
||||
////
|
||||
|
||||
//// tab | Depend (Annotation)
|
||||
```java title="MyPlugin.java"
|
||||
@Plugin(
|
||||
id = "myplugin",
|
||||
name = "MyPlugin",
|
||||
version = "1.0.0",
|
||||
authors = {"author"},
|
||||
dependencies = {
|
||||
@Dependency(
|
||||
id = "advancedserverlist",
|
||||
optional = false // Default, not required
|
||||
)
|
||||
}
|
||||
)
|
||||
public class MyPlugin {
|
||||
|
||||
// ...
|
||||
|
||||
}
|
||||
```
|
||||
////
|
||||
///
|
||||
|
||||
### 4. You're done!
|
||||
|
||||
Your plugin should now hook into AdvancedServerList and register its own custom placeholders to use.
|
||||
|
||||
## Listening for events
|
||||
|
||||
<!-- admo:info This requires the platform specific dependencies -->
|
||||
|
||||
AdvancedServerList provides an Event that your plugin can listen for.
|
||||
The event is called `PreServerListSetEvent` and provides the following methods to use:
|
||||
|
||||
- [`getEntry()`][getentry] - Gets the currently set [`ProfileEntry`][profileentry].
|
||||
- [`setEntry(ProfileEntry)`][setentry] - Sets a new [`ProfileEntry`][profileentry] to use.
|
||||
- [`isCancelled()`][iscancelled] - Gets the current cancelled state of the event.
|
||||
- [`setCancelled(boolean)`][setcancelled] - Sets the current cancelled state.
|
||||
|
||||
Setting the event's cancelled state to true will result in AdvancedServerList not altering the Server list.
|
||||
|
||||
Please check the server/proxy's documentation on how to listen for events with your plugin.
|
||||
|
||||
[getentry]: reference/api/ch.andre601.advancedserverlist.api/events/genericserverlistevent.md#getentry()
|
||||
[setentry]: reference/api/ch.andre601.advancedserverlist.api/events/genericserverlistevent.md#setentry(profileentry)
|
||||
[iscancelled]: reference/api/ch.andre601.advancedserverlist.api/events/genericserverlistevent.md#iscancelled()
|
||||
[setcancelled]: reference/api/ch.andre601.advancedserverlist.api/events/genericserverlistevent.md#setcancelled(boolean)
|
||||
|
||||
[profileentry]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/index.md
|
||||
|
||||
### ProfileEntry
|
||||
|
||||
The ProfileEntry record is the core class used within the `PreServerListSetEvent`. It sets what values (MOTD, Favicon, Players, etc.) should be displayed.
|
||||
Note that the record is - by nature - immutable and that the [`Builder`][builder] class should be used to create a new ProfileEntry instance to use.
|
||||
|
||||
A convenience method exists to create a `Builder` instance from an existing `ProfileEntry` in case you only want to alter certain options while everything else unchanged.
|
||||
|
||||
This allows you to customize the Server list using your plugin. Just keep in mind that other plugins may also do the same, overriding your changes.
|
||||
|
||||
[builder]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
template: redirect.html
|
||||
|
||||
location: https://docs.andre601.ch/asl-api
|
||||
|
||||
title: Javadocs
|
||||
icon: octicons/link-external-24
|
||||
---
|
||||
|
||||
<!-- Comment to trigger proper build -->
|
||||
@@ -0,0 +1,6 @@
|
||||
nav:
|
||||
- index.md
|
||||
- api: api
|
||||
- platform-bukkit: platform-bukkit
|
||||
- platform-bungeecord: platform-bungeecord
|
||||
- platform-velocity: platform-velocity
|
||||
@@ -0,0 +1,3 @@
|
||||
nav:
|
||||
- index.md
|
||||
- ch.andre601.advancedserverlist.api: ch.andre601.advancedserverlist.api
|
||||
@@ -0,0 +1,54 @@
|
||||
---
|
||||
template: api-doc.html
|
||||
|
||||
methods:
|
||||
- name: 'get'
|
||||
description: |
|
||||
Retrieve the instance used of this API.<br>
|
||||
If no instance has been made so far will a new one be created.
|
||||
returns: 'Instance of this API.'
|
||||
attributes:
|
||||
- static
|
||||
type:
|
||||
name: 'AdvancedServerListAPI'
|
||||
type: 'object'
|
||||
- name: 'addPlaceholderProvider'
|
||||
description: |
|
||||
Adds the provided <a href="./../placeholderprovider/"><code>PlaceholderProvider</code></a> to the list, if it passes the following checks:<br>
|
||||
<ul>
|
||||
<li>Provided PlaceholderProvider instance is not null.</li>
|
||||
<li>The identifier is not null nor empty.</li>
|
||||
<li>The identifier does not contain any spaces.</li>
|
||||
<li>A PlaceholderProvider with the same identifier doesn't exist already.</li>
|
||||
</ul>
|
||||
Not passing any of the above checks results in a <a href="./../exceptions/invalidplaceholderproviderexception/"><code>InvalidPlaceholderProviderException</code></a> being thrown.
|
||||
parameters:
|
||||
- name: 'placeholderProvider'
|
||||
description: 'The <a href="./../placeholderprovider/"><code>PlaceholderProvider</code></a> to add.'
|
||||
type: PlaceholderProvider
|
||||
attributes:
|
||||
- notnull
|
||||
throws:
|
||||
- name: 'InvalidPlaceholderProviderException'
|
||||
description: 'When the provided <a href="./../placeholderprovider/"><code>PlaceholderProvider</code> instance</a> is null, has a null or empty identifier, the identifier contains spaces, or another PlaceholderProvider with the same identifier is already in use.'
|
||||
type:
|
||||
name: 'void'
|
||||
- name: 'retrievePlaceholderProvider'
|
||||
description: 'Retrieves the <a href="./../placeholderprovider/"><code>PlaceholderProvider</code></a> associated with the provided identifier, or <code>null</code> should no such entry exist.'
|
||||
parameters:
|
||||
- name: 'identifier'
|
||||
description: 'The identifier to find a matching <a href="./../placeholderprovider/"><code>PlaceholderProvider</code></a> for.'
|
||||
type: String
|
||||
returns: 'Possibly-null <a href="./../placeholderprovider/"><code>PlaceholderProvider</code> instance</a>.'
|
||||
attributes:
|
||||
- nullable
|
||||
type:
|
||||
name: PlaceholderProvider
|
||||
type: object
|
||||
link: './../placeholderprovider'
|
||||
---
|
||||
|
||||
# <api__class></api__class> AdvancedServerListAPI
|
||||
|
||||
Core class of the API for AdvancedServerList.
|
||||
Use [`get()`](#get) to retrieve the instance currently used.
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
---
|
||||
template: api-doc.html
|
||||
|
||||
methods:
|
||||
- name: 'getEntry'
|
||||
description: 'Gets the <a href="../../profiles/profileentry/"><code>ProfileEntry</code></a> currently set.'
|
||||
returns: The currently used ProfileEntry.
|
||||
type:
|
||||
name: ProfileEntry
|
||||
type: object
|
||||
link: '../../profiles/profileentry/'
|
||||
- name: 'setEntry'
|
||||
description: |-
|
||||
Sets the new <a href="../../profiles/profileentry/"><code>ProfileEntry</code></a> to use.<br>
|
||||
This may not be <code>null</code>.
|
||||
parameters:
|
||||
- name: 'entry'
|
||||
description: 'The new <a href="../../profiles/profileentry/"><code>ProfileEntry</code></a> to use.'
|
||||
type: ProfileEntry
|
||||
attributes:
|
||||
- notnull
|
||||
throws:
|
||||
- name: 'IllegalArgumentException'
|
||||
description: 'When the provided ProfileEntry is <code>null</code>'
|
||||
type:
|
||||
name: 'void'
|
||||
- name: 'isCancelled'
|
||||
description: Returns whether this event has been cancelled or not.
|
||||
returns: Whether this event has been cancelled or not.
|
||||
type:
|
||||
name: boolean
|
||||
- name: 'setCancelled'
|
||||
description: Sets the event's cancel state
|
||||
parameters:
|
||||
- name: 'cancelled'
|
||||
description: 'Boolean to set the event''s cancelled state.'
|
||||
type: boolean
|
||||
type:
|
||||
name: 'void'
|
||||
---
|
||||
|
||||
# <api__interface></api__interface> GenericServerListEvent
|
||||
|
||||
Interface used for the platform-specific PreServerListSetEvent instances.
|
||||
This allows the plugin to pull common info such as ProfileEntry or if the event has been cancelled by another plugin.
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
---
|
||||
template: 'api-doc.html'
|
||||
|
||||
constructors:
|
||||
- name: 'InvalidPlaceholderProviderException'
|
||||
parameters:
|
||||
- name: msg
|
||||
type: String
|
||||
---
|
||||
|
||||
# <api__class></api__class> InvalidPlaceholderProviderException
|
||||
|
||||
RuntimeException thrown whenever an invalid [`PlaceholderProvider`](../placeholderprovider.md) has been given.
|
||||
@@ -0,0 +1,42 @@
|
||||
---
|
||||
template: api-doc.html
|
||||
|
||||
methods:
|
||||
- name: 'getName'
|
||||
description: |
|
||||
Returns the name of the player.<br>
|
||||
Note that on Spigot, Paper and other forks can the name differ from the one cached by AdvancedServerList, if the plugin was able to retrieve an OfflinePlayer instance from the server. On BungeeCord and Velocity will the returned String always be the name from the cache.<br>
|
||||
<br>
|
||||
Name may be whatever has been defined in AdvancedServerList's config.yml, should the player not be cached yet by the plugin.
|
||||
returns: 'String representing the player''s name'
|
||||
type:
|
||||
name: String
|
||||
type: object
|
||||
- name: 'getProtocol'
|
||||
description: |
|
||||
Returns the protocol ID the player is using.<br>
|
||||
The protocol ID is an integer used by Minecraft to determine what version a server or client is running.
|
||||
returns: 'Integer representing the protocol version of this player.'
|
||||
type:
|
||||
name: int
|
||||
- name: 'getUUID'
|
||||
description: |
|
||||
Returns the unique ID associated with this player.<br>
|
||||
<br>
|
||||
UUID may be whatever has been defined in AdvancedServerList's config.yml, should the player not be cached yet by AdvancedServerList.
|
||||
returns: 'UUID of the player'
|
||||
type:
|
||||
name: UUID
|
||||
type: object
|
||||
---
|
||||
|
||||
# <api__interface></api__interface> GenericPlayer
|
||||
|
||||
A basic interface used to store generic player data to use in placeholder resolving.
|
||||
The different variants of AdvancedServerList implement this into their own class and may provide additional data not available through this interface.
|
||||
|
||||
The following values will always be present, no matter the platform this interface is used on:
|
||||
|
||||
- [Name of the Player](#getname())
|
||||
- [Protocol version of the Player](#getprotocol())
|
||||
- [UUID of the Player](#getuuid())
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
template: api-doc.html
|
||||
|
||||
methods:
|
||||
- name: 'getPlayersOnline'
|
||||
description: 'Returns the number of players currently online on the server.'
|
||||
returns: 'Number of players online on the server.'
|
||||
type:
|
||||
name: int
|
||||
- name: 'getPlayersMax'
|
||||
description: 'Returns the number of total players that can join the server.'
|
||||
returns: 'Number of total players that can join the server.'
|
||||
type:
|
||||
name: int
|
||||
- name: 'getHost'
|
||||
description: 'Returns the IP/Domain that got pinged by the player.'
|
||||
returns: 'Possibly-null String containing the IP/Domain that got pinged by the player'
|
||||
attributes:
|
||||
- nullable
|
||||
type:
|
||||
name: 'String'
|
||||
type: 'object'
|
||||
---
|
||||
|
||||
# <api__interface></api__interface> GenericServer
|
||||
|
||||
Simple class used to wrap around some generic server data such as online player count, number of total players that can join and the host (IP/Domain) that got pinged by the player.
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
template: api-doc.html
|
||||
|
||||
enums:
|
||||
- name: 'true'
|
||||
description: 'Boolean value <code>true</code>'
|
||||
- name: 'false'
|
||||
description: 'Boolean value <code>false</code>'
|
||||
- name: 'not_set'
|
||||
description: 'Boolean value <code>null</code>'
|
||||
|
||||
methods:
|
||||
- name: 'resolve'
|
||||
description: |
|
||||
Returns a NullBool instance based on the provided <code>Boolean</code> value.<br>
|
||||
In case of <code>null</code> being provided will <a href="#not_set"><code>NullBool.NOT_SET</code></a> be returned, otherwise will the corresponding NullBool instance matching the Boolean value be returned.
|
||||
returns: 'NullBool instance based on the provided <code>Boolean</code> value.'
|
||||
parameters:
|
||||
- name: 'bool'
|
||||
description: 'The <code>Boolean</code> value to receive a NullBool instance for.'
|
||||
type: Boolean
|
||||
attributes:
|
||||
- nullable
|
||||
attributes:
|
||||
- static
|
||||
type:
|
||||
name: 'NullBool'
|
||||
type: 'object'
|
||||
- name: 'isNotSet'
|
||||
description: 'Returns whether the NullBool is <a href="#not_set"><code>NullBool.NOT_SET</code></a>.'
|
||||
returns: 'True if the instance is <a href="#not_set"><code>NullBool.NOT_SET</code></a>, otherwise false.'
|
||||
type:
|
||||
name: 'boolean'
|
||||
type: 'primitive'
|
||||
- name: 'getOrDefault'
|
||||
description: |
|
||||
Gets the corresponding boolean value associated with the NullBool instance.<br>
|
||||
In the case of NullBool <a href="#isnotset()">not being set</a> will the provided default value be returned.
|
||||
returns: 'True or false depending on the NullBool instance and the provided default value.'
|
||||
parameters:
|
||||
- name: 'def'
|
||||
description: 'The default boolean value to return should the NullBool instance be <a href="#not_set"><code>NullBool.NOT_SET</code></a>.'
|
||||
type: boolean
|
||||
type:
|
||||
name: 'boolean'
|
||||
type: 'primitive'
|
||||
---
|
||||
|
||||
# <api__enum></api__enum> NullBool
|
||||
|
||||
Enum used to return a `Boolean` value with a default one should no value be set.
|
||||
Loaded 100 of 209 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user