Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a2cb2078d | ||
|
|
05381bd538 | ||
|
|
51e561f2ba | ||
|
|
71a3bddc62 | ||
|
|
3eeffd5520 | ||
|
|
3590e4fa12 | ||
|
|
e1e7907d0f | ||
|
|
1e8f71092c | ||
|
|
1c12180fe3 | ||
|
|
7a41e27788 | ||
|
|
ddfc8763c4 | ||
|
|
086905ad53 | ||
|
|
4526e91e0f | ||
|
|
cfb74b277e | ||
|
|
d7c3a7d756 | ||
|
|
36c6af0a43 | ||
|
|
f9df11c9f8 | ||
|
|
8f42b63733 | ||
|
|
10604f4064 | ||
|
|
7a574513af | ||
|
|
deeea1578d | ||
|
|
ac379b1668 | ||
|
|
c636764f4b | ||
|
|
a823aebafd | ||
|
|
dd4c3c0eb3 | ||
|
|
23afe54e29 | ||
|
|
fab3731cf4 | ||
|
|
49a782d560 | ||
|
|
cdac325e71 | ||
|
|
88f4278f3f | ||
|
|
de4617e450 | ||
|
|
4c4573b1e0 | ||
|
|
f74f3ef766 | ||
|
|
806a920d32 | ||
|
|
c9db8cbc97 | ||
|
|
3e3cd112ec | ||
|
|
fcc7d7c6b6 | ||
|
|
cb31fc6f5a | ||
|
|
b26a614f87 | ||
|
|
eb6f4180bf | ||
|
|
02d6b1958b | ||
|
|
bf3c979819 | ||
|
|
b5af4b9c47 | ||
|
|
6b9cff2945 | ||
|
|
d17549ee68 | ||
|
|
8b73eb3c8c | ||
|
|
1ee9ae473d | ||
|
|
37006063cf | ||
|
|
76d97de029 | ||
|
|
cd8f6f4c22 | ||
|
|
ce14274e4c | ||
|
|
a5d777f4f1 | ||
|
|
f94e578694 | ||
|
|
4ff55ddf28 | ||
|
|
7c441e6ab5 | ||
|
|
2779f565a9 | ||
|
|
6d3cd0c505 | ||
|
|
cf95f11fdb | ||
|
|
679dbb8c0b | ||
|
|
f44e2759b9 | ||
|
|
29239cc4ed | ||
|
|
bcd5e77166 | ||
|
|
5d2fa03601 | ||
|
|
8f1a5e5a37 | ||
|
|
05fde902a4 | ||
|
|
d69e70c485 | ||
|
|
fba1e84171 | ||
|
|
530f0fd954 | ||
|
|
8bec42bb91 | ||
|
|
94982ff1e8 | ||
|
|
1f9795ed97 | ||
|
|
c6f95cb78a | ||
|
|
571f9f6b38 | ||
|
|
17d0802e41 | ||
|
|
6d7fbb8c25 | ||
|
|
d3d83e5e11 | ||
|
|
82fb9c90f4 | ||
|
|
6841a5a6e0 | ||
|
|
6f41cd4e3a | ||
|
|
379f36832e | ||
|
|
5d8a39cd22 | ||
|
|
9dba820840 | ||
|
|
58712ca5c5 | ||
|
|
e19e942799 | ||
|
|
03434130c4 | ||
|
|
99df25551a | ||
|
|
4f31e4ce6f | ||
|
|
ba097c538d | ||
|
|
aa52435591 | ||
|
|
f44194d24f | ||
|
|
0e2d760ea6 | ||
|
|
c1e7e6b3ff | ||
|
|
96d383a5a1 | ||
|
|
79ba7877bf | ||
|
|
86b9aaa7c6 | ||
|
|
0cb3c036af | ||
|
|
b1f7b75e2d | ||
|
|
e9bc72c165 | ||
|
|
93203249fe | ||
|
|
2523ccb425 | ||
|
|
94972dad31 | ||
|
|
f8ac310259 | ||
|
|
5d8f5d81ed | ||
|
|
3111d7933d | ||
|
|
55f7e17d34 | ||
|
|
0e88a50deb | ||
|
|
83f351de6d | ||
|
|
b96d1cb1a9 | ||
|
|
517ff1df82 | ||
|
|
e8c7c4ee18 | ||
|
|
da44eac70e | ||
|
|
e85c121ee4 | ||
|
|
0c175999fc | ||
|
|
9c3f237f6d | ||
|
|
777545c94f | ||
|
|
dd197609e1 | ||
|
|
14ee306463 | ||
|
|
a635aa8c91 | ||
|
|
050ac3262a | ||
|
|
89aa309c90 | ||
|
|
e9b004c3f2 | ||
|
|
3ecca64a3d | ||
|
|
96dcea4e5b | ||
|
|
400f4709f5 | ||
|
|
5d4307128b | ||
|
|
65c96690f6 | ||
|
|
483d582cd1 | ||
|
|
6f14e17ae7 | ||
|
|
ff32cc1005 | ||
|
|
bcc18d7738 | ||
|
|
629079b438 | ||
|
|
bce03b68a8 | ||
|
|
841c32de0d | ||
|
|
f321ef0162 | ||
|
|
eca32d1858 | ||
|
|
f2c1f6e491 | ||
|
|
af31aac07e | ||
|
|
f8db3e7706 | ||
|
|
3d3ea2913c | ||
|
|
7b7042a856 | ||
|
|
c66c4f21f3 | ||
|
|
890a3f7b46 | ||
|
|
73b969bc51 | ||
|
|
55c93d8d59 | ||
|
|
e1ed8c1cb2 | ||
|
|
e2a91a461a | ||
|
|
8a454004a4 | ||
|
|
8df862530d | ||
|
|
4a1c93fb1b | ||
|
|
e795cf31eb | ||
|
|
e8d93d064f | ||
|
|
6a2a90b868 | ||
|
|
9cea1d3841 | ||
|
|
7453b43d6b | ||
|
|
7e30f937bd | ||
|
|
176a8ac42e | ||
|
|
f480ff51e1 | ||
|
|
e72b772cb9 | ||
|
|
c91faa899e | ||
|
|
e5c6d77e3d | ||
|
|
e8ad2c8266 | ||
|
|
d244f2816a | ||
|
|
73f3172504 | ||
|
|
d7c9f73898 | ||
|
|
2b6818180f | ||
|
|
c7c14799e3 | ||
|
|
59774347f6 | ||
|
|
e45f9a1e73 | ||
|
|
a44235dc10 | ||
|
|
52569a3588 | ||
|
|
602a8e27ea | ||
|
|
81a23953e5 | ||
|
|
9daf8f3a3e | ||
|
|
3d5b4501e3 | ||
|
|
67047e9877 | ||
|
|
7fcb0e78e3 | ||
|
|
8b8018245e | ||
|
|
b34143d4f5 | ||
|
|
a33c096cf4 | ||
|
|
0957edbcd8 | ||
|
|
70adf4e216 | ||
|
|
da42e8c137 | ||
|
|
f4eecda209 | ||
|
|
b934d1a856 | ||
|
|
bbec0aa064 | ||
|
|
ba1f620eee | ||
|
|
f0281adf8a | ||
|
|
c702f61c21 | ||
|
|
dec23e0412 | ||
|
|
782dcb8382 | ||
|
|
e401d1f8c1 | ||
|
|
5e6654b3ef | ||
|
|
25a9e8ef63 | ||
|
|
558e47a7da | ||
|
|
740896c304 | ||
|
|
62d9aa81a3 | ||
|
|
7220b633cf | ||
|
|
0908ddad5e | ||
|
|
d1549b1441 | ||
|
|
57f618e7e2 | ||
|
|
911c64f7ad | ||
|
|
fdeeb35fa9 | ||
|
|
c2c653e613 | ||
|
|
8fa7c1593d | ||
|
|
b2dc74951f | ||
|
|
099c45e4c4 | ||
|
|
e38f6648ee | ||
|
|
2d701aa8a8 | ||
|
|
1f32c22ebf | ||
|
|
610d86ad1b | ||
|
|
658ec8dd74 | ||
|
|
85b7210e7c | ||
|
|
98b99b37de | ||
|
|
bc3aaa4d28 | ||
|
|
a3d0342f28 | ||
|
|
6e057422b6 | ||
|
|
7ee65c6c21 | ||
|
|
b4b754e483 | ||
|
|
b7c0c8a312 | ||
|
|
cf6006f9d6 | ||
|
|
6bf44f6208 | ||
|
|
428dd3cd06 | ||
|
|
871e2efbe2 | ||
|
|
a5b45e2c82 | ||
|
|
9feb3dfac6 | ||
|
|
5961d0dca0 | ||
|
|
ea0f0f09f4 | ||
|
|
3d5d4fcab2 | ||
|
|
0763a9b3b4 | ||
|
|
2d67a89fc2 | ||
|
|
4207d875f9 | ||
|
|
5da420c6c6 | ||
|
|
1ffa4842c3 | ||
|
|
819e194f27 | ||
|
|
269e55b93f | ||
|
|
04412f7138 | ||
|
|
0fce9d01e1 | ||
|
|
1c29301635 | ||
|
|
8bd7bbb5d7 | ||
|
|
1a99663b59 | ||
|
|
36e31279b2 | ||
|
|
4aa7eba675 | ||
|
|
3bbe2d26b8 | ||
|
|
782ad838be | ||
|
|
ceddb26137 | ||
|
|
ff044d75c7 | ||
|
|
8955df695d | ||
|
|
8ddcb208f5 | ||
|
|
95834df89f | ||
|
|
2f67f26cbe | ||
|
|
00957f9458 | ||
|
|
2e9e886c48 | ||
|
|
d2d4e48b73 | ||
|
|
fe16df27f2 | ||
|
|
cc29f70dff | ||
|
|
e136f7cfaf | ||
|
|
fd52f124fb | ||
|
|
5a656cee39 | ||
|
|
21a89f9b14 | ||
|
|
9ded4d2d57 | ||
|
|
fb64d92879 | ||
|
|
1a4bcae4d1 | ||
|
|
25ee4da4f4 | ||
|
|
35cb39c35e | ||
|
|
3a5f232f92 | ||
|
|
4ed201fba9 | ||
|
|
03835f71d9 | ||
|
|
480e50e71e | ||
|
|
39110b2898 | ||
|
|
e8db70e319 | ||
|
|
eb907988fb | ||
|
|
95935022b8 | ||
|
|
1e70cb0651 | ||
|
|
1594d062e5 | ||
|
|
04b266f558 | ||
|
|
9989fec809 | ||
|
|
ab8eabc348 | ||
|
|
931b8b5c36 | ||
|
|
64957ba13c | ||
|
|
a03be990ab | ||
|
|
44729495f5 | ||
|
|
9e7500f0cd | ||
|
|
d10ff8bdbc | ||
|
|
f91fc36365 | ||
|
|
84ddff07a2 | ||
|
|
4a89658cf4 | ||
|
|
5daef41031 | ||
|
|
07cc1e8160 | ||
|
|
8b2d763207 | ||
|
|
fb8c556e24 | ||
|
|
397fa12f12 | ||
|
|
d86ecf8d8b | ||
|
|
2882e9ecdf | ||
|
|
69a4a05069 | ||
|
|
361a340ef1 | ||
|
|
ee7c0451af | ||
|
|
200c7cbfea | ||
|
|
9a665ddf26 | ||
|
|
c4327ac238 | ||
|
|
9f4b798848 | ||
|
|
3cc18f4dc0 | ||
|
|
9637308045 | ||
|
|
772603e785 | ||
|
|
f9417ee2f7 | ||
|
|
2db85bff60 | ||
|
|
527b5aa25c | ||
|
|
5d9bb0dc4a | ||
|
|
cc51756f0d | ||
|
|
5ff66adb0c | ||
|
|
8e9cc98ded | ||
|
|
4387e78007 | ||
|
|
4fff1e24cc | ||
|
|
9791ed0cee | ||
|
|
e8e6f3a8fd | ||
|
|
5e6da9b24e | ||
|
|
59bd9239b2 | ||
|
|
08436a278c | ||
|
|
5d512e5e89 | ||
|
|
ec1a367691 | ||
|
|
457450683b | ||
|
|
a8d76d6b0f | ||
|
|
5036d62824 | ||
|
|
4f5f6e724f | ||
|
|
71f7532fe3 | ||
|
|
9ea37af603 | ||
|
|
1964a6b4e3 | ||
|
|
94a9ea31a0 | ||
|
|
2855d268da | ||
|
|
d6d576da20 | ||
|
|
34ed832d79 | ||
|
|
42ef8c0c39 | ||
|
|
1ce0c2db4e | ||
|
|
028aaa1cf7 | ||
|
|
66937916c4 | ||
|
|
82a053095e | ||
|
|
f24e62687d | ||
|
|
184cf8443c | ||
|
|
2b06bcc497 | ||
|
|
743f4cc5eb | ||
|
|
45ccb18133 | ||
|
|
3812e11702 | ||
|
|
c731cd3c87 | ||
|
|
466a24eea3 | ||
|
|
d747a0c19a | ||
|
|
59a64620bf | ||
|
|
f36b4b4078 | ||
|
|
9298b0270b | ||
|
|
d8dc50ceec | ||
|
|
60be698c61 | ||
|
|
0b37e92260 | ||
|
|
b7b1b63c4e | ||
|
|
98b923aa54 | ||
|
|
b24d7cb849 | ||
|
|
7df7157d5f | ||
|
|
47263746db | ||
|
|
ff06b06966 | ||
|
|
fe42d282d1 | ||
|
|
12df4e49c6 | ||
|
|
06812b2725 | ||
|
|
93e4ae7ca7 | ||
|
|
d57f3f20e3 | ||
|
|
f418fb961b | ||
|
|
267af92ceb | ||
|
|
57448ddaf6 | ||
|
|
9f40af4553 | ||
|
|
e25da2c6c5 | ||
|
|
897cccaa86 | ||
|
|
512efd0efe | ||
|
|
b67fa683c6 | ||
|
|
34387925b8 | ||
|
|
303dbc5ae9 | ||
|
|
ee565ff6f7 | ||
|
|
98baaab36a | ||
|
|
92e9d790a4 | ||
|
|
b8f2e2932b | ||
|
|
45f9202bdd | ||
|
|
ffeffc70c3 | ||
|
|
60080a5af6 | ||
|
|
1191265c8c | ||
|
|
27dfeea12c | ||
|
|
e50ec1632d | ||
|
|
a0d4dedc9d | ||
|
|
9eda026738 | ||
|
|
f3b81b7cb6 | ||
|
|
cf766ddd9a | ||
|
|
12cd2f5e6b | ||
|
|
04ef50ea91 | ||
|
|
d4c627fa79 | ||
|
|
deffc28ab6 | ||
|
|
833f8f5dbb | ||
|
|
5bdf2fa301 | ||
|
|
d13607873c | ||
|
|
a1f11dac03 | ||
|
|
74f1805441 | ||
|
|
21046d8eee | ||
|
|
0c37e3bb35 | ||
|
|
3f9ea7035f | ||
|
|
b55c56af12 | ||
|
|
498a948605 | ||
|
|
76a1890bba | ||
|
|
8899770518 | ||
|
|
a7d29d292f | ||
|
|
a9ca388f4e | ||
|
|
c42a88142c | ||
|
|
9fe78d3e6e | ||
|
|
816a58493a | ||
|
|
bc84cd2ec9 | ||
|
|
5f7fda250c | ||
|
|
03b58da260 | ||
|
|
238049b58c | ||
|
|
34a701cbe9 | ||
|
|
bdf42b3ef1 | ||
|
|
7b82fa17d0 | ||
|
|
05f1f285d0 | ||
|
|
12813a4a00 | ||
|
|
176b02ebe3 | ||
|
|
bd53bf7eb2 | ||
|
|
ae17d965e6 | ||
|
|
17b69fd38c | ||
|
|
ee9c6f77ec | ||
|
|
ddeb523154 | ||
|
|
04ec8e1927 | ||
|
|
f3f3cc7927 | ||
|
|
c7dd3f5344 | ||
|
|
19f534845f | ||
|
|
3c3110a3f8 | ||
|
|
2aa551090c | ||
|
|
57861e435c | ||
|
|
205e1e065d | ||
|
|
79ee776167 | ||
|
|
19869084e5 | ||
|
|
f1bd608fca | ||
|
|
2474e390f7 | ||
|
|
ef737d5566 | ||
|
|
9c64d3521e | ||
|
|
c7c8636720 | ||
|
|
cda72b3b3a | ||
|
|
04a1101045 | ||
|
|
44e3e51bbc | ||
|
|
40f2c44b5d | ||
|
|
16c26af04e | ||
|
|
85aa30f82c | ||
|
|
0ad119b6e0 | ||
|
|
a612e2216b | ||
|
|
2c0d3db9f4 | ||
|
|
8de820747a | ||
|
|
6469893b15 | ||
|
|
a46feb5e03 | ||
|
|
2e39683687 | ||
|
|
78464ac222 | ||
|
|
92b12fd612 | ||
|
|
5e90191aa4 | ||
|
|
1b4ee54b73 | ||
|
|
409c007759 | ||
|
|
49cd7410cf | ||
|
|
978b21360e | ||
|
|
0d1fbc15ce | ||
|
|
1cf3ba543d | ||
|
|
358830cbfb | ||
|
|
ea193d7bd3 | ||
|
|
8e59336833 | ||
|
|
5083f0a3d2 | ||
|
|
d20fdd3086 | ||
|
|
e005d80192 | ||
|
|
afd791b808 | ||
|
|
0acdcba09b | ||
|
|
872078ff05 | ||
|
|
4bfb1ec29b | ||
|
|
97f073685e | ||
|
|
08ab52d7f0 | ||
|
|
e7b7c78b11 | ||
|
|
7df02868ad | ||
|
|
063b5f90e9 | ||
|
|
dd700f99e2 | ||
|
|
7b9f418b23 | ||
|
|
fa163e0593 | ||
|
|
8ba86bec71 | ||
|
|
971f404f20 | ||
|
|
f378b1e10a | ||
|
|
13a281ebf7 | ||
|
|
e7f210739f | ||
|
|
addca59c39 | ||
|
|
f93880a0f5 | ||
|
|
489e8b60aa | ||
|
|
bf418d8a9a | ||
|
|
1e1f11cde9 | ||
|
|
34179eb850 | ||
|
|
cfcd488d44 | ||
|
|
a49b838b83 | ||
|
|
fdeec1e97c | ||
|
|
39ba75410e | ||
|
|
c20d6be447 | ||
|
|
d2f7f256d3 | ||
|
|
fb6abf7161 | ||
|
|
445bdac8a7 | ||
|
|
7bdabf93b8 | ||
|
|
8d9c0549b7 | ||
|
|
4d94a4879b | ||
|
|
924a72c537 | ||
|
|
75abdccd06 | ||
|
|
bb4b92e37e | ||
|
|
880616135f | ||
|
|
be72744651 | ||
|
|
c43090bdd8 | ||
|
|
50143c2374 | ||
|
|
951f1853fc | ||
|
|
a69962dd86 | ||
|
|
29e0bf8476 | ||
|
|
ee41a234e8 | ||
|
|
c8cf01319a | ||
|
|
3f4da7884f | ||
|
|
965df44783 | ||
|
|
b9b8f8b36d | ||
|
|
d293cdfb39 | ||
|
|
e3dc3ea548 | ||
|
|
3037d3a742 | ||
|
|
2230800deb | ||
|
|
1f0b8f783f | ||
|
|
da8d4e93ab | ||
|
|
aa38567232 | ||
|
|
b6757b9622 | ||
|
|
ca288fdf75 | ||
|
|
8b74c29bbe | ||
|
|
5aae4a17ef | ||
|
|
778212d48a | ||
|
|
8d126436ea | ||
|
|
ec40db1b26 | ||
|
|
263c197845 | ||
|
|
7bdc14aa30 | ||
|
|
7ba5209222 | ||
|
|
71e62e0bae | ||
|
|
4a8029ec31 | ||
|
|
382038b9a4 | ||
|
|
7f59851a3b | ||
|
|
0ebcc449f8 | ||
|
|
323614d8c5 | ||
|
|
264dedca34 | ||
|
|
ce26decb7d | ||
|
|
37085e82f0 | ||
|
|
041430e842 | ||
|
|
6762cbc245 | ||
|
|
917d3640f0 | ||
|
|
0cece71f37 | ||
|
|
d9c9f30cea | ||
|
|
dcb119df96 | ||
|
|
78ae7fbcb2 | ||
|
|
1545aad32d | ||
|
|
035d485561 | ||
|
|
f34a1ad2e4 | ||
|
|
5ceef81927 | ||
|
|
6315f74312 | ||
|
|
086a45593b | ||
|
|
1095166155 | ||
|
|
bf89a7cb12 | ||
|
|
729b671c5a | ||
|
|
380791cd45 | ||
|
|
ca80083414 | ||
|
|
ee7fa16514 | ||
|
|
c86a3d4101 | ||
|
|
6fd6a8fe38 | ||
|
|
b05b38e0e8 | ||
|
|
d55298d61b | ||
|
|
37ccf7176c | ||
|
|
868c93ac09 | ||
|
|
f927e836f5 | ||
|
|
2172628985 | ||
|
|
628b1763da | ||
|
|
bbe5fea132 | ||
|
|
8b555a8f53 |
No files matched your search
@@ -0,0 +1,43 @@
|
||||
name: "Deploy Wiki"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
tags-ignore:
|
||||
- "**"
|
||||
paths:
|
||||
- ".forgejo/workflows/deploy_wiki.yml"
|
||||
- "docs/**"
|
||||
- "domains"
|
||||
- "mkdocs.yml"
|
||||
- "requirements.txt"
|
||||
|
||||
jobs:
|
||||
deployWiki:
|
||||
runs-on: codeberg-tiny
|
||||
steps:
|
||||
- name: "Checkout Source Repository"
|
||||
uses: https://code.forgejo.org/actions/checkout@v4
|
||||
with:
|
||||
token: "${{ secrets.BOT_TOKEN }}"
|
||||
- name: "Checkout Target Repository"
|
||||
run: "git clone -b pages https://codeberg.org/Andre601/asl-docs site"
|
||||
- name: "Setup Python 3.x"
|
||||
uses: https://code.forgejo.org/actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.x
|
||||
- name: "Install Dependencies"
|
||||
run: "pip install -r requirements.txt"
|
||||
- name: "Build Website"
|
||||
run: "mkdocs build"
|
||||
- name: "Commit and Push"
|
||||
run: |
|
||||
git config --global user.email "andre_601-bot@noreply.codeberg.org"
|
||||
git config --global user.name "ASL Wiki Builder"
|
||||
mv domains site/.domains
|
||||
cd site
|
||||
git remote set-url origin https://${{ secrets.BOT_TOKEN }}@codeberg.org/Andre601/asl-docs
|
||||
git add --all
|
||||
git commit -m "Update Wiki ($( env TZ=Europe/Zurich date +"%d.%m.%Y %Z" ))"
|
||||
git push
|
||||
@@ -0,0 +1,116 @@
|
||||
name: Pull Request Preview
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
- synchronize
|
||||
paths:
|
||||
- ".forgejo/workflows/pr_preview.yml"
|
||||
- "docs/**"
|
||||
- "mkdocs.yml"
|
||||
- "preview_domains"
|
||||
- "requirements.txt"
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
BRANCH_NAME: "${{ github.event.repository.name }}/${{ github.event.pull_request.number }}"
|
||||
RUN_URL: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_number }}"
|
||||
|
||||
jobs:
|
||||
createPreview:
|
||||
runs-on: codeberg-tiny
|
||||
steps:
|
||||
#
|
||||
# Finding and updating comment in Pull request.
|
||||
# If not found, have one created instead.
|
||||
#
|
||||
- name: "Find Comment"
|
||||
id: find-comment
|
||||
uses: https://github.com/peter-evans/find-comment@v3
|
||||
with:
|
||||
issue-number: "${{ github.event.pull_request.number }}"
|
||||
comment-author: "Andre_601-Bot"
|
||||
- name: "Create or update Comment"
|
||||
id: comment
|
||||
uses: https://github.com/peter-evans/create-or-update-comment@v4
|
||||
with:
|
||||
body: |-
|
||||
## Pull request Preview
|
||||
|
||||
Creating Preview for Pull request. Please wait...
|
||||
comment-id: "${{ steps.find-comment.outputs.comment-id }}"
|
||||
issue-number: "${{ github.event.pull_request.number }}"
|
||||
token: "${{ secrets.BOT_TOKEN }}"
|
||||
edit-mode: replace
|
||||
#
|
||||
# Setup source and target repository.
|
||||
# Build website and push.
|
||||
#
|
||||
- name: "Checkout Source Repository"
|
||||
uses: https://code.forgejo.org/actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.BOT_TOKEN }}
|
||||
fetch-depth: 0
|
||||
ref: "${{ github.event.pull_request.head.sha }}"
|
||||
- name: "Checkout Target Repository"
|
||||
run: |
|
||||
git clone https://codeberg.org/Andre601/preview site
|
||||
cd site
|
||||
git switch ${{ env.BRANCH_NAME }} 2>/dev/null || git switch -c ${{ env.BRANCH_NAME }}
|
||||
- name: "Setup Python 3.x"
|
||||
uses: https://code.forgejo.org/actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.x
|
||||
- name: "Install Dependencies"
|
||||
run: "pip install -r requirements.txt"
|
||||
- name: "Build Website"
|
||||
run: "mkdocs build"
|
||||
- name: "Commit and Push"
|
||||
run: |
|
||||
git config --global user.email "andre_601-bot@noreply.codeberg.org"
|
||||
git config --global user.name "PR Docs Preview Builder"
|
||||
mv preview_domains site/.domains
|
||||
cd site
|
||||
git remote add upstream https://${{ secrets.BOT_TOKEN }}@codeberg.org/Andre601/preview.git
|
||||
git add --all
|
||||
git commit -m "Update Preview for ${{ env.BRANCH_NAME }} ($( env TZ=Europe/Zurich date +"%d.%m.%Y %Z" ))"
|
||||
git push --set-upstream upstream ${{ env.BRANCH_NAME }} -f
|
||||
#
|
||||
# Update comment on success or failure.
|
||||
#
|
||||
- name: "Comment Success"
|
||||
uses: https://github.com/peter-evans/create-or-update-comment@v4
|
||||
with:
|
||||
body: |-
|
||||
## Pull request Preview
|
||||
|
||||
Pull request Preview created successfully!
|
||||
|
||||
| Name | Link |
|
||||
|---------|----------------------------------------------------------------------------------------------------------|
|
||||
| Commit | ${{ github.event.pull_request.head.sha }} |
|
||||
| Preview | https://preview.andre601.ch/@${{ github.event.repository.name }}~${{ github.event.pull_request.number }} |
|
||||
| Logs | ${{ env.RUN_URL }} |
|
||||
comment-id: "${{ steps.comment.outputs.comment-id }}"
|
||||
issue-number: "${{ github.event.pull_request.number }}"
|
||||
token: "${{ secrets.BOT_TOKEN }}"
|
||||
edit-mode: replace
|
||||
- name: "Comment Failure"
|
||||
if: ${{ failure() }}
|
||||
uses: https://github.com/peter-evans/create-or-update-comment@v4
|
||||
with:
|
||||
body: |-
|
||||
## Pull request Preview
|
||||
|
||||
Pull request Preview failed! Check the logs for details.
|
||||
|
||||
| Name | Link |
|
||||
|---------|-------------------------------------------|
|
||||
| Commit | ${{ github.event.pull_request.head.sha }} |
|
||||
| Logs | ${{ RUN_URL }} |
|
||||
comment-id: "${{ steps.comment.outputs.comment-id }}"
|
||||
issue-number: "${{ github.event.pull_request.number }}"
|
||||
token: "${{ secrets.BOT_TOKEN }}"
|
||||
edit-mode: replace
|
||||
@@ -0,0 +1,11 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: API Support
|
||||
about: For API support, please create an issue in the `asl-api` repository.
|
||||
url: https://codeberg.org/Andre601/asl-api
|
||||
- name: Discord Server
|
||||
about: Please ask questions in the `#asl-support` channel on the M.O.S.S. Discord Server.
|
||||
url: https://discord.gg/MyPTjpsgGH
|
||||
- name: Wiki
|
||||
about: Check the Wiki for explanations about the features and examples.
|
||||
url: https://asl.andre601.ch
|
||||
@@ -0,0 +1,103 @@
|
||||
<center><strong><u><font size="6">AdvancedServerList</font ></u></strong></center>
|
||||
|
||||
AdvancedServerList is a plugin designed to allow the largest possible customization for your server's appearance in a Player's multiplayer screen.
|
||||
The plugin offers extensive customization including changing the MOTD, player count text, player count hover and favicon of your server. All while also allowing you to create multiple profiles with priorities and conditions to set when a specific profile should be displayed.
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
<a href="https://papermc.io" target="_blank">
|
||||
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/supported/paper_vector.svg&h=48" alt="platform-paper" title="Tested on Paper">
|
||||
</a>
|
||||
<br>
|
||||
<a href="https://www.spigotmc.org" target="_blank">
|
||||
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/supported/bungeecord_vector.svg&h=48" alt="platform-bungeecord" title="Tested on BungeeCord">
|
||||
</a>
|
||||
<br>
|
||||
<a href="https://www.papermc.io" target="_blank">
|
||||
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/supported/waterfall_vector.svg&h=48" alt="platform-waterfall" title="Tested on Waterfall">
|
||||
</a>
|
||||
<br>
|
||||
<a href="https://velocitypowered.com" target="_blank">
|
||||
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/supported/velocity_vector.svg&h=48" alt="platform-velocity" title="Tested on Velocity">
|
||||
</a>
|
||||
|
||||
## Server List Profiles
|
||||
|
||||
A Server List Profile is a single YAML file located in the plugin's `profiles` folder. It contains settings that allow you to modify the server's appearance within a Player's multiplayer screen.
|
||||
|
||||
### Priority and Conditions
|
||||
|
||||
Each file has a priority and optional condition. The priority is used to determine what file AdvancedServerList should use first - starting from highest number to lowest - with conditions being used to set when the profile should be used.
|
||||
Once a profile has been found with a condition returning true - which is the default should there be no condition - will AdvancedServerList use said profile.
|
||||
|
||||
> *Read more about [Priority](https://asl.andre601.ch/profiles/#priority) and [Conditions](https://asl.andre601.ch/profiles/#condition)*
|
||||
|
||||
### Placeholders
|
||||
|
||||
AdvancedServerList supports two sets of placeholders. The first one being its own placeholders using the `${<type> <values>}` format adobted from BungeeTabListPlus and the second one being placeholders from PlaceholderAPI using its `%<identifier>_<values>%` placeholder format.
|
||||
|
||||
Note that internal placeholders can be used in all text-based options of a profile, while PlaceholderAPI placeholders can be used in all text-based options except the `condition` one.
|
||||
As a final note can plugins provide their own placeholders to use within AdvancedServerList by using its API.
|
||||
|
||||
> *Read more about [Placeholders](https://asl.andre601.ch/profiles/placeholders/)*
|
||||
|
||||
### Formatting
|
||||
|
||||
AdvancedServerList utilizes the MiniMessage formatting to handle colors and formatting of text. This option was chosen over legacy formatting - using `&` character - for being more clear and readable in its design, not to mention having an easier way for more complex features such as RGB gradients.
|
||||
|
||||
> *Read more about [Formatting](https://asl.andre601.ch/profiles/formatting/)*
|
||||
|
||||
## Dependencies
|
||||
|
||||
AdvancedServerList soft-depends on the following plugins, meaning their inclusion is not required.
|
||||
|
||||
| Plugin | Supported Platforms |
|
||||
|-------------------------------------------------------------------------|----------------------------------------|
|
||||
| [PlaceholderAPI](https://hangar.papermc.io/HelpChat/PlaceholderAPI) | Paper |
|
||||
| [ViaVersion](https://hangar.papermc.io/ViaVersion/ViaVersion) | Paper |
|
||||
| [PAPIProxyBridge](https://hangar.papermc.io/William278/PAPIProxyBridge) | BungeeCord, Waterfall, Velocity |
|
||||
| [Maintenance](https://hangar.papermc.io/kennytv/Maintenance) | Paper, BungeeCord, Waterfall, Velocity |
|
||||
|
||||
## Statistics
|
||||
|
||||
The plugin sends statistics to [bStats](https://bstats.org) to show.
|
||||
You can disable the sending of statistics in the global bStats config located inside `/plugins/bstats/`.
|
||||
|
||||
You can find the bStats pages of the plugin for the following platforms:
|
||||
|
||||
- [Paper](https://bstats.org/plugin/bungeecord/AdvancedServerList/15584)
|
||||
- [BungeeCord, Waterfall](https://bstats.org/plugin/bungeecord/AdvancedServerList/15585)
|
||||
- [Velocity](https://bstats.org/plugin/velocity/AdvancedServerList/15587)
|
||||
|
||||
## Videos
|
||||
|
||||
Below can you find a collection of videos made for my plugin. If you made a video and it isn't shown here, let me know and I'll add it.
|
||||
|
||||
<details><summary>Click to show/hide Videos</summary>
|
||||
<p>
|
||||
|
||||
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>
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
## Screenshots
|
||||
|
||||
<a href="https://modrinth.com/plugin/advancedserverlist/gallery" target="_blank">
|
||||
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/documentation/modrinth-gallery_vector.svg&h=48" alt="gallery" title="Check out the Gallery">
|
||||
</a>
|
||||
|
||||
## Support
|
||||
|
||||
<a href="https://discord.gg/MyPTjpsgGH" target="_blank">
|
||||
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/social/discord-singular_vector.svg&h=48" alt="discord" title="Join the M.O.S.S. Discord Server">
|
||||
</a>
|
||||
<br>
|
||||
<a href="https://app.revolt.chat/invite/74TpERXA" target="_blank">
|
||||
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/social/revolt-singular_vector.svg&h=48" alt="revolt" title="Join my Revolt Server">
|
||||
</a>
|
||||
<br>
|
||||
<a href="https://swiss.social/@andre_601" target="_blank">
|
||||
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/social/mastodon-singular_vector.svg&h=48" alt="revolt" title="Chat with me on Mastodon">
|
||||
</a>
|
||||
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 71 KiB |
|
After Width: | Height: | Size: 876 KiB |
|
Before Width: | Height: | Size: 156 KiB After Width: | Height: | Size: 156 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 877 KiB |
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
@@ -0,0 +1,37 @@
|
||||
name: Pull Request
|
||||
description: Create a new Pull request
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |-
|
||||
Thank you for creating a Pull request!
|
||||
|
||||
Please be sure to fill out this template with all requested information to ensure it being valid and not being closed unmerged.
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Type
|
||||
description: What kind of Pull request is this?
|
||||
options:
|
||||
- Enhancement
|
||||
- Bugfix
|
||||
- Documentation
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Breaking Change?
|
||||
description: |-
|
||||
Is this a breaking change?
|
||||
A breaking change means that it becomes incompatible with previous server/proxy versions or plugin versions.
|
||||
options:
|
||||
- Yes
|
||||
- No
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Description
|
||||
description: Provide a detailed description of what this Pull request is doing. Link any issues this Pull request may fix/close.
|
||||
validations:
|
||||
required: true
|
||||
@@ -1,2 +0,0 @@
|
||||
patreon: andre_601
|
||||
ko_fi: andre_601
|
||||
@@ -1,41 +0,0 @@
|
||||
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
|
||||
@@ -1,8 +0,0 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Discord Server
|
||||
about: Ask questions about the plugin in the `#advancedserverlist` channel.
|
||||
url: https://discord.gg/6dazXp6
|
||||
- name: Wiki
|
||||
about: Check the Wiki for explanations about the features and examples.
|
||||
url: https://docs.andre601.ch/AdvancedServerList
|
||||
@@ -1,108 +0,0 @@
|
||||
# AdvancedServerList
|
||||
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.
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
<a href="https://www.spigotmc.org" target="_blank">
|
||||
<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://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://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://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://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?
|
||||
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.
|
||||
|
||||
> [*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.
|
||||
|
||||
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
|
||||
|
||||
This plugin sends statistics to [bStats] to display.
|
||||
You can disable this in the global bStats config file located in `/plugins/bstats/`
|
||||
|
||||
- [BungeeCord][bstats-bungee]
|
||||
- [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://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://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://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://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://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
|
||||
[bstats-spigot]: https://bstats.org/plugin/bukkit/AdvancedServerList/15584
|
||||
[bstats-velocity]: https://bstats.org/plugin/velocity/AdvancedServerList/15587
|
||||
|
||||
[gallery]: https://modrinth.com/mod/advancedserverlist/gallery
|
||||
@@ -1,14 +0,0 @@
|
||||
"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/**"]
|
||||
@@ -1,49 +0,0 @@
|
||||
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,52 +0,0 @@
|
||||
when:
|
||||
- event: pull_request
|
||||
path:
|
||||
include: ['.woodpecker/pr_preview.yml', 'requirements.txt', 'mkdocs.yml', 'docs/**']
|
||||
|
||||
variables:
|
||||
setup_git: &setup_git
|
||||
- apk add git
|
||||
- git config --global user.email "andre@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 https://codeberg.org/Andre601/asl-docs.git site
|
||||
- chmod -R a+w site
|
||||
- cd site
|
||||
- git switch pr-${CI_COMMIT_PULL_REQUEST} 2>/dev/null || git switch -c pr-${CI_COMMIT_PULL_REQUEST}
|
||||
buildDocs:
|
||||
image: woodpeckerci/plugin-mkdocs:latest
|
||||
settings:
|
||||
pip_install_file: requirements.txt
|
||||
commitAndPush:
|
||||
image: alpine:3.18.4
|
||||
secrets:
|
||||
- bot_token
|
||||
commands:
|
||||
- <<: *setup_git
|
||||
- mv domains site/.domains
|
||||
- cd site
|
||||
- git remote add upstream https://$BOT_TOKEN@codeberg.org/Andre601/asl-docs.git
|
||||
- git add --all
|
||||
- git commit -m "Update Preview for PR ${CI_COMMIT_PULL_REQUEST} ($( env TZ=Europe/Zurich date +"%d.%m.%Y %Z" )) [SKIP CI]"
|
||||
- git push --set-upstream upstream pr-${CI_COMMIT_PULL_REQUEST} -f
|
||||
writeComment:
|
||||
image: mcs94/gitea-comment
|
||||
secrets:
|
||||
- bot_token
|
||||
settings:
|
||||
gitea_address: https://codeberg.org
|
||||
gitea_token:
|
||||
from_secret: BOT_TOKEN
|
||||
comment: |-
|
||||
Build-preview created!
|
||||
|
||||
| Name | Value |
|
||||
|--------|-------------------------------------------------------|
|
||||
| Commit | ${CI_COMMIT_SHA} |
|
||||
| Link | https://asl.andre601.ch/@pr-${CI_COMMIT_PULL_REQUEST} |
|
||||
@@ -0,0 +1,64 @@
|
||||
when:
|
||||
- event: pull_request
|
||||
path:
|
||||
include: [".woodpecker/pr_preview.yml", "docs/**", "mkdocs.yml", "requirements.txt"]
|
||||
|
||||
variables:
|
||||
setup_git: &setup_git
|
||||
- apk add git
|
||||
- git config --global user.email "andre_601-bot@noreply.codeberg.org"
|
||||
- git config --global user.name "PR Docs Preview Builder"
|
||||
|
||||
steps:
|
||||
- name: "Clone Preview Repository"
|
||||
image: alpine:3.20.3
|
||||
commands:
|
||||
- chmod -R a+w .
|
||||
- <<: *setup_git
|
||||
- git clone https://codeberg.org/Andre601/preview.git site
|
||||
- chmod -R a+w site
|
||||
- cd site
|
||||
- git switch ${CI_REPO_NAME,,}/${CI_COMMIT_PULL_REQUEST} 2>/dev/null || git switch -c ${CI_REPO_NAME,,}/${CI_COMMIT_PULL_REQUEST}
|
||||
- name: "Build Docs"
|
||||
image: woodpeckerci/plugin-mkdocs:latest
|
||||
settings:
|
||||
pip_install_file: requirements.txt
|
||||
- name: "Commit and Push"
|
||||
image: alpine:3.20.3
|
||||
secrets:
|
||||
- bot_token
|
||||
commands:
|
||||
- <<: *setup_git
|
||||
- mv preview-domains site/.domains
|
||||
- cd site
|
||||
- git remote add upstream https://$BOT_TOKEN@codeberg.org/Andre601/preview.git
|
||||
- git add --all
|
||||
- git commit -m "Update Preview for ${CI_REPO_NAME}/${CI_COMMIT_PULL_REQUEST} ($( env TZ=Europe/Zurich date +"%d.%m.%Y %Z" )) [SKIP CI]"
|
||||
- git push --set-upstream upstream ${CI_REPO_NAME,,}/${CI_COMMIT_PULL_REQUEST} -f
|
||||
- name: "Comment on Success"
|
||||
image: mcs94/gitea-comment
|
||||
when:
|
||||
- status: ["success"]
|
||||
settings:
|
||||
gitea_address: https://codeberg.org
|
||||
gitea_token:
|
||||
from_secret: BOT_TOKEN
|
||||
comment: |-
|
||||
Pull request Preview Ready!
|
||||
|
||||
| Name | Value |
|
||||
|--------|--------------------------------------------------------------------------|
|
||||
| Commit | ${CI_COMMIT_SHA} |
|
||||
| Link | https://preview.andre601.ch/@${CI_REPO_NAME,,}~${CI_COMMIT_PULL_REQUEST} |
|
||||
- name: "Comment on Failure"
|
||||
image: mcs94/gitea-comment
|
||||
when:
|
||||
- status: ["failure"]
|
||||
settings:
|
||||
gitea_address: https://codeberg.org
|
||||
gitea_token:
|
||||
from_secret: BOT_TOKEN
|
||||
comment: |-
|
||||
Pull request Preview **failed**!
|
||||
|
||||
Please check the CI logs for details: ${CI_PIPELINE_URL}
|
||||
@@ -1,29 +1,26 @@
|
||||
when:
|
||||
- event: tag
|
||||
branch: master
|
||||
branch: ${CI_REPO_DEFAULT_BRANCH}
|
||||
|
||||
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
|
||||
- name: "Build Jar and Upload"
|
||||
image: maven:3.9.9-eclipse-temurin-21
|
||||
environment:
|
||||
CODEBERG_API_TOKEN:
|
||||
from_secret: cb_token
|
||||
MODRINTH_API_TOKEN:
|
||||
from_secret: modrinth_api_token
|
||||
HANGAR_API_TOKEN:
|
||||
from_secret: hangar_api_token
|
||||
DISCORD_WEBHOOK_URL:
|
||||
from_secret: discord_webhook_url
|
||||
commands:
|
||||
# Create the jar files.
|
||||
- mvn clean install
|
||||
# Move VersionUploader jar file
|
||||
- cd version-uploader/target/
|
||||
- cd version-uploader/target
|
||||
- mv VersionUploader.jar ../../
|
||||
- cd ../../
|
||||
# Execute Jar file
|
||||
- java -jar VersionUploader.jar --all
|
||||
uploadToCodeberg:
|
||||
- name: "Upload Jars to Codeberg"
|
||||
image: woodpeckerci/plugin-gitea-release
|
||||
settings:
|
||||
base_url: https://codeberg.org
|
||||
@@ -33,14 +30,19 @@ steps:
|
||||
- "velocity/target/AdvancedServerList-*.jar"
|
||||
- "addons/banplugins/target/AdvancedServerList-*.jar"
|
||||
api_key:
|
||||
from_secret: CB_TOKEN
|
||||
postOnMastodon:
|
||||
from_secret: cb_token
|
||||
- name: "Create Post on Mastodon"
|
||||
image: woodpeckerci/plugin-mastodon-post
|
||||
when:
|
||||
- status: ['success']
|
||||
- status: ["success"]
|
||||
settings:
|
||||
server: https://blobfox.coffee
|
||||
server_url: https://swiss.social
|
||||
access_token:
|
||||
from_secret: MASTODON_TOKEN
|
||||
status: '${CI_COMMIT_TAG} of #AdvancedServerList has been released and can be found on Modrinth (https://modrinth.com/plugin/AdvancedServerList), Hangar (https://hangar.papermc.io/Andre_601/AdvancedServerList) and Codeberg (https://codeberg.org/Andre601/AdvancedServerList).'
|
||||
from_secret: mastodon_token
|
||||
status: |-
|
||||
#AdvancedServerList was updated to ${CI_COMMIT_TAG} and can be downloaded from #Modrinth, #Hangar and #Codeberg!
|
||||
|
||||
Modrinth - https://modrinth.com/plugin/advancedserverlist
|
||||
Hangar - https://hangar.papermc.io/Andre_601/AdvancedServerList
|
||||
Codeberg - https://codeberg.org/Andre601/AdvancedServerList
|
||||
visibility: public
|
||||
@@ -1,29 +1,29 @@
|
||||
when:
|
||||
- branch: '${CI_REPO_DEFAULT_BRANCH}'
|
||||
event: push
|
||||
- event: push
|
||||
branch: ${CI_REPO_DEFAULT_BRANCH}
|
||||
path:
|
||||
include: ['.woodpecker/publish_docs.yml', 'requirements.txt', 'mkdocs.yml', 'docs/**']
|
||||
include: [".woodpecker/publish_docs.yml", "docs/**", "mkdocs.yml", "requirements.txt"]
|
||||
|
||||
variables:
|
||||
setup_git: &setup_git
|
||||
- apk add git
|
||||
- git config --global user.email "github@andre601.ch"
|
||||
- git config --global user.email "andre_601-bot@noreply.codeberg.org"
|
||||
- git config --global user.name "ASL Docs Builder"
|
||||
|
||||
steps:
|
||||
cloneTargetRepo:
|
||||
image: alpine:3.18.4
|
||||
- name: "Clone target Repository"
|
||||
image: alpine:3.20.3
|
||||
commands:
|
||||
- chmod -R a+w .
|
||||
- <<: *setup_git
|
||||
- git clone -b pages https://codeberg.org/Andre601/asl-docs site
|
||||
- git clone -b pages https://codeberg.org/Andre601/asl-docs.git site
|
||||
- chmod -R a+w site
|
||||
buildDocs:
|
||||
- name: "Build Docs"
|
||||
image: woodpeckerci/plugin-mkdocs:latest
|
||||
settings:
|
||||
pip_install_file: requirements.txt
|
||||
commitAndPush:
|
||||
image: alpine:3.18.4
|
||||
- name: "Commit and Push"
|
||||
image: alpine:3.20.3
|
||||
secrets:
|
||||
- bot_token
|
||||
commands:
|
||||
@@ -1,121 +1,116 @@
|
||||
# AdvancedServerList
|
||||
|
||||
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.
|
||||
AdvancedServerList is a plugin designed to allow the largest possible customization for your server's appearance in a Player's multiplayer screen.
|
||||
The plugin offers extensive customization including changing the MOTD, player count text, player count hover and favicon of your server. All while also allowing you to create multiple profiles with priorities and conditions to set when a specific profile should be displayed.
|
||||
|
||||
## 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">
|
||||
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact/available/modrinth_vector.svg" height="48" 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">
|
||||
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact/available/hangar_vector.svg" height="48" alt="hangar" title="Available on Hangar">
|
||||
</a>
|
||||
-->
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
<a href="https://papermc.io" target="_blank">
|
||||
<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">
|
||||
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/supported/paper_vector.svg" height="48" alt="platform-paper" title="Tested on Paper">
|
||||
</a>
|
||||
<br>
|
||||
<a href="https://www.spigotmc.org" target="_blank">
|
||||
<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">
|
||||
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/supported/bungeecord_vector.svg" height="48" alt="platform-bungeecord" title="Tested on BungeeCord">
|
||||
</a>
|
||||
<br>
|
||||
<a href="https://www.papermc.io" target="_blank">
|
||||
<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">
|
||||
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/supported/waterfall_vector.svg" height="48" alt="platform-waterfall" title="Tested on Waterfall">
|
||||
</a>
|
||||
<br>
|
||||
<a href="https://velocitypowered.com" target="_blank">
|
||||
<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">
|
||||
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/supported/velocity_vector.svg" height="48" alt="platform-velocity" title="Tested on Velocity">
|
||||
</a>
|
||||
|
||||
## What is a Server List Profile?
|
||||
## Server List Profiles
|
||||
|
||||
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.
|
||||
A Server List Profile is a single YAML file located in the plugin's `profiles` folder. It contains settings that allow you to modify the server's appearance within a Player's multiplayer screen.
|
||||
|
||||
> [*Read More*][profiles]
|
||||
### Priority and Conditions
|
||||
|
||||
### Conditions
|
||||
Each file has a priority and optional condition. The priority is used to determine what file AdvancedServerList should use first - starting from highest number to lowest - with conditions being used to set when the profile should be used.
|
||||
Once a profile has been found with a condition returning true - which is the default should there be no condition - will AdvancedServerList use said profile.
|
||||
|
||||
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]
|
||||
> *Read more about [Priority](https://asl.andre601.ch/profiles/#priority) and [Conditions](https://asl.andre601.ch/profiles/#condition)*
|
||||
|
||||
### Placeholders
|
||||
|
||||
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.
|
||||
AdvancedServerList supports two sets of placeholders. The first one being its own placeholders using the `${<type> <values>}` format adobted from BungeeTabListPlus and the second one being placeholders from PlaceholderAPI using its `%<identifier>_<values>%` placeholder format.
|
||||
|
||||
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.
|
||||
Note that internal placeholders can be used in all text-based options of a profile, while PlaceholderAPI placeholders can be used in all text-based options except the `condition` one.
|
||||
As a final note can plugins provide their own placeholders to use within AdvancedServerList by using its API.
|
||||
|
||||
If you're a plugin dev can you even add your own custom placeholders through AdvancedServerList's own API.
|
||||
|
||||
> [*Read More*][placeholders]
|
||||
> *Read more about [Placeholders](https://asl.andre601.ch/profiles/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.
|
||||
AdvancedServerList utilizes the MiniMessage formatting to handle colors and formatting of text. This option was chosen over legacy formatting - using `&` character - for being more clear and readable in its design, not to mention having an easier way for more complex features such as RGB gradients.
|
||||
|
||||
> [*Read More*][minimessage]
|
||||
> *Read more about [Formatting](https://asl.andre601.ch/profiles/formatting/)*
|
||||
|
||||
## Dependencies
|
||||
|
||||
All listed dependencies are optional.
|
||||
AdvancedServerList soft-depends on the following plugins, meaning their inclusion is not required.
|
||||
|
||||
| Dependency | Platforms |
|
||||
|-------------------|----------------------|
|
||||
| [PlaceholderAPI] | Paper |
|
||||
| [ViaVersion] | Paper |
|
||||
| [PAPIProxyBridge] | BungeeCord, Velocity |
|
||||
| [Maintenance] | All |
|
||||
| Plugin | Supported Platforms |
|
||||
|-------------------------------------------------------------------------|----------------------------------------|
|
||||
| [PlaceholderAPI](https://hangar.papermc.io/HelpChat/PlaceholderAPI) | Paper |
|
||||
| [ViaVersion](https://hangar.papermc.io/ViaVersion/ViaVersion) | Paper |
|
||||
| [PAPIProxyBridge](https://hangar.papermc.io/William278/PAPIProxyBridge) | BungeeCord, Waterfall, Velocity |
|
||||
| [Maintenance](https://hangar.papermc.io/kennytv/Maintenance) | Paper, BungeeCord, Waterfall, Velocity |
|
||||
|
||||
## Statistics
|
||||
|
||||
This plugin sends statistics to [bStats] to display.
|
||||
You can disable this in the global bStats config file located in `/plugins/bstats/`
|
||||
The plugin sends statistics to [bStats](https://bstats.org) to show.
|
||||
You can disable the sending of statistics in the global bStats config located inside `/plugins/bstats/`.
|
||||
|
||||
- [BungeeCord][bstats-bungee]
|
||||
- [Paper/Spigot][bstats-spigot]
|
||||
- [Velocity][bstats-velocity]
|
||||
You can find the bStats pages of the plugin for the following platforms:
|
||||
|
||||
- [Paper](https://bstats.org/plugin/bungeecord/AdvancedServerList/15584)
|
||||
- [BungeeCord, Waterfall](https://bstats.org/plugin/bungeecord/AdvancedServerList/15585)
|
||||
- [Velocity](https://bstats.org/plugin/velocity/AdvancedServerList/15587)
|
||||
|
||||
## Videos
|
||||
|
||||
Below can you find a collection of videos made for my plugin. If you made a video and it isn't shown here, let me know and I'll add it.
|
||||
|
||||
<details><summary>Click to show/hide Videos</summary>
|
||||
<p>
|
||||
|
||||
English Video by KasaiSora
|
||||
[](https://youtube.com/watch?v=9cU0uUWHOO0)
|
||||
|
||||
Spanish Video by Ajneb97
|
||||
[](https://youtube.com/watch?v=rIbljm_4HVI)
|
||||
|
||||
</p>
|
||||
</details>
|
||||
|
||||
## Screenshots
|
||||
|
||||
<a href="https://modrinth.com/plugin/advancedserverlist/gallery" target="_blank">
|
||||
<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">
|
||||
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/documentation/modrinth-gallery_vector.svg" height="48" alt="gallery" title="Check out the Gallery">
|
||||
</a>
|
||||
|
||||
## Support
|
||||
|
||||
<a href="https://discord.gg/6dazXp6" target="_blank">
|
||||
<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 href="https://discord.gg/MyPTjpsgGH" target="_blank">
|
||||
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/social/discord-singular_vector.svg" height="48" alt="discord" title="Join the M.O.S.S. Discord Server">
|
||||
</a>
|
||||
<br>
|
||||
<a href="https://app.revolt.chat/invite/74TpERXA" target="_blank">
|
||||
<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">
|
||||
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/social/revolt-singular_vector.svg" height="48" alt="revolt" title="Join my Revolt Server">
|
||||
</a>
|
||||
<a href="https://blobfox.coffee/@andre_601" target="_blank">
|
||||
<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://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
|
||||
|
||||
[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
|
||||
[bstats-spigot]: https://bstats.org/plugin/bukkit/AdvancedServerList/15584
|
||||
[bstats-velocity]: https://bstats.org/plugin/velocity/AdvancedServerList/15587
|
||||
|
||||
[gallery]: https://modrinth.com/mod/advancedserverlist/gallery
|
||||
<br>
|
||||
<a href="https://swiss.social/@andre_601" target="_blank">
|
||||
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/social/mastodon-singular_vector.svg" height="48" alt="revolt" title="Chat with me on Mastodon">
|
||||
</a>
|
||||
@@ -0,0 +1,60 @@
|
||||
# Supported Versions
|
||||
|
||||
To ensure proper safety and support are only certain versions and Platforms of AdvancedServerList maintained and supported.
|
||||
|
||||
## Supported Plugin Versions
|
||||
|
||||
| Major Version | Supported |
|
||||
|---------------|-----------|
|
||||
| v5 | Yes |
|
||||
| v4 | Yes* |
|
||||
| v3 | No** |
|
||||
| v2 | No |
|
||||
| v1 | No |
|
||||
|
||||
\*Only receives support but no updates or bug fixes.
|
||||
\*\*Support ended on December 31st, 2024.
|
||||
|
||||
## Supported Server/Proxy Versions
|
||||
|
||||
| Server/Proxy Version* | Supported |
|
||||
|-----------------------|-----------|
|
||||
| 1.21.x | Yes |
|
||||
| 1.20.x | Yes |
|
||||
| 1.19.x | No |
|
||||
| 1.18.x | No |
|
||||
| 1.17.x | No |
|
||||
| 1.16.x | No |
|
||||
| 1.15.x | No |
|
||||
| 1.14.x | No |
|
||||
| 1.13.x | No |
|
||||
| 1.12.x | No |
|
||||
| 1.11.x | No |
|
||||
| 1.10.x | No |
|
||||
| 1.19.x | No |
|
||||
| 1.8.x | No |
|
||||
|
||||
\*Only the latest patch version is actively supported should "Supported" have "Yes".
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
### Servers
|
||||
|
||||
| Server | Supported |
|
||||
|--------|-----------|
|
||||
| Spigot | No |
|
||||
| Paper | Yes |
|
||||
| Purpur | Yes* |
|
||||
| Mohist | No |
|
||||
|
||||
\*Support hasn't actively been tested, but should work without issues.
|
||||
|
||||
### Proxies
|
||||
|
||||
| Proxy | Supported |
|
||||
|------------|-----------|
|
||||
| BungeeCord | Yes** |
|
||||
| Waterfall | Yes** |
|
||||
| Velocity | Yes |
|
||||
|
||||
\*\*Platform version of this plugin is maintenance only, not receiving any bug fixes for major breaking changes anymore.
|
||||
@@ -40,8 +40,8 @@
|
||||
<version>${plugin.version}</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>16</maven.compiler.source>
|
||||
<maven.compiler.target>16</maven.compiler.target>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
</repository>
|
||||
<repository>
|
||||
<id>papermc</id>
|
||||
<url>https://papermc.io/repo/repository/maven-public/</url>
|
||||
<url>https://repo.papermc.io/repository/maven-public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>libertybans</id>
|
||||
@@ -79,7 +79,7 @@
|
||||
<dependency>
|
||||
<groupId>io.papermc.paper</groupId>
|
||||
<artifactId>paper-api</artifactId>
|
||||
<version>1.20-R0.1-SNAPSHOT</version>
|
||||
<version>1.21-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -99,7 +99,13 @@
|
||||
<dependency>
|
||||
<groupId>space.arim.libertybans</groupId>
|
||||
<artifactId>bans-api</artifactId>
|
||||
<version>1.1.0-RC1</version>
|
||||
<version>1.1.0-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.gitlab.ruany</groupId>
|
||||
<artifactId>LiteBansAPI</artifactId>
|
||||
<version>0.5.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -111,19 +117,12 @@
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>AdvancedServerList-BanPlugins-Addon-${plugin.version}</finalName>
|
||||
<finalName>AdvancedServerList-BanPlugins-Addon-${plugin.version}${project.build.build_id}</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.13.0</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -23,35 +23,48 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.banplugins.bungeecord;
|
||||
package ch.andre601.advancedserverlist.banplugins;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.banplugins.placeholders.AdvancedBanPlaceholders;
|
||||
import ch.andre601.advancedserverlist.banplugins.placeholders.LibertyBansPlaceholders;
|
||||
import ch.andre601.advancedserverlist.banplugins.placeholders.LiteBansPlaceholders;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public enum BungeeCordBanPlugins{
|
||||
public enum BanPluginsList{
|
||||
|
||||
ADVANCED_BAN("AdvancedBan", new AdvancedBanPlaceholders()),
|
||||
LIBERTY_BANS("LibertyBans", new LibertyBansPlaceholders());
|
||||
ADVANCED_BAN("AdvancedBan", new AdvancedBanPlaceholders(), true, true, false),
|
||||
LIBERTY_BANS("LibertyBans", new LibertyBansPlaceholders(), true, true, true),
|
||||
LITE_BANS("LiteBans", new LiteBansPlaceholders(), true, true, true);
|
||||
|
||||
private final String plugin;
|
||||
private final String name;
|
||||
private final PlaceholderProvider placeholderProvider;
|
||||
private final boolean paper, bungeecord, velocity;
|
||||
|
||||
BungeeCordBanPlugins(String plugin, PlaceholderProvider placeholderProvider){
|
||||
this.plugin = plugin;
|
||||
BanPluginsList(String name, PlaceholderProvider placeholderProvider, boolean paper, boolean bungeecord, boolean velocity){
|
||||
this.name = name;
|
||||
this.placeholderProvider = placeholderProvider;
|
||||
this.paper = paper;
|
||||
this.bungeecord = bungeecord;
|
||||
this.velocity = velocity;
|
||||
}
|
||||
|
||||
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;
|
||||
public String getName(){
|
||||
return name;
|
||||
}
|
||||
|
||||
public PlaceholderProvider getPlaceholderProvider(){
|
||||
return placeholderProvider;
|
||||
}
|
||||
|
||||
public boolean supportsPaper(){
|
||||
return paper;
|
||||
}
|
||||
|
||||
public boolean supportsBungeeCord(){
|
||||
return bungeecord;
|
||||
}
|
||||
|
||||
public boolean supportsVelocity(){
|
||||
return velocity;
|
||||
}
|
||||
}
|
||||
@@ -26,11 +26,9 @@
|
||||
package ch.andre601.advancedserverlist.banplugins.bungeecord;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.AdvancedServerListAPI;
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.banplugins.BanPluginsList;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class BungeeCordBanPluginsAddon extends Plugin{
|
||||
|
||||
@Override
|
||||
@@ -50,14 +48,16 @@ public class BungeeCordBanPluginsAddon extends Plugin{
|
||||
|
||||
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!");
|
||||
for(BanPluginsList entry : BanPluginsList.values()){
|
||||
if(!entry.supportsBungeeCord())
|
||||
continue;
|
||||
|
||||
if(getProxy().getPluginManager().getPlugin(entry.getName()) != null){
|
||||
getLogger().info("Registering Placeholders for " + entry.getName() + "...");
|
||||
api.addPlaceholderProvider(entry.getPlaceholderProvider());
|
||||
getLogger().info("Placeholders successfully registered!");
|
||||
|
||||
loaded++;
|
||||
}
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* 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 ch.andre601.advancedserverlist.banplugins.placeholders.LibertyBansPlaceholders;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public enum PaperBanPlugins{
|
||||
|
||||
ADVANCED_BAN("AdvancedBan", new AdvancedBanPlaceholders()),
|
||||
LIBERTY_BANS("LibertyBans", new LibertyBansPlaceholders());
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -26,11 +26,9 @@
|
||||
package ch.andre601.advancedserverlist.banplugins.paper;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.AdvancedServerListAPI;
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.banplugins.BanPluginsList;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class PaperBanPluginsAddon extends JavaPlugin{
|
||||
|
||||
@Override
|
||||
@@ -53,14 +51,16 @@ public class PaperBanPluginsAddon extends JavaPlugin{
|
||||
|
||||
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!");
|
||||
for(BanPluginsList entry : BanPluginsList.values()){
|
||||
if(!entry.supportsPaper())
|
||||
continue;
|
||||
|
||||
if(getServer().getPluginManager().isPluginEnabled(entry.getName())){
|
||||
getLogger().info("Registering Placeholders for " + entry.getName() + "...");
|
||||
api.addPlaceholderProvider(entry.getPlaceholderProvider());
|
||||
getLogger().info("Placeholders successfully registered!");
|
||||
|
||||
loaded++;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ import ch.andre601.advancedserverlist.banplugins.providers.AdvancedBanProvider;
|
||||
|
||||
public class AdvancedBanPlaceholders extends PlaceholderProvider{
|
||||
|
||||
private final AdvancedBanProvider provider = new AdvancedBanProvider();
|
||||
private AdvancedBanProvider provider = null;
|
||||
|
||||
public AdvancedBanPlaceholders(){
|
||||
super("advancedban");
|
||||
@@ -40,11 +40,14 @@ public class AdvancedBanPlaceholders extends PlaceholderProvider{
|
||||
|
||||
@Override
|
||||
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
|
||||
if(provider == null)
|
||||
provider = new AdvancedBanProvider();
|
||||
|
||||
String[] args = placeholder.split("\\s", 2);
|
||||
|
||||
return switch(args[0]) {
|
||||
// Mute-related placeholders
|
||||
case "isMuted" -> String.valueOf(provider.muted(player));
|
||||
case "isMuted" -> provider.muted(player);
|
||||
case "muteReason" -> provider.muteReason(player);
|
||||
case "muteDuration" -> {
|
||||
if(args.length == 1)
|
||||
@@ -61,7 +64,7 @@ public class AdvancedBanPlaceholders extends PlaceholderProvider{
|
||||
}
|
||||
|
||||
// Ban-related placeholders
|
||||
case "isBanned" -> String.valueOf(provider.banned(player));
|
||||
case "isBanned" -> provider.banned(player);
|
||||
case "banReason" -> provider.banReason(player);
|
||||
case "banDuration" -> {
|
||||
if(args.length == 1)
|
||||
|
||||
@@ -32,7 +32,7 @@ import ch.andre601.advancedserverlist.banplugins.providers.LibertyBansProvider;
|
||||
|
||||
public class LibertyBansPlaceholders extends PlaceholderProvider{
|
||||
|
||||
private final LibertyBansProvider provider = LibertyBansProvider.create();
|
||||
private LibertyBansProvider provider = null;
|
||||
|
||||
public LibertyBansPlaceholders(){
|
||||
super("libertybans");
|
||||
@@ -40,11 +40,14 @@ public class LibertyBansPlaceholders extends PlaceholderProvider{
|
||||
|
||||
@Override
|
||||
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
|
||||
if(provider == null)
|
||||
provider = LibertyBansProvider.create();
|
||||
|
||||
String[] args = placeholder.split("\\s", 2);
|
||||
|
||||
return switch(args[0]){
|
||||
// Mute-related placeholders
|
||||
case "isMuted" -> String.valueOf(provider.muted(player));
|
||||
case "isMuted" -> provider.muted(player);
|
||||
case "muteReason" -> provider.muteReason(player);
|
||||
case "muteExpiration" -> {
|
||||
if(args.length == 1)
|
||||
@@ -54,7 +57,7 @@ public class LibertyBansPlaceholders extends PlaceholderProvider{
|
||||
}
|
||||
|
||||
// Ban-related placeholders
|
||||
case "isBanned" -> String.valueOf(provider.banned(player));
|
||||
case "isBanned" -> provider.banned(player);
|
||||
case "banReason" -> provider.banReason(player);
|
||||
case "banExpiration" -> {
|
||||
if(args.length == 1)
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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.LiteBansProvider;
|
||||
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
|
||||
public class LiteBansPlaceholders extends PlaceholderProvider{
|
||||
|
||||
private LiteBansProvider provider = null;
|
||||
|
||||
public LiteBansPlaceholders(){
|
||||
super("litebans");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
|
||||
if(provider == null)
|
||||
provider = new LiteBansProvider();
|
||||
|
||||
String[] args = placeholder.split("\\s", 2);
|
||||
|
||||
CompletableFuture<String> future = CompletableFuture.supplyAsync(() ->
|
||||
switch(args[0]){
|
||||
// Mute-related placeholders
|
||||
case "isMuted" -> provider.muted(player);
|
||||
case "muteReason" -> provider.muteReason(player);
|
||||
case "muteDuration" -> provider.muteDuration(player);
|
||||
case "muteExpiration" -> {
|
||||
if(args.length == 1)
|
||||
yield provider.muteExpirationDate(player);
|
||||
|
||||
yield provider.muteExpirationDate(player, args[1]);
|
||||
}
|
||||
|
||||
// Ban-related placeholders
|
||||
case "isBanned" -> provider.banned(player);
|
||||
case "banReason" -> provider.banReason(player);
|
||||
case "banDuration" -> provider.banDuration(player);
|
||||
case "banExpiration" -> {
|
||||
if(args.length == 1)
|
||||
yield provider.banExpirationDate(player);
|
||||
|
||||
yield provider.banExpirationDate(player, args[1]);
|
||||
}
|
||||
|
||||
//Unknown/Invalid placeholder
|
||||
default -> null;
|
||||
}
|
||||
);
|
||||
|
||||
try{
|
||||
return future.join();
|
||||
}catch(CancellationException | CompletionException ex){
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,40 +31,18 @@ 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 String muted(GenericPlayer player){
|
||||
return String.valueOf(getAPI().isMuted(noDashesUUID(player.getUUID())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean muted(GenericPlayer player){
|
||||
return getAPI().isMuted(noDashesUUID(player.getUUID()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean banned(GenericPlayer player){
|
||||
return getAPI().isBanned(noDashesUUID(player.getUUID()));
|
||||
public String banned(GenericPlayer player){
|
||||
return String.valueOf(getAPI().isBanned(noDashesUUID(player.getUUID())));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -136,4 +114,24 @@ public class AdvancedBanProvider implements PunishmentProvider{
|
||||
|
||||
return ban.getDuration(fromStart);
|
||||
}
|
||||
|
||||
private PunishmentManager getAPI(){
|
||||
return PunishmentManager.get();
|
||||
}
|
||||
|
||||
private String noDashesUUID(UUID uuid){
|
||||
return hexString(uuid.getMostSignificantBits()) + hexString(uuid.getLeastSignificantBits());
|
||||
}
|
||||
|
||||
private Punishment mute(GenericPlayer player){
|
||||
return getAPI().getMute(noDashesUUID(player.getUUID()));
|
||||
}
|
||||
|
||||
private Punishment ban(GenericPlayer player){
|
||||
return getAPI().getBan(noDashesUUID(player.getUUID()));
|
||||
}
|
||||
|
||||
private String hexString(long unsigned){
|
||||
return Strings.padStart(UnsignedLongs.toString(unsigned, 16), 16, '0');
|
||||
}
|
||||
}
|
||||
@@ -53,13 +53,13 @@ public class LibertyBansProvider implements PunishmentProvider{
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean muted(GenericPlayer player){
|
||||
return punishment(player.getUUID(), PunishmentType.MUTE) != null;
|
||||
public String muted(GenericPlayer player){
|
||||
return String.valueOf(punishment(player.getUUID(), PunishmentType.MUTE) != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean banned(GenericPlayer player){
|
||||
return punishment(player.getUUID(), PunishmentType.BAN) != null;
|
||||
public String banned(GenericPlayer player){
|
||||
return String.valueOf(punishment(player.getUUID(), PunishmentType.BAN) != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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 litebans.api.Database;
|
||||
import litebans.api.Entry;
|
||||
|
||||
public class LiteBansProvider implements PunishmentProvider{
|
||||
|
||||
@Override
|
||||
public String muted(GenericPlayer player){
|
||||
return String.valueOf(Database.get().isPlayerMuted(player.getUUID(), null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String banned(GenericPlayer player){
|
||||
return String.valueOf(Database.get().isPlayerBanned(player.getUUID(), null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String muteReason(GenericPlayer player){
|
||||
Entry mute = Database.get().getMute(player.getUUID(), null, null);
|
||||
if(mute == null)
|
||||
return null;
|
||||
|
||||
return mute.getReason();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String banReason(GenericPlayer player){
|
||||
Entry ban = Database.get().getBan(player.getUUID(), null, null);
|
||||
if(ban == null)
|
||||
return null;
|
||||
|
||||
return ban.getReason();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String muteDuration(GenericPlayer player){
|
||||
Entry mute = Database.get().getMute(player.getUUID(), null, null);
|
||||
if(mute == null)
|
||||
return null;
|
||||
|
||||
return mute.getDurationString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String banDuration(GenericPlayer player){
|
||||
Entry ban = Database.get().getBan(player.getUUID(), null, null);
|
||||
if(ban == null)
|
||||
return null;
|
||||
|
||||
return ban.getDurationString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String muteExpirationDate(GenericPlayer player, String pattern){
|
||||
Entry mute = Database.get().getMute(player.getUUID(), null, null);
|
||||
if(mute == null)
|
||||
return null;
|
||||
|
||||
if(mute.isPermanent())
|
||||
return "never";
|
||||
|
||||
return this.returnDate(pattern, mute.getDateEnd());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String banExpirationDate(GenericPlayer player, String pattern){
|
||||
Entry ban = Database.get().getBan(player.getUUID(), null, null);
|
||||
if(ban == null)
|
||||
return null;
|
||||
|
||||
if(ban.isPermanent())
|
||||
return "never";
|
||||
|
||||
return this.returnDate(pattern, ban.getDateEnd());
|
||||
}
|
||||
}
|
||||
@@ -32,9 +32,9 @@ import java.util.Date;
|
||||
|
||||
public interface PunishmentProvider{
|
||||
|
||||
boolean muted(GenericPlayer player);
|
||||
String muted(GenericPlayer player);
|
||||
|
||||
boolean banned(GenericPlayer player);
|
||||
String banned(GenericPlayer player);
|
||||
|
||||
String muteReason(GenericPlayer player);
|
||||
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* 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.velocity;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.banplugins.paper.PaperBanPlugins;
|
||||
import ch.andre601.advancedserverlist.banplugins.placeholders.LibertyBansPlaceholders;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public enum VelocityBanPlugins{
|
||||
|
||||
LIBERTY_BANS("libertybans", new LibertyBansPlaceholders());
|
||||
|
||||
private final String plugin;
|
||||
private final PlaceholderProvider placeholderProvider;
|
||||
|
||||
VelocityBanPlugins(String plugin, PlaceholderProvider placeholderProvider){
|
||||
this.plugin = plugin;
|
||||
this.placeholderProvider = placeholderProvider;
|
||||
}
|
||||
|
||||
public static Map<String, PlaceholderProvider> getBanPlugins(){
|
||||
Map<String, PlaceholderProvider> content = new HashMap<>();
|
||||
|
||||
for(VelocityBanPlugins velocityBanPlugins : VelocityBanPlugins.values()){
|
||||
content.put(velocityBanPlugins.plugin, velocityBanPlugins.placeholderProvider);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
@@ -26,15 +26,15 @@
|
||||
package ch.andre601.advancedserverlist.banplugins.velocity;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.AdvancedServerListAPI;
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.banplugins.BanPluginsList;
|
||||
import com.google.inject.Inject;
|
||||
import com.velocitypowered.api.event.Subscribe;
|
||||
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Locale;
|
||||
|
||||
public class VelocityBanPluginsAddon{
|
||||
|
||||
@@ -49,7 +49,7 @@ public class VelocityBanPluginsAddon{
|
||||
|
||||
@Subscribe
|
||||
public void init(ProxyInitializeEvent event){
|
||||
if(proxy.getPluginManager().getPlugin("advancedserverlist") == null){
|
||||
if(!proxy.getPluginManager().isLoaded("advancedserverlist")){
|
||||
logger.warn("AdvancedServerList is not enabled. This plugin requires it to function!");
|
||||
return;
|
||||
}
|
||||
@@ -64,14 +64,16 @@ public class VelocityBanPluginsAddon{
|
||||
|
||||
private int loadPlaceholderProviders(){
|
||||
int loaded = 0;
|
||||
Map<String, PlaceholderProvider> banPlugins = VelocityBanPlugins.getBanPlugins();
|
||||
AdvancedServerListAPI api = AdvancedServerListAPI.get();
|
||||
|
||||
for(Map.Entry<String, PlaceholderProvider> entry : banPlugins.entrySet()){
|
||||
if(proxy.getPluginManager().getPlugin(entry.getKey()) != null){
|
||||
logger.info("Registering placeholders for {}...", entry.getKey());
|
||||
api.addPlaceholderProvider(entry.getValue());
|
||||
logger.info("Placeholder successfully registered!");
|
||||
for(BanPluginsList entry : BanPluginsList.values()){
|
||||
if(!entry.supportsVelocity())
|
||||
continue;
|
||||
|
||||
if(proxy.getPluginManager().isLoaded(entry.getName().toLowerCase(Locale.ROOT))){
|
||||
logger.info("Registering Placeholders for " + entry.getName() + "...");
|
||||
api.addPlaceholderProvider(entry.getPlaceholderProvider());
|
||||
logger.info("Placeholders successfully registered!");
|
||||
|
||||
loaded++;
|
||||
}
|
||||
|
||||
@@ -7,5 +7,6 @@ softDepends:
|
||||
- AdvancedServerList
|
||||
- AdvancedBan
|
||||
- LibertyBans
|
||||
- LiteBans
|
||||
|
||||
main: 'ch.andre601.advancedserverlist.banplugins.bungeecord.BungeeCordBanPluginsAddon'
|
||||
@@ -2,7 +2,7 @@ name: 'ASLBanPluginsAddon'
|
||||
author: 'Andre_601'
|
||||
version: '${plugin.version}'
|
||||
|
||||
main: 'ch.andre601.advancedserverlist.banplugins.paper.AdvancedBanPlaceholders'
|
||||
main: 'ch.andre601.advancedserverlist.banplugins.paper.PaperBanPluginsAddon'
|
||||
|
||||
api-version: '1.19'
|
||||
|
||||
@@ -11,9 +11,12 @@ dependencies:
|
||||
AdvancedServerList:
|
||||
required: false
|
||||
load: BEFORE
|
||||
AdvancedBans:
|
||||
AdvancedBan:
|
||||
required: false
|
||||
load: BEFORE
|
||||
LibertyBans:
|
||||
required: false
|
||||
load: BEFORE
|
||||
LiteBans:
|
||||
required: false
|
||||
load: BEFORE
|
||||
@@ -14,6 +14,10 @@
|
||||
{
|
||||
"id": "libertybans",
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"id": "litebans",
|
||||
"optional": true
|
||||
}
|
||||
],
|
||||
"main": "ch.andre601.advancedserverlist.banplugins.velocity.VelocityBanPluginsAddon"
|
||||
|
||||
@@ -40,8 +40,9 @@
|
||||
<description>${plugin.description}</description>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>16</maven.compiler.source>
|
||||
<maven.compiler.target>16</maven.compiler.target>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
@@ -49,6 +50,10 @@
|
||||
<id>sonatype</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>repo-sayandevelopment</id>
|
||||
<url>https://repo.sayandev.org/releases/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
@@ -69,43 +74,43 @@
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>1.20-R0.2</version>
|
||||
<version>1.21-R0.1-SNAPSHOT</version>
|
||||
<type>jar</type>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>1.20-R0.2</version>
|
||||
<version>1.21-R0.1-SNAPSHOT</version>
|
||||
<type>javadoc</type>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Adventure Library. Needs to be shaded in -->
|
||||
<!-- Adventure Library -->
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-api</artifactId>
|
||||
<version>4.16.0</version>
|
||||
<scope>compile</scope>
|
||||
<version>${dependency.adventure-api}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-text-minimessage</artifactId>
|
||||
<version>4.16.0</version>
|
||||
<scope>compile</scope>
|
||||
<version>${dependency.adventure-text-minimessage}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-platform-bungeecord</artifactId>
|
||||
<version>4.3.2</version>
|
||||
<scope>compile</scope>
|
||||
<version>${dependency.adventure-platform-bungeecord}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Metrics -->
|
||||
<dependency>
|
||||
<groupId>org.bstats</groupId>
|
||||
<artifactId>bstats-bungeecord</artifactId>
|
||||
<version>3.0.2</version>
|
||||
<version>3.1.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -113,8 +118,8 @@
|
||||
<dependency>
|
||||
<groupId>org.spongepowered</groupId>
|
||||
<artifactId>configurate-yaml</artifactId>
|
||||
<version>4.1.2</version>
|
||||
<scope>compile</scope>
|
||||
<version>${dependency.configurate-yaml}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Plugins -->
|
||||
@@ -124,10 +129,36 @@
|
||||
<version>2.9.0-4</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.sayandev</groupId>
|
||||
<artifactId>sayanvanish-api</artifactId>
|
||||
<version>1.6.4</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.sayandev</groupId>
|
||||
<artifactId>sayanvanish-proxy-bungeecord</artifactId>
|
||||
<version>1.6.4</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Other -->
|
||||
<dependency>
|
||||
<groupId>com.alessiodp.libby</groupId>
|
||||
<artifactId>libby-bungee</artifactId>
|
||||
<version>2.0.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.incendo</groupId>
|
||||
<artifactId>cloud-bungee</artifactId>
|
||||
<version>${dependency.cloud-bungee}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>AdvancedServerList-BungeeCord-${plugin.version}</finalName>
|
||||
<finalName>AdvancedServerList-BungeeCord-${plugin.version}${project.build.build_id}</finalName>
|
||||
<resources>
|
||||
<resource>
|
||||
<filtering>true</filtering>
|
||||
@@ -135,47 +166,51 @@
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.13.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.5.2</version>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>org.spongepowered.configurate</pattern>
|
||||
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.configurate</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>net.kyori</pattern>
|
||||
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.kyori</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.bstats</pattern>
|
||||
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.bstats</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
<filters>
|
||||
<filter>
|
||||
<artifact>*:*</artifact>
|
||||
<excludes>
|
||||
<exclude>META-INF/*.SF</exclude>
|
||||
<exclude>META-INF/*.RSA</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
</filters>
|
||||
</configuration>
|
||||
<version>3.6.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>org.bstats</pattern>
|
||||
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.bstats</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>com.alessiodp.libby</pattern>
|
||||
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.libby</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>ch.andre601.expressionparser</pattern>
|
||||
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.expressionparser</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>com.unascribed.flexver</pattern>
|
||||
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.flexver</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.incendo.cloud</pattern>
|
||||
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.cloud</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
<filters>
|
||||
<filter>
|
||||
<artifact>*:*</artifact>
|
||||
<excludes>
|
||||
<exclude>META-INF/*.SF</exclude>
|
||||
<exclude>META-INF/*.DSA</exclude>
|
||||
<exclude>META-INF/*.RSA</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
</filters>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
@@ -25,54 +25,92 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.bungeecord;
|
||||
|
||||
import ch.andre601.advancedserverlist.bungeecord.commands.CmdAdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.bungeecord.listeners.JoinEvent;
|
||||
import ch.andre601.advancedserverlist.bungeecord.listeners.PingEvent;
|
||||
import ch.andre601.advancedserverlist.bungeecord.commands.BungeeCommandManagerInterface;
|
||||
import ch.andre601.advancedserverlist.bungeecord.listeners.PlayerJoinEventListener;
|
||||
import ch.andre601.advancedserverlist.bungeecord.listeners.ProxyPingEventListener;
|
||||
import ch.andre601.advancedserverlist.bungeecord.logging.BungeeLogger;
|
||||
import ch.andre601.advancedserverlist.bungeecord.objects.placeholders.BungeePlayerPlaceholders;
|
||||
import ch.andre601.advancedserverlist.bungeecord.objects.placeholders.BungeeProxyPlaceholders;
|
||||
import ch.andre601.advancedserverlist.bungeecord.objects.placeholders.BungeeServerPlaceholders;
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
|
||||
import ch.andre601.advancedserverlist.core.profiles.favicon.FaviconHandler;
|
||||
import ch.andre601.advancedserverlist.core.profiles.handlers.FaviconHandler;
|
||||
import com.alessiodp.libby.BungeeLibraryManager;
|
||||
import com.alessiodp.libby.Library;
|
||||
import de.myzelyam.api.vanish.BungeeVanishAPI;
|
||||
import net.kyori.adventure.platform.bungeecord.BungeeAudiences;
|
||||
import net.md_5.bungee.api.Favicon;
|
||||
import net.md_5.bungee.api.ServerPing;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
import org.bstats.bungeecord.Metrics;
|
||||
import org.bstats.charts.SimplePie;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
import org.sayandev.sayanvanish.bungeecord.api.SayanVanishBungeeAPI;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
|
||||
|
||||
private final PluginLogger logger = new BungeeLogger(this);
|
||||
private final Map<String, ServerPing> fetchedServers = new ConcurrentHashMap<>();
|
||||
|
||||
private boolean successfulLoad = false;
|
||||
|
||||
private AdvancedServerList<Favicon> core;
|
||||
private FaviconHandler<Favicon> faviconHandler = null;
|
||||
private final PluginLogger logger = new BungeeLogger(this);
|
||||
private BungeeAudiences audiences = null;
|
||||
private BungeeCommandManagerInterface handler;
|
||||
|
||||
private BungeeLibraryManager libraryManager = null;
|
||||
|
||||
@Override
|
||||
public void onLoad(){
|
||||
// Using getLogger() here, because PluginLogger requires MiniMessage, which isn't loaded at this stage.
|
||||
getLogger().info("Loading libraries. This may take a while...");
|
||||
successfulLoad = loadLibs();
|
||||
if(successfulLoad){
|
||||
getLogger().info("Library loading completed successfully!");
|
||||
}else{
|
||||
getLogger().warning("Library loading completed with errors!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable(){
|
||||
this.core = AdvancedServerList.init(this, BungeePlayerPlaceholders.init(), BungeeServerPlaceholders.init(this));
|
||||
if(!successfulLoad){
|
||||
logger.warn("There were issues during the plugins Loading-phase! Please see the console for possible reasons.");
|
||||
logger.warn("Aborting further enabling of the plugin to avoid errors.");
|
||||
return;
|
||||
}
|
||||
|
||||
this.audiences = BungeeAudiences.create(this);
|
||||
this.handler = new BungeeCommandManagerInterface(this);
|
||||
this.core = AdvancedServerList.init(this,
|
||||
BungeePlayerPlaceholders.init(), BungeeServerPlaceholders.init(this), BungeeProxyPlaceholders.init(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable(){
|
||||
core.disable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadCommands(){
|
||||
getProxy().getPluginManager().registerCommand(this, new CmdAdvancedServerList(this));
|
||||
getProxy().getScheduler().cancel(this);
|
||||
audiences.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadEvents(){
|
||||
new JoinEvent(this);
|
||||
new PingEvent(this);
|
||||
new PlayerJoinEventListener(this);
|
||||
new ProxyPingEventListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -96,6 +134,28 @@ public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
|
||||
faviconHandler.cleanCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void downloadLibrary(String groupId, String artifactId, String version){
|
||||
if(libraryManager == null){
|
||||
libraryManager = new BungeeLibraryManager(this);
|
||||
libraryManager.addRepository("https://repo.papermc.io/repository/maven-public");
|
||||
}
|
||||
|
||||
Library lib = Library.builder()
|
||||
.groupId(groupId)
|
||||
.artifactId(artifactId)
|
||||
.version(version)
|
||||
.resolveTransitiveDependencies(true)
|
||||
.build();
|
||||
|
||||
libraryManager.loadLibrary(lib);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startScheduler(){
|
||||
getProxy().getScheduler().schedule(this, this::fetchServers, 0, 10, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdvancedServerList<Favicon> getCore(){
|
||||
return core;
|
||||
@@ -120,13 +180,13 @@ public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlatformName(){
|
||||
return getProxy().getName();
|
||||
public CommandManager<CmdSender> getCommandManager(){
|
||||
return handler.commandHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlatformVersion(){
|
||||
return getProxy().getVersion();
|
||||
public String getPlatformInfo(){
|
||||
return getProxy().getName() + " " + getProxy().getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -134,19 +194,61 @@ public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
|
||||
return "bungeecord";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPluginEnabled(String plugin){
|
||||
return getProxy().getPluginManager().getPlugin(plugin) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Favicon createFavicon(BufferedImage image) throws IllegalArgumentException{
|
||||
return Favicon.create(image);
|
||||
}
|
||||
|
||||
public BungeeAudiences getAudiences(){
|
||||
return audiences;
|
||||
}
|
||||
|
||||
public int getOnlinePlayers(ServerInfo server){
|
||||
List<ProxiedPlayer> players = new ArrayList<>(server == null ? getProxy().getPlayers() : server.getPlayers());
|
||||
|
||||
// Exclude players when PremiumVanish is enabled and player is hidden.
|
||||
if(getProxy().getPluginManager().getPlugin("PremiumVanish") != null){
|
||||
players.removeIf(BungeeVanishAPI::isInvisible);
|
||||
}else // Do the same if SayanVanish is enabled.
|
||||
if(getProxy().getPluginManager().getPlugin("SayanVanish") != null){
|
||||
players.removeIf(player -> SayanVanishBungeeAPI.getInstance().isVanished(player.getUniqueId()));
|
||||
}
|
||||
|
||||
return players.size();
|
||||
}
|
||||
|
||||
public Map<String, ServerPing> getFetchedServers(){
|
||||
return fetchedServers;
|
||||
}
|
||||
|
||||
private boolean loadLibs(){
|
||||
try{
|
||||
if(libraryManager == null){
|
||||
libraryManager = new BungeeLibraryManager(this);
|
||||
libraryManager.addRepository("https://repo.papermc.io/repository/maven-public");
|
||||
}
|
||||
|
||||
libraryManager.configureFromJSON("dependencies.json");
|
||||
|
||||
return true;
|
||||
}catch(Exception ex){
|
||||
getLogger().log(Level.WARNING, "Encountered an Exception while trying to load dependencies.", ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void fetchServers(){
|
||||
fetchedServers.clear();
|
||||
getProxy().getServers().forEach((name, server) -> server.ping((ping, throwable) -> {
|
||||
if(throwable != null)
|
||||
return;
|
||||
|
||||
fetchedServers.put(name, ping);
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -27,8 +27,10 @@ package ch.andre601.advancedserverlist.bungeecord.commands;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
|
||||
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.platform.bungeecord.BungeeAudiences;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
|
||||
public class BungeeCmdSender implements CmdSender{
|
||||
|
||||
@@ -40,13 +42,22 @@ public class BungeeCmdSender implements CmdSender{
|
||||
this.bungeeAudiences = bungeeAudiences;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String permission){
|
||||
return sender.hasPermission(permission) || sender.hasPermission("advancedserverlist.admin");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMsg(String msg, Object... args){
|
||||
bungeeAudiences.sender(sender).sendMessage(ComponentParser.text(String.format(msg, args)).toComponent());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Audience audience(){
|
||||
return bungeeAudiences.sender(sender);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPlayer(){
|
||||
return sender instanceof ProxiedPlayer;
|
||||
}
|
||||
|
||||
public CommandSender sender(){
|
||||
return sender;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
* Copyright (c) 2022-2025 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
|
||||
@@ -20,29 +20,41 @@
|
||||
* 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.commands;
|
||||
|
||||
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
|
||||
import net.kyori.adventure.platform.bungeecord.BungeeAudiences;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CommandManagerInterface;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
import org.incendo.cloud.SenderMapper;
|
||||
import org.incendo.cloud.bungee.BungeeCommandManager;
|
||||
import org.incendo.cloud.execution.ExecutionCoordinator;
|
||||
|
||||
public class CmdAdvancedServerList extends Command{
|
||||
public class BungeeCommandManagerInterface implements CommandManagerInterface<CommandSender>{
|
||||
|
||||
private final BungeeCordCore plugin;
|
||||
private final BungeeAudiences audiences;
|
||||
|
||||
public CmdAdvancedServerList(BungeeCordCore plugin){
|
||||
super("advancedserverlist", "advancedserverlist.command.asl", "asl");
|
||||
public BungeeCommandManagerInterface(BungeeCordCore plugin){
|
||||
this.plugin = plugin;
|
||||
this.audiences = BungeeAudiences.create(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender, String[] args){
|
||||
plugin.getCore().getCommandHandler().handle(new BungeeCmdSender(sender, audiences), args);
|
||||
public CommandManager<CmdSender> commandHandler(){
|
||||
return new BungeeCommandManager<>(
|
||||
plugin,
|
||||
ExecutionCoordinator.asyncCoordinator(),
|
||||
senderMapper()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SenderMapper<CommandSender, CmdSender> senderMapper(){
|
||||
return SenderMapper.create(
|
||||
cmdSender -> new BungeeCmdSender(cmdSender, plugin.getAudiences()),
|
||||
sender -> ((BungeeCmdSender)sender).sender()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,8 @@ import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
|
||||
import ch.andre601.advancedserverlist.bungeecord.objects.impl.BungeePlayerImpl;
|
||||
import ch.andre601.advancedserverlist.bungeecord.objects.impl.BungeeProxyImpl;
|
||||
import ch.andre601.advancedserverlist.core.events.PingEventHandler;
|
||||
import ch.andre601.advancedserverlist.core.compat.maintenance.MaintenanceUtil;
|
||||
import ch.andre601.advancedserverlist.core.compat.papi.PAPIUtil;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.events.GenericEventWrapper;
|
||||
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
|
||||
@@ -78,6 +79,11 @@ public class BungeeEventWrapper implements GenericEventWrapper<Favicon, BungeePl
|
||||
ping.getPlayers().setMax(maxPlayers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnlinePlayers(int onlinePlayers){
|
||||
ping.getPlayers().setOnline(onlinePlayers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMotd(Component component){
|
||||
ping.setDescriptionComponent(new TextComponent(BungeeComponentSerializer.get().serialize(component)));
|
||||
@@ -101,8 +107,9 @@ public class BungeeEventWrapper implements GenericEventWrapper<Favicon, BungeePl
|
||||
for(int i = 0; i < players.length; i++){
|
||||
String parsed = ComponentParser.text(lines.get(i))
|
||||
.modifyText(text -> StringReplacer.replace(text, player, server))
|
||||
.modifyText(text -> parsePAPIPlaceholders(text, player))
|
||||
.toString();
|
||||
|
||||
|
||||
ServerPing.PlayerInfo pi = new ServerPing.PlayerInfo(parsed, UUID.randomUUID());
|
||||
players[i] = pi;
|
||||
}
|
||||
@@ -111,6 +118,11 @@ public class BungeeEventWrapper implements GenericEventWrapper<Favicon, BungeePl
|
||||
ping.getPlayers().setSample(players);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayersHidden(){
|
||||
ping.getPlayers().setSample(new ServerPing.PlayerInfo[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFavicon(Favicon favicon){
|
||||
ping.setFavicon(favicon);
|
||||
@@ -137,12 +149,12 @@ public class BungeeEventWrapper implements GenericEventWrapper<Favicon, BungeePl
|
||||
if(plugin.getProxy().getPluginManager().getPlugin("Maintenance") == null)
|
||||
return false;
|
||||
|
||||
return PingEventHandler.getMaintenanceUtil().isMaintenanceEnabled();
|
||||
return MaintenanceUtil.get().isMaintenanceEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtocolVersion(){
|
||||
return this.protocol.getProtocol();
|
||||
return event.getConnection().getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -165,10 +177,10 @@ public class BungeeEventWrapper implements GenericEventWrapper<Favicon, BungeePl
|
||||
if(plugin.getProxy().getPluginManager().getPlugin("PAPIProxyBridge") == null)
|
||||
return text;
|
||||
|
||||
if(!PingEventHandler.getPAPIUtil().isCompatible())
|
||||
if(!PAPIUtil.get().isCompatible())
|
||||
return text;
|
||||
|
||||
String server = PingEventHandler.getPAPIUtil().getServer();
|
||||
String server = PAPIUtil.get().getServer();
|
||||
if(server == null || server.isEmpty())
|
||||
return text;
|
||||
|
||||
@@ -176,11 +188,11 @@ public class BungeeEventWrapper implements GenericEventWrapper<Favicon, BungeePl
|
||||
if(serverInfo == null || serverInfo.getPlayers().isEmpty())
|
||||
return text;
|
||||
|
||||
ProxiedPlayer carrier = PingEventHandler.getPAPIUtil().getPlayer(serverInfo.getPlayers());
|
||||
ProxiedPlayer carrier = PAPIUtil.get().getPlayer(serverInfo.getPlayers());
|
||||
if(carrier == null)
|
||||
return text;
|
||||
|
||||
return PingEventHandler.getPAPIUtil().parse(text, carrier.getUniqueId(), player.getUUID());
|
||||
return PAPIUtil.get().parse(text, carrier.getUniqueId(), player.getUUID());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
package ch.andre601.advancedserverlist.bungeecord.listeners;
|
||||
|
||||
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
|
||||
import ch.andre601.advancedserverlist.bungeecord.commands.BungeeCmdSender;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.PostLoginEvent;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
@@ -33,11 +34,10 @@ import net.md_5.bungee.event.EventHandler;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
public class JoinEvent implements Listener{
|
||||
|
||||
public class PlayerJoinEventListener implements Listener{
|
||||
private final BungeeCordCore plugin;
|
||||
|
||||
public JoinEvent(BungeeCordCore plugin){
|
||||
public PlayerJoinEventListener(BungeeCordCore plugin){
|
||||
this.plugin = plugin;
|
||||
plugin.getProxy().getPluginManager().registerListener(plugin, this);
|
||||
}
|
||||
@@ -48,5 +48,14 @@ public class JoinEvent implements Listener{
|
||||
ProxiedPlayer player = event.getPlayer();
|
||||
|
||||
plugin.getCore().getPlayerHandler().addPlayer(address.getHostString(), player.getName(), player.getUniqueId());
|
||||
|
||||
if(player.hasPermission("advancedserverlist.admin") || player.hasPermission("advancedserverlist.updatecheck")){
|
||||
if(plugin.getAudiences() == null || plugin.getCore().getUpdateChecker() == null)
|
||||
return;
|
||||
|
||||
BungeeCmdSender sender = new BungeeCmdSender(player, plugin.getAudiences());
|
||||
|
||||
plugin.getCore().getUpdateChecker().performCachedUpdateCheck(sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,11 +33,11 @@ import net.md_5.bungee.api.event.ProxyPingEvent;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
|
||||
public class PingEvent implements Listener{
|
||||
public class ProxyPingEventListener implements Listener{
|
||||
|
||||
private final BungeeCordCore plugin;
|
||||
|
||||
public PingEvent(BungeeCordCore plugin){
|
||||
public ProxyPingEventListener(BungeeCordCore plugin){
|
||||
this.plugin = plugin;
|
||||
plugin.getProxy().getPluginManager().registerListener(plugin, this);
|
||||
}
|
||||
@@ -27,6 +27,7 @@ package ch.andre601.advancedserverlist.bungeecord.logging;
|
||||
|
||||
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@@ -55,21 +56,21 @@ public class BungeeLogger implements PluginLogger{
|
||||
|
||||
@Override
|
||||
public void info(String msg, Object... args){
|
||||
logger.info(String.format(msg, args));
|
||||
logger.info(ComponentParser.textFormatted(msg, args).toStringStriped());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Object... args){
|
||||
logger.warning(String.format(msg, args));
|
||||
logger.warning(ComponentParser.textFormatted(msg, args).toStringStriped());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Throwable throwable){
|
||||
logger.log(Level.WARNING, msg, throwable);
|
||||
logger.log(Level.WARNING, ComponentParser.text(msg).toStringStriped(), throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Throwable throwable, Object... args){
|
||||
logger.log(Level.WARNING, String.format(msg, args), throwable);
|
||||
logger.log(Level.WARNING, ComponentParser.textFormatted(msg, args).toStringStriped(), throwable);
|
||||
}
|
||||
}
|
||||
@@ -25,14 +25,25 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.bungeecord.objects.impl;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.bungeecord.objects.BungeePlayer;
|
||||
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.players.GenericPlayerImpl;
|
||||
|
||||
public class BungeePlayerImpl extends GenericPlayerImpl{
|
||||
import java.util.UUID;
|
||||
|
||||
public record BungeePlayerImpl(CachedPlayer player, int protocol) implements BungeePlayer{
|
||||
|
||||
public BungeePlayerImpl(CachedPlayer player, int protocol){
|
||||
this.name = player.name();
|
||||
this.protocol = protocol;
|
||||
this.uuid = player.uuid();
|
||||
@Override
|
||||
public String getName(){
|
||||
return player.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtocol(){
|
||||
return protocol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUUID(){
|
||||
return player.uuid();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package ch.andre601.advancedserverlist.bungeecord.objects.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.bungeecord.BungeeCordCore;
|
||||
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer;
|
||||
import net.md_5.bungee.api.ServerPing;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
|
||||
public class BungeeProxyPlaceholders extends PlaceholderProvider{
|
||||
|
||||
private final BungeeCordCore plugin;
|
||||
|
||||
private BungeeProxyPlaceholders(BungeeCordCore plugin){
|
||||
super("proxy");
|
||||
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public static BungeeProxyPlaceholders init(BungeeCordCore plugin){
|
||||
return new BungeeProxyPlaceholders(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
|
||||
String[] args = placeholder.split("\\s", 2);
|
||||
if(args.length < 2)
|
||||
return null;
|
||||
|
||||
ServerPing ping = plugin.getFetchedServers().get(args[1]);
|
||||
|
||||
return switch(args[0]){
|
||||
case "status" -> ping == null ? "offline" : "online";
|
||||
case "motd" -> {
|
||||
if(ping == null)
|
||||
yield "none";
|
||||
|
||||
BaseComponent[] components = new BaseComponent[]{ping.getDescriptionComponent()};
|
||||
Component component = BungeeComponentSerializer.get().deserialize(components);
|
||||
|
||||
yield ComponentParser.toMMString(component);
|
||||
}
|
||||
case "players" -> {
|
||||
if(ping == null)
|
||||
yield "0";
|
||||
|
||||
yield String.valueOf(ping.getPlayers().getOnline());
|
||||
}
|
||||
case "maxPlayers" -> {
|
||||
if(ping == null)
|
||||
yield "0";
|
||||
|
||||
yield String.valueOf(ping.getPlayers().getMax());
|
||||
}
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -79,18 +79,18 @@ public class BungeeServerPlaceholders extends PlaceholderProvider{
|
||||
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 "";
|
||||
|
||||
yield String.valueOf(proxy.getPlayersMax());
|
||||
}
|
||||
case "host" -> {
|
||||
if(args.length > 2)
|
||||
yield null;
|
||||
yield "";
|
||||
|
||||
if(args.length == 2){
|
||||
if(args.length == 2 && args[1] != null && !args[1].isEmpty()){
|
||||
ServerInfo info = proxy.getServers().get(args[1]);
|
||||
if(info == null)
|
||||
yield null;
|
||||
yield "";
|
||||
|
||||
yield String.valueOf(((InetSocketAddress)info.getSocketAddress()).getHostString());
|
||||
}
|
||||
|
||||
@@ -6,5 +6,6 @@ description: '${plugin.description}'
|
||||
softDepends:
|
||||
- PAPIProxyBridge
|
||||
- Maintenance
|
||||
- ServerListPlus
|
||||
|
||||
main: 'ch.andre601.advancedserverlist.bungeecord.BungeeCordCore'
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"libraries": [
|
||||
{
|
||||
"groupId": "net{}kyori",
|
||||
"artifactId": "adventure-api",
|
||||
"version": "${dependency.adventure-api}",
|
||||
"resolveTransitiveDependencies": true
|
||||
},
|
||||
{
|
||||
"groupId": "net{}kyori",
|
||||
"artifactId": "adventure-text-minimessage",
|
||||
"version": "${dependency.adventure-text-minimessage}",
|
||||
"resolveTransitiveDependencies": true
|
||||
},
|
||||
{
|
||||
"groupId": "net{}kyori",
|
||||
"artifactId": "adventure-platform-bungeecord",
|
||||
"version": "${dependency.adventure-platform-bungeecord}",
|
||||
"resolveTransitiveDependencies": true
|
||||
},
|
||||
{
|
||||
"groupId": "org{}spongepowered",
|
||||
"artifactId": "configurate-yaml",
|
||||
"version": "${dependency.configurate-yaml}",
|
||||
"resolveTransitiveDependencies": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -39,9 +39,11 @@
|
||||
<version>${plugin.version}</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>16</maven.compiler.source>
|
||||
<maven.compiler.target>16</maven.compiler.target>
|
||||
<plugin.config.version>5</plugin.config.version>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
||||
<plugin.config.version>8</plugin.config.version>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
@@ -61,6 +63,10 @@
|
||||
<id>codeberg</id>
|
||||
<url>https://codeberg.org/api/packages/Andre601/maven/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>codemc</id>
|
||||
<url>https://repo.codemc.io/repository/maven-releases/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
@@ -73,12 +79,20 @@
|
||||
<dependency>
|
||||
<groupId>ch.andre601</groupId>
|
||||
<artifactId>expressionparser</artifactId>
|
||||
<version>1.3.0</version>
|
||||
<version>1.6.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Configuration -->
|
||||
<dependency>
|
||||
<groupId>org.spongepowered</groupId>
|
||||
<artifactId>configurate-yaml</artifactId>
|
||||
<version>${dependency.configurate-yaml}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spongepowered</groupId>
|
||||
<artifactId>configurate-hocon</artifactId>
|
||||
<version>4.1.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
@@ -87,19 +101,19 @@
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-api</artifactId>
|
||||
<version>4.16.0</version>
|
||||
<version>${dependency.adventure-api}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-text-minimessage</artifactId>
|
||||
<version>4.16.0</version>
|
||||
<version>${dependency.adventure-text-minimessage}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-text-serializer-legacy</artifactId>
|
||||
<version>4.16.0</version>
|
||||
<version>${dependency.adventure-text-serializer-legacy}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -107,7 +121,7 @@
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.10.1</version>
|
||||
<version>2.12.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -119,21 +133,45 @@
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>33.1.0-jre</version>
|
||||
<version>33.4.0-jre</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.incendo</groupId>
|
||||
<artifactId>cloud-annotations</artifactId>
|
||||
<version>${dependency.cloud-annotations}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.incendo</groupId>
|
||||
<artifactId>cloud-minecraft-extras</artifactId>
|
||||
<version>${dependency.cloud-minecraft-extras}</version>
|
||||
<scope>compile</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>*</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- Plugins -->
|
||||
<dependency>
|
||||
<groupId>net.william278</groupId>
|
||||
<artifactId>papiproxybridge</artifactId>
|
||||
<version>1.5</version>
|
||||
<version>1.7.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>eu.kennytv.maintenance</groupId>
|
||||
<artifactId>maintenance-api</artifactId>
|
||||
<version>4.2.0-SNAPSHOT</version>
|
||||
<version>4.2.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.minecrell</groupId>
|
||||
<artifactId>ServerListPlus</artifactId>
|
||||
<version>3.5.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -141,17 +179,27 @@
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>5.10.2</version>
|
||||
<version>5.11.4</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>AdvancedServerList-Core-${plugin.version}</finalName>
|
||||
<finalName>AdvancedServerList-Core-${plugin.version}${project.build.build_id}</finalName>
|
||||
<resources>
|
||||
<resource>
|
||||
<filtering>true</filtering>
|
||||
<directory>${project.basedir}/src/main/resources</directory>
|
||||
<excludes>
|
||||
<exclude>char-widths.json.gz</exclude>
|
||||
</excludes>
|
||||
</resource>
|
||||
<resource>
|
||||
<filtering>false</filtering>
|
||||
<directory>${project.basedir}/src/main/resources</directory>
|
||||
<includes>
|
||||
<include>char-widths.json.gz</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
@@ -159,41 +207,11 @@
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.13.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.5.2</version>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<filters>
|
||||
<filter>
|
||||
<artifact>*:*</artifact>
|
||||
<excludes>
|
||||
<exclude>META-INF/*.SF</exclude>
|
||||
<exclude>META-INF/*.RSA</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
</filters>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<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>
|
||||
<compilerArgs>
|
||||
<arg>-parameters</arg>
|
||||
</compilerArgs>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
@@ -29,10 +29,26 @@ 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.compat.maintenance.MaintenancePlaceholder;
|
||||
import ch.andre601.advancedserverlist.core.file.FileHandler;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CommandType;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
|
||||
import ch.andre601.advancedserverlist.core.parsing.TextCenterUtil;
|
||||
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.ProfileConditionParser;
|
||||
import ch.andre601.advancedserverlist.core.profiles.players.PlayerHandler;
|
||||
import ch.andre601.advancedserverlist.core.profiles.handlers.PlayerHandler;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
import org.incendo.cloud.annotations.AnnotationParser;
|
||||
import org.incendo.cloud.description.Description;
|
||||
import org.incendo.cloud.injection.ParameterInjector;
|
||||
import org.incendo.cloud.parser.ParserDescriptor;
|
||||
import org.incendo.cloud.parser.standard.BooleanParser;
|
||||
import org.incendo.cloud.parser.standard.IntegerParser;
|
||||
import org.incendo.cloud.parser.standard.StringParser;
|
||||
import org.incendo.cloud.permission.Permission;
|
||||
import org.incendo.cloud.suggestion.Suggestion;
|
||||
import org.incendo.cloud.suggestion.SuggestionProvider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -42,10 +58,15 @@ import java.util.Properties;
|
||||
|
||||
public class AdvancedServerList<F>{
|
||||
|
||||
public static <F> AdvancedServerList<F> init(PluginCore<F> plugin, PlaceholderProvider... placeholders){
|
||||
return new AdvancedServerList<>(plugin, Arrays.asList(placeholders));
|
||||
}
|
||||
|
||||
private final PluginCore<F> plugin;
|
||||
private final FileHandler fileHandler;
|
||||
private final CommandHandler commandHandler;
|
||||
private final PlayerHandler playerHandler;
|
||||
private final TextCenterUtil textCenterUtil;
|
||||
|
||||
private static final AdvancedServerListAPI api = AdvancedServerListAPI.get();
|
||||
private final ProfileConditionParser parser = ProfileConditionParser.create();
|
||||
|
||||
@@ -56,16 +77,24 @@ public class AdvancedServerList<F>{
|
||||
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);
|
||||
this.textCenterUtil = new TextCenterUtil(this);
|
||||
|
||||
placeholders.forEach(AdvancedServerList.getApi()::addPlaceholderProvider);
|
||||
plugin.getPluginLogger().info("Registering internal Placeholders...");
|
||||
|
||||
placeholders.forEach(this::addPlaceholder);
|
||||
|
||||
if(plugin.isPluginEnabled("Maintenance")){
|
||||
addPlaceholder(new MaintenancePlaceholder(this));
|
||||
}
|
||||
|
||||
resolveVersion();
|
||||
getPlugin().getPluginLogger().info("Starting <white>AdvancedServerList v%s</white>...", version);
|
||||
load();
|
||||
}
|
||||
|
||||
public static <F> AdvancedServerList<F> init(PluginCore<F> plugin, PlaceholderProvider... placeholders){
|
||||
return new AdvancedServerList<>(plugin, Arrays.asList(placeholders));
|
||||
public static AdvancedServerListAPI getApi(){
|
||||
return api;
|
||||
}
|
||||
|
||||
public PluginCore<F> getPlugin(){
|
||||
@@ -76,10 +105,6 @@ public class AdvancedServerList<F>{
|
||||
return fileHandler;
|
||||
}
|
||||
|
||||
public CommandHandler getCommandHandler(){
|
||||
return commandHandler;
|
||||
}
|
||||
|
||||
public PlayerHandler getPlayerHandler(){
|
||||
return playerHandler;
|
||||
}
|
||||
@@ -88,24 +113,28 @@ public class AdvancedServerList<F>{
|
||||
return version;
|
||||
}
|
||||
|
||||
public static AdvancedServerListAPI getApi(){
|
||||
return api;
|
||||
}
|
||||
|
||||
public ProfileConditionParser getParser(){
|
||||
return parser;
|
||||
}
|
||||
|
||||
public UpdateChecker getUpdateChecker(){
|
||||
return updateChecker;
|
||||
}
|
||||
|
||||
public TextCenterUtil getTextCenterUtil(){
|
||||
return textCenterUtil;
|
||||
}
|
||||
|
||||
public void disable(){
|
||||
getPlugin().getPluginLogger().info("Saving playercache.json file...");
|
||||
getPlugin().getPluginLogger().info("[-] Saving <white>playercache.json</white> file...");
|
||||
getPlayerHandler().save();
|
||||
|
||||
if(updateChecker != null){
|
||||
getPlugin().getPluginLogger().info("Disabling Update Checker...");
|
||||
getPlugin().getPluginLogger().info("[-] Disabling Update Checker...");
|
||||
updateChecker.disable();
|
||||
}
|
||||
|
||||
getPlugin().getPluginLogger().info("AdvancedServerList disabled!");
|
||||
getPlugin().getPluginLogger().success("AdvancedServerList disabled!");
|
||||
}
|
||||
|
||||
public void clearFaviconCache(){
|
||||
@@ -117,66 +146,55 @@ public class AdvancedServerList<F>{
|
||||
}
|
||||
|
||||
private void load(){
|
||||
printBanner();
|
||||
resolveVersion();
|
||||
|
||||
getPlugin().getPluginLogger().info("Starting AdvancedServerList v%s...", version);
|
||||
getPlugin().getPluginLogger().info("Platform: " + plugin.getPlatformName() + " " + plugin.getPlatformVersion());
|
||||
|
||||
if(getFileHandler().loadConfig()){
|
||||
getPlugin().getPluginLogger().info("Successfully loaded config.yml!");
|
||||
}else{
|
||||
getPlugin().getPluginLogger().warn("Unable to load config.yml! Check previous lines for errors.");
|
||||
if(!getFileHandler().loadConfig()){
|
||||
getPlugin().getPluginLogger().failure("Unable to load <white>config.yml</white>! Check previous lines for errors.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(getFileHandler().isOldConfig()){
|
||||
getPlugin().getPluginLogger().info("Detected old config.yml. Attempting to migrate...");
|
||||
getPlugin().getPluginLogger().info("[-] Detected old <white>config.yml</white>. Attempting to migrate...");
|
||||
if(getFileHandler().migrateConfig()){
|
||||
getPlugin().getPluginLogger().info("Migration completed successfully!");
|
||||
getPlugin().getPluginLogger().success("Migration completed successfully!");
|
||||
}else{
|
||||
getPlugin().getPluginLogger().warn("Couldn't migrate config.yml! Check previous lines for errors.");
|
||||
getPlugin().getPluginLogger().failure("Couldn't migrate <white>config.yml</white>! Check previous lines for errors.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(getFileHandler().getBool(true, "printBanner")){
|
||||
printBanner();
|
||||
}
|
||||
|
||||
getPlugin().getPluginLogger().info("Platform: <white>%s</white>", plugin.getPlatformInfo());
|
||||
getPlugin().getPluginLogger().info("");
|
||||
|
||||
if(getFileHandler().loadProfiles()){
|
||||
getPlugin().getPluginLogger().info("Successfully loaded %d profile(s)!", getFileHandler().getProfiles().size());
|
||||
getPlugin().getPluginLogger().success("Successfully loaded <white>%d</white> profile(s)!", getFileHandler().getProfiles().size());
|
||||
}else{
|
||||
getPlugin().getPluginLogger().warn("Unable to load profiles! Check previous lines for errors.");
|
||||
getPlugin().getPluginLogger().failure("Unable to load profiles! Check previous lines for errors.");
|
||||
return;
|
||||
}
|
||||
|
||||
getPlugin().loadFaviconHandler(this);
|
||||
|
||||
getPlugin().getPluginLogger().info("Loading Commands...");
|
||||
plugin.loadCommands();
|
||||
getPlugin().getPluginLogger().info("Commands loaded!");
|
||||
|
||||
getPlugin().getPluginLogger().info("Loading events...");
|
||||
loadCommands();
|
||||
|
||||
plugin.loadEvents();
|
||||
getPlugin().getPluginLogger().info("Events loaded!");
|
||||
|
||||
getPlugin().getPluginLogger().info("Loading playercache.json...");
|
||||
getPlayerHandler().load();
|
||||
|
||||
getPlugin().getPluginLogger().info("Loading bStats metrics. Disable it in the global config under /plugins/bstats/");
|
||||
plugin.loadMetrics();
|
||||
getPlugin().getPluginLogger().info("Metrics loaded!");
|
||||
plugin.startScheduler();
|
||||
|
||||
getPlugin().getPluginLogger().info("AdvancedServerList is ready!");
|
||||
getPlugin().getPluginLogger().success("<green>AdvancedServerList is ready!");
|
||||
|
||||
if(getFileHandler().getBoolean("checkUpdates"))
|
||||
this.updateChecker = new UpdateChecker(this);
|
||||
}
|
||||
|
||||
private void printBanner(){
|
||||
getPlugin().getPluginLogger().info(" _____ _");
|
||||
getPlugin().getPluginLogger().info(" /\\ / ____| |");
|
||||
getPlugin().getPluginLogger().info(" / \\ | (___ | |");
|
||||
getPlugin().getPluginLogger().info(" / /\\ \\ \\___ \\| |");
|
||||
getPlugin().getPluginLogger().info(" / ____ \\ ____) | |____");
|
||||
getPlugin().getPluginLogger().info("/_/ \\_\\_____/|______|");
|
||||
getPlugin().getPluginLogger().info("<#3b90ff> __ _______ ___");
|
||||
getPlugin().getPluginLogger().info("<#3b90ff> /\\ \\ / ____|_| | |");
|
||||
getPlugin().getPluginLogger().info("<#3b90ff> / \\ \\ | (_(___ | | |");
|
||||
getPlugin().getPluginLogger().info("<#3b90ff> / /\\ \\ \\ \\___ \\ \\| | |");
|
||||
getPlugin().getPluginLogger().info("<#3b90ff> / ____ \\ \\ ____) | | |_|____");
|
||||
getPlugin().getPluginLogger().info("<#3b90ff>/_/_/ \\_\\_\\_____/_/|______|_|");
|
||||
getPlugin().getPluginLogger().info("");
|
||||
}
|
||||
|
||||
@@ -191,4 +209,78 @@ public class AdvancedServerList<F>{
|
||||
version = "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
private void addPlaceholder(PlaceholderProvider placeholderProvider){
|
||||
AdvancedServerList.getApi().addPlaceholderProvider(placeholderProvider);
|
||||
}
|
||||
|
||||
private void loadCommands(){
|
||||
getPlugin().loadFaviconHandler(this);
|
||||
|
||||
CommandManager<CmdSender> commandManager = plugin.getCommandManager();
|
||||
|
||||
commandManager.parameterInjectorRegistry().registerInjector(AdvancedServerList.class, ParameterInjector.constantInjector(this));
|
||||
|
||||
AnnotationParser<CmdSender> annotationParser = new AnnotationParser<>(commandManager, CmdSender.class);
|
||||
annotationParser.registerBuilderModifier(
|
||||
CommandType.class,
|
||||
(annotation, builder) -> builder.meta(CommandHandler.COMMAND_TYPE, annotation.value())
|
||||
);
|
||||
annotationParser.parse(new CommandHandler(commandManager));
|
||||
|
||||
for(String option : CommandHandler.PROFILE_OPTIONS){
|
||||
commandManager.command(
|
||||
commandManager.commandBuilder("advancedserverlist", "asl")
|
||||
.literal("profiles")
|
||||
.literal("set")
|
||||
.required(
|
||||
"profile",
|
||||
StringParser.stringParser(),
|
||||
Description.of("The profile to edit."),
|
||||
SuggestionProvider.suggesting(
|
||||
getFileHandler().getProfiles().stream()
|
||||
.map(ServerListProfile::file)
|
||||
.map(Suggestion::suggestion)
|
||||
.toList()
|
||||
)
|
||||
)
|
||||
.literal(option)
|
||||
.optional("value", descriptor(option), description(option))
|
||||
.commandDescription(Description.of("Sets or resets profile values."))
|
||||
.handler(context -> CommandHandler.handleSet(this, context))
|
||||
.meta(CommandHandler.OPTION, option)
|
||||
.permission(
|
||||
Permission.anyOf(
|
||||
Permission.permission("advancedserverlist.admin"),
|
||||
Permission.permission("advancedserverlist.command.profiles")
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
getPlugin().getPluginLogger().success("Loaded Command <white>/advancedserverlist</white>!");
|
||||
}
|
||||
|
||||
private ParserDescriptor<CmdSender, ?> descriptor(String option){
|
||||
return switch(option){
|
||||
case "playercount.hideplayers", "playercount.hideplayershover", "playercount.extraplayers.enabled",
|
||||
"playercount.maxplayers.enabled", "playercount.onlineplayers.enabled" -> BooleanParser.booleanParser();
|
||||
case "priority" -> IntegerParser.integerParser();
|
||||
default -> StringParser.greedyStringParser();
|
||||
};
|
||||
}
|
||||
|
||||
private Description description(String option){
|
||||
return switch(option){
|
||||
case "playercount.hideplayers", "playercount.hideplayershover", "playercount.extraplayers.enabled",
|
||||
"playercount.maxplayers.enabled", "playercount.onlineplayers.enabled" -> Description.of(
|
||||
"Whether this option should be enabled or not. Leave empty to unset it."
|
||||
);
|
||||
case "priority" -> Description.of("Priority this Profile should have. Leave empty to reset.");
|
||||
case "motd", "playercount.hover" -> Description.of(
|
||||
"Lines to set. Use \\n or <newline> to set a linebreak. Leave empty to reset."
|
||||
);
|
||||
default -> Description.of("The Value to use for this option. Leave empty to reset.");
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,8 @@ package ch.andre601.advancedserverlist.core.check;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
|
||||
import ch.andre601.advancedserverlist.core.objects.ValueCache;
|
||||
import com.google.gson.FieldNamingPolicy;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
@@ -40,6 +42,7 @@ import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executors;
|
||||
@@ -48,32 +51,66 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class UpdateChecker{
|
||||
|
||||
@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()
|
||||
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
|
||||
.setPrettyPrinting()
|
||||
.setLenient()
|
||||
.create();
|
||||
|
||||
private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(new UpdateCheckThread());
|
||||
|
||||
private final ValueCache<CompletableFuture<ModrinthVersion>> cache = new ValueCache<>(Duration.ofMinutes(5));
|
||||
|
||||
private final AdvancedServerList<?> core;
|
||||
private final PluginLogger logger;
|
||||
private final String loader;
|
||||
private final HttpClient client;
|
||||
|
||||
public UpdateChecker(AdvancedServerList<?> core){
|
||||
this.core = core;
|
||||
this.logger = core.getPlugin().getPluginLogger();
|
||||
this.loader = core.getPlugin().getLoader();
|
||||
this.client = HttpClient.newBuilder().executor(Executors.newSingleThreadExecutor(new UpdateCheckThread())).build();
|
||||
|
||||
startUpdateChecker();
|
||||
}
|
||||
|
||||
public void performCachedUpdateCheck(CmdSender sender){
|
||||
CompletableFuture<ModrinthVersion> modrinthVersion = cache.get(this::performUpdateCheck);
|
||||
|
||||
modrinthVersion.whenComplete((version, throwable) -> {
|
||||
if(throwable != null){
|
||||
logger.warn("Encountered an Exception while checking for an update!", throwable);
|
||||
sender.sendErrorMsg("There was an exception while checking for an update. Please check the console for details.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(version == null)
|
||||
return;
|
||||
|
||||
int result = version.compare(core.getVersion());
|
||||
if(result == -1){
|
||||
sender.sendPrefixedMsg("<green>A new Version of AdvancedServerList is available!");
|
||||
sender.sendPrefixedMsg("<green>Your version: <white>%s", core.getVersion());
|
||||
sender.sendPrefixedMsg("<green>Version on Modrinth: <white>%s", version.versionNumber());
|
||||
sender.sendPrefixedMsg(
|
||||
"<click:open_url:'https://modrinth.com/plugin/advancedserverlist/version/%s'>" +
|
||||
"<green>[<white>Download Page</white>]" +
|
||||
"</click>",
|
||||
version.id()
|
||||
);
|
||||
}else
|
||||
if(result == 1){
|
||||
sender.sendPrefixedMsg(
|
||||
"Your version (<white>%</white>) is newer than what is available on Modrinth (<white>%s</white>).",
|
||||
core.getVersion(),
|
||||
version.versionNumber()
|
||||
);
|
||||
sender.sendPrefixedMsg("Are you using a Development Version?");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void disable(){
|
||||
executor.shutdown();
|
||||
try{
|
||||
@@ -90,11 +127,11 @@ public class UpdateChecker{
|
||||
|
||||
private void startUpdateChecker(){
|
||||
executor.scheduleAtFixedRate(() -> {
|
||||
logger.info("Looking for an update...");
|
||||
logger.info("[-] Looking for an update...");
|
||||
|
||||
performUpdateCheck().whenComplete((version, throwable) -> {
|
||||
if(version == null || throwable != null){
|
||||
logger.warn("Failed to look for any updates. Check previous messages for causes.");
|
||||
logger.failure("Failed to look for any updates. Check previous messages for causes.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -103,18 +140,26 @@ public class UpdateChecker{
|
||||
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()
|
||||
);
|
||||
case 0 -> logger.success("You are running the latest version!");
|
||||
case 1 -> {
|
||||
logger.info(
|
||||
"[?] Your version (<white>%s</white>) is newer than what is available on Modrint (<white>%s</white>).",
|
||||
core.getVersion(),
|
||||
version.versionNumber()
|
||||
);
|
||||
logger.info(" Are you using a Development Version?");
|
||||
}
|
||||
}
|
||||
});
|
||||
}, 0L, 12L, TimeUnit.HOURS);
|
||||
}
|
||||
|
||||
private CompletableFuture<ModrinthVersion> performUpdateCheck(){
|
||||
String finalUrl = String.format(url, loader);
|
||||
String finalUrl = String.format(
|
||||
// 'https://api.modrinth.com/v2/project/advancedserverlist/version?loaders=["%s"]' URL encoded.
|
||||
"https://api.modrinth.com/v2/project/advancedserverlist/version?loaders=%%5B%%22%s%%22%%5D",
|
||||
loader
|
||||
);
|
||||
|
||||
logger.debug(UpdateChecker.class, "Checking '%s' for updates...", finalUrl);
|
||||
|
||||
@@ -127,6 +172,7 @@ public class UpdateChecker{
|
||||
try{
|
||||
request = HttpRequest.newBuilder()
|
||||
.uri(new URI(finalUrl))
|
||||
.timeout(Duration.ofSeconds(5))
|
||||
.header("User-Agent", "AdvancedServerList-" + loader + "/" + core.getVersion())
|
||||
.build();
|
||||
}catch(URISyntaxException ex){
|
||||
@@ -144,22 +190,22 @@ public class UpdateChecker{
|
||||
}
|
||||
|
||||
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: %s", version.versionNumber());
|
||||
logger.info("");
|
||||
logger.warn("=======================================================================");
|
||||
logger.warn("You are running an outdated version of AdvancedServerList!");
|
||||
logger.warn("");
|
||||
logger.warn("Your version: <white>%s</white>", core.getVersion());
|
||||
logger.warn("Modrinth: <white>%s</white>", version.versionNumber());
|
||||
logger.warn("");
|
||||
|
||||
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.warn("<bold>WARNING!</bold>");
|
||||
logger.warn("This is a %s version and may contain breaking changes and/or bugs!", version.versionType());
|
||||
logger.warn("");
|
||||
}
|
||||
|
||||
logger.info("Download the latest version from here:");
|
||||
logger.info("https://modrinth.com/plugin/advancedserverlist/version/%s", version.id());
|
||||
logger.info("==================================================================");
|
||||
logger.warn("Download the latest version from here:");
|
||||
logger.warn("<white>https://modrinth.com/plugin/advancedserverlist/version/%s</white>", version.id());
|
||||
logger.warn("=======================================================================");
|
||||
}
|
||||
|
||||
public record ModrinthVersion(String id, String versionNumber, String versionType){
|
||||
@@ -171,10 +217,5 @@ public class UpdateChecker{
|
||||
public int compare(String version){
|
||||
return FlexVerComparator.compare(version, versionNumber());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
return String.format("ModrinthVersion{id=%s,versionNumber=%s,versionType=%s}", id, versionNumber, versionType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2025 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.commands;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.NullBool;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class ProfileOptionsSender{
|
||||
|
||||
private final List<OptionStringBuilder> builders = new ArrayList<>();
|
||||
private final String file;
|
||||
|
||||
public ProfileOptionsSender(String file){
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public ProfileOptionsSender append(OptionStringBuilder builder){
|
||||
this.builders.add(builder.file(file));
|
||||
return this;
|
||||
}
|
||||
|
||||
public void send(CmdSender sender){
|
||||
sender.sendMsg();
|
||||
sender.sendPrefixedMsg("Profile Info [<white>%s</white>]", file);
|
||||
for(OptionStringBuilder builder : builders){
|
||||
sender.sendMsg(builder.build());
|
||||
}
|
||||
sender.sendMsg();
|
||||
sender.sendMsg("[<grey>Hover for info, click for command</grey>]");
|
||||
sender.sendMsg();
|
||||
}
|
||||
|
||||
public static class OptionStringBuilder{
|
||||
|
||||
public static OptionStringBuilder of(String displayName, String hover){
|
||||
return new OptionStringBuilder(displayName)
|
||||
.hover(hover == null || hover.isEmpty() ? "<i>Not set</i>" : hover)
|
||||
.color(hover == null || hover.isEmpty() ? ColorName.RED : ColorName.GREEN);
|
||||
}
|
||||
|
||||
public static OptionStringBuilder of(String displayName, List<String> hover){
|
||||
return new OptionStringBuilder(displayName)
|
||||
.hover(hover == null || hover.isEmpty() ? "<i>Not set</i>" : String.join("\n<reset>", hover))
|
||||
.color(hover == null || hover.isEmpty() ? ColorName.RED : ColorName.GREEN);
|
||||
}
|
||||
|
||||
public static OptionStringBuilder of(String displayName, NullBool hover){
|
||||
return new OptionStringBuilder(displayName)
|
||||
.hover(hover == null || !hover.getOrDefault(false) ? "<red>Disabled</red>" : "<green>Enabled</green>")
|
||||
.color(hover == null || !hover.getOrDefault(false) ? ColorName.RED : ColorName.GREEN);
|
||||
}
|
||||
|
||||
public static OptionStringBuilder of(String displayName, int hover){
|
||||
return new OptionStringBuilder(displayName)
|
||||
.hover(String.valueOf(hover));
|
||||
}
|
||||
|
||||
public static OptionStringBuilder of(String displayName){
|
||||
return new OptionStringBuilder(displayName).hover(null);
|
||||
}
|
||||
|
||||
private final String displayName;
|
||||
private String file = null;
|
||||
private String prefix = "├─";
|
||||
private ColorName color = ColorName.AQUA;
|
||||
private String hover = "<i>Not set</i>";
|
||||
private String option = null;
|
||||
|
||||
private OptionStringBuilder(String displayName){
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public OptionStringBuilder file(String file){
|
||||
this.file = file;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OptionStringBuilder prefix(String prefix){
|
||||
this.prefix = prefix;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OptionStringBuilder color(ColorName color){
|
||||
this.color = color;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OptionStringBuilder hover(String hover){
|
||||
this.hover = hover;
|
||||
return this;
|
||||
}
|
||||
|
||||
public OptionStringBuilder option(String option){
|
||||
this.option = option;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String build(){
|
||||
StringBuilder builder = new StringBuilder("<grey>")
|
||||
.append(prefix)
|
||||
.append(" <white>[")
|
||||
.append('<')
|
||||
.append(color)
|
||||
.append('>');
|
||||
|
||||
if(hover != null && !hover.isEmpty()){
|
||||
builder.append("<hover:show_text:\"")
|
||||
.append(hover)
|
||||
.append("\">");
|
||||
}
|
||||
|
||||
if(option != null && !option.isEmpty() && file != null && !file.isEmpty()){
|
||||
builder.append("<click:suggest_command:/asl profiles set ")
|
||||
.append(file)
|
||||
.append(" ")
|
||||
.append(option)
|
||||
.append(" >");
|
||||
}
|
||||
|
||||
builder.append(displayName);
|
||||
|
||||
if(option != null && !option.isEmpty())
|
||||
builder.append("</click>");
|
||||
|
||||
if(hover != null && !hover.isEmpty())
|
||||
builder.append("</hover>");
|
||||
|
||||
builder.append("</")
|
||||
.append(color)
|
||||
.append(">]</white></grey>");
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
enum ColorName{
|
||||
RED,
|
||||
GREEN,
|
||||
AQUA;
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
return this.name().toLowerCase(Locale.ROOT);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package ch.andre601.advancedserverlist.core.compat.maintenance;
|
||||
|
||||
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.AdvancedServerList;
|
||||
|
||||
public class MaintenancePlaceholder extends PlaceholderProvider{
|
||||
|
||||
private final AdvancedServerList<?> plugin;
|
||||
|
||||
public MaintenancePlaceholder(AdvancedServerList<?> plugin){
|
||||
super("maintenance");
|
||||
|
||||
this.plugin = plugin;
|
||||
}
|
||||
@Override
|
||||
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
|
||||
if(!placeholder.equals("maintenanceEnabled") || !plugin.getPlugin().isPluginEnabled("Maintenance"))
|
||||
return null;
|
||||
|
||||
return String.valueOf(MaintenanceUtil.get().isMaintenanceEnabled());
|
||||
}
|
||||
}
|
||||
@@ -30,12 +30,21 @@ import eu.kennytv.maintenance.api.MaintenanceProvider;
|
||||
|
||||
public class MaintenanceUtil{
|
||||
|
||||
private static MaintenanceUtil instance;
|
||||
|
||||
private final Maintenance api;
|
||||
|
||||
public MaintenanceUtil(){
|
||||
private MaintenanceUtil(){
|
||||
this.api = MaintenanceProvider.get();
|
||||
}
|
||||
|
||||
public static MaintenanceUtil get(){
|
||||
if(instance != null)
|
||||
return instance;
|
||||
|
||||
return (instance = new MaintenanceUtil());
|
||||
}
|
||||
|
||||
public boolean isMaintenanceEnabled(){
|
||||
return api.isMaintenance();
|
||||
}
|
||||
|
||||
@@ -25,31 +25,42 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.core.compat.papi;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.objects.ValueCache;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
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.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
public class PAPIUtil{
|
||||
|
||||
private static PAPIUtil instance;
|
||||
|
||||
private final ValueCache<CompletableFuture<Set<String>>> serversCache = new ValueCache<>(Duration.ofSeconds(10));
|
||||
private final Cache<UUID, CompletableFuture<String>> textCache = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(Duration.ofSeconds(10))
|
||||
.build();
|
||||
private final PlaceholderAPI papi;
|
||||
|
||||
private final PAPICache cache = new PAPICache();
|
||||
|
||||
public PAPIUtil(){
|
||||
private PAPIUtil(){
|
||||
this.papi = PlaceholderAPI.createInstance();
|
||||
}
|
||||
|
||||
public static PAPIUtil get(){
|
||||
if(instance != null)
|
||||
return instance;
|
||||
|
||||
return (instance = new PAPIUtil());
|
||||
}
|
||||
|
||||
// Make sure the version of PAPIProxyBridge we get has the required methods we need...
|
||||
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||
public boolean isCompatible(){
|
||||
try{
|
||||
papi.getClass().getMethod("findServers");
|
||||
papi.getClass().getMethod("getServers");
|
||||
return true;
|
||||
}catch(NoSuchMethodException ex){
|
||||
return false;
|
||||
@@ -57,19 +68,11 @@ public class PAPIUtil{
|
||||
}
|
||||
|
||||
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);
|
||||
});
|
||||
Set<String> values = serversCache.get(papi::getServers).getNow(Collections.emptySet());
|
||||
if(values.isEmpty())
|
||||
return null;
|
||||
|
||||
return List.copyOf(values).get(0);
|
||||
}
|
||||
|
||||
public <P> P getPlayer(Collection<P> players){
|
||||
@@ -81,9 +84,8 @@ public class PAPIUtil{
|
||||
|
||||
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 textCache.get(player, () -> papi.formatPlaceholders(text, carrier, player)).getNow(text);
|
||||
}catch(ExecutionException ex){
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,6 @@ 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;
|
||||
@@ -38,12 +36,13 @@ import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
|
||||
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
|
||||
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileManager;
|
||||
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.JoinConfiguration;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PingEventHandler{
|
||||
|
||||
private static PAPIUtil papiUtil = null;
|
||||
private static MaintenanceUtil maintenanceUtil = null;
|
||||
|
||||
public static <F, P extends GenericPlayer> ProfileEntry handleEvent(GenericEventWrapper<F, P> event){
|
||||
event.getPlugin().getPluginLogger().debug(PingEventHandler.class, "Received ping event. Handling it...");
|
||||
if(event.isInvalidProtocol()){
|
||||
@@ -75,61 +74,98 @@ public class PingEventHandler{
|
||||
|
||||
logger.debug(PingEventHandler.class, "Received valid Server List Profile. Calling PreServerListSetEvent...");
|
||||
|
||||
GenericServerListEvent e = event.callEvent(ProfileManager.merge(profile));
|
||||
if(e == null || e.isCancelled()){
|
||||
GenericServerListEvent slEvent = event.callEvent(ProfileManager.merge(profile));
|
||||
if(slEvent == null || slEvent.isCancelled()){
|
||||
logger.debug(PingEventHandler.class, "PreServerListSetEvent was cancelled. Stopping ping handling...");
|
||||
return null;
|
||||
}
|
||||
|
||||
logger.debug(PingEventHandler.class, "PreServerListSetEvent completed. Proceeding with ping handling...");
|
||||
|
||||
ProfileEntry entry = e.getEntry();
|
||||
ProfileEntry entry = slEvent.getEntry();
|
||||
if(entry.isInvalid()){
|
||||
logger.debugWarn(PingEventHandler.class, "No valid ProfileEntry retrieved. Cancelling ping handling...");
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean extraPlayers = ProfileManager.checkOption(entry.extraPlayersEnabled());
|
||||
|
||||
if(extraPlayers && ignoreMaintenance(event, "extraPlayers")){
|
||||
max = online + (entry.extraPlayersCount() == null ? 0 : entry.extraPlayersCount());
|
||||
if(ProfileManager.checkOption(entry.onlinePlayersEnabled()) && ignoreMaintenance(event, "onlinePlayers")){
|
||||
logger.debug(PingEventHandler.class, "'playerCount -> onlinePlayers -> enabled' option is true. Trying to apply '%s'...", entry.onlinePlayersCount());
|
||||
String onlinePlayers = ComponentParser.text(entry.onlinePlayersCount())
|
||||
.modifyText(text -> StringReplacer.replace(text, player, server))
|
||||
.modifyText(text -> event.parsePAPIPlaceholders(text, player))
|
||||
.toString();
|
||||
|
||||
logger.debug(PingEventHandler.class, "Extra Players enabled. Applying '%d' as max player count...", max);
|
||||
|
||||
event.setMaxPlayers(max);
|
||||
try{
|
||||
online = onlinePlayers == null ? online : Integer.parseInt(onlinePlayers);
|
||||
event.setOnlinePlayers(online);
|
||||
}catch(NumberFormatException ex){
|
||||
logger.warn("Option 'playerCount -> onlinePlayers -> amount' is not a valid Number!");
|
||||
}
|
||||
}
|
||||
|
||||
if(ProfileManager.checkOption(entry.maxPlayersEnabled()) && !extraPlayers && ignoreMaintenance(event, "maxPlayers")){
|
||||
max = (entry.maxPlayersCount() == null) ? 0 : entry.maxPlayersCount();
|
||||
boolean extraPlayersEnabled = ProfileManager.checkOption(entry.extraPlayersEnabled());
|
||||
|
||||
if(extraPlayersEnabled && ignoreMaintenance(event, "extraPlayers")){
|
||||
logger.debug(PingEventHandler.class, "'playerCount -> extraPlayers -> enabled' option is true. Trying to apply '%s'...", entry.extraPlayersCount());
|
||||
String extraPlayers = ComponentParser.text(entry.extraPlayersCount())
|
||||
.modifyText(text -> StringReplacer.replace(text, player, server))
|
||||
.modifyText(text -> event.parsePAPIPlaceholders(text, player))
|
||||
.toString();
|
||||
|
||||
logger.debug(PingEventHandler.class, "Max Players enabled. Applying '%d' as max player count...", max);
|
||||
try{
|
||||
max = online + (extraPlayers == null ? 0 : Integer.parseInt(extraPlayers));
|
||||
|
||||
logger.debug(PingEventHandler.class, "'playerCount -> extraPlayers -> amount' is a valid number. Applying it...");
|
||||
event.setMaxPlayers(max);
|
||||
}catch(NumberFormatException ex){
|
||||
logger.warn("Option 'playerCount -> extraPlayers -> amount' is not a valid Number!");
|
||||
}
|
||||
}
|
||||
|
||||
if(ProfileManager.checkOption(entry.maxPlayersEnabled()) && !extraPlayersEnabled && ignoreMaintenance(event, "maxPlayers")){
|
||||
logger.debug(PingEventHandler.class, "'playerCount -> maxPlayers -> enabled' option is true. Trying to apply '%s'...", entry.maxPlayersCount());
|
||||
String maxPlayers = ComponentParser.text(entry.maxPlayersCount())
|
||||
.modifyText(text -> StringReplacer.replace(text, player, server))
|
||||
.modifyText(text -> event.parsePAPIPlaceholders(text, player))
|
||||
.toString();
|
||||
|
||||
event.setMaxPlayers(max);
|
||||
try{
|
||||
max = maxPlayers == null ? 0 : Integer.parseInt(maxPlayers);
|
||||
|
||||
logger.debug(PingEventHandler.class, "'playerCount -> maxPlayers -> amount' is a valid number. Applying it...");
|
||||
event.setMaxPlayers(max);
|
||||
}catch(NumberFormatException ex){
|
||||
logger.warn("Option 'playerCount -> maxPlayers -> amount' is not a valid Number!");
|
||||
}
|
||||
}
|
||||
|
||||
GenericServer finalServer = event.createGenericServer(online, max, host);
|
||||
|
||||
if(ProfileManager.checkOption(entry.motd()) && ignoreMaintenance(event, "motd")){
|
||||
logger.debug(PingEventHandler.class, "MOTD set. Applying '%s'...", String.join("\\n", entry.motd()));
|
||||
logger.debug(PingEventHandler.class, "'motd' option present. Applying ['%s']...", String.join("', '", entry.motd()));
|
||||
|
||||
event.setMotd(
|
||||
ComponentParser.list(entry.motd())
|
||||
List<Component> motd = entry.motd().stream()
|
||||
.map(line -> ComponentParser.text(line)
|
||||
.modifyText(text -> StringReplacer.replace(text, player, finalServer))
|
||||
.modifyText(text -> event.parsePAPIPlaceholders(text, player))
|
||||
.modifyText(text -> plugin.getCore().getTextCenterUtil().getCenteredText(text))
|
||||
.toComponent()
|
||||
);
|
||||
)
|
||||
.toList();
|
||||
|
||||
event.setMotd(Component.join(JoinConfiguration.separator(Component.newline()), motd));
|
||||
}
|
||||
|
||||
boolean hidePlayers = ProfileManager.checkOption(entry.hidePlayersEnabled());
|
||||
|
||||
if(hidePlayers && ignoreMaintenance(event, "hidePlayers")){
|
||||
logger.debug(PingEventHandler.class, "Hide Players enabled. Hiding player count...");
|
||||
if(hidePlayers && ignoreMaintenance(event, "hidePlayers") && ignoreMaintenance(event, "hidePlayersHover")){
|
||||
logger.debug(PingEventHandler.class, "'playerCount -> hidePlayers' enabled. Hiding player count...");
|
||||
|
||||
event.hidePlayers();
|
||||
}
|
||||
|
||||
if(ProfileManager.checkOption(entry.playerCountText()) && !hidePlayers && ignoreMaintenance(event, "playerCountText")){
|
||||
logger.debug(PingEventHandler.class, "Player Count Text set. Applying '%s'...", entry.playerCountText());
|
||||
logger.debug(PingEventHandler.class, "'playerCount -> text' option set. Applying '%s'...", entry.playerCountText());
|
||||
|
||||
event.setPlayerCount(
|
||||
ComponentParser.text(entry.playerCountText())
|
||||
@@ -139,14 +175,20 @@ public class PingEventHandler{
|
||||
);
|
||||
}
|
||||
|
||||
if(ProfileManager.checkOption(entry.players()) && !hidePlayers && ignoreMaintenance(event, "playerCountHover")){
|
||||
logger.debug(PingEventHandler.class, "Player Count Hover set. Applying '%s'...", String.join("\\n", entry.players()));
|
||||
boolean hidePlayersHover = ProfileManager.checkOption(entry.hidePlayersHoverEnabled());
|
||||
if(hidePlayersHover){
|
||||
logger.debug(PingEventHandler.class, "'playerCount -> hidePlayersHover' option set. Hiding Player Hover...");
|
||||
event.setPlayersHidden();
|
||||
}
|
||||
|
||||
if(ProfileManager.checkOption(entry.players()) && !hidePlayers && !hidePlayersHover && ignoreMaintenance(event, "playerCountHover")){
|
||||
logger.debug(PingEventHandler.class, "'playerCount -> hover' option set. Applying ['%s']...", String.join("', '", entry.players()));
|
||||
|
||||
event.setPlayers(entry.players(), player, server);
|
||||
}
|
||||
|
||||
if(ProfileManager.checkOption(entry.favicon()) && ignoreMaintenance(event, "favicon")){
|
||||
logger.debug(PingEventHandler.class, "Favicon set. Resolving '%s'...", entry.favicon());
|
||||
logger.debug(PingEventHandler.class, "'favicon' option set. Resolving '%s'...", entry.favicon());
|
||||
|
||||
String faviconString = StringReplacer.replace(entry.favicon(), player, server);
|
||||
|
||||
@@ -169,20 +211,6 @@ public class PingEventHandler{
|
||||
return entry;
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
private static <F, P extends GenericPlayer> boolean ignoreMaintenance(GenericEventWrapper<F, P> event, String option){
|
||||
if(!event.isMaintenanceModeActive())
|
||||
return true;
|
||||
|
||||
@@ -46,13 +46,46 @@ public class ConfigMigrator{
|
||||
public static ConfigurationTransformation.Versioned create(){
|
||||
return ConfigurationTransformation.versionedBuilder()
|
||||
.versionKey("configVersion")
|
||||
.addVersion(LATEST, fourToFive())
|
||||
.addVersion(LATEST, sevenToEight())
|
||||
.addVersion(7, sixToSeven())
|
||||
.addVersion(6, fiveToSix())
|
||||
.addVersion(5, fourToFive())
|
||||
.addVersion(4, threeToFour())
|
||||
.addVersion(3, twoToThree())
|
||||
.addVersion(2, oneToTwo())
|
||||
.build();
|
||||
}
|
||||
|
||||
public static ConfigurationTransformation sevenToEight(){
|
||||
return ConfigurationTransformation.builder()
|
||||
.addAction(NodePath.path("disableDuringMaintenance"), (path, value) -> {
|
||||
value.node("hidePlayersHover").set(true);
|
||||
|
||||
return null;
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
public static ConfigurationTransformation sixToSeven(){
|
||||
return ConfigurationTransformation.builder()
|
||||
.addAction(NodePath.path(), (path, value) -> {
|
||||
value.node("printBanner").set(true);
|
||||
|
||||
return null;
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
public static ConfigurationTransformation fiveToSix(){
|
||||
return ConfigurationTransformation.builder()
|
||||
.addAction(NodePath.path("disableDuringMaintenance"), (path, value) -> {
|
||||
value.node("onlinePlayers").set(true);
|
||||
|
||||
return null;
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
public static ConfigurationTransformation fourToFive(){
|
||||
return ConfigurationTransformation.builder()
|
||||
.addAction(NodePath.path(), (path, value) -> {
|
||||
@@ -111,7 +144,7 @@ public class ConfigMigrator{
|
||||
versioned.apply(node);
|
||||
final int endVersion = versioned.version(node);
|
||||
if(startVersion < endVersion)
|
||||
logger.info("Migrated config.yml from v" + startVersion + " to v" + endVersion);
|
||||
logger.success("Successfully migrated config from <white>v%d</white> to <white>v%d</white>", startVersion, endVersion);
|
||||
}
|
||||
|
||||
return node;
|
||||
|
||||
@@ -72,7 +72,6 @@ public class FileHandler{
|
||||
}
|
||||
|
||||
public boolean loadConfig(){
|
||||
logger.info("Loading config.yml...");
|
||||
File folder = plugin.getPlugin().getFolderPath().toFile();
|
||||
if(!folder.exists() && !folder.mkdirs()){
|
||||
logger.warn("Couldn't create folder for plugin. Is it missing Write permissions?");
|
||||
@@ -87,7 +86,7 @@ public class FileHandler{
|
||||
}
|
||||
|
||||
Files.copy(stream, config);
|
||||
logger.info("Created new config.yml!");
|
||||
logger.success("Created new config.yml!");
|
||||
}catch(IOException ex){
|
||||
logger.warn("Cannot create config.yml for plugin.", ex);
|
||||
return false;
|
||||
@@ -98,24 +97,37 @@ public class FileHandler{
|
||||
}
|
||||
|
||||
public boolean loadProfiles(){
|
||||
logger.info("Loading profiles...");
|
||||
if(!profilesFolder.toFile().exists() && profilesFolder.toFile().mkdirs()){
|
||||
logger.info("Successfully created profiles folder.");
|
||||
|
||||
try(InputStream stream = plugin.getClass().getResourceAsStream("/profiles/default.yml")){
|
||||
if(stream == null){
|
||||
logger.warn("Cannot retrieve default.yml from Plugin.");
|
||||
return false;
|
||||
}
|
||||
|
||||
Files.copy(stream, profilesFolder.resolve("default.yml"));
|
||||
}catch(IOException ex){
|
||||
logger.warn("Cannot create default.yml for plugin.", ex);
|
||||
return false;
|
||||
}
|
||||
logger.info("[-] Loading profiles...");
|
||||
|
||||
if(createFile("default.yml")){
|
||||
return reloadProfiles();
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean createFile(String name){
|
||||
if(Files.notExists(profilesFolder) && profilesFolder.toFile().mkdirs()){
|
||||
logger.debugSuccess(FileHandler.class, "Successfully created profiles folder.");
|
||||
}
|
||||
|
||||
return reloadProfiles();
|
||||
File file = new File(profilesFolder.toFile(), name);
|
||||
if(file.exists()){
|
||||
return true;
|
||||
}
|
||||
|
||||
try(InputStream stream = plugin.getClass().getResourceAsStream("/profiles/default.yml")){
|
||||
if(stream == null){
|
||||
logger.warn("Cannot retrieve content of internal default.yml file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
Files.copy(stream, profilesFolder.resolve(name));
|
||||
return true;
|
||||
}catch(IOException ex){
|
||||
logger.warn("Encountered IOException while trying to create file <white>%s</white>", ex, name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean migrateConfig(){
|
||||
@@ -147,7 +159,7 @@ public class FileHandler{
|
||||
|
||||
File[] files = profilesFolder.toFile().listFiles(((dir, name) -> name.endsWith(".yml")));
|
||||
if(files == null || files.length == 0){
|
||||
logger.warn("Cannot load files from profiles folder! No valid YAML files present.");
|
||||
logger.failure("Cannot load files from profiles folder! No valid YAML files present.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -157,11 +169,11 @@ public class FileHandler{
|
||||
continue;
|
||||
|
||||
profiles.add(ServerListProfile.Builder.resolve(file.getName(), tmp, logger).build());
|
||||
logger.info("Loaded '%s'!", file.getName());
|
||||
logger.debugSuccess(FileHandler.class, "Loaded '<white>%s</white>'!", file.getName());
|
||||
}
|
||||
|
||||
if(profiles.isEmpty()){
|
||||
logger.warn("Couldn't load any profile from profiles folder!");
|
||||
logger.failure("Couldn't load any profile from profiles folder!");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -178,7 +190,7 @@ public class FileHandler{
|
||||
try{
|
||||
return loader.load();
|
||||
}catch(IOException ex){
|
||||
logger.warn("Cannot load '%s' due to an IOException!", ex, path.toFile().getName());
|
||||
logger.warn("Cannot load '<white>%s</white>' due to an IOException!", ex, path.toFile().getName());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -205,11 +217,11 @@ public class FileHandler{
|
||||
}
|
||||
|
||||
private boolean makeBackup(){
|
||||
logger.info("Making backup of old config.yml...");
|
||||
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!");
|
||||
logger.failure("Cannot create backups folder for migration!");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -218,16 +230,16 @@ public class FileHandler{
|
||||
File configBackup = new File(backups, "config_" + date.replace(":", "_") + ".yml");
|
||||
try{
|
||||
if(!configBackup.exists() && !configBackup.createNewFile()){
|
||||
logger.warn("Cannot create backup file for config.yml!");
|
||||
logger.failure("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());
|
||||
logger.success("Saved backup as '<white>%s</white>'!", configBackup.getName());
|
||||
|
||||
return true;
|
||||
}catch(IOException ex){
|
||||
logger.warn("Encountered IOException while trying to create a backup.", ex);
|
||||
logger.failure("Encountered IOException while trying to create a backup.", ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,10 +27,18 @@ package ch.andre601.advancedserverlist.core.interfaces;
|
||||
|
||||
public interface PluginLogger{
|
||||
|
||||
default void debugSuccess(Class<?> clazz, String msg, Object... args){
|
||||
debug(clazz, "[<green>✓</green>] " + msg, args);
|
||||
}
|
||||
|
||||
void debug(Class<?> clazz, String msg, Object... args);
|
||||
|
||||
void debugWarn(Class<?> clazz, String msg, Object... args);
|
||||
|
||||
default void success(String msg, Object... args){
|
||||
info("[<green>✓</green>] " + msg, args);
|
||||
}
|
||||
|
||||
void info(String msg, Object... args);
|
||||
|
||||
void warn(String msg, Object... args);
|
||||
@@ -38,4 +46,8 @@ public interface PluginLogger{
|
||||
void warn(String msg, Throwable throwable);
|
||||
|
||||
void warn(String msg, Throwable throwable, Object... args);
|
||||
|
||||
default void failure(String msg, Object... args){
|
||||
warn("[<red>x</red>] " + msg, args);
|
||||
}
|
||||
}
|
||||
@@ -25,12 +25,12 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.core.interfaces.commands;
|
||||
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
|
||||
public interface CmdSender{
|
||||
|
||||
String prefix = "<grey>[<gradient:aqua:white>AdvancedServerList</gradient>] ";
|
||||
String errorPrefix = "<grey>[<gradient:dark_red:red>AdvancedServerList</gradient>] ";
|
||||
|
||||
boolean hasPermission(String permission);
|
||||
String prefix = "<grey>[<aqua>ASL</aqua>] ";
|
||||
String errorPrefix = "<grey>[<red>ASL</red>] ";
|
||||
|
||||
void sendMsg(String msg, Object... args);
|
||||
|
||||
@@ -45,4 +45,8 @@ public interface CmdSender{
|
||||
default void sendErrorMsg(String msg, Object... args){
|
||||
sendMsg(errorPrefix + msg, args);
|
||||
}
|
||||
|
||||
Audience audience();
|
||||
|
||||
boolean isPlayer();
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
* Copyright (c) 2022-2025 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
|
||||
@@ -20,24 +20,15 @@
|
||||
* 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.velocity.commands;
|
||||
package ch.andre601.advancedserverlist.core.interfaces.commands;
|
||||
|
||||
import ch.andre601.advancedserverlist.velocity.VelocityCore;
|
||||
import com.velocitypowered.api.command.SimpleCommand;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
import org.incendo.cloud.SenderMapper;
|
||||
|
||||
public class CmdAdvancedServerList implements SimpleCommand{
|
||||
public interface CommandManagerInterface<S>{
|
||||
CommandManager<CmdSender> commandHandler();
|
||||
|
||||
private final VelocityCore plugin;
|
||||
|
||||
public CmdAdvancedServerList(VelocityCore plugin){
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Invocation invocation){
|
||||
plugin.getCore().getCommandHandler().handle(new VelocityCmdSender(invocation.source()), invocation.arguments());
|
||||
}
|
||||
SenderMapper<S, CmdSender> senderMapper();
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
* Copyright (c) 2022-2025 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
|
||||
@@ -20,28 +20,22 @@
|
||||
* 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;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
public abstract class PluginCommand{
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||
public @interface CommandType{
|
||||
Type value();
|
||||
|
||||
private final String argument;
|
||||
|
||||
public PluginCommand(String argument){
|
||||
this.argument = argument;
|
||||
enum Type{
|
||||
ALL,
|
||||
PLAYER_ONLY
|
||||
}
|
||||
|
||||
public String getArgument(){
|
||||
return argument;
|
||||
}
|
||||
|
||||
public String getPermission(){
|
||||
return "advancedserverlist.command." + getArgument().toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
public abstract void handle(CmdSender sender);
|
||||
}
|
||||
@@ -27,15 +27,15 @@ package ch.andre601.advancedserverlist.core.interfaces.core;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import ch.andre601.advancedserverlist.core.profiles.favicon.FaviconHandler;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
|
||||
import ch.andre601.advancedserverlist.core.profiles.handlers.FaviconHandler;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public interface PluginCore<F>{
|
||||
|
||||
void loadCommands();
|
||||
|
||||
void loadEvents();
|
||||
|
||||
void loadMetrics();
|
||||
@@ -44,6 +44,10 @@ public interface PluginCore<F>{
|
||||
|
||||
void clearFaviconCache();
|
||||
|
||||
void downloadLibrary(String groupId, String artifactId, String version);
|
||||
|
||||
void startScheduler();
|
||||
|
||||
AdvancedServerList<F> getCore();
|
||||
|
||||
Path getFolderPath();
|
||||
@@ -52,12 +56,14 @@ public interface PluginCore<F>{
|
||||
|
||||
FaviconHandler<F> getFaviconHandler();
|
||||
|
||||
String getPlatformName();
|
||||
CommandManager<CmdSender> getCommandManager();
|
||||
|
||||
String getPlatformVersion();
|
||||
String getPlatformInfo();
|
||||
|
||||
String getLoader();
|
||||
|
||||
boolean isPluginEnabled(String plugin);
|
||||
|
||||
F createFavicon(BufferedImage image) throws Exception;
|
||||
|
||||
default boolean isDebugEnabled(){
|
||||
|
||||
@@ -42,6 +42,8 @@ public interface GenericEventWrapper<F, P extends GenericPlayer>{
|
||||
|
||||
void setMaxPlayers(int maxPlayers);
|
||||
|
||||
void setOnlinePlayers(int onlinePlayers);
|
||||
|
||||
void setMotd(Component component);
|
||||
|
||||
void hidePlayers();
|
||||
@@ -50,6 +52,8 @@ public interface GenericEventWrapper<F, P extends GenericPlayer>{
|
||||
|
||||
void setPlayers(List<String> players, P player, GenericServer server);
|
||||
|
||||
void setPlayersHidden();
|
||||
|
||||
void setFavicon(F favicon);
|
||||
|
||||
void setDefaultFavicon();
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* 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.migration.minimotd;
|
||||
|
||||
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.interfaces.PluginLogger;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
|
||||
import ch.andre601.advancedserverlist.core.migration.minimotd.serializing.MiniMOTDConfig;
|
||||
import ch.andre601.advancedserverlist.core.migration.minimotd.serializing.MiniMOTDSerializer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileSerializer;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.hocon.HoconConfigurationLoader;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
import org.spongepowered.configurate.yaml.NodeStyle;
|
||||
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class MiniMOTDConfigMigrator{
|
||||
|
||||
public static boolean migrate(AdvancedServerList<?> core, CmdSender sender){
|
||||
core.getPlugin().downloadLibrary("org.spongepowered", "configurate-hocon", "4.1.2");
|
||||
|
||||
PluginLogger logger = core.getPlugin().getPluginLogger();
|
||||
String folder = core.getPlugin().getLoader().equals("velocity") ? "minimotd-velocity" : "MiniMOTD";
|
||||
|
||||
Path mainConf = core.getPlugin().getFolderPath().getParent().resolve(folder).resolve("main.conf");
|
||||
if(!Files.exists(mainConf)){
|
||||
logger.warn("[<white>Migrator - MiniMOTD</white>] Cannot find a main.conf file in <white>/plugins/%s/</white> folder.", folder);
|
||||
sender.sendErrorMsg(" -> <red>No main.conf file found.");
|
||||
return false;
|
||||
}
|
||||
|
||||
HoconConfigurationLoader loader = HoconConfigurationLoader.builder()
|
||||
.path(mainConf)
|
||||
.defaultOptions(options -> options.serializers(builder ->
|
||||
builder.register(MiniMOTDConfig.class, MiniMOTDSerializer.MINI_MOTD_SERIALIZER)
|
||||
.register(MiniMOTDConfig.Motd.class, MiniMOTDSerializer.MOTD_SERIALIZER)
|
||||
.register(MiniMOTDConfig.PlayerCount.class, MiniMOTDSerializer.PLAYER_COUNT_SERIALIZER)
|
||||
))
|
||||
.build();
|
||||
|
||||
MiniMOTDConfig config;
|
||||
try{
|
||||
ConfigurationNode node = loader.load();
|
||||
|
||||
config = node.get(MiniMOTDConfig.class);
|
||||
}catch(IOException ex){
|
||||
logger.warn("[<white>Migrator - MiniMOTD</white>] Encountered IOException while loading main.conf file.", ex);
|
||||
sender.sendErrorMsg(" -> <red>IOException while loading</red> main.conf <red>file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(config == null){
|
||||
logger.warn("[<white>Migrator - MiniMOTD</white>] Retrieved main.conf file returned null.");
|
||||
sender.sendErrorMsg(" -> <red>Received invalid</red> main.conf <red>file.");
|
||||
return false;
|
||||
}
|
||||
|
||||
ProfileEntry.Builder profileBuilder = ProfileEntry.empty().builder();
|
||||
List<ProfileEntry.Builder> profilesBuilders = new ArrayList<>();
|
||||
|
||||
if(config.motdEnabled() && config.motds().size() > 1){
|
||||
for(int i = 0; i < config.motds().size(); i++){
|
||||
profilesBuilders.add(ProfileEntry.empty().builder());
|
||||
}
|
||||
}
|
||||
|
||||
if(config.motdEnabled()){
|
||||
if(config.motds().size() == 1){
|
||||
applyMotd(profileBuilder, config.motds().get(0));
|
||||
}else
|
||||
if(config.motds().size() > 1){
|
||||
for(int i = 0; i < config.motds().size(); i++){
|
||||
applyMotd(profilesBuilders.get(i), config.motds().get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(config.iconEnabled()){
|
||||
if(config.motds().size() == 1){
|
||||
MiniMOTDConfig.Motd motd = config.motds().get(0);
|
||||
if(!motd.icon().isEmpty()){
|
||||
profileBuilder.favicon(motd.icon());
|
||||
}
|
||||
}else
|
||||
if(config.motds().size() > 1){
|
||||
for(int i = 0; i < config.motds().size(); i++){
|
||||
MiniMOTDConfig.Motd motd = config.motds().get(i);
|
||||
if(!motd.icon().isEmpty()){
|
||||
profilesBuilders.get(i).favicon(motd.icon());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(config.playerCount() != null){
|
||||
MiniMOTDConfig.PlayerCount playerCount = config.playerCount();
|
||||
|
||||
NullBool hidePlayers = NullBool.resolve(playerCount.hidePlayers());
|
||||
NullBool xMoreEnabled = NullBool.resolve(playerCount.xMoreEnabled());
|
||||
int xMore = playerCount.xMore();
|
||||
NullBool maxPlayersEnabled = NullBool.resolve(playerCount.maxPlayersEnabled());
|
||||
int maxPlayers = playerCount.maxPlayers();
|
||||
|
||||
profileBuilder.hidePlayersEnabled(hidePlayers)
|
||||
.extraPlayersEnabled(xMoreEnabled)
|
||||
.extraPlayersCount(String.valueOf(xMore))
|
||||
.maxPlayersEnabled(maxPlayersEnabled)
|
||||
.maxPlayersCount(String.valueOf(maxPlayers));
|
||||
}
|
||||
|
||||
ProfileEntry entry = profileBuilder.build();
|
||||
List<ProfileEntry> profiles = profilesBuilders.stream()
|
||||
.map(ProfileEntry.Builder::build)
|
||||
.toList();
|
||||
|
||||
boolean profilesInvalid = profiles.isEmpty() || profiles.stream().allMatch(ProfileEntry::isInvalid);
|
||||
if(entry.isInvalid() && profilesInvalid){
|
||||
logger.warn("[<white>Migrator - MiniMOTD</white>] Main ProfileEntry was invalid and profiles were empty.");
|
||||
sender.sendErrorMsg(" -> <red>Received invalid configuration.");
|
||||
return false;
|
||||
}
|
||||
|
||||
Path profile = core.getPlugin().getFolderPath().resolve("profiles").resolve("minimotd_migrated.yml");
|
||||
if(Files.exists(profile)){
|
||||
logger.warn("[<white>Migrator - MiniMOTD</white>] Cannot create new file minimotd_migrated.yml. One with the same name is already present.");
|
||||
sender.sendErrorMsg(" -> <red>File</red> minimotd_migrated.yml <red>already present.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
try{
|
||||
Files.createFile(profile);
|
||||
}catch(IOException ex){
|
||||
logger.warn("[<white>Migrator - MiniMOTD</white>] Encountered an IOException while trying to create file minimotd_migrated.yml.", ex);
|
||||
sender.sendErrorMsg(" -> <red>File creation error.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
YamlConfigurationLoader yamlLoader = YamlConfigurationLoader.builder()
|
||||
.path(profile)
|
||||
.indent(2)
|
||||
.nodeStyle(NodeStyle.BLOCK)
|
||||
.defaultOptions(option -> option.serializers(builder -> builder.register(ProfileEntry.class, ProfileSerializer.INSTANCE)))
|
||||
.build();
|
||||
|
||||
ConfigurationNode migrated;
|
||||
try{
|
||||
migrated = yamlLoader.load();
|
||||
}catch(IOException ex){
|
||||
logger.warn("[<white>Migrator - MiniMOTD</white>] Encountered an IOException while trying to load file minimotd_migrated.yml.", ex);
|
||||
sender.sendErrorMsg(" -> <red>File loading error.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if(migrated == null){
|
||||
logger.warn("[<white>Migrator - MiniMOTD</white>] Cannot migrate Configuration. ConfigurationNode was null.");
|
||||
sender.sendErrorMsg(" -> <red>File loading error.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
try{
|
||||
migrated.node("priority").set(0);
|
||||
|
||||
if(!profiles.isEmpty()){
|
||||
migrated.node("profiles").setList(ProfileEntry.class, profiles);
|
||||
}
|
||||
|
||||
migrated.set(entry);
|
||||
}catch(SerializationException ex){
|
||||
logger.warn("[<white>Migrator - MiniMOTD</white>] Encountered a SerializationException while setting values.", ex);
|
||||
sender.sendErrorMsg(" -> <red>Error while updating file</red> minimotd_migrated.yml<red>.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
try{
|
||||
yamlLoader.save(migrated);
|
||||
sender.sendPrefixedMsg(" -> <green>Completed!");
|
||||
|
||||
return true;
|
||||
}catch(IOException ex){
|
||||
logger.warn("[<white>Migrator - MiniMOTD</white>] Encountered an IOException while trying to save new file minimotd_migrated.yml.", ex);
|
||||
sender.sendErrorMsg(" -> <red>File saving error.");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void applyMotd(ProfileEntry.Builder builder, MiniMOTDConfig.Motd motd){
|
||||
if(motd.line1().isEmpty() && !motd.line2().isEmpty()){
|
||||
builder.motd(List.of("<grey>", motd.line2()));
|
||||
}else
|
||||
if(!motd.line1().isEmpty() && motd.line2().isEmpty()){
|
||||
builder.motd(Collections.singletonList(motd.line1()));
|
||||
}else
|
||||
if(!motd.line1().isEmpty()){ // Line2 is by logic not empty here. So this check is not required.
|
||||
builder.motd(List.of(motd.line1(), motd.line2()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,30 +23,13 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.players;
|
||||
package ch.andre601.advancedserverlist.core.migration.minimotd.serializing;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import java.util.List;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public abstract class GenericPlayerImpl implements GenericPlayer{
|
||||
public record MiniMOTDConfig(boolean iconEnabled, boolean motdEnabled, List<Motd> motds, PlayerCount playerCount){
|
||||
|
||||
protected String name = null;
|
||||
protected int protocol = 0;
|
||||
protected UUID uuid = null;
|
||||
public record Motd(String icon, String line1, String line2){}
|
||||
|
||||
@Override
|
||||
public String getName(){
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtocol(){
|
||||
return protocol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUUID(){
|
||||
return uuid;
|
||||
}
|
||||
public record PlayerCount(boolean hidePlayers, boolean xMoreEnabled, int xMore, boolean maxPlayersEnabled, int maxPlayers){}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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.migration.minimotd.serializing;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
import org.spongepowered.configurate.serialize.TypeSerializer;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class MiniMOTDSerializer implements TypeSerializer<MiniMOTDConfig>{
|
||||
|
||||
public static final MiniMOTDSerializer MINI_MOTD_SERIALIZER = new MiniMOTDSerializer();
|
||||
public static final MotdSerializer MOTD_SERIALIZER = new MotdSerializer();
|
||||
public static final PlayerCountSerializer PLAYER_COUNT_SERIALIZER = new PlayerCountSerializer();
|
||||
|
||||
@Override
|
||||
public MiniMOTDConfig deserialize(Type type, ConfigurationNode node) throws SerializationException{
|
||||
boolean iconsEnabled = node.node("icon-enabled").getBoolean();
|
||||
boolean motdEnabled = node.node("motd-enabled").getBoolean();
|
||||
|
||||
List<MiniMOTDConfig.Motd> motds = node.node("motds").getList(MiniMOTDConfig.Motd.class);
|
||||
MiniMOTDConfig.PlayerCount playerCount = node.node("player-count-settings").get(MiniMOTDConfig.PlayerCount.class);
|
||||
|
||||
return new MiniMOTDConfig(iconsEnabled, motdEnabled, motds, playerCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(Type type, @Nullable MiniMOTDConfig obj, ConfigurationNode node) throws SerializationException{
|
||||
if(obj == null){
|
||||
node.raw(null);
|
||||
return;
|
||||
}
|
||||
|
||||
node.node("icon-enabled").set(obj.iconEnabled());
|
||||
node.node("motd-enable").set(obj.motdEnabled());
|
||||
node.node("motds").setList(MiniMOTDConfig.Motd.class, obj.motds());
|
||||
node.node("player-count-settings").set(MiniMOTDConfig.PlayerCount.class, obj.playerCount());
|
||||
}
|
||||
|
||||
public static class MotdSerializer implements TypeSerializer<MiniMOTDConfig.Motd>{
|
||||
|
||||
@Override
|
||||
public MiniMOTDConfig.Motd deserialize(Type type, ConfigurationNode node) throws SerializationException{
|
||||
String icon = node.node("icon").getString("");
|
||||
String line1 = node.node("line1").getString("");
|
||||
String line2 = node.node("line2").getString("");
|
||||
|
||||
return new MiniMOTDConfig.Motd(icon, line1, line2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(Type type, MiniMOTDConfig.@Nullable Motd obj, ConfigurationNode node) throws SerializationException{
|
||||
if(obj == null){
|
||||
node.raw(null);
|
||||
return;
|
||||
}
|
||||
|
||||
node.node("icon").set(obj.icon());
|
||||
node.node("line1").set(obj.line1());
|
||||
node.node("line2").set(obj.line2());
|
||||
}
|
||||
}
|
||||
|
||||
public static class PlayerCountSerializer implements TypeSerializer<MiniMOTDConfig.PlayerCount>{
|
||||
|
||||
@Override
|
||||
public MiniMOTDConfig.PlayerCount deserialize(Type type, ConfigurationNode node) throws SerializationException{
|
||||
boolean hidePlayerCount = node.node("hide-player-count").getBoolean();
|
||||
boolean xMoreEnabled = node.node("just-x-more-settings", "just-x-more-enabled").getBoolean();
|
||||
int xMore = node.node("just-x-more-settings", "x-value").getInt();
|
||||
boolean maxPlayersEnabled = node.node("max-players-enabled").getBoolean();
|
||||
int maxPlayers = node.node("max-players").getInt();
|
||||
|
||||
|
||||
return new MiniMOTDConfig.PlayerCount(hidePlayerCount, xMoreEnabled, xMore, maxPlayersEnabled, maxPlayers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(Type type, MiniMOTDConfig.@Nullable PlayerCount obj, ConfigurationNode node) throws SerializationException{
|
||||
if(obj == null){
|
||||
node.raw(null);
|
||||
return;
|
||||
}
|
||||
|
||||
node.node("allow-exceeding-maximum").set(false);
|
||||
node.node("disable-player-list-hover").set(false);
|
||||
|
||||
node.node("fake-players", "fake-players").set("25%");
|
||||
node.node("fake-players", "fake-players-enabled").set(false);
|
||||
|
||||
node.node("hide-player-count").set(obj.hidePlayers());
|
||||
|
||||
node.node("just-x-more-settings", "just-x-more-enabled").set(obj.xMoreEnabled());
|
||||
node.node("just-x-more-settings", "x-value").set(obj.xMore());
|
||||
|
||||
node.node("max-players").set(obj.maxPlayers());
|
||||
node.node("max-players-enabled").set(obj.maxPlayersEnabled());
|
||||
|
||||
node.node("servers").setList(String.class, Collections.emptyList());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,467 @@
|
||||
/*
|
||||
* 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.migration.serverlistplus;
|
||||
|
||||
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.interfaces.PluginLogger;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
|
||||
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileSerializer;
|
||||
import net.minecrell.serverlistplus.core.ServerListPlusCore;
|
||||
import net.minecrell.serverlistplus.core.config.PersonalizedStatusConf;
|
||||
import net.minecrell.serverlistplus.core.config.ServerStatusConf;
|
||||
import net.minecrell.serverlistplus.core.util.BooleanOrList;
|
||||
import net.minecrell.serverlistplus.core.util.IntegerRange;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
import org.spongepowered.configurate.yaml.NodeStyle;
|
||||
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class SLPConfigMigrator{
|
||||
|
||||
private static final Pattern RGB_COLOR_PATTERN = Pattern.compile("&(?<color>#[a-fA-F0-9]{6})");
|
||||
private static final Pattern COLOR_CODE_PATTERN = Pattern.compile("&(?<color>[abcdefklmnorABCDEFKLMNOR0123456789])");
|
||||
private static final Pattern RGB_GRADIENT_PATTERN = Pattern.compile(
|
||||
"%gradient" +
|
||||
"(?<start>#[a-fA-F0-9]{6})" + // Starting color
|
||||
"(?<end>#[a-fA-F0-9]{6})" + // Ending color
|
||||
"%" +
|
||||
"(?<text>.+?)" + // Text
|
||||
"%gradient%"
|
||||
);
|
||||
|
||||
private static final Map<String, String> STATIC_REPLACEMENTS = Map.of(
|
||||
"%player%", "${player name}",
|
||||
"%uuid%", "${player uuid}",
|
||||
"%_uuid_%", "${player uuid}",
|
||||
"%online%", "${server playersOnline}",
|
||||
"%max%", "${server playersMax}"
|
||||
);
|
||||
private static final Map<String, String> COLOR_TO_MINIMESSAGE_TAG = new HashMap<>(){{
|
||||
// Color Codes.
|
||||
put("a", "<green>");
|
||||
put("b", "<aqua>");
|
||||
put("c", "<red>");
|
||||
put("d", "<light_purple>");
|
||||
put("e", "<yellow>");
|
||||
put("f", "<white>");
|
||||
put("0", "<black>");
|
||||
put("1", "<dark_blue>");
|
||||
put("2", "<dark_green>");
|
||||
put("3", "<dark_aqua>");
|
||||
put("4", "<dark_red>");
|
||||
put("5", "<dark_purple>");
|
||||
put("6", "<gold>");
|
||||
put("7", "<grey>");
|
||||
put("8", "<dark_grey>");
|
||||
put("9", "<blue>");
|
||||
|
||||
// Formatting Codes
|
||||
put("k", "<obfuscated>");
|
||||
put("l", "<bold>");
|
||||
put("m", "<strikethrough>");
|
||||
put("n", "<underlined>");
|
||||
put("o", "<italic>");
|
||||
put("r", "<reset>");
|
||||
}};
|
||||
|
||||
public static int migrate(AdvancedServerList<?> core, CmdSender sender){
|
||||
ServerListPlusCore slpCore = ServerListPlusCore.getInstance();
|
||||
PluginLogger logger = core.getPlugin().getPluginLogger();
|
||||
if(slpCore == null){
|
||||
logger.warn("[<white>Migrator - ServerListPlus</white>] Cannot migrate ServerListPlus config. ServerListPlus is not active!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ServerStatusConf conf = slpCore.getConf(ServerStatusConf.class);
|
||||
if(conf == null){
|
||||
logger.warn("[<white>Migrator - ServerListPlus</white>] Cannot migrate ServerListPlus configuration. Received configuration was null.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
PersonalizedStatusConf.StatusConf defConf = conf.Default;
|
||||
PersonalizedStatusConf.StatusConf personalizedConf = conf.Personalized;
|
||||
PersonalizedStatusConf.StatusConf banned = conf.Banned;
|
||||
|
||||
sender.sendPrefixedMsg("Migrating <white>Default</white>...");
|
||||
int defConfParsed = parseConf(core, sender, defConf, Type.DEFAULT);
|
||||
|
||||
sender.sendPrefixedMsg("Migrating <white>Personalized</white>...");
|
||||
int personalizedParsed = parseConf(core, sender, personalizedConf, Type.PERSONALIZED);
|
||||
|
||||
sender.sendPrefixedMsg("Migrating <white>Banned</white>...");
|
||||
int bannedParsed = parseConf(core, sender, banned, Type.BANNED);
|
||||
|
||||
return defConfParsed + personalizedParsed + bannedParsed;
|
||||
}
|
||||
|
||||
private static int parseConf(AdvancedServerList<?> core, CmdSender sender, PersonalizedStatusConf.StatusConf conf, Type type){
|
||||
PluginLogger logger = core.getPlugin().getPluginLogger();
|
||||
if(conf == null){
|
||||
logger.info("[<white>Migrator - ServerListPlus</white>] No StatusConf found for type <white>%s</white>. Skipping...", type.getName());
|
||||
sender.sendPrefixedMsg(" -> Not found! Skipping...");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ProfileEntry.Builder builder = ProfileEntry.empty().builder();
|
||||
List<ProfileEntry.Builder> profiles = new ArrayList<>();
|
||||
|
||||
List<List<String>> motds = resolveMotds(conf.Description);
|
||||
List<String> favicons = resolveFavicons(conf.Favicon);
|
||||
List<List<String>> hovers = resolveHover(conf.Players);
|
||||
NullBool hidePlayers = conf.Players != null ? NullBool.resolve(conf.Players.Hidden) : NullBool.NOT_SET;
|
||||
List<Integer> maxPlayers = resolveMaxPlayers(conf.Players);
|
||||
List<String> playerCount = resolvePlayerCounts(conf.Players);
|
||||
|
||||
int size = getMaxListSize(motds, favicons, hovers, maxPlayers, playerCount);
|
||||
// Only add profiles entries when there are more than 2 entries of an option.
|
||||
// Avoids a profiles option with a single entry that has no options whatsoever.
|
||||
if(size > 1){
|
||||
for(int i = 0; i < size; i++){
|
||||
profiles.add(ProfileEntry.empty().builder());
|
||||
}
|
||||
}
|
||||
|
||||
apply(motds, builder, profiles, ProfileEntry.Builder::motd);
|
||||
apply(favicons, builder, profiles, ProfileEntry.Builder::favicon);
|
||||
apply(hovers, builder, profiles, ProfileEntry.Builder::players);
|
||||
apply(maxPlayers, builder, profiles, (build, count) -> build.maxPlayersEnabled(NullBool.TRUE).maxPlayersCount(String.valueOf(count)));
|
||||
apply(playerCount, builder, profiles, ProfileEntry.Builder::playerCountText);
|
||||
|
||||
builder.hidePlayersEnabled(hidePlayers);
|
||||
|
||||
ProfileEntry entry = builder.build();
|
||||
List<ProfileEntry> profileEntries = profiles.stream()
|
||||
.map(ProfileEntry.Builder::build)
|
||||
.toList();
|
||||
|
||||
boolean profilesInvalid = profileEntries.isEmpty() || profileEntries.stream().anyMatch(ProfileEntry::isInvalid);
|
||||
if(entry.isInvalid() && profilesInvalid){
|
||||
logger.warn("[<white>Migrator - ServerListPlus</white>] Unable to parse ServerListPlus configuration of type <white>%s</white>. Generated ProfileEntry was invalid.", type.getName());
|
||||
sender.sendErrorMsg(" -> <red>Received invalid Configuration.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Path profile = core.getPlugin().getFolderPath().resolve("profiles").resolve(type.getFile());
|
||||
if(Files.exists(profile)){
|
||||
logger.warn("[<white>Migrator - ServerListPlus</white>] Cannot create new file <white>%s</white>. One with the same name is already present", type.getFile());
|
||||
sender.sendErrorMsg(" -> <red>File</red> %s <red>already present.", type.getFile());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
try{
|
||||
Files.createFile(profile);
|
||||
}catch(IOException ex){
|
||||
logger.warn("[<white>Migrator - ServerListPlus</white>] Encountered an IOException while trying to create file <white>%s</white>.", ex, type.getFile());
|
||||
sender.sendErrorMsg(" -> <red>File creation error.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
YamlConfigurationLoader loader = YamlConfigurationLoader.builder()
|
||||
.path(profile)
|
||||
.indent(2)
|
||||
.nodeStyle(NodeStyle.BLOCK)
|
||||
.defaultOptions(opt -> opt.serializers(build -> build.register(ProfileEntry.class, ProfileSerializer.INSTANCE)))
|
||||
.build();
|
||||
|
||||
ConfigurationNode node;
|
||||
try{
|
||||
node = loader.load();
|
||||
}catch(IOException ex){
|
||||
logger.warn("[<white>Migrator - ServerListPlus</white>] Encountered an IOException while trying to load file <white>%s</white>.", ex, type.getFile());
|
||||
sender.sendErrorMsg(" -> <red>File loading error.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(node == null){
|
||||
logger.warn("[<white>Migrator - ServerListPlus</white>] Cannot migrate Configuration of type <white>%s</white>. ConfigurationNode was null.", type.getName());
|
||||
sender.sendErrorMsg(" -> <red>File loading error.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
try{
|
||||
node.node("priority")
|
||||
.set(type != Type.DEFAULT ? 1 : 0);
|
||||
|
||||
if(type == Type.PERSONALIZED){
|
||||
node.node("condition")
|
||||
.set("${player name} != \"" + core.getFileHandler().getString("Anonymous", "unknownPlayer", "name") + "\"");
|
||||
}else
|
||||
if(type == Type.BANNED){
|
||||
node.node("condition")
|
||||
.set("${player isBanned}");
|
||||
}
|
||||
|
||||
if(!profiles.isEmpty()){
|
||||
node.node("profiles").setList(ProfileEntry.class, profileEntries);
|
||||
}
|
||||
|
||||
node.set(entry);
|
||||
}catch(SerializationException ex){
|
||||
logger.warn("[<white>Migrator - ServerListPlus</white>] Encountered a SerializationException while setting values.", ex);
|
||||
sender.sendErrorMsg(" -> <red>Error while updating file</red> %s<red>.", type.getFile());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
try{
|
||||
loader.save(node);
|
||||
sender.sendPrefixedMsg(" -> <green>Completed!");
|
||||
|
||||
return 1;
|
||||
}catch(IOException ex){
|
||||
logger.warn("[<white>Migrator - ServerListPlus</white>] Encountered an IOException while trying to save new file <white>%s</white>.", ex, type.getFile());
|
||||
sender.sendErrorMsg(" -> <red>File saving error.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static int getMaxListSize(List<?>... lists){
|
||||
int size = 0;
|
||||
for(List<?> list : lists){
|
||||
if(list.size() > size)
|
||||
size = list.size();
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
private static List<List<String>> resolveMotds(List<String> descriptions){
|
||||
if(descriptions == null || descriptions.isEmpty())
|
||||
return Collections.emptyList();
|
||||
|
||||
List<List<String>> motds = new ArrayList<>();
|
||||
for(String line : descriptions){
|
||||
motds.add(getList(line));
|
||||
}
|
||||
|
||||
return motds;
|
||||
}
|
||||
|
||||
private static List<String> resolveFavicons(PersonalizedStatusConf.StatusConf.FaviconConf faviconConf){
|
||||
if(faviconConf == null || faviconConf.Disabled != null && faviconConf.Disabled)
|
||||
return Collections.emptyList();
|
||||
|
||||
List<String> list = new ArrayList<>();
|
||||
|
||||
if(faviconConf.Heads != null){
|
||||
for(String head : faviconConf.Heads){
|
||||
list.add(
|
||||
"https://mc-heads.net/avatar/" +
|
||||
replacePlaceholders(head) +
|
||||
"/64/nohelm"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if(faviconConf.Helms != null){
|
||||
for(String helm : faviconConf.Helms){
|
||||
list.add(replacePlaceholders(helm));
|
||||
}
|
||||
}
|
||||
|
||||
if(faviconConf.Files != null){
|
||||
for(String file : faviconConf.Files){
|
||||
if(!file.toLowerCase(Locale.ROOT).endsWith(".png"))
|
||||
continue;
|
||||
|
||||
list.add(replacePlaceholders(file));
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private static List<List<String>> resolveHover(PersonalizedStatusConf.StatusConf.PlayersConf playersConf){
|
||||
if(playersConf == null)
|
||||
return Collections.emptyList();
|
||||
|
||||
BooleanOrList<String> booleanOrList = playersConf.Hover;
|
||||
if(booleanOrList == null)
|
||||
return Collections.emptyList();
|
||||
|
||||
if(booleanOrList.getList() != null){
|
||||
List<List<String>> hovers = new ArrayList<>();
|
||||
for(String line : booleanOrList.getList()){
|
||||
if(line == null)
|
||||
continue;
|
||||
|
||||
hovers.add(getList(line));
|
||||
}
|
||||
|
||||
return hovers;
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private static List<Integer> resolveMaxPlayers(PersonalizedStatusConf.StatusConf.PlayersConf playersConf){
|
||||
if(playersConf == null)
|
||||
return Collections.emptyList();
|
||||
|
||||
List<IntegerRange> maxPlayers = playersConf.Max;
|
||||
if(maxPlayers == null)
|
||||
return Collections.emptyList();
|
||||
|
||||
List<Integer> values = new ArrayList<>();
|
||||
for(IntegerRange range : maxPlayers){
|
||||
if(range == null)
|
||||
continue;
|
||||
|
||||
values.add(range.to());
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
private static List<String> resolvePlayerCounts(PersonalizedStatusConf.StatusConf.PlayersConf playersConf){
|
||||
if(playersConf == null)
|
||||
return Collections.emptyList();
|
||||
|
||||
if(playersConf.Slots == null)
|
||||
return Collections.emptyList();
|
||||
|
||||
return playersConf.Slots.stream()
|
||||
.map(SLPConfigMigrator::replacePlaceholders)
|
||||
.toList();
|
||||
}
|
||||
|
||||
private static <T> void apply(List<T> list, ProfileEntry.Builder builder, List<ProfileEntry.Builder> profiles,
|
||||
BiConsumer<ProfileEntry.Builder, T> builderConsumer){
|
||||
if(list.size() == 1){
|
||||
builderConsumer.accept(builder, list.get(0));
|
||||
}else
|
||||
if(list.size() > 1){
|
||||
for(int i = 0; i < list.size(); i++){
|
||||
builderConsumer.accept(profiles.get(i), list.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> getList(String line){
|
||||
return Arrays.asList(replacePlaceholders(line).split("\n"));
|
||||
}
|
||||
|
||||
private static String replacePlaceholders(String input){
|
||||
StringBuilder parsed = new StringBuilder(input);
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
Matcher rgbColorMatcher = RGB_COLOR_PATTERN.matcher(parsed.toString());
|
||||
if(rgbColorMatcher.find()){
|
||||
do{
|
||||
rgbColorMatcher.appendReplacement(builder, "<" + rgbColorMatcher.group("color") + ">");
|
||||
}while(rgbColorMatcher.find());
|
||||
|
||||
rgbColorMatcher.appendTail(builder);
|
||||
parsed = builder;
|
||||
}
|
||||
|
||||
Matcher colorCodeMatcher = COLOR_CODE_PATTERN.matcher(parsed.toString());
|
||||
if(colorCodeMatcher.find()){
|
||||
builder.setLength(0);
|
||||
do{
|
||||
for(Map.Entry<String, String> colorCodes : COLOR_TO_MINIMESSAGE_TAG.entrySet()){
|
||||
if(!colorCodeMatcher.group("color").equalsIgnoreCase(colorCodes.getKey()))
|
||||
continue;
|
||||
|
||||
colorCodeMatcher.appendReplacement(builder, colorCodes.getValue());
|
||||
}
|
||||
}while(colorCodeMatcher.find());
|
||||
|
||||
colorCodeMatcher.appendTail(builder);
|
||||
parsed = builder;
|
||||
}
|
||||
|
||||
Matcher rgbGradientMatcher = RGB_GRADIENT_PATTERN.matcher(parsed.toString());
|
||||
if(rgbGradientMatcher.find()){
|
||||
builder.setLength(0);
|
||||
do{
|
||||
String start = rgbGradientMatcher.group("start");
|
||||
String end = rgbGradientMatcher.group("end");
|
||||
String text = rgbGradientMatcher.group("text");
|
||||
|
||||
rgbGradientMatcher.appendReplacement(builder, "<gradient:" + start + ":" + end + ">" + text + "</gradient>");
|
||||
}while(rgbGradientMatcher.find());
|
||||
|
||||
rgbGradientMatcher.appendTail(builder);
|
||||
parsed = builder;
|
||||
}
|
||||
|
||||
return replaceStaticPlaceholders(parsed);
|
||||
}
|
||||
|
||||
private static String replaceStaticPlaceholders(StringBuilder input){
|
||||
if(input.isEmpty())
|
||||
return "";
|
||||
|
||||
for(Map.Entry<String, String> entry : STATIC_REPLACEMENTS.entrySet()){
|
||||
int index = 0;
|
||||
while((index = input.indexOf(entry.getKey(), index)) != -1){
|
||||
input.replace(index, index + entry.getKey().length(), entry.getValue());
|
||||
index += entry.getValue().length();
|
||||
}
|
||||
}
|
||||
|
||||
return input.toString();
|
||||
}
|
||||
|
||||
private enum Type{
|
||||
DEFAULT("Default", "slp_default.yml"),
|
||||
PERSONALIZED("Personalized", "slp_personalized.yml"),
|
||||
BANNED("Banned", "slp_banned.yml");
|
||||
|
||||
private final String name, file;
|
||||
|
||||
Type(String name, String file){
|
||||
this.name = name;
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public String getName(){
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getFile(){
|
||||
return file;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,27 +23,30 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.compat.papi;
|
||||
package ch.andre601.advancedserverlist.core.objects;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class PAPICache{
|
||||
public class ValueCache<T>{
|
||||
|
||||
private CacheValue cache = null;
|
||||
private final Duration duration;
|
||||
private CacheValue<T> 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();
|
||||
public ValueCache(Duration duration){
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
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;
|
||||
public T get(Supplier<T> supplier){
|
||||
if(cache == null || cache.expired())
|
||||
cache = new CacheValue<>(System.currentTimeMillis(), duration, supplier.get());
|
||||
|
||||
return cache.value();
|
||||
}
|
||||
|
||||
private record CacheValue<T>(long timestamp, Duration duration, T value){
|
||||
public boolean expired(){
|
||||
return (timestamp < 0L) || System.currentTimeMillis() - timestamp >= duration.toMillis();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,6 @@ import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class ComponentParser{
|
||||
@@ -52,12 +51,13 @@ public class ComponentParser{
|
||||
return new ComponentParser(text);
|
||||
}
|
||||
|
||||
public static ComponentParser list(List<String> lines){
|
||||
return new ComponentParser(String.join("\n", lines));
|
||||
public static ComponentParser textFormatted(String text, Object... args){
|
||||
return text(String.format(text, args));
|
||||
}
|
||||
|
||||
public ComponentParser modifyText(Function<String, String> function){
|
||||
this.text = function.apply(text);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -65,8 +65,16 @@ public class ComponentParser{
|
||||
return mm.deserialize(text);
|
||||
}
|
||||
|
||||
public static String toMMString(Component component){
|
||||
return mm.serialize(component);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
return legacy.serialize(toComponent());
|
||||
}
|
||||
|
||||
public String toStringStriped(){
|
||||
return mm.stripTags(text);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package ch.andre601.advancedserverlist.core.parsing;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import net.kyori.adventure.text.flattener.ComponentFlattener;
|
||||
import net.kyori.adventure.text.flattener.FlattenerListener;
|
||||
import net.kyori.adventure.text.format.Style;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
public class TextCenterUtil{
|
||||
private final ComponentFlattener COMPONENT_FLATTENER = ComponentFlattener.textOnly();
|
||||
|
||||
private final double MAX_WIDTH = 270.0; // Max width of the MOTD
|
||||
private final int SPACE_WIDTH = 4;
|
||||
|
||||
private final Map<String, FontInfo> charWidths;
|
||||
|
||||
public TextCenterUtil(AdvancedServerList<?> plugin){
|
||||
charWidths = loadFontWidths(plugin);
|
||||
}
|
||||
|
||||
public String getCenteredText(String text){
|
||||
if(!text.toLowerCase(Locale.ROOT).startsWith("<center>"))
|
||||
return text;
|
||||
|
||||
if(getDefault() == null)
|
||||
return text;
|
||||
|
||||
text = text.substring("<center>".length());
|
||||
TextFlattenerListener listener = new TextFlattenerListener(this);
|
||||
|
||||
COMPONENT_FLATTENER.flatten(ComponentParser.text(text).toComponent(), listener);
|
||||
|
||||
double width = listener.getWidth();
|
||||
if(width >= MAX_WIDTH)
|
||||
return text;
|
||||
|
||||
return createSpaces(width) + text;
|
||||
}
|
||||
|
||||
private double getCharWidth(int codePoint, boolean isBold, String fontName){
|
||||
FontInfo font = charWidths.getOrDefault(fontName, getDefault());
|
||||
if(font == null)
|
||||
return -1.0;
|
||||
|
||||
int index = Arrays.binarySearch(font.codePoints, codePoint);
|
||||
if(index < 0){
|
||||
return isBold ? 7.0 : 6.0;
|
||||
}else{
|
||||
return isBold ? font.advanceBf[index] : font.advance[index];
|
||||
}
|
||||
}
|
||||
|
||||
private FontInfo getDefault(){
|
||||
return charWidths.get("minecraft:default");
|
||||
}
|
||||
|
||||
private String createSpaces(double length){
|
||||
double remainder = MAX_WIDTH - length;
|
||||
int padding = (int)Math.max(0, Math.floor(remainder / 2.0) - 1);
|
||||
|
||||
return " ".repeat(Math.floorDiv(padding, SPACE_WIDTH));
|
||||
}
|
||||
|
||||
private Map<String, FontInfo> loadFontWidths(AdvancedServerList<?> plugin){
|
||||
try(InputStream stream = plugin.getClass().getResourceAsStream("/char-widths.json.gz")){
|
||||
if(stream == null){
|
||||
plugin.getPlugin().getPluginLogger().warn("Internal char-widths.json.gz couldn't be retrieved.");
|
||||
plugin.getPlugin().getPluginLogger().warn("The <center> Placeholder won't work.");
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
GZIPInputStream gzipStream = new GZIPInputStream(stream);
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(gzipStream));
|
||||
|
||||
return new Gson().fromJson(reader, new TypeToken<Map<String, FontInfo>>(){}.getType());
|
||||
}catch(IOException ex){
|
||||
plugin.getPlugin().getPluginLogger().warn("Encountered IOException while loading font widths.");
|
||||
plugin.getPlugin().getPluginLogger().warn("The <center> Placeholder won't work.");
|
||||
plugin.getPlugin().getPluginLogger().warn("Cause: <white>%s</white>", ex.getMessage());
|
||||
return new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
private static class TextFlattenerListener implements FlattenerListener{
|
||||
private double width = 0.0;
|
||||
private boolean isBold = false;
|
||||
private String font = "minecraft:default";
|
||||
|
||||
private final TextCenterUtil instance;
|
||||
|
||||
public TextFlattenerListener(TextCenterUtil instance){
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pushStyle(@NotNull Style style){
|
||||
if(style.hasDecoration(TextDecoration.BOLD))
|
||||
isBold = true;
|
||||
|
||||
if(style.font() != null)
|
||||
font = style.font().asString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void component(@NotNull String text){
|
||||
for(int i = 0; i < text.length(); i++){
|
||||
width += instance.getCharWidth(text.codePointAt(i), isBold, font);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void popStyle(@NotNull Style style){
|
||||
if(style.hasDecoration(TextDecoration.BOLD))
|
||||
isBold = false;
|
||||
}
|
||||
|
||||
public double getWidth(){
|
||||
return width;
|
||||
}
|
||||
}
|
||||
|
||||
private record FontInfo(int[] codePoints, float[] advance, float[] advanceBf){}
|
||||
}
|
||||
@@ -28,10 +28,9 @@ 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.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
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;
|
||||
|
||||
@@ -42,29 +41,27 @@ import java.util.Random;
|
||||
public record ServerListProfile(int priority, String condition, ProfileEntry defaultProfile, List<ProfileEntry> profiles, String file){
|
||||
private static final Random random = new Random();
|
||||
|
||||
public boolean evalConditions(ProfileConditionParser parser, PluginLogger logger, GenericPlayer player, GenericServer server){
|
||||
public boolean evalConditions(AdvancedServerList<?> core, GenericPlayer player, GenericServer server){
|
||||
if(condition == null || condition.isEmpty())
|
||||
return true;
|
||||
|
||||
ParseWarnCollector collector = new ParseWarnCollector(condition);
|
||||
ExpressionTemplate template = parser.compile(condition, player, server, collector);
|
||||
PluginLogger logger = core.getPlugin().getPluginLogger();
|
||||
|
||||
boolean result = core.getParser().evaluate(condition, player, server, collector);
|
||||
|
||||
if(collector.hasWarnings()){
|
||||
logger.warn("Encountered %d Error(s) while parsing condition for file '%s':", collector.getWarnings().size(), file);
|
||||
logger.warn("Encountered <white>%d</white> Error(s) while parsing condition for file '<white>%s</white>':", collector.getWarnings().size(), file);
|
||||
|
||||
for(ParseWarnCollector.Context context : collector.getWarnings()){
|
||||
logger.warn(" - At position %s:", context.position() == -1 ? "Unknown" : context.position());
|
||||
logger.warn(" %s", condition);
|
||||
logger.warn(" ".repeat(context.position() + 5) + "^");
|
||||
logger.warn(" -> %s", context.message());
|
||||
|
||||
logger.warn(" - At position <white>%s</white>:", context.position() == -1 ? "<italic>Unknown</italic>" : context.position());
|
||||
logger.warn(" <white>%s</white>", condition);
|
||||
logger.warn(" ".repeat(context.position() + 3) + "<red>^</red>");
|
||||
logger.warn(" <grey>-></grey> %s", context.message());
|
||||
}
|
||||
}
|
||||
|
||||
if(template == null)
|
||||
return false;
|
||||
|
||||
return template.returnBooleanExpression().evaluate();
|
||||
return result;
|
||||
}
|
||||
|
||||
public ProfileEntry getRandomProfile(){
|
||||
@@ -131,6 +128,9 @@ public record ServerListProfile(int priority, String condition, ProfileEntry def
|
||||
}
|
||||
|
||||
private Builder resolveCondition(){
|
||||
if(node == null)
|
||||
throw new IllegalStateException("ConfigurationNode was null!");
|
||||
|
||||
String condition = node.node("condition").getString();
|
||||
if(condition == null || condition.isEmpty())
|
||||
return this;
|
||||
@@ -140,20 +140,26 @@ public record ServerListProfile(int priority, String condition, ProfileEntry def
|
||||
}
|
||||
|
||||
private Builder resolveProfiles(){
|
||||
if(node == null)
|
||||
throw new IllegalStateException("ConfigurationNode was null!");
|
||||
|
||||
try{
|
||||
this.profiles = node.node("profiles").getList(ProfileEntry.class);
|
||||
}catch(SerializationException ex){
|
||||
logger.warn("Encountered a SerializationException while resolving the profiles entry for %s", ex, fileName);
|
||||
logger.warn("Encountered a SerializationException while resolving the profiles entry for <white>%s</white>", ex, fileName);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private Builder resolveDefaultProfile(){
|
||||
if(node == null)
|
||||
throw new IllegalStateException("ConfigurationNode was null!");
|
||||
|
||||
try{
|
||||
this.defaultProfile = node.get(ProfileEntry.class);
|
||||
}catch(SerializationException ex){
|
||||
logger.warn("Encountered a SerializationException while resolving the global profile for %s", ex, fileName);
|
||||
logger.warn("Encountered a SerializationException while resolving the global profile for <white>%s</white>", ex, fileName);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -60,8 +60,12 @@ public class ProfileConditionParser implements ExpressionParserEngine{
|
||||
.build();
|
||||
}
|
||||
|
||||
public ExpressionTemplate compile(String text, GenericPlayer player, GenericServer server, ParseWarnCollector collector){
|
||||
return parser.parse(tokenizer.parse(text, player, server, collector), collector);
|
||||
public boolean evaluate(String text, GenericPlayer player, GenericServer server, ParseWarnCollector collector){
|
||||
ExpressionTemplate result = parser.parse(tokenizer.parse(text, player, server, collector), collector);
|
||||
if(result == null)
|
||||
return false;
|
||||
|
||||
return result.returnBooleanExpression().evaluate();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -76,7 +76,14 @@ public class CustomExpressionTokenizer{
|
||||
}
|
||||
}
|
||||
|
||||
collector.appendWarningFormatted(position.getIndex(), "Illegal Token '%c'.", text.charAt(position.getIndex()));
|
||||
if(position.getIndex() >= text.length()){
|
||||
collector.appendWarningFormatted(
|
||||
"Current index position (%d) is larger or equal to Text length (%d) for condition '%s'",
|
||||
position.getIndex(), text.length(), text
|
||||
);
|
||||
}else{
|
||||
collector.appendWarningFormatted(position.getIndex(), "Illegal Token '%c'.", text.charAt(position.getIndex()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,7 +23,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.favicon;
|
||||
package ch.andre601.advancedserverlist.core.profiles.handlers;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
@@ -42,9 +42,8 @@ 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.Map;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@@ -57,6 +56,7 @@ public class FaviconHandler<F>{
|
||||
|
||||
private final Map<String, F> localFavicons = new HashMap<>();
|
||||
private final HttpClient client = HttpClient.newHttpClient();
|
||||
private final Random random = new Random();
|
||||
|
||||
public FaviconHandler(AdvancedServerList<F> core){
|
||||
this.core = core;
|
||||
@@ -70,14 +70,28 @@ public class FaviconHandler<F>{
|
||||
}
|
||||
|
||||
public F getFavicon(String input){
|
||||
if(localFavicons.containsKey(input.toLowerCase(Locale.ROOT).split("\\.")[0])){
|
||||
return localFavicons.get(input.toLowerCase(Locale.ROOT).split("\\.")[0]);
|
||||
if(localFavicons.size() > 0){
|
||||
logger.debug(FaviconHandler.class, "Current Local Favicons:");
|
||||
for(String key : localFavicons.keySet()){
|
||||
logger.debug(FaviconHandler.class, " - %s", key);
|
||||
}
|
||||
}
|
||||
|
||||
if(input.equalsIgnoreCase("random")){
|
||||
logger.debug(FaviconHandler.class, "Input matches 'random'. Returning random Favicon...");
|
||||
return getRandomized();
|
||||
}
|
||||
|
||||
if(localFavicons.containsKey(input.toLowerCase(Locale.ROOT))){
|
||||
logger.debug(FaviconHandler.class, "Input matches local favicon Image. Returning it...");
|
||||
return localFavicons.get(input.toLowerCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
try{
|
||||
logger.debug(FaviconHandler.class, "Getting Favicon image from cache...");
|
||||
return faviconCache.get(input, () -> getFuture(input)).getNow(null);
|
||||
}catch(ExecutionException ex){
|
||||
logger.warn("Received ExecutionException while retrieving Favicon for '%s'.", ex, input);
|
||||
logger.warn("Received ExecutionException while retrieving Favicon for '<white>%s</white>'.", ex, input);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -92,27 +106,46 @@ public class FaviconHandler<F>{
|
||||
logger.debug(FaviconHandler.class, "Resolving URL '%s'...", input);
|
||||
return CompletableFuture.supplyAsync(() -> fromURL(core, input), this.faviconThreadPool);
|
||||
}else
|
||||
if(input.equalsIgnoreCase("random")){
|
||||
return CompletableFuture.completedFuture(getRandomized());
|
||||
}else
|
||||
if(input.toLowerCase(Locale.ROOT).endsWith(".png")){
|
||||
logger.debug(FaviconHandler.class, "Resolving image file '%s'...", input);
|
||||
return CompletableFuture.completedFuture(localFavicons.get(input.toLowerCase(Locale.ROOT).split("\\.")[0]));
|
||||
return CompletableFuture.completedFuture(localFavicons.get(input.toLowerCase(Locale.ROOT)));
|
||||
}else{
|
||||
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 F getRandomized(){
|
||||
logger.debug(FaviconHandler.class, "Obtaining random Favicon...");
|
||||
if(localFavicons.isEmpty())
|
||||
return null;
|
||||
|
||||
List<F> faviconList = List.copyOf(localFavicons.values());
|
||||
|
||||
// Don't use Random for just one entry.
|
||||
if(faviconList.size() == 1)
|
||||
return faviconList.get(0);
|
||||
|
||||
synchronized(random){
|
||||
return faviconList.get(random.nextInt(faviconList.size()));
|
||||
}
|
||||
}
|
||||
|
||||
private void loadLocalFavicons(){
|
||||
this.localFavicons.clear();
|
||||
|
||||
logger.info("Loading local image files as Favicons...");
|
||||
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.");
|
||||
logger.debugSuccess(FaviconHandler.class, "Created favicons folder.");
|
||||
}catch(IOException ex){
|
||||
logger.warn("Cannot create favicons folder. Encountered an IOException.", ex);
|
||||
logger.failure("Cannot create favicons folder. Encountered an IOException.", ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -121,8 +154,10 @@ public class FaviconHandler<F>{
|
||||
pathStream.filter(Files::isRegularFile)
|
||||
.filter(file -> file.getFileName().toString().endsWith(".png"))
|
||||
.forEach(this::loadFile);
|
||||
|
||||
logger.success("Loaded <white>%d</white> local Favicons.", localFavicons.size());
|
||||
}catch(IOException ex){
|
||||
logger.warn("Cannot load files from Favicons folder.", ex);
|
||||
logger.failure("Cannot load files from favicons folder.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,14 +165,14 @@ public class FaviconHandler<F>{
|
||||
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());
|
||||
logger.failure("Cannot create Favicon from file '<white>%s</white>'. Received Favicon was null.", path.getFileName().toString());
|
||||
return;
|
||||
}
|
||||
|
||||
localFavicons.put(path.getFileName().toString().split("\\.")[0], favicon);
|
||||
logger.info("Loaded file '%s' as Favicon.", path.getFileName().toString());
|
||||
localFavicons.put(path.getFileName().toString().toLowerCase(Locale.ROOT), favicon);
|
||||
logger.debugSuccess(FaviconHandler.class, "Loaded file '<white>%s</white>' as Favicon.", path.getFileName().toString());
|
||||
}catch(IOException ex){
|
||||
logger.warn("Cannot create Favicon from file '%s'. Encountered IOException.", ex);
|
||||
logger.failure("Cannot create Favicon from file '<white>%s</white>'. Encountered IOException.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,11 +187,11 @@ public class FaviconHandler<F>{
|
||||
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);
|
||||
logger.warn("Cannot create Favicon from URL '<white>%s</white>'. Encountered an Exception.", ex, url);
|
||||
return null;
|
||||
}
|
||||
}catch(URISyntaxException ex){
|
||||
logger.warn("Cannot create Favicon from URL '%s'. Encountered an IOException.", ex, url);
|
||||
logger.warn("Cannot create Favicon from URL '<white>%s</white>'. Encountered a URISyntaxException.", ex, url);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -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,7 +23,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.players;
|
||||
package ch.andre601.advancedserverlist.core.profiles.handlers;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
@@ -66,7 +66,7 @@ public class PlayerHandler{
|
||||
}
|
||||
|
||||
public void load(){
|
||||
if(!cache.toFile().exists()){
|
||||
if(!Files.exists(cache)){
|
||||
logger.info("No playercache.json file present. Skipping...");
|
||||
return;
|
||||
}
|
||||
@@ -79,43 +79,41 @@ public class PlayerHandler{
|
||||
try(BufferedReader reader = Files.newBufferedReader(cache)){
|
||||
cachedPlayers = gson.fromJson(reader, listType);
|
||||
}catch(IOException ex){
|
||||
logger.warn("Encountered IOException while reading the playercache.json file!", ex);
|
||||
logger.warn("Encountered IOException while reading the <white>playercache.json</white> file!", ex);
|
||||
return;
|
||||
}catch(JsonIOException | JsonSyntaxException ex){
|
||||
logger.warn("Encountered Json exception while parsing playercache.json file!", ex);
|
||||
logger.warn("Encountered JsonSyntaxException while parsing <white>playercache.json</white> file!", ex);
|
||||
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?");
|
||||
logger.warn("Couldn't load players from <white>playercache.json</white> 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());
|
||||
logger.success("Loaded <white>%d</white> players into cache!", cachedPlayers.size());
|
||||
}
|
||||
|
||||
public void save(){
|
||||
if(cachedPlayers.isEmpty()){
|
||||
logger.info("No players in cache to save. Skipping...");
|
||||
logger.debug(PlayerHandler.class, "No players in cache to save. Skipping...");
|
||||
return;
|
||||
}
|
||||
|
||||
if(core.getFileHandler().getBoolean("disableCache")){
|
||||
logger.info("'disable_cache' is set to true. Skipping saving of cached players...");
|
||||
logger.debug(PlayerHandler.class, "[-] 'disable_cache' is set to true. Not saving cached players.");
|
||||
return;
|
||||
}
|
||||
|
||||
try(BufferedWriter writer = Files.newBufferedWriter(cache, StandardCharsets.UTF_8)){
|
||||
gson.toJson(cachedPlayers, listType, writer);
|
||||
logger.info("Successfully saved playercache.json file.");
|
||||
logger.success("Successfully saved <white>playercache.json</white> file.");
|
||||
}catch(IOException ex){
|
||||
logger.warn("Encountered IOException while saving cached players to playercache.json!", ex);
|
||||
logger.failure("Encountered IOException while saving cached players to <white>playercache.json</white>!", ex);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void addPlayer(String ip, String name, UUID uuid){
|
||||
@@ -36,6 +36,7 @@ import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class ProfileManager{
|
||||
|
||||
@@ -44,22 +45,36 @@ public class ProfileManager{
|
||||
* 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.defaultProfile();
|
||||
ProfileEntry entry = profile.getRandomProfile();
|
||||
|
||||
List<String> motd = resolveMOTD(entry, defEntry);
|
||||
List<String> players = resolvePlayers(entry, defEntry);
|
||||
String playerCountText = resolvePlayerCountText(entry, defEntry);
|
||||
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);
|
||||
List<String> motd = resolve(defEntry, entry, ProfileEntry::motd);
|
||||
List<String> players = resolve(defEntry, entry, ProfileEntry::players);
|
||||
String playerCountText = resolve(defEntry, entry, ProfileEntry::playerCountText);
|
||||
String favicon = resolve(defEntry, entry, ProfileEntry::favicon);
|
||||
NullBool hidePlayersEnabled = resolve(defEntry, entry, ProfileEntry::hidePlayersEnabled);
|
||||
NullBool extraPlayersEnabled = resolve(defEntry, entry, ProfileEntry::extraPlayersEnabled);
|
||||
NullBool maxPlayersEnabled = resolve(defEntry, entry, ProfileEntry::maxPlayersEnabled);
|
||||
NullBool onlinePlayersEnabled = resolve(defEntry, entry, ProfileEntry::onlinePlayersEnabled);
|
||||
NullBool hidePlayersHoverEnabled = resolve(defEntry, entry, ProfileEntry::hidePlayersHoverEnabled);
|
||||
String extraPlayersCount = resolve(defEntry, entry, ProfileEntry::extraPlayersCount);
|
||||
String maxPlayersCount = resolve(defEntry, entry, ProfileEntry::maxPlayersCount);
|
||||
String onlinePlayersCount = resolve(defEntry, entry, ProfileEntry::onlinePlayersCount);
|
||||
|
||||
return new ProfileEntry(motd, players, playerCountText, favicon,
|
||||
NullBool.resolve(isHidePlayersEnabled), NullBool.resolve(isExtraPlayersEnabled), NullBool.resolve(isMaxPlayersEnabled),
|
||||
extraPlayersCount, maxPlayersCount);
|
||||
return new ProfileEntry.Builder()
|
||||
.motd(motd)
|
||||
.players(players)
|
||||
.playerCountText(playerCountText)
|
||||
.favicon(favicon)
|
||||
.hidePlayersEnabled(hidePlayersEnabled)
|
||||
.extraPlayersEnabled(extraPlayersEnabled)
|
||||
.maxPlayersEnabled(maxPlayersEnabled)
|
||||
.onlinePlayersEnabled(onlinePlayersEnabled)
|
||||
.hidePlayersHoverEnabled(hidePlayersHoverEnabled)
|
||||
.extraPlayersCount(extraPlayersCount)
|
||||
.maxPlayersCount(maxPlayersCount)
|
||||
.onlinePlayersCount(onlinePlayersCount)
|
||||
.build();
|
||||
}
|
||||
|
||||
public static ServerListProfile resolveProfile(AdvancedServerList<?> core, GenericPlayer player, GenericServer server){
|
||||
@@ -67,7 +82,7 @@ public class ProfileManager{
|
||||
if(profile.isInvalidProfile())
|
||||
continue;
|
||||
|
||||
if(profile.evalConditions(core.getParser(), core.getPlugin().getPluginLogger(), player, server))
|
||||
if(profile.evalConditions(core, player, server))
|
||||
return profile;
|
||||
}
|
||||
|
||||
@@ -82,8 +97,11 @@ public class ProfileManager{
|
||||
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");
|
||||
NullBool onlinePlayersEnabled = resolveNullBool(node, "playerCount", "onlinePlayers", "enabled");
|
||||
NullBool hidePlayersHoverEnabled = resolveNullBool(node, "playerCount", "hidePlayersHover");
|
||||
String extraPlayers = resolveNullableString(node, "playerCount", "extraPlayers", "amount");
|
||||
String maxPlayers = resolveNullableString(node, "playerCount", "maxPlayers", "amount");
|
||||
String onlinePlayers = resolveNullableString(node, "playerCount", "onlinePlayers", "amount");
|
||||
|
||||
return new ProfileEntry.Builder()
|
||||
.motd(motd)
|
||||
@@ -93,8 +111,11 @@ public class ProfileManager{
|
||||
.hidePlayersEnabled(hidePlayers)
|
||||
.extraPlayersEnabled(extraPlayersEnabled)
|
||||
.maxPlayersEnabled(maxPlayersEnabled)
|
||||
.onlinePlayersEnabled(onlinePlayersEnabled)
|
||||
.hidePlayersHoverEnabled(hidePlayersHoverEnabled)
|
||||
.extraPlayersCount(extraPlayers)
|
||||
.maxPlayersCount(maxPlayers)
|
||||
.onlinePlayersCount(onlinePlayers)
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -115,67 +136,11 @@ public class ProfileManager{
|
||||
return false;
|
||||
}
|
||||
|
||||
private static List<String> resolveMOTD(ProfileEntry profile, ProfileEntry defaultProfile){
|
||||
if(profile == null || !checkOption(profile.motd()))
|
||||
return defaultProfile.motd();
|
||||
private static <T> T resolve(ProfileEntry defProfile, ProfileEntry profile, Function<ProfileEntry, T> function){
|
||||
if(profile == null || !checkOption(function.apply(profile)))
|
||||
return function.apply(defProfile);
|
||||
|
||||
return profile.motd();
|
||||
}
|
||||
|
||||
private static List<String> resolvePlayers(ProfileEntry profile, ProfileEntry defaultProfile){
|
||||
if(profile == null || !checkOption(profile.players()))
|
||||
return defaultProfile.players();
|
||||
|
||||
return profile.players();
|
||||
}
|
||||
|
||||
private static String resolvePlayerCountText(ProfileEntry profile, ProfileEntry defaultProfile){
|
||||
if(profile == null || !checkOption(profile.playerCountText()))
|
||||
return defaultProfile.playerCountText();
|
||||
|
||||
return profile.playerCountText();
|
||||
}
|
||||
|
||||
private static String resolveFavicon(ProfileEntry profile, ProfileEntry defaultProfile){
|
||||
if(profile == null || !checkOption(profile.favicon()))
|
||||
return defaultProfile.favicon();
|
||||
|
||||
return profile.favicon();
|
||||
}
|
||||
|
||||
private static boolean resolveHidePlayersEnabled(ProfileEntry profile, ProfileEntry defaultProfile){
|
||||
if(profile == null || !checkOption(profile.hidePlayersEnabled()))
|
||||
return defaultProfile.hidePlayersEnabled().getOrDefault(false);
|
||||
|
||||
return profile.hidePlayersEnabled().getOrDefault(false);
|
||||
}
|
||||
|
||||
private static boolean resolveExtraPlayersEnabled(ProfileEntry profile, ProfileEntry defaultProfile){
|
||||
if(profile == null || !checkOption(profile.extraPlayersEnabled()))
|
||||
return defaultProfile.extraPlayersEnabled().getOrDefault(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.extraPlayersCount() == null)
|
||||
return defaultProfile.extraPlayersCount() == null ? 0 : defaultProfile.extraPlayersCount();
|
||||
|
||||
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();
|
||||
return function.apply(profile);
|
||||
}
|
||||
|
||||
private static List<String> resolveList(ConfigurationNode node, Object... path){
|
||||
@@ -193,10 +158,10 @@ public class ProfileManager{
|
||||
return NullBool.resolve(node.node(path).getBoolean());
|
||||
}
|
||||
|
||||
private static Integer resolveNullableInt(ConfigurationNode node, Object... path){
|
||||
private static String resolveNullableString(ConfigurationNode node, Object... path){
|
||||
if(node.node(path).virtual())
|
||||
return null;
|
||||
|
||||
return node.node(path).getInt();
|
||||
return node.node(path).getString();
|
||||
}
|
||||
}
|
||||
@@ -53,9 +53,12 @@ public class ProfileSerializer implements TypeSerializer<ProfileEntry>{
|
||||
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", "hidePlayersHover").set(profile.hidePlayersHoverEnabled().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", "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());
|
||||
node.node("playerCount", "maxPlayers", "amount").set((profile.maxPlayersCount() == null) ? "0" : profile.maxPlayersCount());
|
||||
node.node("playerCount", "onlinePlayers", "enabled").set(profile.onlinePlayersEnabled().getOrDefault(false));
|
||||
node.node("playerCount", "onlinePlayers", "amount").set(profile.onlinePlayersCount() == null ? "0" : profile.onlinePlayersCount());
|
||||
}
|
||||
}
|
||||
@@ -64,8 +64,6 @@ public class StringReplacer{
|
||||
|
||||
private static String parsePlaceholder0(String input, ParsePosition position, GenericPlayer player, GenericServer server, ParseWarnCollector collector){
|
||||
AdvancedServerListAPI api = AdvancedServerList.getApi();
|
||||
|
||||
int placeholderStart = position.getIndex() - 2;
|
||||
int index = position.getIndex();
|
||||
|
||||
StringBuilder identifier = new StringBuilder();
|
||||
@@ -74,6 +72,9 @@ public class StringReplacer{
|
||||
boolean identified = false;
|
||||
boolean invalid = true;
|
||||
|
||||
int placeholderStart = position.getIndex() - 1;
|
||||
int valueStart = position.getIndex() - 1;
|
||||
|
||||
char[] chars = input.substring(index).toCharArray();
|
||||
for(final char c : chars){
|
||||
index++;
|
||||
@@ -85,6 +86,7 @@ public class StringReplacer{
|
||||
|
||||
if(c == ' ' && !identified){
|
||||
identified = true;
|
||||
valueStart = index + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -100,10 +102,6 @@ public class StringReplacer{
|
||||
|
||||
StringBuilder raw = new StringBuilder();
|
||||
|
||||
// Condition parsing needs one extra increase of index... for some reason
|
||||
if(collector != null)
|
||||
index++;
|
||||
|
||||
position.setIndex(index);
|
||||
|
||||
if(invalid){
|
||||
@@ -113,7 +111,7 @@ public class StringReplacer{
|
||||
raw.append(' ').append(valuesStr);
|
||||
|
||||
if(collector != null)
|
||||
collector.appendWarningFormatted(placeholderStart, "Placeholder '%s' does not have a closing bracket (})", raw.toString());
|
||||
collector.appendWarningFormatted(index, "Placeholder '<white>%s</white>' does not have a closing bracket (})", raw.toString());
|
||||
|
||||
return raw.toString();
|
||||
}
|
||||
@@ -128,7 +126,7 @@ public class StringReplacer{
|
||||
raw.append('}');
|
||||
|
||||
if(collector != null)
|
||||
collector.appendWarningFormatted(placeholderStart, "Placeholder '%s' does not have any available PlaceholderProvider", raw.toString());
|
||||
collector.appendWarningFormatted(placeholderStart, "Placeholder '<white>%s</white>' does not have any available PlaceholderProvider", raw.toString());
|
||||
|
||||
return raw.toString();
|
||||
}
|
||||
@@ -143,7 +141,7 @@ public class StringReplacer{
|
||||
raw.append('}');
|
||||
|
||||
if(collector != null)
|
||||
collector.appendWarningFormatted(placeholderStart, "Placeholder '%s' has an invalid value String '%s'", raw.toString(), valuesStr);
|
||||
collector.appendWarningFormatted(valueStart, "Placeholder '<white>%s</white>' has an invalid value String '<white>%s</white>'", raw.toString(), valuesStr);
|
||||
|
||||
return raw.toString();
|
||||
}
|
||||
|
||||
@@ -3,88 +3,130 @@
|
||||
#
|
||||
unknownPlayer:
|
||||
#
|
||||
# The name to use. Defaults to Anonymous.
|
||||
# The name to use.
|
||||
#
|
||||
# Default: Anonymous
|
||||
#
|
||||
name: "Anonymous"
|
||||
#
|
||||
# The UUID to use. Defaults to 606e2ff0-ed77-4842-9d6c-e1d3321c7838 (UUID of MHF_Question).
|
||||
# The UUID to use.
|
||||
#
|
||||
# Default: 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 name}) will not work while this option is enabled.
|
||||
# When set to true will no player joining the server be cached and saved to the playercache.json file.
|
||||
# This will also cause placeholders using a cached player such as ${player name} to no longer work.
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
# Default: false
|
||||
#
|
||||
disableCache: false
|
||||
|
||||
#
|
||||
# Should AdvancedServerList check for new versions?
|
||||
#
|
||||
# When set to true will AdvancedServerList check for a new version on modrinth.com every 12 hours and inform you in the
|
||||
# console about whether it found any new update or not.
|
||||
# When set to true will AdvancedServerList look for a new update on startup and repeat that check
|
||||
# every 12 hours after that.
|
||||
# It uses Modrinth to check for updates.
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
# Default: 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.
|
||||
# Additional messages prefixed with [DEBUG] will be printed in the console when this option is set
|
||||
# to true.
|
||||
# Enabling this option is only recommended for when you have problems, or have been told to enable
|
||||
# it by the plugin developer, as it can otherwise spam your console.
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
# Default: false
|
||||
#
|
||||
debug: false
|
||||
|
||||
#
|
||||
# Sets the time in minutes for favicons to be cached.
|
||||
# The number cannot be less than 1.
|
||||
# Should the "ASL" ASCI art be displayed on plugin startup?
|
||||
# Setting this to false will hide the banner.
|
||||
#
|
||||
# Defaults to 1 if not set.
|
||||
# Default: true
|
||||
#
|
||||
printBanner: true
|
||||
|
||||
#
|
||||
# Sets how long Favicons should be cached. Value is in minutes with the lowest possible value being 1.
|
||||
#
|
||||
# This option only affects dynamic favicons created from a placeholder or URL. Local favicons will
|
||||
# not be affected.
|
||||
#
|
||||
# Default: 1
|
||||
#
|
||||
faviconCacheTime: 1
|
||||
|
||||
#
|
||||
# List of options that should be disabled while the Maintenance Mode of the plugin Maintenance is active.
|
||||
# Any option not listed here will NOT be disabled, meaning AdvancedServerList will continue to handle it.
|
||||
# Options to disable while the Maintenance Plugin is present and Maintenance Mode is active.
|
||||
#
|
||||
# Each option defaults to true when not present, disabling said option while Maintenance is active.
|
||||
# Should an option be removed from this section will AdvancedServerList continue to set it, as if
|
||||
# the Maintenance plugin isn't active.
|
||||
#
|
||||
disableDuringMaintenance:
|
||||
#
|
||||
# When true (Default), disables handling of MOTD while Maintenance is enabled.
|
||||
# Whether MOTD changing should be disabled while Maintenance mode is active.
|
||||
#
|
||||
# Default: true
|
||||
#
|
||||
motd: true
|
||||
#
|
||||
# When true (Default), disables handling of Favicon while Maintenance is enabled.
|
||||
# Whether favicon changing should be disabled while Maintenance mode is active.
|
||||
#
|
||||
# Default: true
|
||||
#
|
||||
favicon: true
|
||||
#
|
||||
# When true (Default), disables hiding of player count while Maintenance is enabled.
|
||||
# Whether player hiding should be disabled while Maintenance mode is active.
|
||||
#
|
||||
# Default: true
|
||||
#
|
||||
hidePlayers: true
|
||||
#
|
||||
# When true (Default), disables handling of player count text while Maintenance is enabled.
|
||||
# Whether hiding player list on hover should be disabled while Maintenance mode is active.
|
||||
#
|
||||
# Default: true
|
||||
#
|
||||
hidePlayersHover: true
|
||||
#
|
||||
# Whether player count text changing should be disabled while Maintenance mode is active.
|
||||
#
|
||||
# Default: true
|
||||
#
|
||||
playerCountText: true
|
||||
#
|
||||
# When true (Default), disables handling of player count hover while Maintenance is enabled.
|
||||
# Whether player count hover changing should be disabled while Maintenance mode is active.
|
||||
#
|
||||
# Default: true
|
||||
#
|
||||
playerCountHover: true
|
||||
#
|
||||
# When true (Default), disables use of extra players feature while Maintenance is enabled.
|
||||
# Whether the extra players feature should be disabled while Maintenance mode is active.
|
||||
#
|
||||
# Default: true
|
||||
#
|
||||
extraPlayers: true
|
||||
#
|
||||
# When true (Default), disables use of max players feature while Maintenance is enabled.
|
||||
# Whether the max players feature should be disabled while Maintenance mode is active.
|
||||
#
|
||||
# Default: true
|
||||
#
|
||||
maxPlayers: true
|
||||
#
|
||||
# Whether the online players feature should be disabled while Maintenance mode is active.
|
||||
#
|
||||
# Default: true
|
||||
#
|
||||
onlinePlayers: true
|
||||
|
||||
#
|
||||
# DO NOT EDIT!
|
||||
@@ -92,4 +134,4 @@ disableDuringMaintenance:
|
||||
# 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}
|
||||
configVersion: ${plugin.config.version}
|
||||
@@ -58,12 +58,17 @@ motd:
|
||||
# This option supports three types of inputs:
|
||||
#
|
||||
# 1. Name, including .png extension, pointing to an image located in the plugin's favicons folder.
|
||||
# 2. URL pointing to an image.*
|
||||
# 3. Player name, UUID or placeholders returning one of these.*
|
||||
# 2. "random" to display a random PNG from the favicons folder.
|
||||
# 3. URL pointing to an image.
|
||||
# 4. Player name, UUID or placeholders returning one of these.
|
||||
# https://mc-heads.net will be used to retrieve an image of the provided name/UUID.
|
||||
#
|
||||
# * These images are loaded asynchronously, meaning they may not yet be "ready" when AdvancedServerList is done with
|
||||
# the event, requiring a refresh of the server list by the player to have it shown.
|
||||
# Note on favicons not showing:
|
||||
# AdvancedServerList has to create a Favicon object for the Proxy/Server to use which takes time to do so.
|
||||
# To not delay the Proxy/Server from being displayed (increase the loading time on the player end) is this creation
|
||||
# done asynchronously for URL/Player name/UUID. This has the downside that the Proxy/Server may be done handling the
|
||||
# ping before the Favicon is created, causing none to be displayed.
|
||||
# Note that this won't happen with local favicons, as those are created during the plugin's startup.
|
||||
#
|
||||
# Any images above or below 64x64 pixels will be automatically resized to these dimensions.
|
||||
#
|
||||
@@ -90,6 +95,15 @@ playerCount:
|
||||
#
|
||||
hidePlayers: false
|
||||
#
|
||||
# Set whether the List of players is shown when hovering over the player count.
|
||||
# Setting this to true will also make the plugin ignore the hover option below.
|
||||
#
|
||||
# If not present, defaults to false.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#hideplayershover
|
||||
#
|
||||
hidePlayersHover: false
|
||||
#
|
||||
# Set the lines shown when the player hovers over the player count.
|
||||
# Unlike the MOTD option does this one only support basic color and formatting codes. Any RGB colors will be
|
||||
# downsampled to the nearest matching color.
|
||||
@@ -134,6 +148,7 @@ playerCount:
|
||||
enabled: false
|
||||
#
|
||||
# Set the number that should be added to the online player count to then use as the new max player count.
|
||||
# Placeholders resolving to numbers can be used here.
|
||||
#
|
||||
# Example: Setting this to 1 will result in ${server playersMax} displaying 11 while 10 players are online,
|
||||
# 9 when 8 are online and so on.
|
||||
@@ -162,9 +177,34 @@ playerCount:
|
||||
enabled: false
|
||||
#
|
||||
# Set the number that should be used as the new max players count.
|
||||
# Placeholders resolving to numbers can be used here.
|
||||
#
|
||||
# If not present, defaults to 0.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#maxplayers-amount
|
||||
#
|
||||
amount: 0
|
||||
#
|
||||
# The onlinePlayers feature allows to set a number to use as the online player count to display.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#onlineplayers
|
||||
#
|
||||
onlinePlayers:
|
||||
#
|
||||
# Set whether the onlinePlayers feature should be enabled or not.
|
||||
# When set to true, the max player count will be set to the 'amount' value.
|
||||
#
|
||||
# If not present, defaults to false.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#onlineplayers-enabled
|
||||
#
|
||||
enabled: false
|
||||
#
|
||||
# Set the number that should be used as the new online players count.
|
||||
# Placeholders resolving to numbers can be used here.
|
||||
#
|
||||
# If not present, defaults to current online player count.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#onlineplayers-amount
|
||||
#
|
||||
amount: 0
|
||||
@@ -23,7 +23,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.test;
|
||||
package ch.andre601.advancedserverlist.core;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
|
||||
@@ -23,11 +23,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.test;
|
||||
package ch.andre601.advancedserverlist.core;
|
||||
|
||||
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;
|
||||
@@ -46,15 +45,9 @@ public class ExpressionParserTests{
|
||||
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();
|
||||
}
|
||||
boolean result = parser.evaluate(values.getKey(), null, null, collector);
|
||||
|
||||
logger.info("Result (output, isExpected): " + result + ", " + (result == values.getValue()));
|
||||
logger.info("Result (Output, Expected?): %b, %b", result, (result == values.getValue()));
|
||||
assertEquals(result, values.getValue());
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.test;
|
||||
package ch.andre601.advancedserverlist.core;
|
||||
|
||||
import com.unascribed.flexver.FlexVerComparator;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -0,0 +1,15 @@
|
||||
def on_pre_page_macros(env):
|
||||
footer = """
|
||||
|
||||
{% if page.meta and page.meta.api %}
|
||||
{% include 'api_docs/constructor_summaries.md' %}
|
||||
{% include 'api_docs/nested_class_summaries.md' %}
|
||||
{% include 'api_docs/enum_summaries.md' %}
|
||||
{% include 'api_docs/method_summaries.md' %}
|
||||
|
||||
{% include 'api_docs/constructor_details.md' %}
|
||||
{% include 'api_docs/enum_details.md' %}
|
||||
{% include 'api_docs/method_details.md' %}
|
||||
{% endif %}
|
||||
"""
|
||||
env.markdown += footer
|
||||