mirror of
https://codeberg.org/Andre601/AdvancedServerList.git
synced 2026-11-05 17:02:34 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e69c94da06 | ||
|
|
7cd3835785 | ||
|
|
8c36d27360 | ||
|
|
5329ed1b88 | ||
|
|
d66494f4dd | ||
|
|
d03ebf5fb1 | ||
|
|
c7ae2c130f | ||
|
|
017a1893c4 | ||
|
|
7a3af4cb26 | ||
|
|
0d05f2fe1d | ||
|
|
0acb097439 | ||
|
|
8a67fbead8 | ||
|
|
8f3252d66a | ||
|
|
7668a680c4 | ||
|
|
944e5a7262 | ||
|
|
d7cefb77ce | ||
|
|
e7a44711c0 | ||
|
|
96750ec5fd | ||
|
|
16500f29e4 | ||
|
|
25e433d0ed | ||
|
|
21430e9a4e | ||
|
|
de5455ab39 | ||
|
|
a52ca1d8be | ||
|
|
34d8048dd4 | ||
|
|
3b1e676888 | ||
|
|
9332a3e342 | ||
|
|
eacf227650 | ||
|
|
56131f4478 | ||
|
|
b362c34141 | ||
|
|
41718611e7 | ||
|
|
a92d6716e4 | ||
|
|
768509100d | ||
|
|
a64ad0cfa0 | ||
|
|
2abde6ef63 | ||
|
|
da2cf4d501 | ||
|
|
2a00634ce2 | ||
|
|
58108a8b19 | ||
|
|
6e7260d8f2 | ||
|
|
d75f43a4bd | ||
|
|
442c1539e9 | ||
|
|
a6188905dc | ||
|
|
81e0778825 | ||
|
|
afdcd11f7c | ||
|
|
4ca00cd8ad | ||
|
|
3b2d6b98b2 | ||
|
|
348d1fcacf | ||
|
|
4451d2382b | ||
|
|
3d410631ef | ||
|
|
e0ba710aed | ||
|
|
966d817f29 | ||
|
|
838416b1c5 | ||
|
|
23ee4a08ad | ||
|
|
baba7c7076 | ||
|
|
7e7228dd77 | ||
|
|
103bf4f1db | ||
|
|
0c7c8e56db | ||
|
|
cb3161a118 | ||
|
|
326fe7098a | ||
|
|
d79c54f7c9 | ||
|
|
1468febf72 | ||
|
|
afbcad6c3e | ||
|
|
79aefaa6a5 | ||
|
|
d6ac483a0e | ||
|
|
35df0d84ca | ||
|
|
45229bd6d2 | ||
|
|
7bfa88383d | ||
|
|
efaae58562 | ||
|
|
7dfdbb621d | ||
|
|
d2cd554fb1 | ||
|
|
69168efb01 | ||
|
|
55f94a8c27 | ||
|
|
e813bdaba4 | ||
|
|
b3f56aa398 | ||
|
|
87f0573162 | ||
|
|
e49fe391d0 | ||
|
|
d077efdc12 | ||
|
|
90fdaf628c | ||
|
|
9651011b19 | ||
|
|
9bacc04a68 | ||
|
|
515081e395 | ||
|
|
95fec87c12 | ||
|
|
778a415b4f | ||
|
|
db66945d99 | ||
|
|
cf4245842b | ||
|
|
d90084196b | ||
|
|
62b13a3cdf | ||
|
|
be6e5f8bfb | ||
|
|
aaf1439da8 | ||
|
|
b304252140 | ||
|
|
dda321f07b | ||
|
|
f487fd9cc1 | ||
|
|
5681e7a790 | ||
|
|
c3aa8bf536 | ||
|
|
1ce27b2244 | ||
|
|
74bce4c220 | ||
|
|
6605538b0f | ||
|
|
4aa9e946fd | ||
|
|
42ec17997e | ||
|
|
d2587e67f4 | ||
|
|
3f8f0e0ff7 | ||
|
|
b0dbbbfe82 | ||
|
|
6a32ea7826 | ||
|
|
a6bcc7036c | ||
|
|
639b32db23 | ||
|
|
53672243d3 | ||
|
|
3b7e177e4f | ||
|
|
6b43ef4dc3 | ||
|
|
665990aae9 | ||
|
|
70723ce35e | ||
|
|
b2d689306b | ||
|
|
6ae3f0aea6 | ||
|
|
9445e12f8d | ||
|
|
94da2bbd2d | ||
|
|
b5d0246bce | ||
|
|
48b1e53d13 | ||
|
|
5e7a59474d | ||
|
|
bfbc547712 | ||
|
|
2f8273d6a3 | ||
|
|
1f036727d8 | ||
|
|
bc07dadf03 | ||
|
|
ac0c754050 | ||
|
|
b2d664b5b9 | ||
|
|
58e9e55dc6 | ||
|
|
9b8e459b5c | ||
|
|
598343ebc7 | ||
|
|
c1fd983dab | ||
|
|
d05faf30dc | ||
|
|
79a96f30ca | ||
|
|
54ddf4bb4d | ||
|
|
f8b85ce9ed | ||
|
|
2f5c1db3c1 | ||
|
|
de7570ac6e | ||
|
|
41c7db5f27 | ||
|
|
ef0ef4e373 | ||
|
|
e9ab05618e | ||
|
|
a28e62f53c | ||
|
|
e82df2d1f7 | ||
|
|
16a2b05b2b | ||
|
|
5df3d6dd48 | ||
|
|
91a6149dac | ||
|
|
3f224504a1 | ||
|
|
437e155a46 | ||
|
|
8275069315 | ||
|
|
bd564a8638 | ||
|
|
591279f70b | ||
|
|
80e84aa41b | ||
|
|
9024c4dc71 | ||
|
|
bb0f389016 | ||
|
|
f8f8a45b1a | ||
|
|
0bae24bb66 | ||
|
|
2158caebe6 | ||
|
|
f9ea253da3 | ||
|
|
7c53ddf4f4 | ||
|
|
8bcc88d620 | ||
|
|
78b687587d | ||
|
|
168fe364b0 | ||
|
|
cd3f54dba6 | ||
|
|
79f15b2467 | ||
|
|
ade8ad5a33 | ||
|
|
6e343f1516 | ||
|
|
fee436fda6 | ||
|
|
27d4f5acd0 | ||
|
|
e18c70d446 | ||
|
|
0ca3ec62a9 | ||
|
|
461ae5d0aa | ||
|
|
5696a9417b | ||
|
|
0705101cd6 | ||
|
|
69ad3554cf | ||
|
|
7f1de13dcc | ||
|
|
c3e16eec31 | ||
|
|
207970a90b | ||
|
|
2628dbab56 | ||
|
|
3da9f8b400 | ||
|
|
ffd0a8c364 | ||
|
|
d9a7b244f9 | ||
|
|
f1fb5ef6ea | ||
|
|
d3406aad1c | ||
|
|
650bcc3235 | ||
|
|
0cd91c63bb | ||
|
|
e95a4634ec | ||
|
|
d0293ae15e | ||
|
|
f5c6185b96 | ||
|
|
61981db3cc | ||
|
|
52804adfdf | ||
|
|
4b185be8a4 | ||
|
|
46ac4ef5c1 | ||
|
|
00e2a8ebee | ||
|
|
c523da7477 | ||
|
|
01e586fa5e | ||
|
|
9322819538 | ||
|
|
7ef4a9a61b | ||
|
|
af2da61500 | ||
|
|
23d0626250 | ||
|
|
74dfdb3022 | ||
|
|
4a589619bd | ||
|
|
9bdd519246 | ||
|
|
cf4e08fe3e | ||
|
|
70bbb15c60 | ||
|
|
ee8e00f3a2 | ||
|
|
0280668f9b | ||
|
|
e959f478a0 | ||
|
|
f024b2c763 | ||
|
|
c0665b450e | ||
|
|
e50ed552b9 | ||
|
|
1601e41e9c | ||
|
|
f8b80f9e14 | ||
|
|
22bfe2be00 | ||
|
|
7e9c6b909c | ||
|
|
93ecdd736f | ||
|
|
abfbaf4498 | ||
|
|
ce3b80b05c | ||
|
|
9e3a77ad7d | ||
|
|
cdc2115cb3 | ||
|
|
5173f61c6c | ||
|
|
8b12cb2402 | ||
|
|
3ab48396af | ||
|
|
00b34c8b47 | ||
|
|
b06274638e | ||
|
|
cd3b2fe0b4 | ||
|
|
51d8ae6c42 | ||
|
|
1545be4709 | ||
|
|
7693e72728 | ||
|
|
b879110379 | ||
|
|
80900089bb | ||
|
|
df776f4e1c | ||
|
|
72afff8315 | ||
|
|
307384d1e1 | ||
|
|
84f31fad53 | ||
|
|
fe0774303a | ||
|
|
563173679b | ||
|
|
6e96e06109 | ||
|
|
dae25fd00a | ||
|
|
d2ca0cfae5 | ||
|
|
afaae368ac | ||
|
|
522ce7f932 | ||
|
|
3f3d460f2f | ||
|
|
3a03899688 | ||
|
|
e6d4264525 | ||
|
|
61466074fd | ||
|
|
4516157ddf | ||
|
|
82c65bf13c | ||
|
|
3c6e73671d | ||
|
|
c91a2c0d4e | ||
|
|
66b10656c3 | ||
|
|
b82a0ff0d9 | ||
|
|
2e02af5a67 | ||
|
|
5626b38390 | ||
|
|
415456447c | ||
|
|
c555a3c648 | ||
|
|
9ec0c1c4ce | ||
|
|
d3eb43db39 | ||
|
|
b4b4f6a9fc | ||
|
|
3217eee02b | ||
|
|
ea68fca70b | ||
|
|
a8ceb88b67 | ||
|
|
19d6ce28c4 | ||
|
|
05e61794a1 | ||
|
|
46e062eb8f | ||
|
|
2196456dd4 | ||
|
|
bfd1e2e2ad | ||
|
|
21af6df510 | ||
|
|
713062d1b4 | ||
|
|
673a134ab1 | ||
|
|
c777772a90 | ||
|
|
a43a9f8f19 | ||
|
|
d4a416f85e | ||
|
|
bc26ceae55 | ||
|
|
3d19a6688c | ||
|
|
03a8258ddc | ||
|
|
6df5015b0d | ||
|
|
f1f8aaaad2 | ||
|
|
151f5494fc | ||
|
|
f997fa0a89 | ||
|
|
2f1549eb8a | ||
|
|
77dba75c17 | ||
|
|
dfa72cb852 | ||
|
|
dc0cf6ebfc | ||
|
|
2c520e53c0 | ||
|
|
356cca9ba0 | ||
|
|
4e7b17a601 | ||
|
|
033f4bd6ab | ||
|
|
13edca3c4c | ||
|
|
a626dc5b28 | ||
|
|
7a60024bd0 | ||
|
|
cedb1e5748 | ||
|
|
8b0fb99bc5 | ||
|
|
31202a930a | ||
|
|
a105e3186b | ||
|
|
e2df79c428 | ||
|
|
01ecce170c | ||
|
|
3bb171cecf | ||
|
|
f54bbe26e1 | ||
|
|
ddede7abef | ||
|
|
2c6467f176 | ||
|
|
8b92f8fc4d | ||
|
|
7bf6d8de0f | ||
|
|
844a88d381 | ||
|
|
fcea4e90e3 | ||
|
|
6a97debdf7 | ||
|
|
07fa6cf0ec | ||
|
|
367f0f3501 | ||
|
|
16dcaef825 | ||
|
|
f780372fda | ||
|
|
a8f8c0d770 | ||
|
|
70e06afaf0 | ||
|
|
13e087eddd | ||
|
|
31af916f04 | ||
|
|
db06de243f |
No files matched your search
@@ -10,34 +10,28 @@ on:
|
||||
- ".forgejo/workflows/deploy_wiki.yml"
|
||||
- "docs/**"
|
||||
- "domains"
|
||||
- "mkdocs.yml"
|
||||
- "properdocs.yml"
|
||||
- "requirements.txt"
|
||||
|
||||
jobs:
|
||||
deployWiki:
|
||||
runs-on: codeberg-tiny
|
||||
runs-on: codeberg-small
|
||||
steps:
|
||||
- name: "Checkout Source Repository"
|
||||
uses: https://code.forgejo.org/actions/checkout@v4
|
||||
- name: "Checkout Repository"
|
||||
uses: https://code.forgejo.org/actions/checkout@v7
|
||||
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
|
||||
uses: https://code.forgejo.org/actions/setup-python@v6
|
||||
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
|
||||
run: "properdocs build"
|
||||
- name: "Deploy Website"
|
||||
uses: https://code.forgejo.org/actions/git-pages@v2
|
||||
with:
|
||||
site: https://asl.andre601.ch
|
||||
token: ${{ secrets.FORGEJO_TOKEN }}
|
||||
source: site/
|
||||
@@ -9,7 +9,7 @@ on:
|
||||
paths:
|
||||
- ".forgejo/workflows/pr_preview.yml"
|
||||
- "docs/**"
|
||||
- "mkdocs.yml"
|
||||
- "properdocs.yml"
|
||||
- "preview_domains"
|
||||
- "requirements.txt"
|
||||
workflow_dispatch:
|
||||
@@ -20,7 +20,7 @@ env:
|
||||
|
||||
jobs:
|
||||
createPreview:
|
||||
runs-on: codeberg-tiny
|
||||
runs-on: codeberg-small
|
||||
steps:
|
||||
#
|
||||
# Finding and updating comment in Pull request.
|
||||
@@ -28,13 +28,13 @@ jobs:
|
||||
#
|
||||
- name: "Find Comment"
|
||||
id: find-comment
|
||||
uses: https://github.com/peter-evans/find-comment@v3
|
||||
uses: https://github.com/peter-evans/find-comment@v4
|
||||
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
|
||||
uses: https://github.com/peter-evans/create-or-update-comment@v5
|
||||
with:
|
||||
body: |-
|
||||
## Pull request Preview
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
# Build website and push.
|
||||
#
|
||||
- name: "Checkout Source Repository"
|
||||
uses: https://code.forgejo.org/actions/checkout@v4
|
||||
uses: https://code.forgejo.org/actions/checkout@v7
|
||||
with:
|
||||
token: ${{ secrets.BOT_TOKEN }}
|
||||
fetch-depth: 0
|
||||
@@ -60,13 +60,13 @@ jobs:
|
||||
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
|
||||
uses: https://code.forgejo.org/actions/setup-python@v6
|
||||
with:
|
||||
python-version: 3.x
|
||||
- name: "Install Dependencies"
|
||||
run: "pip install -r requirements.txt"
|
||||
- name: "Build Website"
|
||||
run: "mkdocs build"
|
||||
run: "properdocs build"
|
||||
- name: "Commit and Push"
|
||||
run: |
|
||||
git config --global user.email "andre_601-bot@noreply.codeberg.org"
|
||||
@@ -81,7 +81,7 @@ jobs:
|
||||
# Update comment on success or failure.
|
||||
#
|
||||
- name: "Comment Success"
|
||||
uses: https://github.com/peter-evans/create-or-update-comment@v4
|
||||
uses: https://github.com/peter-evans/create-or-update-comment@v5
|
||||
with:
|
||||
body: |-
|
||||
## Pull request Preview
|
||||
@@ -99,7 +99,7 @@ jobs:
|
||||
edit-mode: replace
|
||||
- name: "Comment Failure"
|
||||
if: ${{ failure() }}
|
||||
uses: https://github.com/peter-evans/create-or-update-comment@v4
|
||||
uses: https://github.com/peter-evans/create-or-update-comment@v5
|
||||
with:
|
||||
body: |-
|
||||
## Pull request Preview
|
||||
@@ -109,7 +109,7 @@ jobs:
|
||||
| Name | Link |
|
||||
|---------|-------------------------------------------|
|
||||
| Commit | ${{ github.event.pull_request.head.sha }} |
|
||||
| Logs | ${{ RUN_URL }} |
|
||||
| Logs | ${{ env.RUN_URL }} |
|
||||
comment-id: "${{ steps.comment.outputs.comment-id }}"
|
||||
issue-number: "${{ github.event.pull_request.number }}"
|
||||
token: "${{ secrets.BOT_TOKEN }}"
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
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}
|
||||
@@ -4,7 +4,7 @@ when:
|
||||
|
||||
steps:
|
||||
- name: "Build Jar and Upload"
|
||||
image: maven:3.9.10-eclipse-temurin-21
|
||||
image: maven:3.9.16-eclipse-temurin-25
|
||||
environment:
|
||||
CODEBERG_API_TOKEN:
|
||||
from_secret: cb_token
|
||||
@@ -19,16 +19,16 @@ steps:
|
||||
- cd version-uploader/target
|
||||
- mv VersionUploader.jar ../../
|
||||
- cd ../../
|
||||
- java -jar VersionUploader.jar --all
|
||||
- java -jar VersionUploader.jar upload all
|
||||
- name: "Upload Jars to Codeberg"
|
||||
image: woodpeckerci/plugin-gitea-release
|
||||
settings:
|
||||
base_url: https://codeberg.org
|
||||
files:
|
||||
- "bungeecord/target/AdvancedServerList-*.jar"
|
||||
- "paper/target/AdvancedServerList-*.jar"
|
||||
- "velocity/target/AdvancedServerList-*.jar"
|
||||
- "addons/banplugins/target/AdvancedServerList-*.jar"
|
||||
- "addons/luckperms/target/AdvancedServerList-*.jar"
|
||||
api_key:
|
||||
from_secret: cb_token
|
||||
- name: "Create Post on Mastodon"
|
||||
@@ -45,4 +45,19 @@ steps:
|
||||
Modrinth - https://modrinth.com/plugin/advancedserverlist
|
||||
Hangar - https://hangar.papermc.io/Andre_601/AdvancedServerList
|
||||
Codeberg - https://codeberg.org/Andre601/AdvancedServerList
|
||||
visibility: public
|
||||
visibility: public
|
||||
- name: "Create Post on Bluesky"
|
||||
image: woodpeckerci/plugin-bluesky-post
|
||||
when:
|
||||
- status: ["success"]
|
||||
settings:
|
||||
identifier: andre601.ch
|
||||
app_password:
|
||||
from_secret: bluesky_app_password
|
||||
languages: english
|
||||
text: |-
|
||||
#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
|
||||
@@ -1,36 +0,0 @@
|
||||
when:
|
||||
- event: push
|
||||
branch: ${CI_REPO_DEFAULT_BRANCH}
|
||||
path:
|
||||
include: [".woodpecker/publish_docs.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 "ASL Docs Builder"
|
||||
|
||||
steps:
|
||||
- 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.git site
|
||||
- chmod -R a+w site
|
||||
- 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 domains site/.domains
|
||||
- cd site
|
||||
- git remote set-url origin https://$BOT_TOKEN@codeberg.org/Andre601/asl-docs.git
|
||||
- git add --all
|
||||
- git commit -m "Update AdvancedServerList Docs ($( env TZ=Europe/Zurich date +"%d.%m.%Y %Z" )) [SKIP CI]"
|
||||
- git push
|
||||
@@ -63,7 +63,7 @@ AdvancedServerList soft-depends on the following plugins, meaning their inclusio
|
||||
|
||||
| Plugin | Supported Platforms |
|
||||
|-------------------------------------------------------------------------|----------------------------------------|
|
||||
| [PlaceholderAPI](https://hangar.papermc.io/HelpChat/PlaceholderAPI) | Paper |
|
||||
| [PlaceholderAPI](https://modrinth.com/plugin/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 |
|
||||
|
||||
+5
-5
@@ -19,6 +19,8 @@ To ensure proper safety and support are only certain versions and Platforms of A
|
||||
|
||||
| Server/Proxy Version* | Supported |
|
||||
|-----------------------|-----------|
|
||||
| 26.2 | Yes |
|
||||
| 26.1.x | Yes |
|
||||
| 1.21.x | Yes |
|
||||
| 1.20.x | Yes |
|
||||
| 1.19.x | No |
|
||||
@@ -53,8 +55,6 @@ To ensure proper safety and support are only certain versions and Platforms of A
|
||||
|
||||
| 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.
|
||||
| BungeeCord | No |
|
||||
| Waterfall | No |
|
||||
| Velocity | Yes |
|
||||
@@ -62,30 +62,16 @@
|
||||
|
||||
<dependencies>
|
||||
<!-- Proxy/Server -->
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>1.21-R0.3</version>
|
||||
<type>jar</type>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>1.21-R0.3</version>
|
||||
<type>javadoc</type>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.papermc.paper</groupId>
|
||||
<artifactId>paper-api</artifactId>
|
||||
<version>1.21-R0.1-SNAPSHOT</version>
|
||||
<version>[26.1.2.build,)</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.velocitypowered</groupId>
|
||||
<artifactId>velocity-api</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.4.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -99,7 +85,7 @@
|
||||
<dependency>
|
||||
<groupId>space.arim.libertybans</groupId>
|
||||
<artifactId>bans-api</artifactId>
|
||||
<version>1.1.0</version>
|
||||
<version>1.1.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
-68
@@ -1,68 +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.bungeecord;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.AdvancedServerListAPI;
|
||||
import ch.andre601.advancedserverlist.banplugins.BanPluginsList;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
|
||||
public class BungeeCordBanPluginsAddon extends Plugin{
|
||||
|
||||
@Override
|
||||
public void onEnable(){
|
||||
if(getProxy().getPluginManager().getPlugin("AdvancedServerList") == null){
|
||||
getLogger().warning("AdvancedServerList is not enabled. This plugin requires it to function!");
|
||||
return;
|
||||
}
|
||||
|
||||
int loadedPlaceholders = loadPlaceholderProviders();
|
||||
if(loadedPlaceholders == 0){
|
||||
getLogger().warning("No compatible Ban plugin was found to register placeholders for.");
|
||||
}else{
|
||||
getLogger().info("Loaded " + loadedPlaceholders + " Placeholder Set(s) for AdvancedServerList!");
|
||||
}
|
||||
}
|
||||
|
||||
private int loadPlaceholderProviders(){
|
||||
int loaded = 0;
|
||||
AdvancedServerListAPI api = AdvancedServerListAPI.get();
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
return loaded;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
name: 'ASLBanPluginsAddon'
|
||||
author: 'Andre_601'
|
||||
version: '${plugin.version}'
|
||||
description: 'AdvancedBan Add-on for AdvancedServerList to add placeholders to use.'
|
||||
|
||||
softDepends:
|
||||
- AdvancedServerList
|
||||
- AdvancedBan
|
||||
- LibertyBans
|
||||
- LiteBans
|
||||
|
||||
main: 'ch.andre601.advancedserverlist.banplugins.bungeecord.BungeeCordBanPluginsAddon'
|
||||
@@ -0,0 +1,112 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ MIT License
|
||||
~
|
||||
~ Copyright (c) 2022-2024 Andre_601
|
||||
~
|
||||
~ Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
~ of this software and associated documentation files (the "Software"), to deal
|
||||
~ in the Software without restriction, including without limitation the rights
|
||||
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
~ copies of the Software, and to permit persons to whom the Software is
|
||||
~ furnished to do so, subject to the following conditions:
|
||||
~
|
||||
~ The above copyright notice and this permission notice shall be included in all
|
||||
~ copies or substantial portions of the Software.
|
||||
~
|
||||
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
~ SOFTWARE.
|
||||
~
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>parent</artifactId>
|
||||
<groupId>ch.andre601.advancedserverlist</groupId>
|
||||
<version>parent</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>luckperms</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>${plugin.version}</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>sonatype</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>papermc</id>
|
||||
<url>https://repo.papermc.io/repository/maven-public/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<!-- Proxy/Server -->
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>1.21-R0.4</version>
|
||||
<type>jar</type>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>1.21-R0.4</version>
|
||||
<type>javadoc</type>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.papermc.paper</groupId>
|
||||
<artifactId>paper-api</artifactId>
|
||||
<version>[26.1.2.build,)</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.velocitypowered</groupId>
|
||||
<artifactId>velocity-api</artifactId>
|
||||
<version>3.4.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Plugin APIs -->
|
||||
<dependency>
|
||||
<groupId>ch.andre601.asl-api</groupId>
|
||||
<artifactId>api</artifactId>
|
||||
<version>${api.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.luckperms</groupId>
|
||||
<artifactId>api</artifactId>
|
||||
<version>5.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>AdvancedServerList-LuckPerms-Addon-${plugin.version}${project.build.build_id}</finalName>
|
||||
<resources>
|
||||
<resource>
|
||||
<filtering>true</filtering>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
</project>
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package ch.andre601.advancedserverlist.luckperms.paper;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.AdvancedServerListAPI;
|
||||
import ch.andre601.advancedserverlist.api.exceptions.InvalidPlaceholderProviderException;
|
||||
import ch.andre601.advancedserverlist.luckperms.placeholders.LuckPermsPlaceholder;
|
||||
import net.luckperms.api.LuckPerms;
|
||||
import net.luckperms.api.LuckPermsProvider;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public class LuckPermsAddon extends JavaPlugin{
|
||||
|
||||
@Override
|
||||
public void onEnable(){
|
||||
if(!this.getServer().getPluginManager().isPluginEnabled("AdvancedServerList")){
|
||||
this.getSLF4JLogger().warn("AdvancedServerList not enabled. This plugin is required!");
|
||||
this.getServer().getPluginManager().disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!this.getServer().getPluginManager().isPluginEnabled("LuckPerms")){
|
||||
this.getSLF4JLogger().warn("LuckPerms not enabled. This plugin is required!");
|
||||
this.getServer().getPluginManager().disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
|
||||
LuckPerms luckPerms;
|
||||
try{
|
||||
luckPerms = LuckPermsProvider.get();
|
||||
}catch(IllegalStateException ex){
|
||||
this.getSLF4JLogger().error("Unable to obtain LuckPerms API instance! Disabling plugin...");
|
||||
this.getServer().getPluginManager().disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
|
||||
this.getSLF4JLogger().info("Registering LuckPerms Placeholder...");
|
||||
try{
|
||||
AdvancedServerListAPI.get().addPlaceholderProvider(new LuckPermsPlaceholder(luckPerms));
|
||||
this.getSLF4JLogger().info("Successfully registered Placeholder!");
|
||||
}catch(InvalidPlaceholderProviderException ex){
|
||||
this.getSLF4JLogger().warn("Couldn't register Placeholder. Disabling Plugin...");
|
||||
this.getServer().getPluginManager().disablePlugin(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
package ch.andre601.advancedserverlist.luckperms.placeholders;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import net.luckperms.api.LuckPerms;
|
||||
import net.luckperms.api.model.user.User;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
|
||||
public class LuckPermsPlaceholder extends PlaceholderProvider{
|
||||
|
||||
private final LuckPerms luckPerms;
|
||||
|
||||
private final HashMap<UUID, CacheValue> cache = new HashMap<>();
|
||||
|
||||
public LuckPermsPlaceholder(LuckPerms luckPerms){
|
||||
super("luckperms");
|
||||
this.luckPerms = luckPerms;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String parsePlaceholder(@NonNull String placholder, @NonNull GenericPlayer player, @NonNull GenericServer server){
|
||||
if(luckPerms == null)
|
||||
return "ERR: LuckPerms not available.";
|
||||
|
||||
CacheValue cacheValue = cache.get(player.getUUID());
|
||||
User user;
|
||||
if(cacheValue == null || cacheValue.expired()){
|
||||
// Can cause lag if on main thread.
|
||||
// But the alternative would be a lot more annoying and error-prone.
|
||||
user = luckPerms.getUserManager().loadUser(player.getUUID()).join();
|
||||
cache.put(player.getUUID(), new CacheValue(System.currentTimeMillis(), user));
|
||||
}else{
|
||||
user = cacheValue.user();
|
||||
}
|
||||
|
||||
if(user == null)
|
||||
return "ERR: Player not found.";
|
||||
|
||||
String[] parts = placholder.split("\\s+");
|
||||
if(parts.length == 1)
|
||||
return "ERR: Missing argument for placeholder " + parts[0] + ".";
|
||||
|
||||
return switch(parts[0]){
|
||||
case "hasGroup" -> String.valueOf(
|
||||
user.getCachedData().getPermissionData().checkPermission("group." + parts[1])
|
||||
);
|
||||
case "hasPermission" -> String.valueOf(
|
||||
user.getCachedData().getPermissionData().checkPermission(parts[1]).asBoolean()
|
||||
);
|
||||
case "primaryGroup" -> user.getPrimaryGroup();
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
private record CacheValue(long timestamp, User user){
|
||||
public boolean expired(){
|
||||
// Expired if current timestamp minus old one is more than 60k milliseconds (1 minute)
|
||||
return (timestamp < 0L) || System.currentTimeMillis() - timestamp >= 60_000;
|
||||
}
|
||||
}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package ch.andre601.advancedserverlist.luckperms.velocity;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.AdvancedServerListAPI;
|
||||
import ch.andre601.advancedserverlist.api.exceptions.InvalidPlaceholderProviderException;
|
||||
import ch.andre601.advancedserverlist.luckperms.placeholders.LuckPermsPlaceholder;
|
||||
import com.google.inject.Inject;
|
||||
import com.velocitypowered.api.event.Subscribe;
|
||||
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
import net.luckperms.api.LuckPerms;
|
||||
import net.luckperms.api.LuckPermsProvider;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class LuckPermsAddon{
|
||||
|
||||
private final ProxyServer proxy;
|
||||
private final Logger logger = LoggerFactory.getLogger("ASLLuckPermsAddon");
|
||||
|
||||
@Inject
|
||||
public LuckPermsAddon(ProxyServer proxy){
|
||||
this.proxy = proxy;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void init(ProxyInitializeEvent event){
|
||||
if(!proxy.getPluginManager().isLoaded("advancedserverlist")){
|
||||
logger.warn("AdvancedServerList is not enabled. This plugin is required.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!proxy.getPluginManager().isLoaded("luckperms")){
|
||||
logger.warn("LuckPerms is not enabled. This plugin is required.");
|
||||
return;
|
||||
}
|
||||
|
||||
LuckPerms luckPerms;
|
||||
try{
|
||||
luckPerms = LuckPermsProvider.get();
|
||||
}catch(IllegalStateException ex){
|
||||
logger.warn("Unable to obtain LuckPerms API instance. The plugin won't work.");
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info("Registering LuckPerms Placeholder...");
|
||||
try{
|
||||
AdvancedServerListAPI.get().addPlaceholderProvider(new LuckPermsPlaceholder(luckPerms));
|
||||
logger.info("Successfully registered Placeholder!");
|
||||
}catch(InvalidPlaceholderProviderException ex){
|
||||
logger.warn("Unable to register LuckPerms Placeholder! The plugin won't work.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
name: 'ASLLuckPermsAddon'
|
||||
author: 'Andre_601'
|
||||
version: '${plugin.version}'
|
||||
|
||||
main: 'ch.andre601.advancedserverlist.luckperms.paper.LuckPermsAddon'
|
||||
|
||||
api-version: '1.19'
|
||||
|
||||
dependencies:
|
||||
server:
|
||||
AdvancedServerList:
|
||||
required: false
|
||||
load: BEFORE
|
||||
LuckPerms:
|
||||
required: false
|
||||
load: BEFORE
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"id": "aslluckpermsaddon",
|
||||
"name": "ASLLuckPermsAddon",
|
||||
"version": "${plugin.version}",
|
||||
"description": "LuckPerms Add-on for AdvancedServerList to add placeholders to use.",
|
||||
"authors": [
|
||||
"Andre_601"
|
||||
],
|
||||
"dependencies": [
|
||||
{
|
||||
"id": "advancedserverlist",
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"id": "luckperms",
|
||||
"optional": true
|
||||
}
|
||||
],
|
||||
"main": "ch.andre601.advancedserverlist.luckperms.velocity.LuckPermsAddon"
|
||||
}
|
||||
@@ -1,220 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ MIT License
|
||||
~
|
||||
~ Copyright (c) 2022-2023 Andre_601
|
||||
~
|
||||
~ Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
~ of this software and associated documentation files (the "Software"), to deal
|
||||
~ in the Software without restriction, including without limitation the rights
|
||||
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
~ copies of the Software, and to permit persons to whom the Software is
|
||||
~ furnished to do so, subject to the following conditions:
|
||||
~
|
||||
~ The above copyright notice and this permission notice shall be included in all
|
||||
~ copies or substantial portions of the Software.
|
||||
~
|
||||
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
~ SOFTWARE.
|
||||
~
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>parent</artifactId>
|
||||
<groupId>ch.andre601.advancedserverlist</groupId>
|
||||
<version>parent</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>bungeecord</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>${plugin.version}</version>
|
||||
<description>${plugin.description}</description>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>sonatype</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>repo-sayandevelopment</id>
|
||||
<url>https://repo.sayandev.org/releases/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>ch.andre601.advancedserverlist</groupId>
|
||||
<artifactId>core</artifactId>
|
||||
<version>${plugin.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.andre601.asl-api</groupId>
|
||||
<artifactId>platform-bungeecord</artifactId>
|
||||
<version>${api.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- BungeeCord API -->
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>1.21-R0.3</version>
|
||||
<type>jar</type>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>1.21-R0.3</version>
|
||||
<type>javadoc</type>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Adventure Library -->
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-api</artifactId>
|
||||
<version>${dependency.adventure-api}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-text-minimessage</artifactId>
|
||||
<version>${dependency.adventure-text-minimessage}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-platform-bungeecord</artifactId>
|
||||
<version>${dependency.adventure-platform-bungeecord}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Metrics -->
|
||||
<dependency>
|
||||
<groupId>org.bstats</groupId>
|
||||
<artifactId>bstats-bungeecord</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Configurate -->
|
||||
<dependency>
|
||||
<groupId>org.spongepowered</groupId>
|
||||
<artifactId>configurate-yaml</artifactId>
|
||||
<version>${dependency.configurate-yaml}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Plugins -->
|
||||
<dependency>
|
||||
<groupId>com.github.LeonMangler</groupId>
|
||||
<artifactId>PremiumVanishAPI</artifactId>
|
||||
<version>2.9.18-2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.sayandev</groupId>
|
||||
<artifactId>sayanvanish-api</artifactId>
|
||||
<version>1.6.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.sayandev</groupId>
|
||||
<artifactId>sayanvanish-proxy-bungeecord</artifactId>
|
||||
<version>1.6.5</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}${project.build.build_id}</finalName>
|
||||
<resources>
|
||||
<resource>
|
||||
<filtering>true</filtering>
|
||||
<directory>${project.basedir}/src/main/resources</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<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>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
-254
@@ -1,254 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.bungeecord;
|
||||
|
||||
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.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 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(){
|
||||
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();
|
||||
getProxy().getScheduler().cancel(this);
|
||||
audiences.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadEvents(){
|
||||
new PlayerJoinEventListener(this);
|
||||
new ProxyPingEventListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadMetrics(){
|
||||
new Metrics(this, 15585).addCustomChart(new SimplePie("profiles",
|
||||
() -> String.valueOf(core.getFileHandler().getProfiles().size())
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadFaviconHandler(AdvancedServerList<Favicon> core){
|
||||
faviconHandler = new FaviconHandler<>(core);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearFaviconCache(){
|
||||
if(faviconHandler == null)
|
||||
return;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getFolderPath(){
|
||||
return getDataFolder().toPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginLogger getPluginLogger(){
|
||||
return logger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaviconHandler<Favicon> getFaviconHandler(){
|
||||
if(faviconHandler == null)
|
||||
faviconHandler = new FaviconHandler<>(core);
|
||||
|
||||
return faviconHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandManager<CmdSender> getCommandManager(){
|
||||
return handler.commandHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlatformInfo(){
|
||||
return getProxy().getName() + " " + getProxy().getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLoader(){
|
||||
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);
|
||||
}));
|
||||
}
|
||||
}
|
||||
-63
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.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{
|
||||
|
||||
private final CommandSender sender;
|
||||
private final BungeeAudiences bungeeAudiences;
|
||||
|
||||
public BungeeCmdSender(CommandSender sender, BungeeAudiences bungeeAudiences){
|
||||
this.sender = sender;
|
||||
this.bungeeAudiences = bungeeAudiences;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
-60
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* 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.bungeecord.commands;
|
||||
|
||||
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CommandManagerInterface;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
import org.incendo.cloud.SenderMapper;
|
||||
import org.incendo.cloud.bungee.BungeeCommandManager;
|
||||
import org.incendo.cloud.execution.ExecutionCoordinator;
|
||||
|
||||
public class BungeeCommandManagerInterface implements CommandManagerInterface<CommandSender>{
|
||||
|
||||
private final BungeeCordCore plugin;
|
||||
|
||||
public BungeeCommandManagerInterface(BungeeCordCore plugin){
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
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()
|
||||
);
|
||||
}
|
||||
}
|
||||
-219
@@ -1,219 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.bungeecord.listeners;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.events.GenericServerListEvent;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
|
||||
import ch.andre601.advancedserverlist.bungeecord.objects.impl.BungeePlayerImpl;
|
||||
import ch.andre601.advancedserverlist.bungeecord.objects.impl.BungeeProxyImpl;
|
||||
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;
|
||||
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
|
||||
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer;
|
||||
import net.md_5.bungee.api.Favicon;
|
||||
import net.md_5.bungee.api.ServerPing;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.ProxyPingEvent;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class BungeeEventWrapper implements GenericEventWrapper<Favicon, BungeePlayerImpl>{
|
||||
|
||||
private final BungeeCordCore plugin;
|
||||
private final ProxyPingEvent event;
|
||||
private final ServerPing.Protocol protocol;
|
||||
private final ServerPing ping;
|
||||
|
||||
public BungeeEventWrapper(BungeeCordCore plugin, ProxyPingEvent event){
|
||||
this.plugin = plugin;
|
||||
this.event = event;
|
||||
this.protocol = event.getResponse().getVersion();
|
||||
this.ping = event.getResponse();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GenericServerListEvent callEvent(ProfileEntry entry){
|
||||
PreServerListSetEventImpl event = new PreServerListSetEventImpl(entry);
|
||||
plugin.getProxy().getPluginManager().callEvent(event);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxPlayers(int maxPlayers){
|
||||
ping.getPlayers().setMax(maxPlayers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnlinePlayers(int onlinePlayers){
|
||||
ping.getPlayers().setOnline(onlinePlayers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMotd(Component component){
|
||||
ping.setDescriptionComponent(new TextComponent(BungeeComponentSerializer.get().serialize(component)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hidePlayers(){
|
||||
ping.setPlayers(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerCount(String name){
|
||||
protocol.setName(name);
|
||||
protocol.setProtocol(-1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayers(List<String> lines, BungeePlayerImpl player, GenericServer server){
|
||||
ServerPing.PlayerInfo[] players = new ServerPing.PlayerInfo[lines.size()];
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if(players.length > 0)
|
||||
ping.getPlayers().setSample(players);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayersHidden(){
|
||||
ping.getPlayers().setSample(new ServerPing.PlayerInfo[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFavicon(Favicon favicon){
|
||||
ping.setFavicon(favicon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultFavicon(){
|
||||
ping.setFavicon(ping.getFaviconObject());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateEvent(){
|
||||
this.ping.setVersion(this.protocol);
|
||||
this.event.setResponse(this.ping);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInvalidProtocol(){
|
||||
return protocol == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMaintenanceModeActive(){
|
||||
if(plugin.getProxy().getPluginManager().getPlugin("Maintenance") == null)
|
||||
return false;
|
||||
|
||||
return MaintenanceUtil.get().isMaintenanceEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtocolVersion(){
|
||||
return event.getConnection().getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOnlinePlayers(){
|
||||
return plugin.getOnlinePlayers(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxPlayers(){
|
||||
return ping.getPlayers().getMax();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlayerIP(){
|
||||
return ((InetSocketAddress)event.getConnection().getSocketAddress()).getHostString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parsePAPIPlaceholders(String text, BungeePlayerImpl player){
|
||||
if(plugin.getProxy().getPluginManager().getPlugin("PAPIProxyBridge") == null)
|
||||
return text;
|
||||
|
||||
if(!PAPIUtil.get().isCompatible())
|
||||
return text;
|
||||
|
||||
String server = PAPIUtil.get().getServer();
|
||||
if(server == null || server.isEmpty())
|
||||
return text;
|
||||
|
||||
ServerInfo serverInfo = plugin.getProxy().getServerInfo(server);
|
||||
if(serverInfo == null || serverInfo.getPlayers().isEmpty())
|
||||
return text;
|
||||
|
||||
ProxiedPlayer carrier = PAPIUtil.get().getPlayer(serverInfo.getPlayers());
|
||||
if(carrier == null)
|
||||
return text;
|
||||
|
||||
return PAPIUtil.get().parse(text, carrier.getUniqueId(), player.getUUID());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVirtualHost(){
|
||||
return this.resolveHost(event.getConnection().getVirtualHost());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginCore<Favicon> getPlugin(){
|
||||
return plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BungeePlayerImpl createPlayer(CachedPlayer player, int protocol){
|
||||
return new BungeePlayerImpl(player, protocol);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GenericServer createGenericServer(int playersOnline, int playersMax, String host){
|
||||
Map<String, ServerInfo> servers = plugin.getProxy().getServers();
|
||||
|
||||
return new BungeeProxyImpl(servers, playersOnline, playersMax, host);
|
||||
}
|
||||
}
|
||||
-61
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.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;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
public class PlayerJoinEventListener implements Listener{
|
||||
private final BungeeCordCore plugin;
|
||||
|
||||
public PlayerJoinEventListener(BungeeCordCore plugin){
|
||||
this.plugin = plugin;
|
||||
plugin.getProxy().getPluginManager().registerListener(plugin, this);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onJoin(PostLoginEvent event){
|
||||
InetSocketAddress address = (InetSocketAddress)event.getPlayer().getPendingConnection().getSocketAddress();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
-36
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.bungeecord.listeners;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.bungeecord.events.PreServerListSetEvent;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
|
||||
public class PreServerListSetEventImpl extends PreServerListSetEvent{
|
||||
|
||||
public PreServerListSetEventImpl(ProfileEntry entry){
|
||||
super(entry);
|
||||
}
|
||||
}
|
||||
-51
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.bungeecord.listeners;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.bungeecord.events.PostServerListSetEvent;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
|
||||
import ch.andre601.advancedserverlist.core.events.PingEventHandler;
|
||||
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 ProxyPingEventListener implements Listener{
|
||||
|
||||
private final BungeeCordCore plugin;
|
||||
|
||||
public ProxyPingEventListener(BungeeCordCore plugin){
|
||||
this.plugin = plugin;
|
||||
plugin.getProxy().getPluginManager().registerListener(plugin, this);
|
||||
}
|
||||
|
||||
@EventHandler(priority = 90) // Maintenance has Event Priority 80, so we need to be AFTER it.
|
||||
public void onProxyPing(ProxyPingEvent event){
|
||||
ProfileEntry entry = PingEventHandler.handleEvent(new BungeeEventWrapper(plugin, event));
|
||||
|
||||
plugin.getProxy().getPluginManager().callEvent(new PostServerListSetEvent(entry));
|
||||
}
|
||||
}
|
||||
-76
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.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;
|
||||
|
||||
public class BungeeLogger implements PluginLogger{
|
||||
|
||||
private final BungeeCordCore plugin;
|
||||
private final Logger logger;
|
||||
|
||||
public BungeeLogger(BungeeCordCore plugin){
|
||||
this.plugin = plugin;
|
||||
this.logger = plugin.getLogger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Class<?> clazz, String msg, Object... args){
|
||||
if(plugin.isDebugEnabled())
|
||||
info("[DEBUG] [" + clazz.getSimpleName() + "] " + msg, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debugWarn(Class<?> clazz, String msg, Object... args){
|
||||
if(plugin.isDebugEnabled())
|
||||
warn("[DEBUG] [" + clazz.getSimpleName() + "] " + msg, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String msg, Object... args){
|
||||
logger.info(ComponentParser.textFormatted(msg, args).toStringStriped());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Object... args){
|
||||
logger.warning(ComponentParser.textFormatted(msg, args).toStringStriped());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Throwable throwable){
|
||||
logger.log(Level.WARNING, ComponentParser.text(msg).toStringStriped(), throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Throwable throwable, Object... args){
|
||||
logger.log(Level.WARNING, ComponentParser.textFormatted(msg, args).toStringStriped(), throwable);
|
||||
}
|
||||
}
|
||||
-49
@@ -1,49 +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.bungeecord.objects.impl;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.bungeecord.objects.BungeePlayer;
|
||||
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public record BungeePlayerImpl(CachedPlayer player, int protocol) implements BungeePlayer{
|
||||
|
||||
@Override
|
||||
public String getName(){
|
||||
return player.name();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtocol(){
|
||||
return protocol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUUID(){
|
||||
return player.uuid();
|
||||
}
|
||||
}
|
||||
-53
@@ -1,53 +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.bungeecord.objects.impl;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.bungeecord.objects.BungeeProxy;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public record BungeeProxyImpl(Map<String, ServerInfo> servers, int playersOnline, int playersMax, String host) implements BungeeProxy{
|
||||
@Override
|
||||
public Map<String, ServerInfo> getServers(){
|
||||
return servers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPlayersOnline(){
|
||||
return playersOnline;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPlayersMax(){
|
||||
return playersMax;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHost(){
|
||||
return host;
|
||||
}
|
||||
}
|
||||
-53
@@ -1,53 +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.bungeecord.objects.placeholders;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public class BungeePlayerPlaceholders extends PlaceholderProvider{
|
||||
|
||||
private BungeePlayerPlaceholders(){
|
||||
super("player");
|
||||
}
|
||||
|
||||
public static BungeePlayerPlaceholders init(){
|
||||
return new BungeePlayerPlaceholders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
|
||||
return switch(placeholder.toLowerCase(Locale.ROOT)){
|
||||
case "name" -> player.getName();
|
||||
case "protocol" -> String.valueOf(player.getProtocol());
|
||||
case "uuid" -> String.valueOf(player.getUUID());
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
}
|
||||
-61
@@ -1,61 +0,0 @@
|
||||
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;
|
||||
};
|
||||
}
|
||||
}
|
||||
-103
@@ -1,103 +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.bungeecord.objects.placeholders;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.api.bungeecord.objects.BungeeProxy;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
public class BungeeServerPlaceholders extends PlaceholderProvider{
|
||||
|
||||
private final BungeeCordCore plugin;
|
||||
|
||||
private BungeeServerPlaceholders(BungeeCordCore plugin){
|
||||
super("server");
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public static BungeeServerPlaceholders init(BungeeCordCore plugin){
|
||||
return new BungeeServerPlaceholders(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
|
||||
if(!(server instanceof BungeeProxy proxy))
|
||||
return null;
|
||||
|
||||
String[] args = placeholder.split("\\s", 2);
|
||||
|
||||
return switch(args[0]){
|
||||
case "playersOnline" -> {
|
||||
if(args.length >= 2){
|
||||
String[] servers = args[1].split(",");
|
||||
|
||||
int players = 0;
|
||||
for(String serverName : servers){
|
||||
if(serverName.isEmpty())
|
||||
continue;
|
||||
|
||||
ServerInfo info = proxy.getServers().get(serverName.strip());
|
||||
if(info == null)
|
||||
continue;
|
||||
|
||||
players += plugin.getOnlinePlayers(info);
|
||||
}
|
||||
|
||||
yield String.valueOf(players);
|
||||
}
|
||||
|
||||
yield String.valueOf(proxy.getPlayersOnline());
|
||||
}
|
||||
case "playersMax" -> {
|
||||
// ServerInfo doesn't provide the max players that could join, so we won't allow an extra argument
|
||||
if(args.length >= 2)
|
||||
yield "";
|
||||
|
||||
yield String.valueOf(proxy.getPlayersMax());
|
||||
}
|
||||
case "host" -> {
|
||||
if(args.length > 2)
|
||||
yield "";
|
||||
|
||||
if(args.length == 2 && args[1] != null && !args[1].isEmpty()){
|
||||
ServerInfo info = proxy.getServers().get(args[1]);
|
||||
if(info == null)
|
||||
yield "";
|
||||
|
||||
yield String.valueOf(((InetSocketAddress)info.getSocketAddress()).getHostString());
|
||||
}
|
||||
|
||||
yield proxy.getHost();
|
||||
}
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
name: 'AdvancedServerList'
|
||||
author: 'Andre_601'
|
||||
version: '${plugin.version}'
|
||||
description: '${plugin.description}'
|
||||
|
||||
softDepends:
|
||||
- PAPIProxyBridge
|
||||
- Maintenance
|
||||
- ServerListPlus
|
||||
|
||||
main: 'ch.andre601.advancedserverlist.bungeecord.BungeeCordCore'
|
||||
@@ -1,28 +0,0 @@
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
+14
-8
@@ -43,7 +43,7 @@
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
||||
<plugin.config.version>9</plugin.config.version>
|
||||
<plugin.config.version>10</plugin.config.version>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
@@ -79,7 +79,7 @@
|
||||
<dependency>
|
||||
<groupId>ch.andre601</groupId>
|
||||
<artifactId>expressionparser</artifactId>
|
||||
<version>1.6.0</version>
|
||||
<version>1.7.0-b1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.13.1</version>
|
||||
<version>2.14.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -133,7 +133,7 @@
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>33.4.8-jre</version>
|
||||
<version>33.6.0-jre</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -168,13 +168,13 @@
|
||||
<dependency>
|
||||
<groupId>net.william278</groupId>
|
||||
<artifactId>papiproxybridge</artifactId>
|
||||
<version>1.8.1</version>
|
||||
<version>1.8.4</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>eu.kennytv.maintenance</groupId>
|
||||
<artifactId>maintenance-api</artifactId>
|
||||
<version>4.2.1</version>
|
||||
<version>5.0.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -183,12 +183,18 @@
|
||||
<version>3.5.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.miniplaceholders</groupId>
|
||||
<artifactId>miniplaceholders-api</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Test dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>5.13.2</version>
|
||||
<version>5.14.4</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
@@ -215,7 +221,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.14.0</version>
|
||||
<version>3.15.0</version>
|
||||
<configuration>
|
||||
<compilerArgs>
|
||||
<arg>-parameters</arg>
|
||||
|
||||
@@ -28,20 +28,22 @@ package ch.andre601.advancedserverlist.core;
|
||||
import ch.andre601.advancedserverlist.api.AdvancedServerListAPI;
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.core.check.UpdateChecker;
|
||||
import ch.andre601.advancedserverlist.core.commands.CommandHandler;
|
||||
import ch.andre601.advancedserverlist.core.commands.*;
|
||||
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.placeholders.DatePlaceholder;
|
||||
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.ProfileConditionParser;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.reader.PlaceholderTokenReader;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.reader.PlaceholderValueReader;
|
||||
import ch.andre601.advancedserverlist.core.profiles.handlers.PlayerHandler;
|
||||
import ch.andre601.expressionparser.DefaultExpressionParserEngine;
|
||||
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;
|
||||
@@ -53,6 +55,7 @@ import org.incendo.cloud.suggestion.SuggestionProvider;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
@@ -60,7 +63,10 @@ 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));
|
||||
List<PlaceholderProvider> providers = new ArrayList<>(Arrays.asList(placeholders));
|
||||
providers.add(new DatePlaceholder());
|
||||
|
||||
return new AdvancedServerList<>(plugin, providers);
|
||||
}
|
||||
|
||||
private final PluginCore<F> plugin;
|
||||
@@ -69,7 +75,11 @@ public class AdvancedServerList<F>{
|
||||
private final TextCenterUtil textCenterUtil;
|
||||
|
||||
private static final AdvancedServerListAPI api = AdvancedServerListAPI.get();
|
||||
private final ProfileConditionParser parser = ProfileConditionParser.create();
|
||||
private final DefaultExpressionParserEngine parser = new DefaultExpressionParserEngine.DefaultBuilder()
|
||||
.addDefaults()
|
||||
.addTokenReader(new PlaceholderTokenReader())
|
||||
.addValueReader(new PlaceholderValueReader())
|
||||
.build();
|
||||
|
||||
private UpdateChecker updateChecker;
|
||||
|
||||
@@ -81,7 +91,7 @@ public class AdvancedServerList<F>{
|
||||
this.playerHandler = new PlayerHandler(this);
|
||||
this.textCenterUtil = new TextCenterUtil(this);
|
||||
|
||||
plugin.getPluginLogger().info("Registering internal Placeholders...");
|
||||
plugin.pluginLogger().info("Registering internal Placeholders...");
|
||||
|
||||
placeholders.forEach(this::addPlaceholder);
|
||||
|
||||
@@ -90,52 +100,52 @@ public class AdvancedServerList<F>{
|
||||
}
|
||||
|
||||
resolveVersion();
|
||||
getPlugin().getPluginLogger().info("Starting <white>AdvancedServerList v%s</white>...", version);
|
||||
plugin().pluginLogger().info("Starting <white>AdvancedServerList v%s</white>...", version);
|
||||
load();
|
||||
}
|
||||
|
||||
public static AdvancedServerListAPI getApi(){
|
||||
public static AdvancedServerListAPI api(){
|
||||
return api;
|
||||
}
|
||||
|
||||
public PluginCore<F> getPlugin(){
|
||||
public PluginCore<F> plugin(){
|
||||
return plugin;
|
||||
}
|
||||
|
||||
public FileHandler getFileHandler(){
|
||||
public FileHandler fileHandler(){
|
||||
return fileHandler;
|
||||
}
|
||||
|
||||
public PlayerHandler getPlayerHandler(){
|
||||
public PlayerHandler playerHandler(){
|
||||
return playerHandler;
|
||||
}
|
||||
|
||||
public String getVersion(){
|
||||
public String version(){
|
||||
return version;
|
||||
}
|
||||
|
||||
public ProfileConditionParser getParser(){
|
||||
public DefaultExpressionParserEngine parser(){
|
||||
return parser;
|
||||
}
|
||||
|
||||
public UpdateChecker getUpdateChecker(){
|
||||
public UpdateChecker updateChecker(){
|
||||
return updateChecker;
|
||||
}
|
||||
|
||||
public TextCenterUtil getTextCenterUtil(){
|
||||
public TextCenterUtil textCenterUtil(){
|
||||
return textCenterUtil;
|
||||
}
|
||||
|
||||
public void disable(){
|
||||
getPlugin().getPluginLogger().info("[-] Saving <white>playercache.json</white> file...");
|
||||
getPlayerHandler().save();
|
||||
plugin().pluginLogger().info("[-] Saving <white>playercache.json</white> file...");
|
||||
playerHandler().save();
|
||||
|
||||
if(updateChecker != null){
|
||||
getPlugin().getPluginLogger().info("[-] Disabling Update Checker...");
|
||||
plugin().pluginLogger().info("[-] Disabling Update Checker...");
|
||||
updateChecker.disable();
|
||||
}
|
||||
|
||||
getPlugin().getPluginLogger().success("AdvancedServerList disabled!");
|
||||
plugin().pluginLogger().success("AdvancedServerList disabled!");
|
||||
}
|
||||
|
||||
public void clearFaviconCache(){
|
||||
@@ -143,69 +153,69 @@ public class AdvancedServerList<F>{
|
||||
}
|
||||
|
||||
public void clearPlayerCache(){
|
||||
getPlayerHandler().clearCache();
|
||||
playerHandler().clearCache();
|
||||
}
|
||||
|
||||
private void load(){
|
||||
if(!getFileHandler().loadConfig()){
|
||||
getPlugin().getPluginLogger().failure("Unable to load <white>config.yml</white>! Check previous lines for errors.");
|
||||
if(!fileHandler().loadConfig()){
|
||||
plugin().pluginLogger().failure("Unable to load <white>config.yml</white>! Check previous lines for errors.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(getFileHandler().isOldConfig()){
|
||||
getPlugin().getPluginLogger().info("[-] Detected old <white>config.yml</white>. Attempting to migrate...");
|
||||
if(getFileHandler().migrateConfig()){
|
||||
getPlugin().getPluginLogger().success("Migration completed successfully!");
|
||||
if(fileHandler().isOldConfig()){
|
||||
plugin().pluginLogger().info("[-] Detected old <white>config.yml</white>. Attempting to migrate...");
|
||||
if(fileHandler().migrateConfig()){
|
||||
plugin().pluginLogger().success("Migration completed successfully!");
|
||||
}else{
|
||||
getPlugin().getPluginLogger().failure("Couldn't migrate <white>config.yml</white>! Check previous lines for errors.");
|
||||
plugin().pluginLogger().failure("Couldn't migrate <white>config.yml</white>! Check previous lines for errors.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(getFileHandler().getBool(true, "printBanner")){
|
||||
if(fileHandler().getBool(true, "printBanner")){
|
||||
printBanner();
|
||||
}
|
||||
|
||||
getPlugin().getPluginLogger().info("Platform: <white>%s</white>", plugin.getPlatformInfo());
|
||||
getPlugin().getPluginLogger().info("");
|
||||
plugin().pluginLogger().info("Platform: <white>%s</white>", plugin.platformInfo());
|
||||
plugin().pluginLogger().info("");
|
||||
|
||||
if(getFileHandler().loadProfiles()){
|
||||
getPlugin().getPluginLogger().success("Successfully loaded <white>%d</white> profile(s)!", getFileHandler().getProfiles().size());
|
||||
if(fileHandler().loadProfiles()){
|
||||
plugin().pluginLogger().success("Successfully loaded <white>%d</white> profile(s)!", fileHandler().profiles().size());
|
||||
}else{
|
||||
getPlugin().getPluginLogger().failure("Unable to load profiles! Check previous lines for errors.");
|
||||
plugin().pluginLogger().failure("Unable to load profiles! Check previous lines for errors.");
|
||||
return;
|
||||
}
|
||||
|
||||
loadCommands();
|
||||
|
||||
plugin.loadEvents();
|
||||
getPlayerHandler().load();
|
||||
playerHandler().load();
|
||||
plugin.loadMetrics();
|
||||
plugin.startScheduler();
|
||||
|
||||
getPlugin().getPluginLogger().success("<green>AdvancedServerList is ready!");
|
||||
plugin().pluginLogger().success("<green>AdvancedServerList is ready!");
|
||||
|
||||
if(getFileHandler().getBoolean("checkUpdates"))
|
||||
if(fileHandler().getBoolean("checkUpdates"))
|
||||
this.updateChecker = new UpdateChecker(this);
|
||||
}
|
||||
|
||||
private void printBanner(){
|
||||
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("");
|
||||
plugin().pluginLogger().info("<#3b90ff> __ _______ ___");
|
||||
plugin().pluginLogger().info("<#3b90ff> /\\ \\ / ____|_| | |");
|
||||
plugin().pluginLogger().info("<#3b90ff> / \\ \\ | (_(___ | | |");
|
||||
plugin().pluginLogger().info("<#3b90ff> / /\\ \\ \\ \\___ \\ \\| | |");
|
||||
plugin().pluginLogger().info("<#3b90ff> / ____ \\ \\ ____) | | |_|____");
|
||||
plugin().pluginLogger().info("<#3b90ff>/_/_/ \\_\\_\\_____/_/|______|_|");
|
||||
plugin().pluginLogger().info("");
|
||||
|
||||
seasonalText();
|
||||
}
|
||||
|
||||
private void resolveVersion(){
|
||||
try(InputStream is = getClass().getResourceAsStream("/version.properties")){
|
||||
try(InputStream stream = getClass().getResourceAsStream("/version.properties")){
|
||||
Properties properties = new Properties();
|
||||
|
||||
properties.load(is);
|
||||
properties.load(stream);
|
||||
|
||||
version = properties.getProperty("version");
|
||||
}catch(IOException ex){
|
||||
@@ -214,24 +224,30 @@ public class AdvancedServerList<F>{
|
||||
}
|
||||
|
||||
private void addPlaceholder(PlaceholderProvider placeholderProvider){
|
||||
AdvancedServerList.getApi().addPlaceholderProvider(placeholderProvider);
|
||||
AdvancedServerList.api().addPlaceholderProvider(placeholderProvider);
|
||||
}
|
||||
|
||||
private void loadCommands(){
|
||||
getPlugin().loadFaviconHandler(this);
|
||||
plugin().loadFaviconHandler(this);
|
||||
|
||||
CommandManager<CmdSender> commandManager = plugin.getCommandManager();
|
||||
CommandManager<CmdSender> commandManager = plugin().commandManager();
|
||||
|
||||
commandManager.parameterInjectorRegistry().registerInjector(AdvancedServerList.class, ParameterInjector.constantInjector(this));
|
||||
commandManager.registerCommandPostProcessor(new CommandTypePostprocessor());
|
||||
|
||||
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));
|
||||
annotationParser.parse(
|
||||
CmdClearCache.create(this),
|
||||
CmdHelp.create(commandManager),
|
||||
CmdMigrate.create(this),
|
||||
CmdProfiles.create(this),
|
||||
CmdReload.create(this)
|
||||
);
|
||||
|
||||
for(String option : CommandHandler.PROFILE_OPTIONS){
|
||||
for(String option : CmdProfiles.ProfileOption.list()){
|
||||
commandManager.command(
|
||||
commandManager.commandBuilder("advancedserverlist", "asl")
|
||||
.literal("profiles")
|
||||
@@ -241,7 +257,7 @@ public class AdvancedServerList<F>{
|
||||
StringParser.stringParser(),
|
||||
Description.of("The profile to edit."),
|
||||
SuggestionProvider.suggesting(
|
||||
getFileHandler().getProfiles().stream()
|
||||
fileHandler().profiles().stream()
|
||||
.map(ServerListProfile::file)
|
||||
.map(Suggestion::suggestion)
|
||||
.toList()
|
||||
@@ -259,10 +275,11 @@ public class AdvancedServerList<F>{
|
||||
Permission.permission("advancedserverlist.command.profiles.set")
|
||||
)
|
||||
)
|
||||
.meta(CommandHandler.COMMAND_TYPE, CommandType.Type.ALL)
|
||||
);
|
||||
}
|
||||
|
||||
getPlugin().getPluginLogger().success("Loaded Command <white>/advancedserverlist</white>!");
|
||||
plugin().pluginLogger().success("Loaded Command <white>/advancedserverlist</white>!");
|
||||
}
|
||||
|
||||
private ParserDescriptor<CmdSender, ?> descriptor(String option){
|
||||
@@ -295,34 +312,34 @@ public class AdvancedServerList<F>{
|
||||
switch(date.getMonth()){
|
||||
case JANUARY -> {
|
||||
if(date.getDayOfMonth() == 1){
|
||||
getPlugin().getPluginLogger().info("Happy new Year!");
|
||||
getPlugin().getPluginLogger().info("");
|
||||
plugin().pluginLogger().info("Happy new Year!");
|
||||
plugin().pluginLogger().info("");
|
||||
}
|
||||
}
|
||||
case JUNE -> {
|
||||
getPlugin().getPluginLogger().info("Happy Pride Month!");
|
||||
getPlugin().getPluginLogger().info("");
|
||||
plugin().pluginLogger().info("Happy Pride Month!");
|
||||
plugin().pluginLogger().info("");
|
||||
}
|
||||
case AUGUST -> {
|
||||
if(date.getDayOfMonth() == 1){
|
||||
getPlugin().getPluginLogger().info("Happy Birthday Switzerland!");
|
||||
getPlugin().getPluginLogger().info("");
|
||||
plugin().pluginLogger().info("Happy Birthday Switzerland!");
|
||||
plugin().pluginLogger().info("");
|
||||
}
|
||||
}
|
||||
case OCTOBER -> {
|
||||
if(date.getDayOfMonth() == 31){
|
||||
getPlugin().getPluginLogger().info("Happy Halloween!");
|
||||
getPlugin().getPluginLogger().info("");
|
||||
plugin().pluginLogger().info("Happy Halloween!");
|
||||
plugin().pluginLogger().info("");
|
||||
}
|
||||
}
|
||||
case DECEMBER -> {
|
||||
if(date.getDayOfMonth() == 13){
|
||||
getPlugin().getPluginLogger().info("Happy Birthday Andre_601!");
|
||||
getPlugin().getPluginLogger().info("");
|
||||
plugin().pluginLogger().info("Happy Birthday Andre_601!");
|
||||
plugin().pluginLogger().info("");
|
||||
}else
|
||||
if(date.getDayOfMonth() > 23 && date.getDayOfMonth() < 27){
|
||||
getPlugin().getPluginLogger().info("Merry Christmas!");
|
||||
getPlugin().getPluginLogger().info("");
|
||||
plugin().pluginLogger().info("Merry Christmas!");
|
||||
plugin().pluginLogger().info("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,13 +25,13 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.core.check;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
|
||||
public class UpdateCheckThread implements ThreadFactory{
|
||||
@Override
|
||||
public Thread newThread(@NotNull Runnable r){
|
||||
public Thread newThread(@NonNull Runnable r){
|
||||
Thread t = new Thread(r, "AdvancedServerList-UpdateThread");
|
||||
t.setDaemon(true);
|
||||
return t;
|
||||
|
||||
@@ -68,8 +68,8 @@ public class UpdateChecker{
|
||||
|
||||
public UpdateChecker(AdvancedServerList<?> core){
|
||||
this.core = core;
|
||||
this.logger = core.getPlugin().getPluginLogger();
|
||||
this.loader = core.getPlugin().getLoader();
|
||||
this.logger = core.plugin().pluginLogger();
|
||||
this.loader = core.plugin().loader();
|
||||
this.client = HttpClient.newBuilder().executor(Executors.newSingleThreadExecutor(new UpdateCheckThread())).build();
|
||||
|
||||
startUpdateChecker();
|
||||
@@ -88,10 +88,10 @@ public class UpdateChecker{
|
||||
if(version == null)
|
||||
return;
|
||||
|
||||
int result = version.compare(core.getVersion());
|
||||
int result = version.compare(core.version());
|
||||
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>Your version: <white>%s", core.version());
|
||||
sender.sendPrefixedMsg("<green>Version on Modrinth: <white>%s", version.versionNumber());
|
||||
sender.sendPrefixedMsg(
|
||||
"<click:open_url:'https://modrinth.com/plugin/advancedserverlist/version/%s'>" +
|
||||
@@ -103,7 +103,7 @@ public class UpdateChecker{
|
||||
if(result == 1){
|
||||
sender.sendPrefixedMsg(
|
||||
"Your version (<white>%</white>) is newer than what is available on Modrinth (<white>%s</white>).",
|
||||
core.getVersion(),
|
||||
core.version(),
|
||||
version.versionNumber()
|
||||
);
|
||||
sender.sendPrefixedMsg("Are you using a Development Version?");
|
||||
@@ -137,14 +137,14 @@ public class UpdateChecker{
|
||||
|
||||
logger.debug(UpdateChecker.class, "Comparing versions...");
|
||||
|
||||
int result = version.compare(core.getVersion());
|
||||
int result = version.compare(core.version());
|
||||
switch(result){
|
||||
case -1 -> printUpdateBanner(version);
|
||||
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(),
|
||||
core.version(),
|
||||
version.versionNumber()
|
||||
);
|
||||
logger.info(" Are you using a Development Version?");
|
||||
@@ -163,7 +163,7 @@ public class UpdateChecker{
|
||||
|
||||
logger.debug(UpdateChecker.class, "Checking '%s' for updates...", finalUrl);
|
||||
|
||||
if(core.getVersion().equals("UNKNOWN")){
|
||||
if(core.version().equals("UNKNOWN")){
|
||||
logger.warn("Cannot perform update check. Plugin version is 'UNKNOWN'!");
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
@@ -173,7 +173,7 @@ public class UpdateChecker{
|
||||
request = HttpRequest.newBuilder()
|
||||
.uri(new URI(finalUrl))
|
||||
.timeout(Duration.ofSeconds(5))
|
||||
.header("User-Agent", "AdvancedServerList-" + loader + "/" + core.getVersion())
|
||||
.header("User-Agent", "AdvancedServerList-" + loader + "/" + core.version())
|
||||
.build();
|
||||
}catch(URISyntaxException ex){
|
||||
logger.warn("Cannot perform update check. URL '%s' is not a valid URI.", ex, finalUrl);
|
||||
@@ -193,7 +193,7 @@ public class UpdateChecker{
|
||||
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("Your version: <white>%s</white>", core.version());
|
||||
logger.warn("Modrinth: <white>%s</white>", version.versionNumber());
|
||||
logger.warn("");
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package ch.andre601.advancedserverlist.core.commands;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CommandType;
|
||||
import org.incendo.cloud.annotations.Argument;
|
||||
import org.incendo.cloud.annotations.Command;
|
||||
import org.incendo.cloud.annotations.CommandDescription;
|
||||
import org.incendo.cloud.annotations.Permission;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
|
||||
@Command("advancedserverlist|asl")
|
||||
@CommandDescription("Main Command of the plugin")
|
||||
@Permission("advancedserverlist.admin")
|
||||
@CommandType(CommandType.Type.ALL)
|
||||
public record CmdClearCache(AdvancedServerList<?> core){
|
||||
|
||||
public static CmdClearCache create(AdvancedServerList<?> core){
|
||||
return new CmdClearCache(core);
|
||||
}
|
||||
|
||||
@Command("clearcache [target]")
|
||||
@CommandDescription("Cleares the Favicon and/or Player Cache.")
|
||||
@Permission({"advancedserverlist.admin", "advancedserverlist.command.clearcache"})
|
||||
@CommandType(CommandType.Type.ALL)
|
||||
public void handle(
|
||||
CmdSender sender,
|
||||
@Nullable @Argument(description = "The type of Cache to clean. Defaults to ALL.") CacheTarget target
|
||||
){
|
||||
if(target == null)
|
||||
target = CacheTarget.ALL;
|
||||
|
||||
sender.sendPrefixedMsg("Clearing cache...");
|
||||
|
||||
if(target == CacheTarget.ALL || target == CacheTarget.FAVICON){
|
||||
core().clearFaviconCache();
|
||||
sender.sendPrefixedMsg("Cleared Favicon Cache.");
|
||||
}
|
||||
|
||||
if(target == CacheTarget.ALL || target == CacheTarget.PLAYER){
|
||||
core().clearPlayerCache();
|
||||
sender.sendPrefixedMsg("Cleared Player Cache.");
|
||||
}
|
||||
|
||||
sender.sendPrefixedMsg("<green>Cache clearing complete!");
|
||||
}
|
||||
|
||||
public enum CacheTarget{
|
||||
ALL,
|
||||
FAVICON,
|
||||
PLAYER
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package ch.andre601.advancedserverlist.core.commands;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CommandType;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
import org.incendo.cloud.annotation.specifier.Greedy;
|
||||
import org.incendo.cloud.annotations.Argument;
|
||||
import org.incendo.cloud.annotations.Command;
|
||||
import org.incendo.cloud.annotations.CommandDescription;
|
||||
import org.incendo.cloud.annotations.Permission;
|
||||
import org.incendo.cloud.annotations.suggestion.Suggestions;
|
||||
import org.incendo.cloud.context.CommandContext;
|
||||
import org.incendo.cloud.help.result.CommandEntry;
|
||||
import org.incendo.cloud.minecraft.extras.MinecraftHelp;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Command("advancedserverlist|asl")
|
||||
@CommandDescription("Main Command of the plugin")
|
||||
@Permission("advancedserverlist.admin")
|
||||
@CommandType(CommandType.Type.ALL)
|
||||
public record CmdHelp(CommandManager<CmdSender> manager, MinecraftHelp<CmdSender> help){
|
||||
|
||||
public static CmdHelp create(CommandManager<CmdSender> manager){
|
||||
MinecraftHelp<CmdSender> help = MinecraftHelp.<CmdSender>builder()
|
||||
.commandManager(manager)
|
||||
.audienceProvider(CmdSender::audience)
|
||||
.commandPrefix("/asl help")
|
||||
.colors(MinecraftHelp.helpColors(
|
||||
NamedTextColor.WHITE, NamedTextColor.AQUA, NamedTextColor.WHITE, NamedTextColor.GRAY, NamedTextColor.DARK_GRAY
|
||||
))
|
||||
.build();
|
||||
|
||||
return new CmdHelp(manager, help);
|
||||
}
|
||||
|
||||
@Command("help [query]")
|
||||
@CommandDescription("Displays all commands or provides info about a specific one.")
|
||||
@Permission({"advancedserverlist.admin", "advancedserverlist.command.help"})
|
||||
@CommandType(CommandType.Type.ALL)
|
||||
public void handle(
|
||||
CmdSender sender,
|
||||
@Nullable @Argument(description = "Search Query for a specific command", suggestions = "help") @Greedy String query
|
||||
){
|
||||
this.help.queryCommands(query == null ? "" : query, sender);
|
||||
}
|
||||
|
||||
@Suggestions("help")
|
||||
public List<String> helpQueries(CommandContext<CmdSender> context) {
|
||||
return this.manager.createHelpHandler()
|
||||
.queryRootIndex(context.sender())
|
||||
.entries()
|
||||
.stream()
|
||||
.filter(entry -> context.hasPermission(entry.command().commandPermission()))
|
||||
.filter(entry -> {
|
||||
CommandType.Type type = entry.command().commandMeta().getOrDefault(CommandHandler.COMMAND_TYPE, CommandType.Type.ALL);
|
||||
|
||||
return type == CommandType.Type.ALL || type == CommandType.Type.PLAYER_ONLY && context.sender().isPlayer();
|
||||
})
|
||||
.map(CommandEntry::syntax)
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package ch.andre601.advancedserverlist.core.commands;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CommandType;
|
||||
import ch.andre601.advancedserverlist.core.migration.minimotd.MiniMOTDConfigMigrator;
|
||||
import ch.andre601.advancedserverlist.core.migration.serverlistplus.SLPConfigMigrator;
|
||||
import org.incendo.cloud.annotations.Argument;
|
||||
import org.incendo.cloud.annotations.Command;
|
||||
import org.incendo.cloud.annotations.CommandDescription;
|
||||
import org.incendo.cloud.annotations.Permission;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
@Command("advancedserverlist|asl")
|
||||
@CommandDescription("Main Command of the plugin")
|
||||
@Permission("advancedserverlist.admin")
|
||||
@CommandType(CommandType.Type.ALL)
|
||||
public record CmdMigrate(AdvancedServerList<?> core){
|
||||
|
||||
public static CmdMigrate create(AdvancedServerList<?> core){
|
||||
return new CmdMigrate(core);
|
||||
}
|
||||
|
||||
@Command("migrate <plugin>")
|
||||
@CommandDescription("Migrates Profiles from supported Plugins to ASL.")
|
||||
@Permission({"advancedserverlist.admin", "advancedserverlist.command.migrate"})
|
||||
@CommandType(CommandType.Type.ALL)
|
||||
public void handle(
|
||||
CmdSender sender,
|
||||
@NonNull @Argument(description = "Name of the plugin to migrate from") MigratablePlugin plugin
|
||||
){
|
||||
if(plugin == MigratablePlugin.SERVERLISTPLUS){
|
||||
if(!core().plugin().isPluginEnabled("ServerListPlus")){
|
||||
sender.sendErrorMsg("<red>ServerListPlus not enabled.");
|
||||
sender.sendErrorMsg("<red>The plugin needs to be enabled for the migration to work.");
|
||||
return;
|
||||
}
|
||||
|
||||
sender.sendPrefixedMsg("Migrating from ServerListPlus...");
|
||||
|
||||
int migrated = SLPConfigMigrator.migrate(core(), sender);
|
||||
if(migrated == 0){
|
||||
sender.sendErrorMsg("<red>Couldn't migrate any profiles from ServerListPlus.");
|
||||
sender.sendErrorMsg("<red>See the server console for any errors.");
|
||||
return;
|
||||
}else{
|
||||
sender.sendPrefixedMsg("<green>Successfully migrated </green>%d<green> Profile(s)!", migrated);
|
||||
}
|
||||
}else
|
||||
if(plugin == MigratablePlugin.MINIMOTD){
|
||||
sender.sendPrefixedMsg("Migrating from MiniMOTD...");
|
||||
|
||||
if(MiniMOTDConfigMigrator.migrate(core(), sender)){
|
||||
sender.sendPrefixedMsg("<green>Successfully migrated config from MiniMOTD!");
|
||||
}else{
|
||||
sender.sendErrorMsg("<red>Couldn't migrate config from MiniMOTD.");
|
||||
sender.sendErrorMsg("<red>See the server console for any errors.");
|
||||
return;
|
||||
}
|
||||
}else{
|
||||
sender.sendErrorMsg("<red>Received invalid Plugin </red>%s<red>!", plugin.toString());
|
||||
sender.sendErrorMsg("<red>Only the following plugins are supported:");
|
||||
|
||||
for(MigratablePlugin pl : MigratablePlugin.values()){
|
||||
sender.sendErrorMsg("- <click:suggest_command:/asl migrate %s>%s</click>", pl.name().toLowerCase(Locale.ROOT), pl.name().toLowerCase(Locale.ROOT));
|
||||
}
|
||||
}
|
||||
|
||||
sender.sendPrefixedMsg("<green>Run <white><click:suggest_command:/asl reload>/asl reload</click></white> to load the new Profile(s).");
|
||||
}
|
||||
|
||||
public enum MigratablePlugin{
|
||||
SERVERLISTPLUS,
|
||||
MINIMOTD
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,483 @@
|
||||
package ch.andre601.advancedserverlist.core.commands;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CommandType;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.dialogs.IDialog;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.dialogs.IDialogList;
|
||||
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
|
||||
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileSerializer;
|
||||
import org.incendo.cloud.annotations.Argument;
|
||||
import org.incendo.cloud.annotations.Command;
|
||||
import org.incendo.cloud.annotations.CommandDescription;
|
||||
import org.incendo.cloud.annotations.Permission;
|
||||
import org.incendo.cloud.annotations.suggestion.Suggestions;
|
||||
import org.incendo.cloud.context.CommandInput;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
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.*;
|
||||
|
||||
@Command("advancedserverlist|asl")
|
||||
@CommandDescription("Main Command of the plugin.")
|
||||
@Permission("advancedserverlist.admin")
|
||||
@CommandType(CommandType.Type.ALL)
|
||||
public record CmdProfiles(AdvancedServerList<?> core){
|
||||
|
||||
public static CmdProfiles create(AdvancedServerList<?> core){
|
||||
return new CmdProfiles(core);
|
||||
}
|
||||
|
||||
@Command("profiles add <name>")
|
||||
@CommandDescription("Creates a new Profile with default values applied.")
|
||||
@Permission({"advancedserverlist.admin", "advancedserverlist.command.profiles", "advancedserverlist.command.profiles.add"})
|
||||
@CommandType(CommandType.Type.ALL)
|
||||
public void add(
|
||||
CmdSender sender,
|
||||
@NonNull @Argument(description = "Name of the profile to create.") String name
|
||||
){
|
||||
if(name.isEmpty()){
|
||||
sender.sendErrorMsg("<red>Insufficient arguments.");
|
||||
sender.sendErrorMsg("<red>A profile name needs to be provided.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(CommandHandler.profile(core(), name) != null){
|
||||
sender.sendErrorMsg("<red>A profile with the name </red>%s<red> already exists.", name);
|
||||
return;
|
||||
}
|
||||
|
||||
String file = CommandHandler.profileName(name);
|
||||
|
||||
if(core().fileHandler().createFile(file)){
|
||||
sender.sendPrefixedMsg("<green>Successfully created </green>%s<green>!", file);
|
||||
sender.sendPrefixedMsg("<green>Use <white><click:suggest_command:/asl reload>/asl reload</click></white> to load the file.");
|
||||
}else{
|
||||
sender.sendErrorMsg("<red>Error while creating new profile.");
|
||||
sender.sendErrorMsg("<red>Check the server console for details.");
|
||||
}
|
||||
}
|
||||
|
||||
@Command("profiles copy <profile> <name>")
|
||||
public void copy(
|
||||
CmdSender sender,
|
||||
@NonNull @Argument(description = "Name of the profile to copy.", suggestions = "profiles") String profile,
|
||||
@NonNull @Argument(description = "Name of the copy to have.") String name
|
||||
){
|
||||
if(profile.isEmpty() || name.isEmpty()){
|
||||
sender.sendErrorMsg("<red>Insufficient arguments.");
|
||||
sender.sendErrorMsg("<red>A profile name and name for the copy need to be provided.");
|
||||
return;
|
||||
}
|
||||
|
||||
String profileName = CommandHandler.profileName(profile);
|
||||
String copyName = CommandHandler.profileName(name);
|
||||
|
||||
ServerListProfile original = CommandHandler.profile(core(), profileName);
|
||||
|
||||
if(original == null){
|
||||
sender.sendErrorMsg("<red>A profile with name </red>%s<red> does not exist.", profile);
|
||||
return;
|
||||
}
|
||||
|
||||
boolean copyExists = CommandHandler.profile(core(), copyName) != null;
|
||||
if(copyExists){
|
||||
sender.sendErrorMsg("<red>A profile with name </red>%s<red> already exists.", name);
|
||||
return;
|
||||
}
|
||||
|
||||
Path profilePath = core().plugin().folderPath().resolve("profiles").resolve(copyName);
|
||||
if(!Files.exists(profilePath)){
|
||||
try{
|
||||
Files.createFile(profilePath);
|
||||
}catch(IOException ex){
|
||||
sender.sendErrorMsg("<red>Encountered an IOException while creating </red>%s<red>.", copyName);
|
||||
sender.sendErrorMsg("<red>Please see the server console for further details.");
|
||||
|
||||
core.plugin().pluginLogger().warn("Encountered IOException while creating file <white>%s</white>", ex, copyName);
|
||||
return;
|
||||
}
|
||||
|
||||
YamlConfigurationLoader loader = YamlConfigurationLoader.builder()
|
||||
.path(profilePath)
|
||||
.indent(2)
|
||||
.nodeStyle(NodeStyle.BLOCK)
|
||||
.defaultOptions(opt -> opt.serializers(builder -> builder.register(ProfileEntry.class, ProfileSerializer.INSTANCE)))
|
||||
.build();
|
||||
|
||||
ConfigurationNode node;
|
||||
try{
|
||||
node = loader.load();
|
||||
}catch(IOException ex){
|
||||
sender.sendErrorMsg("<red>Encountered an IOException while loading file </red>%s<red>.", copyName);
|
||||
sender.sendErrorMsg("<red>Please see the server console for further details.");
|
||||
|
||||
core().plugin().pluginLogger().warn("Encountered IOException while loading file <white>%s</white>.", ex, copyName);
|
||||
return;
|
||||
}
|
||||
|
||||
try{
|
||||
node.node("priority").set(original.priority());
|
||||
node.node("condition").set(original.condition());
|
||||
|
||||
node.node("profiles").setList(ProfileEntry.class, original.profiles());
|
||||
|
||||
node.set(ProfileEntry.class, original.defaultProfile());
|
||||
}catch(SerializationException ex){
|
||||
sender.sendErrorMsg("<red>Encountered a SerializationException while copying values from </red>%s<red> to </red>%s<red>.", profileName, copyName);
|
||||
sender.sendErrorMsg("<red>Please see the server console for further details.");
|
||||
|
||||
core().plugin().pluginLogger().warn("<red>Encountered a SerializationException while copying values from </red>%s<red> to </red>%s<red>.", ex, profileName, copyName);
|
||||
return;
|
||||
}
|
||||
|
||||
try{
|
||||
loader.save(node);
|
||||
sender.sendPrefixedMsg("<green>Successfully created copy of </green>%s<green> as </green>%s<green>!", profileName, copyName);
|
||||
sender.sendPrefixedMsg("<green>Use <white><click:suggest_command:/asl reload>/asl reload</click></white> to load the file.");
|
||||
}catch(IOException ex){
|
||||
sender.sendErrorMsg("<red>There was an IOException while loading file </red>%s<red>!", copyName);
|
||||
sender.sendErrorMsg("<red>Please see the server console for further details.");
|
||||
|
||||
core.plugin().pluginLogger().warn("Encountered an IOException while loading file <white>%s</white>", ex, copyName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Command("profiles edit <profile>")
|
||||
@CommandDescription("Opens a Dialog to edit a specific profile ingame.")
|
||||
@Permission({"advancedserverlist.admin", "advancedserverlist.command.profiles", "advancedserverlist.command.profiles.edit"})
|
||||
@CommandType(CommandType.Type.PLAYER_ONLY)
|
||||
public void edit(
|
||||
CmdSender sender,
|
||||
@NonNull @Argument(description = "Name of the profile to edit.", suggestions = "profiles") String profile
|
||||
){
|
||||
if(!core().plugin().isDialogsSupported()){
|
||||
sender.sendErrorMsg("Dialogs are not supported on this server or proxy version.");
|
||||
return;
|
||||
}
|
||||
|
||||
ServerListProfile slp = CommandHandler.profile(core(), profile);
|
||||
if(slp == null){
|
||||
sender.sendErrorMsg("<red>A profile with name </red>%s<red> does not exist.", profile);
|
||||
return;
|
||||
}
|
||||
|
||||
IDialogList.IDialogListBuilder listBuilder = core().plugin().createDialogListBuilder(slp.file());
|
||||
String warning = """
|
||||
<gold><bold>WARNING!</bold></gold>
|
||||
|
||||
Dialog-based Profile editing is currently an <italic>experimental feature</italic>!
|
||||
Please create backups of your profiles before using this feature and report any bugs and/or glitches you encounter.""";
|
||||
|
||||
listBuilder.appendBody(warning);
|
||||
|
||||
listBuilder.appendDialog(
|
||||
createDialog("Main Settings", warning, slp, slp.defaultProfile(), slp.priority(), slp.condition(), -1)
|
||||
);
|
||||
|
||||
for(int i = 0; i < slp.profiles().size(); i++){
|
||||
listBuilder.appendDialog(
|
||||
createDialog("Profiles #" + (i + 1), warning, slp, slp.profiles().get(i), -1, null, i)
|
||||
);
|
||||
}
|
||||
|
||||
listBuilder.build().show(sender);
|
||||
}
|
||||
|
||||
@Command("profiles info <profile>")
|
||||
@CommandDescription("Provides info about a specific profile.")
|
||||
@Permission({"advancedserverlist.admin", "advancedserverlist.command.profiles", "advancedserverlist.command.profiles.info"})
|
||||
@CommandType(CommandType.Type.PLAYER_ONLY)
|
||||
public void info(
|
||||
CmdSender sender,
|
||||
@NonNull @Argument(description = "Name of the profile to view.", suggestions = "profiles") String profile
|
||||
){
|
||||
if(profile.isEmpty()){
|
||||
sender.sendErrorMsg("<red>Insufficient arguments.");
|
||||
sender.sendErrorMsg("<red>A profile name needs to be provided.");
|
||||
return;
|
||||
}
|
||||
|
||||
ServerListProfile slp = CommandHandler.profile(core(), profile);
|
||||
|
||||
if(slp == null){
|
||||
sender.sendErrorMsg("<red>Unable to find profile with name </red>%s<red>.", profile);
|
||||
sender.sendErrorMsg("<red>Make sure you typed it correctly.");
|
||||
return;
|
||||
}
|
||||
|
||||
ProfileOptionsSender optionsSender = new ProfileOptionsSender(slp.file());
|
||||
|
||||
optionsSender
|
||||
.append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Priority", slp.priority())
|
||||
.option(ProfileOption.PRIORITY)
|
||||
).append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Condition", slp.condition())
|
||||
.option(ProfileOption.CONDITION)
|
||||
).append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Profiles")
|
||||
.color(slp.profiles().isEmpty() ? ProfileOptionsSender.ColorName.RED : ProfileOptionsSender.ColorName.GREEN)
|
||||
);
|
||||
|
||||
if(!slp.profiles().isEmpty()){
|
||||
for(int i = 0; i < slp.profiles().size(); i++){
|
||||
optionsSender.append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("#" + (i + 1), profileHover(slp.profiles().get(i)))
|
||||
.prefix("│ %s─".formatted((i + 1) == slp.profiles().size() ? "└" : "├"))
|
||||
.color(ProfileOptionsSender.ColorName.AQUA)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ProfileEntry entry = slp.defaultProfile();
|
||||
|
||||
optionsSender
|
||||
.append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("MOTD", entry.motd())
|
||||
.option(ProfileOption.MOTD)
|
||||
).append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Favicon", entry.favicon())
|
||||
.option(ProfileOption.FAVICON)
|
||||
).append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Player count")
|
||||
.prefix("└─")
|
||||
.color(ProfileOptionsSender.ColorName.AQUA)
|
||||
).append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Hide Player count?", entry.hidePlayersEnabled())
|
||||
.prefix(" ├─")
|
||||
.option(ProfileOption.PLAYERCOUNT_HIDEPLAYERS)
|
||||
).append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Hide Player count hover?", entry.hidePlayersHoverEnabled())
|
||||
.prefix(" ├─")
|
||||
.option(ProfileOption.PLAYERCOUNT_HIDEPLAYERSHOVER)
|
||||
).append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Player count hover", entry.players())
|
||||
.prefix(" ├─")
|
||||
.option(ProfileOption.PLAYERCOUNT_HOVER)
|
||||
).append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Player count text", entry.playerCountText())
|
||||
.prefix(" ├─")
|
||||
.option(ProfileOption.PLAYERCOUNT_TEXT)
|
||||
).append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Extra Players")
|
||||
.prefix(" ├─")
|
||||
.color(ProfileOptionsSender.ColorName.AQUA)
|
||||
).append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Enabled?", entry.extraPlayersEnabled())
|
||||
.prefix(" │ ├─")
|
||||
.option(ProfileOption.PLAYERCOUNT_EXTRAPLAYERS_ENABLED)
|
||||
).append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Amount", entry.extraPlayersCount())
|
||||
.prefix(" │ └─")
|
||||
.option(ProfileOption.PLAYERCOUNT_EXTRAPLAYERS_AMOUNT)
|
||||
).append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Max Players")
|
||||
.prefix(" ├─")
|
||||
.color(ProfileOptionsSender.ColorName.AQUA)
|
||||
).append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Enabled?", entry.maxPlayersEnabled())
|
||||
.prefix(" │ ├─")
|
||||
.option(ProfileOption.PLAYERCOUNT_MAXPLAYERS_ENABLED)
|
||||
).append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Amount", entry.maxPlayersCount())
|
||||
.prefix(" │ └─")
|
||||
.option(ProfileOption.PLAYERCOUNT_MAXPLAYERS_AMOUNT)
|
||||
).append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Online Players")
|
||||
.prefix(" └─")
|
||||
.color(ProfileOptionsSender.ColorName.AQUA)
|
||||
).append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Enabled?", entry.onlinePlayersEnabled())
|
||||
.prefix(" ├─")
|
||||
.option(ProfileOption.PLAYERCOUNT_ONLINEPLAYERS_ENABLED)
|
||||
).append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Amount", entry.onlinePlayersCount())
|
||||
.prefix(" └─")
|
||||
.option(ProfileOption.PLAYERCOUNT_ONLINEPLAYERS_AMOUNT)
|
||||
).send(sender);
|
||||
}
|
||||
|
||||
@Command("profiles list")
|
||||
@CommandDescription("Lists all available profiles with priority, conditions and if they are valid.")
|
||||
@Permission({"advancedserverlist.admin", "advancedserverlist.command.profiles", "advancedserverlist.command.profiles.list"})
|
||||
@CommandType(CommandType.Type.ALL)
|
||||
public void list(CmdSender sender){
|
||||
sender.sendMsg();
|
||||
sender.sendPrefixedMsg("Available Profiles:");
|
||||
sender.sendMsg("<dark_grey>|");
|
||||
|
||||
List<ServerListProfile> profiles = core().fileHandler().profiles().stream()
|
||||
.sorted(Comparator.comparingInt(ServerListProfile::priority).reversed())
|
||||
.toList();
|
||||
|
||||
if(profiles.isEmpty()){
|
||||
sender.sendMsg("<dark_grey></dark_grey> <i>No profiles found.</i>");
|
||||
}else{
|
||||
for(int i = 0; i < profiles.size(); i++){
|
||||
sender.sendMsg(
|
||||
"<dark_grey>%s</dark_grey> <aqua>" +
|
||||
"<hover:show_text:\"%s\">" +
|
||||
"<click:suggest_command:/asl profiles info %s>" +
|
||||
"%s" +
|
||||
"</click>" +
|
||||
"</hover>" +
|
||||
"</aqua>",
|
||||
(i + 1) == profiles.size() ? "" : "-",
|
||||
hover(profiles.get(i)),
|
||||
profiles.get(i).file(),
|
||||
profiles.get(i).file()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
sender.sendMsg();
|
||||
sender.sendMsg("<grey><i>Hover</i></grey> = Show details.");
|
||||
sender.sendMsg("<grey><i>Click</i></grey> = Get Command.");
|
||||
}
|
||||
|
||||
@Suggestions("profiles")
|
||||
public List<String> profilesSuggestions(CommandInput input){
|
||||
String name = input.readString();
|
||||
List<String> profiles = core().fileHandler().profiles().stream()
|
||||
.map(profile -> profile.file().substring(0, profile.file().lastIndexOf('.')))
|
||||
.toList();
|
||||
if(name.isEmpty())
|
||||
return profiles;
|
||||
|
||||
List<String> matches = new ArrayList<>(profiles.size());
|
||||
for(String str : profiles){
|
||||
if(str.length() >= name.length() && str.regionMatches(true, 0, name, 0, name.length()))
|
||||
matches.add(str);
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
private String hover(ServerListProfile profile){
|
||||
return """
|
||||
<grey>Priority: <white>%d</white>
|
||||
Condition: <white>%s</white>
|
||||
|
||||
Valid? %s""".formatted(
|
||||
profile.priority(),
|
||||
profile.condition() == null || profile.condition().isEmpty() ? "<i>None</i>" : profile.condition(),
|
||||
profile.isInvalidProfile() ? "<red>No</red>" : "<green>Yes</green>"
|
||||
);
|
||||
}
|
||||
|
||||
private String profileHover(ProfileEntry entry){
|
||||
return """
|
||||
<grey>MOTD:
|
||||
%s<reset>
|
||||
|
||||
<grey>Favicon: %s<reset>
|
||||
|
||||
<grey>Hide Player count? %s
|
||||
Hide Player count Hover? %s
|
||||
|
||||
Player count Hover:
|
||||
%s<reset>
|
||||
|
||||
<grey>Player count Text: %s<reset>
|
||||
|
||||
<grey>Extra Players: %s<reset>
|
||||
<grey>Max Players: %s<reset>
|
||||
<grey>Online Players: %s""".formatted(
|
||||
entry.motd() == null || entry.motd().isEmpty() ?
|
||||
"<i><white>None</white></i>" : String.join("<reset>\n", entry.motd()),
|
||||
entry.favicon() == null || entry.favicon().isEmpty() ?
|
||||
"<i><white>None</white></i>" : entry.favicon(),
|
||||
entry.hidePlayersEnabled().getOrDefault(false) ? "<green>Enabled</green>" : "<red>Disabled</red>",
|
||||
entry.hidePlayersHoverEnabled().getOrDefault(false) ? "<green>Enabled</green>" : "<red>Disabled</red>",
|
||||
entry.players().isEmpty() ? "<i><white>None</white></i>" : String.join("<reset>\n", entry.players()),
|
||||
entry.playerCountText() == null || entry.playerCountText().isEmpty() ?
|
||||
"<i><white>None</white></i>" : entry.playerCountText(),
|
||||
entry.extraPlayersEnabled().getOrDefault(false) ? entry.extraPlayersCount() : "<red>Disabled</red>",
|
||||
entry.maxPlayersEnabled().getOrDefault(false) ? entry.maxPlayersCount() : "<red>Disabled</red>",
|
||||
entry.onlinePlayersEnabled().getOrDefault(false) ? entry.onlinePlayersCount() : "<red>Disabled</red>"
|
||||
);
|
||||
}
|
||||
|
||||
private IDialog<?> createDialog(
|
||||
String title,
|
||||
String warning,
|
||||
ServerListProfile slp,
|
||||
ProfileEntry entry,
|
||||
int priority,
|
||||
String condition,
|
||||
int index
|
||||
){
|
||||
IDialog.IDialogBuilder builder = core.plugin().createDialogBuilder(title, slp, index);
|
||||
builder.appendBody(warning);
|
||||
|
||||
if(index < 0){
|
||||
builder.appendNumberRange(ProfileOption.PRIORITY, "Priority", priority)
|
||||
.appendTextInput(ProfileOption.CONDITION, "Condition", condition, 100);
|
||||
}
|
||||
|
||||
builder.appendTextbox(ProfileOption.MOTD, "MOTD", entry.motd(), 200, 2)
|
||||
.appendTextInput(ProfileOption.FAVICON, "Favicon", entry.favicon(), 100)
|
||||
.appendBoolean(ProfileOption.PLAYERCOUNT_HIDEPLAYERS, "Hide Player Count", entry.hidePlayersEnabled())
|
||||
.appendBoolean(ProfileOption.PLAYERCOUNT_HIDEPLAYERSHOVER, "Hide Player Count Hover", entry.hidePlayersHoverEnabled())
|
||||
.appendTextbox(ProfileOption.PLAYERCOUNT_HOVER, "Player Count Hover", entry.players(), 200, 10)
|
||||
.appendTextInput(ProfileOption.PLAYERCOUNT_TEXT, "Player Count Text", entry.playerCountText(), 100)
|
||||
.appendBoolean(ProfileOption.PLAYERCOUNT_EXTRAPLAYERS_ENABLED, "Enable Extra Players", entry.extraPlayersEnabled())
|
||||
.appendTextInput(ProfileOption.PLAYERCOUNT_EXTRAPLAYERS_AMOUNT, "Extra Players Count", entry.extraPlayersCount(), 100)
|
||||
.appendBoolean(ProfileOption.PLAYERCOUNT_MAXPLAYERS_ENABLED, "Enable Max Players", entry.maxPlayersEnabled())
|
||||
.appendTextInput(ProfileOption.PLAYERCOUNT_MAXPLAYERS_AMOUNT, "Max Players Count", entry.maxPlayersCount(), 100)
|
||||
.appendBoolean(ProfileOption.PLAYERCOUNT_ONLINEPLAYERS_ENABLED, "Enable Online Players", entry.onlinePlayersEnabled())
|
||||
.appendTextInput(ProfileOption.PLAYERCOUNT_ONLINEPLAYERS_AMOUNT, "Online Players Count", entry.onlinePlayersCount(), 100);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public enum ProfileOption{
|
||||
PRIORITY,
|
||||
CONDITION,
|
||||
MOTD,
|
||||
FAVICON,
|
||||
PLAYERCOUNT_HIDEPLAYERS,
|
||||
PLAYERCOUNT_HIDEPLAYERSHOVER,
|
||||
PLAYERCOUNT_HOVER,
|
||||
PLAYERCOUNT_TEXT,
|
||||
PLAYERCOUNT_EXTRAPLAYERS_ENABLED,
|
||||
PLAYERCOUNT_EXTRAPLAYERS_AMOUNT,
|
||||
PLAYERCOUNT_MAXPLAYERS_ENABLED,
|
||||
PLAYERCOUNT_MAXPLAYERS_AMOUNT,
|
||||
PLAYERCOUNT_ONLINEPLAYERS_ENABLED,
|
||||
PLAYERCOUNT_ONLINEPLAYERS_AMOUNT;
|
||||
|
||||
public static List<String> list(){
|
||||
return Arrays.stream(values())
|
||||
.map(ProfileOption::toString)
|
||||
.toList();
|
||||
}
|
||||
|
||||
public static ProfileOption fromString(String input){
|
||||
for(ProfileOption option : values()){
|
||||
if(option.toString().equalsIgnoreCase(input))
|
||||
return option;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
return this.name().toLowerCase(Locale.ROOT).replace("_", ".");
|
||||
}
|
||||
|
||||
public String toDialogKey(){
|
||||
return this.name().toLowerCase(Locale.ROOT);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package ch.andre601.advancedserverlist.core.commands;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CommandType;
|
||||
import org.incendo.cloud.annotations.Command;
|
||||
import org.incendo.cloud.annotations.CommandDescription;
|
||||
import org.incendo.cloud.annotations.Permission;
|
||||
|
||||
|
||||
@Command("advancedserverlist|asl")
|
||||
@CommandDescription("Main Command of the plugin")
|
||||
@Permission("advancedserverlist.admin")
|
||||
@CommandType(CommandType.Type.ALL)
|
||||
public record CmdReload(AdvancedServerList<?> core){
|
||||
|
||||
public static CmdReload create(AdvancedServerList<?> core){
|
||||
return new CmdReload(core);
|
||||
}
|
||||
|
||||
@Command("reload")
|
||||
@CommandDescription("Reloads the plugin's main config and its profiles.")
|
||||
@Permission({"advancedserverlist.admin", "advancedserverlist.command.reload"})
|
||||
@CommandType(CommandType.Type.ALL)
|
||||
public void handle(CmdSender sender){
|
||||
sender.sendPrefixedMsg("Reloading plugin...");
|
||||
|
||||
if(core().fileHandler().reloadConfig()){
|
||||
sender.sendPrefixedMsg("<green>Reloaded </green>config.yml<green>!");
|
||||
}else{
|
||||
sender.sendErrorMsg("<red>Encountered an error while reloading the </red>config.yml<red>.");
|
||||
sender.sendErrorMsg("<red>See the server console for details.");
|
||||
}
|
||||
|
||||
if(core().fileHandler().reloadProfiles()){
|
||||
sender.sendPrefixedMsg("<green>(Re)loaded <white>%d</white> Profile(s)!", core().fileHandler().profiles().size());
|
||||
}else{
|
||||
sender.sendErrorMsg("<red>Encountered errors while (re)loading profiles.");
|
||||
sender.sendErrorMsg("<red>See the server console for details.");
|
||||
}
|
||||
|
||||
sender.sendPrefixedMsg("<green>Reload complete!");
|
||||
}
|
||||
}
|
||||
+31
-622
@@ -29,59 +29,16 @@ import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CommandType;
|
||||
import ch.andre601.advancedserverlist.core.migration.minimotd.MiniMOTDConfigMigrator;
|
||||
import ch.andre601.advancedserverlist.core.migration.serverlistplus.SLPConfigMigrator;
|
||||
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
|
||||
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileSerializer;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
import org.incendo.cloud.annotation.specifier.Greedy;
|
||||
import org.incendo.cloud.annotations.Argument;
|
||||
import org.incendo.cloud.annotations.Command;
|
||||
import org.incendo.cloud.annotations.CommandDescription;
|
||||
import org.incendo.cloud.annotations.Permission;
|
||||
import org.incendo.cloud.annotations.suggestion.Suggestions;
|
||||
import org.incendo.cloud.context.CommandContext;
|
||||
import org.incendo.cloud.context.CommandInput;
|
||||
import org.incendo.cloud.help.result.CommandEntry;
|
||||
import org.incendo.cloud.key.CloudKey;
|
||||
import org.incendo.cloud.minecraft.extras.MinecraftHelp;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
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.*;
|
||||
|
||||
@Command("advancedserverlist|asl")
|
||||
@CommandDescription("Main command of the plugin.")
|
||||
@Permission("advancedserverlist.admin")
|
||||
@CommandType(CommandType.Type.ALL)
|
||||
public class CommandHandler{
|
||||
|
||||
public static final CloudKey<CommandType.Type> COMMAND_TYPE = CloudKey.of("command_type", CommandType.Type.class);
|
||||
public static final CloudKey<String> OPTION = CloudKey.of("profile_option", String.class);
|
||||
public static final List<String> PROFILE_OPTIONS = List.of(
|
||||
"priority",
|
||||
"condition",
|
||||
"motd",
|
||||
"favicon",
|
||||
"playercount.hideplayers",
|
||||
"playercount.hideplayershover",
|
||||
"playercount.hover",
|
||||
"playercount.text",
|
||||
"playercount.extraplayers.enabled",
|
||||
"playercount.extraplayers.amount",
|
||||
"playercount.maxplayers.enabled",
|
||||
"playercount.maxplayers.amount",
|
||||
"playercount.onlineplayers.enabled",
|
||||
"playercount.onlineplayers.amount"
|
||||
);
|
||||
|
||||
public static void handleSet(AdvancedServerList<?> core, CommandContext<CmdSender> context){
|
||||
CmdSender sender = context.sender();
|
||||
@@ -103,8 +60,8 @@ public class CommandHandler{
|
||||
List<String> oldValues = new ArrayList<>();
|
||||
List<String> newValues = new ArrayList<>();
|
||||
|
||||
switch(option.toLowerCase(Locale.ROOT)){
|
||||
case "priority" -> {
|
||||
switch(CmdProfiles.ProfileOption.fromString(option)){
|
||||
case PRIORITY -> {
|
||||
oldValues.add(String.valueOf(slp.priority()));
|
||||
|
||||
if(value == null || value.isEmpty()){
|
||||
@@ -121,7 +78,7 @@ public class CommandHandler{
|
||||
return;
|
||||
}
|
||||
}
|
||||
case "condition" -> {
|
||||
case CONDITION -> {
|
||||
oldValues.add(slp.condition());
|
||||
|
||||
if(value == null || value.isEmpty()){
|
||||
@@ -132,7 +89,7 @@ public class CommandHandler{
|
||||
condition = value;
|
||||
newValues.add(value);
|
||||
}
|
||||
case "motd" -> {
|
||||
case MOTD -> {
|
||||
oldValues.addAll(entry.motd());
|
||||
|
||||
if(value == null || value.isEmpty()){
|
||||
@@ -140,7 +97,7 @@ public class CommandHandler{
|
||||
break;
|
||||
}
|
||||
|
||||
String[] lines = value.split("\\\\n|<newline>");
|
||||
String[] lines = value.split("\\\\n|<newline>|<br>");
|
||||
if(lines.length == 0){
|
||||
builder.motd(Collections.emptyList());
|
||||
break;
|
||||
@@ -157,7 +114,7 @@ public class CommandHandler{
|
||||
|
||||
newValues.addAll(Arrays.asList(lines));
|
||||
}
|
||||
case "favicon" -> {
|
||||
case FAVICON -> {
|
||||
oldValues.add(entry.favicon());
|
||||
|
||||
if(value == null || value.isEmpty()){
|
||||
@@ -169,7 +126,7 @@ public class CommandHandler{
|
||||
|
||||
newValues.add(value);
|
||||
}
|
||||
case "playercount.hideplayers" -> {
|
||||
case PLAYERCOUNT_HIDEPLAYERS -> {
|
||||
if(!entry.hidePlayersEnabled().isNotSet())
|
||||
oldValues.add(String.valueOf(entry.hidePlayersEnabled().getOrDefault(false)));
|
||||
|
||||
@@ -183,7 +140,7 @@ public class CommandHandler{
|
||||
|
||||
newValues.add(String.valueOf(bool.getOrDefault(false)));
|
||||
}
|
||||
case "playercount.hideplayershover" -> {
|
||||
case PLAYERCOUNT_HIDEPLAYERSHOVER -> {
|
||||
if(!entry.hidePlayersHoverEnabled().isNotSet())
|
||||
oldValues.add(String.valueOf(entry.hidePlayersHoverEnabled().getOrDefault(false)));
|
||||
|
||||
@@ -197,7 +154,7 @@ public class CommandHandler{
|
||||
|
||||
newValues.add(String.valueOf(bool.getOrDefault(false)));
|
||||
}
|
||||
case "playercount.hover" -> {
|
||||
case PLAYERCOUNT_HOVER -> {
|
||||
oldValues.addAll(entry.players());
|
||||
|
||||
if(value == null || value.isEmpty()){
|
||||
@@ -215,7 +172,7 @@ public class CommandHandler{
|
||||
|
||||
newValues.addAll(Arrays.asList(lines));
|
||||
}
|
||||
case "playercount.text" -> {
|
||||
case PLAYERCOUNT_TEXT -> {
|
||||
if(!entry.playerCountText().isEmpty())
|
||||
oldValues.add(entry.playerCountText());
|
||||
|
||||
@@ -228,7 +185,7 @@ public class CommandHandler{
|
||||
|
||||
newValues.add(value);
|
||||
}
|
||||
case "playercount.extraplayers.enabled" -> {
|
||||
case PLAYERCOUNT_EXTRAPLAYERS_ENABLED -> {
|
||||
if(!entry.extraPlayersEnabled().isNotSet())
|
||||
oldValues.add(String.valueOf(entry.extraPlayersEnabled().getOrDefault(false)));
|
||||
|
||||
@@ -242,7 +199,7 @@ public class CommandHandler{
|
||||
|
||||
newValues.add(String.valueOf(bool.getOrDefault(false)));
|
||||
}
|
||||
case "playercount.extraplayers.amount" -> {
|
||||
case PLAYERCOUNT_EXTRAPLAYERS_AMOUNT -> {
|
||||
if(!entry.extraPlayersCount().isEmpty())
|
||||
oldValues.add(entry.extraPlayersCount());
|
||||
|
||||
@@ -255,7 +212,7 @@ public class CommandHandler{
|
||||
|
||||
newValues.add(value);
|
||||
}
|
||||
case "playercount.maxplayers.enabled" -> {
|
||||
case PLAYERCOUNT_MAXPLAYERS_ENABLED -> {
|
||||
if(!entry.maxPlayersEnabled().isNotSet())
|
||||
oldValues.add(String.valueOf(entry.maxPlayersEnabled().getOrDefault(false)));
|
||||
|
||||
@@ -269,7 +226,7 @@ public class CommandHandler{
|
||||
|
||||
newValues.add(String.valueOf(bool.getOrDefault(false)));
|
||||
}
|
||||
case "playercount.maxplayers.amount" -> {
|
||||
case PLAYERCOUNT_MAXPLAYERS_AMOUNT -> {
|
||||
if(!entry.maxPlayersCount().isEmpty())
|
||||
oldValues.add(entry.extraPlayersCount());
|
||||
|
||||
@@ -282,7 +239,7 @@ public class CommandHandler{
|
||||
|
||||
newValues.add(value);
|
||||
}
|
||||
case "playercount.onlineplayers.enabled" -> {
|
||||
case PLAYERCOUNT_ONLINEPLAYERS_ENABLED -> {
|
||||
if(!entry.onlinePlayersEnabled().isNotSet())
|
||||
oldValues.add(String.valueOf(entry.onlinePlayersEnabled().getOrDefault(false)));
|
||||
|
||||
@@ -296,7 +253,7 @@ public class CommandHandler{
|
||||
|
||||
newValues.add(String.valueOf(bool.getOrDefault(false)));
|
||||
}
|
||||
case "playercount.onlineplayers.amount" -> {
|
||||
case PLAYERCOUNT_ONLINEPLAYERS_AMOUNT -> {
|
||||
if(!entry.onlinePlayersCount().isEmpty())
|
||||
oldValues.add(entry.onlinePlayersCount());
|
||||
|
||||
@@ -309,57 +266,13 @@ public class CommandHandler{
|
||||
|
||||
newValues.add(value);
|
||||
}
|
||||
default -> {
|
||||
sender.sendErrorMsg("<red>Unknown option</red> %s<red>!", option);
|
||||
case null, default -> {
|
||||
sender.sendErrorMsg("<red>Unknown option </red>%s<red>!", option);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Path path = core.getPlugin().getFolderPath().resolve("profiles").resolve(profileName(profile));
|
||||
if(!Files.exists(path)){
|
||||
sender.sendErrorMsg("<red>No file with name</red> %s <red>found!", profile);
|
||||
return;
|
||||
}
|
||||
|
||||
YamlConfigurationLoader loader = YamlConfigurationLoader.builder()
|
||||
.path(path)
|
||||
.indent(2)
|
||||
.nodeStyle(NodeStyle.BLOCK)
|
||||
.defaultOptions(opt -> opt.serializers(optBuilder -> optBuilder.register(ProfileEntry.class, ProfileSerializer.INSTANCE)))
|
||||
.build();
|
||||
|
||||
ConfigurationNode node;
|
||||
try{
|
||||
node = loader.load();
|
||||
}catch(IOException ex){
|
||||
sender.sendErrorMsg("<red>Encountered an IOException while trying to load file</red> %s<red>.", profile);
|
||||
sender.sendErrorMsg("<red>Check console for details.");
|
||||
|
||||
core.getPlugin().getPluginLogger().warn("Encountered IOException while loading file <white>%s.yml</white>", profile);
|
||||
return;
|
||||
}
|
||||
|
||||
if(node == null){
|
||||
sender.sendErrorMsg("<red>Unable to load file</red> %s<red>.", profile);
|
||||
return;
|
||||
}
|
||||
|
||||
try{
|
||||
node.node("priority").set(priority);
|
||||
node.node("condition").set(condition);
|
||||
node.node("profiles").setList(ProfileEntry.class, slp.profiles());
|
||||
node.set(ProfileEntry.class, builder.build());
|
||||
}catch(SerializationException ex){
|
||||
sender.sendErrorMsg("<red>Encountered a SerializationException while updating</red> %s<red>!", profile);
|
||||
sender.sendErrorMsg("<red>Check console for details.");
|
||||
|
||||
core.getPlugin().getPluginLogger().warn("Encountered SerializationException while updating <white>%s</white>", profile);
|
||||
return;
|
||||
}
|
||||
|
||||
try{
|
||||
loader.save(node);
|
||||
|
||||
if(core.fileHandler().saveProfile(profileName(profile), priority, condition, slp.profiles(), builder.build())){
|
||||
if(sender.isPlayer()){
|
||||
sender.sendPrefixedMsg(
|
||||
"<green>Successfully updated <white>[<grey><hover:show_text:\"%s\">%s</hover></grey>]</white>!",
|
||||
@@ -389,22 +302,22 @@ public class CommandHandler{
|
||||
sender.sendPrefixedMsg(
|
||||
"<green>Use <white><click:suggest_command:/asl reload>/asl reload</click></white> to apply changes."
|
||||
);
|
||||
}catch(IOException ex){
|
||||
}else{
|
||||
sender.sendErrorMsg("<red>Encountered an IOException while trying to save file</red> %s<red>.", profile);
|
||||
sender.sendErrorMsg("<red>Check console for details.");
|
||||
|
||||
core.getPlugin().getPluginLogger().warn("Encountered IOException while saving file <white>%s.yml</white>", profile);
|
||||
core.plugin().pluginLogger().warn("Encountered IOException while saving file <white>%s.yml</white>", profile);
|
||||
}
|
||||
}
|
||||
|
||||
private static ServerListProfile profile(AdvancedServerList<?> core, String name){
|
||||
return core.getFileHandler().getProfiles().stream()
|
||||
public static ServerListProfile profile(AdvancedServerList<?> core, String name){
|
||||
return core.fileHandler().profiles().stream()
|
||||
.filter(p -> p.file().equalsIgnoreCase(profileName(name)))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private static String profileName(String name){
|
||||
public static String profileName(String name){
|
||||
if(name == null || name.isEmpty())
|
||||
return "";
|
||||
|
||||
@@ -424,516 +337,12 @@ public class CommandHandler{
|
||||
}
|
||||
|
||||
private static String getOptionValue(Object obj){
|
||||
if(obj == null){
|
||||
return "";
|
||||
}else
|
||||
if(obj instanceof Boolean bool){
|
||||
return Boolean.toString(bool);
|
||||
}else
|
||||
if(obj instanceof Integer integer){
|
||||
return Integer.toString(integer);
|
||||
}else
|
||||
if(obj instanceof String str){
|
||||
return str;
|
||||
}else{
|
||||
return obj.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private final CommandManager<CmdSender> commandManager;
|
||||
private final MinecraftHelp<CmdSender> help;
|
||||
|
||||
public CommandHandler(CommandManager<CmdSender> commandManager){
|
||||
this.commandManager = commandManager;
|
||||
this.help = MinecraftHelp.<CmdSender>builder()
|
||||
.commandManager(commandManager)
|
||||
.audienceProvider(CmdSender::audience)
|
||||
.commandPrefix("/advancedserverlist help")
|
||||
.colors(MinecraftHelp.helpColors(
|
||||
NamedTextColor.WHITE, NamedTextColor.AQUA, NamedTextColor.WHITE, NamedTextColor.GRAY, NamedTextColor.DARK_GRAY
|
||||
))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Command("help [query]")
|
||||
@CommandDescription("Displays the commands available for AdvancedServerList")
|
||||
@Permission({"advancedserverlist.admin", "advancedserverlist.command.help"})
|
||||
@CommandType(CommandType.Type.ALL)
|
||||
public void help(
|
||||
CmdSender sender,
|
||||
@Nullable @Argument(description = "Query to receive info of a specific command.", suggestions = "help") @Greedy String query
|
||||
){
|
||||
this.help.queryCommands(query == null ? "" : query, sender);
|
||||
}
|
||||
|
||||
@Command("reload")
|
||||
@CommandDescription("Reloads the config.yml and all existing profiles.")
|
||||
@Permission({"advancedserverlist.admin", "advancedserverlist.command.reload"})
|
||||
@CommandType(CommandType.Type.ALL)
|
||||
public void reload(CmdSender sender, AdvancedServerList<?> core){
|
||||
sender.sendPrefixedMsg("Reloading plugin...");
|
||||
|
||||
if(core.getFileHandler().reloadConfig()){
|
||||
sender.sendPrefixedMsg("<green>Reloaded </green>config.yml<green>!");
|
||||
}else{
|
||||
sender.sendErrorMsg("<red>Error while reloading </red>config.yml<red>.");
|
||||
sender.sendErrorMsg("<red>Check console for details.");
|
||||
}
|
||||
|
||||
if(core.getFileHandler().reloadProfiles()){
|
||||
sender.sendPrefixedMsg("<green>(Re)loaded </green>%d<green> Profile(s)!", core.getFileHandler().getProfiles().size());
|
||||
}else{
|
||||
sender.sendErrorMsg("<red>Error while (re)loading profiles.");
|
||||
sender.sendErrorMsg("<red>Check console for details.");
|
||||
}
|
||||
|
||||
sender.sendPrefixedMsg("<green>Reload complete!");
|
||||
}
|
||||
|
||||
@Command("clearcache")
|
||||
@CommandDescription("Clears the Favicon and Player cache of the plugin.")
|
||||
@Permission({"advancedserverlist.admin", "advancedserverlist.command.clearcache"})
|
||||
@CommandType(CommandType.Type.ALL)
|
||||
public void clearCache(CmdSender sender, AdvancedServerList<?> core){
|
||||
sender.sendPrefixedMsg("Clearing cache...");
|
||||
|
||||
core.clearFaviconCache();
|
||||
sender.sendPrefixedMsg("Cleared Favicon cache.");
|
||||
|
||||
core.clearPlayerCache();
|
||||
sender.sendPrefixedMsg("Cleared Player cache.");
|
||||
|
||||
sender.sendPrefixedMsg("<green>Cache clearing complete!");
|
||||
}
|
||||
|
||||
@Command("migrate <plugin>")
|
||||
@CommandDescription("Migrates Profiles from other plugins to itself.")
|
||||
@Permission({"advancedserverlist.admin", "advancedserverlist.command.migrate"})
|
||||
@CommandType(CommandType.Type.ALL)
|
||||
public void migrate(
|
||||
CmdSender sender,
|
||||
AdvancedServerList<?> core,
|
||||
@NonNull @Argument(description = "The plugin to migrate from.") Plugin plugin
|
||||
){
|
||||
if(plugin == Plugin.SERVERLISTPLUS){
|
||||
if(!core.getPlugin().isPluginEnabled("ServerListPlus")){
|
||||
sender.sendErrorMsg("<red>ServerListPlus is not enabled.");
|
||||
sender.sendErrorMsg("<red>The plugin is required for the migration to work.");
|
||||
return;
|
||||
}
|
||||
|
||||
sender.sendPrefixedMsg("Migrating from ServerListPlus...");
|
||||
|
||||
int migrated = SLPConfigMigrator.migrate(core, sender);
|
||||
if(migrated == 0){
|
||||
sender.sendErrorMsg("<red>Unable to migrate any profiles from ServerListPlus.");
|
||||
sender.sendErrorMsg("<red>Check console for details.");
|
||||
}else{
|
||||
sender.sendPrefixedMsg("<green>Successfully migrated </green>%d<green> Profile(s)", migrated);
|
||||
}
|
||||
}else
|
||||
if(plugin == Plugin.MINIMOTD){
|
||||
sender.sendPrefixedMsg("Migrating from MiniMOTD...");
|
||||
|
||||
if(MiniMOTDConfigMigrator.migrate(core, sender)){
|
||||
sender.sendPrefixedMsg("<green>Successfully migrated from MiniMOTD!");
|
||||
}else{
|
||||
sender.sendErrorMsg("<red>Unable to migrate from MiniMOTD.");
|
||||
sender.sendErrorMsg("<red>Check console for details.");
|
||||
}
|
||||
}else{
|
||||
sender.sendErrorMsg("<red>Received invalid Plugin name </red>%s<red>.", plugin);
|
||||
sender.sendMsg("<grey>Supported plugins [Click for command]:");
|
||||
sender.sendMsg();
|
||||
sender.sendMsg(" <grey>-</grey> <click:suggest_command:/asl migrate serverlistplus>ServerListPlus</click>");
|
||||
sender.sendMsg(" <grey>-</grey> <click:suggest_command:/asl migrate minimotd>MiniMOTD</click>");
|
||||
}
|
||||
}
|
||||
|
||||
@Command("profiles list")
|
||||
@CommandDescription("Lists all available profiles with their priority, conditions and if they are valid.")
|
||||
@Permission({"advancedserverlist.admin", "advancedserverlist.command.profiles", "advancedserverlist.command.profiles.list"})
|
||||
@CommandType(CommandType.Type.ALL)
|
||||
public void list(CmdSender sender, AdvancedServerList<?> core){
|
||||
sender.sendMsg();
|
||||
sender.sendPrefixedMsg("Available Profiles");
|
||||
sender.sendMsg("<dark_grey>│");
|
||||
|
||||
List<ServerListProfile> profiles = core.getFileHandler().getProfiles().stream()
|
||||
.sorted(Comparator.comparingInt(ServerListProfile::priority).reversed())
|
||||
.toList();
|
||||
|
||||
if(profiles.isEmpty()){
|
||||
sender.sendMsg("<dark_grey>└─</dark_grey> <i>No profiles found</i>");
|
||||
}else{
|
||||
for(int i = 0; i < profiles.size(); i++){
|
||||
sender.sendMsg(
|
||||
"<dark_grey>%s─</dark_grey> <aqua>" +
|
||||
"<hover:show_text:\"%s\">" +
|
||||
"<click:suggest_command:/asl profiles info %s>" +
|
||||
"%s" +
|
||||
"</click>" +
|
||||
"</hover>" +
|
||||
"</aqua>",
|
||||
(i + 1) == profiles.size() ? "└" : "├",
|
||||
hover(profiles.get(i)),
|
||||
profiles.get(i).file(),
|
||||
profiles.get(i).file()
|
||||
);
|
||||
}
|
||||
}
|
||||
if(sender.isPlayer()){
|
||||
sender.sendMsg();
|
||||
sender.sendMsg("<grey>[<white>Hover a name for details. Click for a command</white>]</grey>");
|
||||
}
|
||||
sender.sendMsg();
|
||||
}
|
||||
|
||||
@Command("profiles info <profile>")
|
||||
@CommandDescription("Provides info about a profile.")
|
||||
@Permission({"advancedserverlist.admin", "advancedserverlist.command.profiles", "advancedserverlist.command.profiles.info"})
|
||||
@CommandType(CommandType.Type.PLAYER_ONLY)
|
||||
public void info(
|
||||
CmdSender sender,
|
||||
AdvancedServerList<?> core,
|
||||
@NonNull @Argument(description = "Name of the profile to view.", suggestions = "profiles") String profile
|
||||
){
|
||||
if(!sender.isPlayer()){
|
||||
sender.sendErrorMsg("<red>This command can only be executed by Players!");
|
||||
return;
|
||||
}
|
||||
|
||||
if(profile.isEmpty()){
|
||||
sender.sendErrorMsg("<red>Insufficient arguments.");
|
||||
sender.sendErrorMsg("<red>Please provide a proper profile name.");
|
||||
return;
|
||||
}
|
||||
|
||||
ServerListProfile slp = profile(core, profile);
|
||||
|
||||
if(slp == null){
|
||||
sender.sendErrorMsg("<red>Unable to find profile with name </red>%s<red>.", profile);
|
||||
sender.sendErrorMsg("<red>Make sure you typed it correctly.");
|
||||
return;
|
||||
}
|
||||
|
||||
ProfileOptionsSender optionsSender = new ProfileOptionsSender(slp.file());
|
||||
|
||||
optionsSender
|
||||
.append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Priority", slp.priority())
|
||||
.option("priority")
|
||||
)
|
||||
.append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Condition", slp.condition())
|
||||
.option("condition")
|
||||
)
|
||||
.append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Profiles")
|
||||
.color(slp.profiles().isEmpty() ? ProfileOptionsSender.ColorName.RED : ProfileOptionsSender.ColorName.GREEN)
|
||||
);
|
||||
|
||||
if(!slp.profiles().isEmpty()){
|
||||
for(int i = 0; i < slp.profiles().size(); i++){
|
||||
optionsSender.append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("#" + (i + 1), profileHover(slp.profiles().get(i)))
|
||||
.prefix("│ %s─".formatted((i + 1) == slp.profiles().size() ? "└" : "├"))
|
||||
.color(ProfileOptionsSender.ColorName.AQUA)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ProfileEntry entry = slp.defaultProfile();
|
||||
|
||||
optionsSender
|
||||
.append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("MOTD", entry.motd())
|
||||
.option("motd")
|
||||
)
|
||||
.append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Favicon", entry.favicon())
|
||||
.option("favicon")
|
||||
)
|
||||
.append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Player count")
|
||||
.prefix("└─")
|
||||
.color(ProfileOptionsSender.ColorName.AQUA)
|
||||
)
|
||||
.append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Hide Player count?", entry.hidePlayersEnabled())
|
||||
.prefix(" ├─")
|
||||
.option("playercount.hideplayers")
|
||||
)
|
||||
.append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Hide Player count hover?", entry.hidePlayersHoverEnabled())
|
||||
.prefix(" ├─")
|
||||
.option("playercount.hideplayershover")
|
||||
)
|
||||
.append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Player count hover", entry.players())
|
||||
.prefix(" ├─")
|
||||
.option("playercount.hover")
|
||||
)
|
||||
.append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Player count text", entry.playerCountText())
|
||||
.prefix(" ├─")
|
||||
.option("playercount.text")
|
||||
)
|
||||
.append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Extra Players")
|
||||
.prefix(" ├─")
|
||||
.color(ProfileOptionsSender.ColorName.AQUA)
|
||||
)
|
||||
.append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Enabled?", entry.extraPlayersEnabled())
|
||||
.prefix(" │ ├─")
|
||||
.option("playercount.extraplayers.enabled")
|
||||
)
|
||||
.append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Amount", entry.extraPlayersCount())
|
||||
.prefix(" │ └─")
|
||||
.option("playercount.extraplayers.amount")
|
||||
)
|
||||
.append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Max Players")
|
||||
.prefix(" ├─")
|
||||
.color(ProfileOptionsSender.ColorName.AQUA)
|
||||
)
|
||||
.append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Enabled?", entry.maxPlayersEnabled())
|
||||
.prefix(" │ ├─")
|
||||
.option("playercount.maxplayers.enabled")
|
||||
)
|
||||
.append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Amount", entry.maxPlayersCount())
|
||||
.prefix(" │ └─")
|
||||
.option("playercount.maxplayers.amount")
|
||||
)
|
||||
.append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Online Players")
|
||||
.prefix(" └─")
|
||||
.color(ProfileOptionsSender.ColorName.AQUA)
|
||||
)
|
||||
.append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Enabled?", entry.onlinePlayersEnabled())
|
||||
.prefix(" ├─")
|
||||
.option("playercount.onlineplayers.enabled")
|
||||
)
|
||||
.append(
|
||||
ProfileOptionsSender.OptionStringBuilder.of("Amount", entry.onlinePlayersCount())
|
||||
.prefix(" └─")
|
||||
.option("playercount.onlineplayers.amount")
|
||||
)
|
||||
.send(sender);
|
||||
}
|
||||
|
||||
@Command("profiles add <name>")
|
||||
@CommandDescription("Creates a new profile with default values applied.")
|
||||
@Permission({"advancedserverlist.admin", "advancedserverlist.command.profiles", "advancedserverlist.command.profiles.add"})
|
||||
@CommandType(CommandType.Type.ALL)
|
||||
public void add(
|
||||
CmdSender sender,
|
||||
AdvancedServerList<?> core,
|
||||
@NonNull @Argument(description = "Name of the profile to create.") String name
|
||||
){
|
||||
if(name.isEmpty()){
|
||||
sender.sendErrorMsg("<red>Insufficient arguments.");
|
||||
sender.sendErrorMsg("<red>Please provide a proper file name.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(profile(core, name) != null){
|
||||
sender.sendErrorMsg("<red>A profile with name </red>%s<red> already exists.", name);
|
||||
return;
|
||||
}
|
||||
|
||||
String fileName = profileName(name);
|
||||
|
||||
if(core.getFileHandler().createFile(fileName)){
|
||||
sender.sendPrefixedMsg("<green>Successfully created </green>%s<green>!", fileName);
|
||||
sender.sendPrefixedMsg("<green>Use <white><click:suggest_command:/asl reload>/asl reload</click></white> to load the file.");
|
||||
}else{
|
||||
sender.sendErrorMsg("<red>Error while creating new profile.");
|
||||
sender.sendErrorMsg("<red>Check console for details.");
|
||||
}
|
||||
}
|
||||
|
||||
@Command("profiles copy <profile> <name>")
|
||||
@CommandDescription("Creates a copy of an existing profile.")
|
||||
@Permission({"advancedserverlist.admin", "advancedserverlist.command.profiles", "advancedserverlist.command.profiles.copy"})
|
||||
@CommandType(CommandType.Type.ALL)
|
||||
public void copy(
|
||||
CmdSender sender,
|
||||
AdvancedServerList<?> core,
|
||||
@NonNull @Argument(description = "Name of the profile to copy.", suggestions = "profiles") String profile,
|
||||
@NonNull @Argument(description = "Name of the copy.") String name
|
||||
){
|
||||
if(profile.isEmpty() || name.isEmpty()){
|
||||
sender.sendErrorMsg("<red>Insufficient arguments.");
|
||||
sender.sendErrorMsg("<red>Please provide a profile name and name for the copy.");
|
||||
return;
|
||||
}
|
||||
|
||||
String profileName = profileName(profile);
|
||||
String copyName = profileName(name);
|
||||
|
||||
ServerListProfile targetProfile = profile(core, profile);
|
||||
boolean copyExists = profile(core, name) != null;
|
||||
|
||||
if(targetProfile == null){
|
||||
sender.sendErrorMsg("<red>No profile with name </red>%s<red> exists.", profile);
|
||||
return;
|
||||
}
|
||||
|
||||
if(copyExists){
|
||||
sender.sendErrorMsg("<red>A file with name </red>%<red> already exists!", copyName);
|
||||
return;
|
||||
}
|
||||
|
||||
Path profilePath = core.getPlugin().getFolderPath().resolve("profiles").resolve(copyName);
|
||||
if(!Files.exists(profilePath)){
|
||||
try{
|
||||
Files.createFile(profilePath);
|
||||
}catch(IOException ex){
|
||||
sender.sendErrorMsg("<red>Encountered IOException while creating file </red>%s<red>.", copyName);
|
||||
sender.sendErrorMsg("<red>Check console for details.");
|
||||
|
||||
core.getPlugin().getPluginLogger().warn("Encountered IOException while creating file <white>%s</white>", ex, copyName);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
YamlConfigurationLoader loader = YamlConfigurationLoader.builder()
|
||||
.path(profilePath)
|
||||
.indent(2)
|
||||
.nodeStyle(NodeStyle.BLOCK)
|
||||
.defaultOptions(opt -> opt.serializers(builder -> builder.register(ProfileEntry.class, ProfileSerializer.INSTANCE)))
|
||||
.build();
|
||||
|
||||
ConfigurationNode node;
|
||||
try{
|
||||
node = loader.load();
|
||||
}catch(IOException ex){
|
||||
sender.sendErrorMsg("<red>There was an IOException while loading file </red>%s<red>!", copyName);
|
||||
sender.sendErrorMsg("<red>Check console for details.");
|
||||
|
||||
core.getPlugin().getPluginLogger().warn("Encountered IOException while loading file <white>%s</white>", ex, copyName);
|
||||
return;
|
||||
}
|
||||
|
||||
if(node == null){
|
||||
sender.sendErrorMsg("<red>Cannot create ConfigurationNode for file </red>%s<red>", copyName);
|
||||
return;
|
||||
}
|
||||
|
||||
try{
|
||||
node.node("priority").set(targetProfile.priority());
|
||||
node.node("condition").set(targetProfile.condition());
|
||||
|
||||
node.node("profiles").setList(ProfileEntry.class, targetProfile.profiles());
|
||||
|
||||
node.set(ProfileEntry.class, targetProfile.defaultProfile());
|
||||
}catch(SerializationException ex){
|
||||
sender.sendErrorMsg("<red>There was a SerializationException while copying values from </red>%s<red>.", profile);
|
||||
sender.sendErrorMsg("<red>Check console for details.");
|
||||
|
||||
core.getPlugin().getPluginLogger().warn("Encountered IOException while copying data from <white>%s</white> to <white>%s</white>.", ex, profileName, copyName);
|
||||
return;
|
||||
}
|
||||
|
||||
try{
|
||||
loader.save(node);
|
||||
sender.sendPrefixedMsg("<green>Successfully made copy of </green>%s<green> as </green>%s<green>!", profile, copyName);
|
||||
sender.sendPrefixedMsg("<green>Use </green><click:suggest_command:/asl reload>/asl reload</click><green> to load the file.");
|
||||
}catch(IOException ex){
|
||||
sender.sendErrorMsg("<red>There was an IOException while loading file </red>%s<red>!", copyName);
|
||||
sender.sendErrorMsg("<red>Check console for details.");
|
||||
|
||||
core.getPlugin().getPluginLogger().warn("Encountered IOException while loading file <white>%s</white>", ex, copyName);
|
||||
}
|
||||
}
|
||||
|
||||
@Suggestions("help")
|
||||
public List<String> helpQueries(CommandContext<CmdSender> context){
|
||||
return this.commandManager.createHelpHandler()
|
||||
.queryRootIndex(context.sender())
|
||||
.entries()
|
||||
.stream()
|
||||
.filter(entry -> context.hasPermission(entry.command().commandPermission()))
|
||||
.filter(entry -> {
|
||||
CommandType.Type type = entry.command().commandMeta().getOrDefault(COMMAND_TYPE, CommandType.Type.ALL);
|
||||
|
||||
return type == CommandType.Type.ALL || type == CommandType.Type.PLAYER_ONLY && context.sender().isPlayer();
|
||||
})
|
||||
.map(CommandEntry::syntax)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Suggestions("profiles")
|
||||
public List<String> profilesSuggestions(CommandInput input, AdvancedServerList<?> core){
|
||||
String name = input.readString();
|
||||
List<String> profiles = core.getFileHandler().getProfiles().stream()
|
||||
.map(profile -> profile.file().substring(0, profile.file().lastIndexOf('.')))
|
||||
.toList();
|
||||
if(name.isEmpty())
|
||||
return profiles;
|
||||
|
||||
List<String> matches = new ArrayList<>(profiles.size());
|
||||
for(String str : profiles){
|
||||
if(str.length() >= name.length() && str.regionMatches(true, 0, name, 0, name.length()))
|
||||
matches.add(str);
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
private String hover(ServerListProfile profile){
|
||||
return """
|
||||
<grey>Priority: <white>%d</white>
|
||||
Condition: <white>%s</white>
|
||||
|
||||
Is valid? %s""".formatted(
|
||||
profile.priority(),
|
||||
profile.condition() == null || profile.condition().isEmpty() ? "<i>None</i>" : profile.condition(),
|
||||
profile.isInvalidProfile() ? "<red>No</red>" : "<green>Yes</green>"
|
||||
);
|
||||
}
|
||||
|
||||
private String profileHover(ProfileEntry entry){
|
||||
return """
|
||||
<grey>MOTD:
|
||||
%s<reset>
|
||||
|
||||
<grey>Favicon: %s<reset>
|
||||
|
||||
<grey>Hide Playercount? %s
|
||||
Hide Playercount Hover? %s
|
||||
|
||||
Playercount Hover:
|
||||
%s<reset>
|
||||
|
||||
<grey>Playercount Text: %s<reset>
|
||||
|
||||
<grey>Extra Players: %s<reset>
|
||||
<grey>Max Players: %s<reset>
|
||||
<grey>Online Players: %s""".formatted(
|
||||
entry.motd() == null || entry.motd().isEmpty() ?
|
||||
"<i><white>None</white></i>" : String.join("<reset>\n", entry.motd()),
|
||||
entry.favicon() == null || entry.favicon().isEmpty() ?
|
||||
"<i><white>None</white></i>" : entry.favicon(),
|
||||
entry.hidePlayersEnabled().getOrDefault(false) ? "<green>Enabled</green>" : "<red>Disabled</red>",
|
||||
entry.hidePlayersHoverEnabled().getOrDefault(false) ? "<green>Enabled</green>" : "<red>Disabled</red>",
|
||||
entry.players().isEmpty() ? "<i><white>None</white></i>" : String.join("<reset>\n", entry.players()),
|
||||
entry.playerCountText() == null || entry.playerCountText().isEmpty() ?
|
||||
"<i><white>None</white></i>" : entry.playerCountText(),
|
||||
entry.extraPlayersEnabled().getOrDefault(false) ? entry.extraPlayersCount() : "<red>Disabled</red>",
|
||||
entry.maxPlayersEnabled().getOrDefault(false) ? entry.maxPlayersCount() : "<red>Disabled</red>",
|
||||
entry.onlinePlayersEnabled().getOrDefault(false) ? entry.onlinePlayersCount() : "<red>Disabled</red>"
|
||||
);
|
||||
}
|
||||
|
||||
public enum Plugin {
|
||||
SERVERLISTPLUS,
|
||||
MINIMOTD
|
||||
return switch(obj){
|
||||
case null -> "";
|
||||
case Boolean bool -> Boolean.toString(bool);
|
||||
case Integer integer -> Integer.toString(integer);
|
||||
case String str -> str;
|
||||
default -> obj.toString();
|
||||
};
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
package ch.andre601.advancedserverlist.core.commands;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CommandType;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.incendo.cloud.execution.postprocessor.CommandPostprocessingContext;
|
||||
import org.incendo.cloud.execution.postprocessor.CommandPostprocessor;
|
||||
import org.incendo.cloud.services.type.ConsumerService;
|
||||
|
||||
public class CommandTypePostprocessor implements CommandPostprocessor<CmdSender>{
|
||||
@Override
|
||||
public void accept(@NonNull CommandPostprocessingContext<CmdSender> context){
|
||||
CmdSender sender = context.commandContext().sender();
|
||||
CommandType.Type type = context.commandContext().command().commandMeta().get(CommandHandler.COMMAND_TYPE);
|
||||
|
||||
if(type == CommandType.Type.ALL || (type == CommandType.Type.PLAYER_ONLY && sender.isPlayer()))
|
||||
return;
|
||||
|
||||
sender.sendErrorMsg("<red>This command can only be executed by players!");
|
||||
ConsumerService.interrupt();
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -90,7 +90,7 @@ public class ProfileOptionsSender{
|
||||
private String prefix = "├─";
|
||||
private ColorName color = ColorName.AQUA;
|
||||
private String hover = "<i>Not set</i>";
|
||||
private String option = null;
|
||||
private CmdProfiles.ProfileOption option = null;
|
||||
|
||||
private OptionStringBuilder(String displayName){
|
||||
this.displayName = displayName;
|
||||
@@ -116,7 +116,7 @@ public class ProfileOptionsSender{
|
||||
return this;
|
||||
}
|
||||
|
||||
public OptionStringBuilder option(String option){
|
||||
public OptionStringBuilder option(CmdProfiles.ProfileOption option){
|
||||
this.option = option;
|
||||
return this;
|
||||
}
|
||||
@@ -135,7 +135,7 @@ public class ProfileOptionsSender{
|
||||
.append("\">");
|
||||
}
|
||||
|
||||
if(option != null && !option.isEmpty() && file != null && !file.isEmpty()){
|
||||
if(option != null && file != null && !file.isEmpty()){
|
||||
builder.append("<click:suggest_command:/asl profiles set ")
|
||||
.append(file)
|
||||
.append(" ")
|
||||
@@ -145,7 +145,7 @@ public class ProfileOptionsSender{
|
||||
|
||||
builder.append(displayName);
|
||||
|
||||
if(option != null && !option.isEmpty())
|
||||
if(option != null && file != null && !file.isEmpty())
|
||||
builder.append("</click>");
|
||||
|
||||
if(hover != null && !hover.isEmpty())
|
||||
@@ -159,7 +159,7 @@ public class ProfileOptionsSender{
|
||||
}
|
||||
}
|
||||
|
||||
enum ColorName{
|
||||
public enum ColorName{
|
||||
RED,
|
||||
GREEN,
|
||||
AQUA;
|
||||
|
||||
+5
-2
@@ -4,7 +4,10 @@ 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;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@NullMarked
|
||||
public class MaintenancePlaceholder extends PlaceholderProvider{
|
||||
|
||||
private final AdvancedServerList<?> plugin;
|
||||
@@ -15,8 +18,8 @@ public class MaintenancePlaceholder extends PlaceholderProvider{
|
||||
this.plugin = plugin;
|
||||
}
|
||||
@Override
|
||||
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
|
||||
if(!placeholder.equals("maintenanceEnabled") || !plugin.getPlugin().isPluginEnabled("Maintenance"))
|
||||
public @Nullable String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
|
||||
if(!placeholder.equals("maintenanceEnabled") || !plugin.plugin().isPluginEnabled("Maintenance"))
|
||||
return null;
|
||||
|
||||
return String.valueOf(MaintenanceUtil.get().isMaintenanceEnabled());
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package ch.andre601.advancedserverlist.core.compat.miniplaceholders;
|
||||
|
||||
import io.github.miniplaceholders.api.MiniPlaceholders;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
|
||||
public class MiniPlaceholdersUtil{
|
||||
|
||||
public static TagResolver tagResolvers(){
|
||||
return MiniPlaceholders.globalPlaceholders();
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,7 @@ 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()
|
||||
private final Cache<CacheKey, CompletableFuture<String>> textCache = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(Duration.ofSeconds(10))
|
||||
.build();
|
||||
private final PlaceholderAPI papi;
|
||||
@@ -72,21 +72,23 @@ public class PAPIUtil{
|
||||
if(values.isEmpty())
|
||||
return null;
|
||||
|
||||
return List.copyOf(values).get(0);
|
||||
return List.copyOf(values).getFirst();
|
||||
}
|
||||
|
||||
public <P> P getPlayer(Collection<P> players){
|
||||
if(players.isEmpty())
|
||||
return null;
|
||||
|
||||
return List.copyOf(players).get(0);
|
||||
return List.copyOf(players).getFirst();
|
||||
}
|
||||
|
||||
public String parse(String text, UUID carrier, UUID player){
|
||||
try{
|
||||
return textCache.get(player, () -> papi.formatPlaceholders(text, carrier, player)).getNow(text);
|
||||
return textCache.get(new CacheKey(player, text), () -> papi.formatPlaceholders(text, carrier, player)).getNow(text);
|
||||
}catch(ExecutionException ex){
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
private record CacheKey(UUID uuid, String text){}
|
||||
}
|
||||
+29
-24
@@ -44,28 +44,28 @@ import java.util.List;
|
||||
public class PingEventHandler{
|
||||
|
||||
public static <F, P extends GenericPlayer> ProfileEntry handleEvent(GenericEventWrapper<F, P> event){
|
||||
event.getPlugin().getPluginLogger().debug(PingEventHandler.class, "Received ping event. Handling it...");
|
||||
event.plugin().pluginLogger().debug(PingEventHandler.class, "Received ping event. Handling it...");
|
||||
if(event.isInvalidProtocol()){
|
||||
event.getPlugin().getPluginLogger().debug(PingEventHandler.class, "Not handling event. Protocol was invalid.");
|
||||
event.plugin().pluginLogger().debug(PingEventHandler.class, "Not handling event. Protocol was invalid.");
|
||||
return null;
|
||||
}
|
||||
|
||||
PluginCore<F> plugin = event.getPlugin();
|
||||
String host = event.getVirtualHost();
|
||||
PluginLogger logger = plugin.getPluginLogger();
|
||||
PluginCore<F> plugin = event.plugin();
|
||||
String host = event.virtualHost();
|
||||
PluginLogger logger = plugin.pluginLogger();
|
||||
|
||||
logger.debug(PingEventHandler.class, "Protocol valid. Continue handling...");
|
||||
|
||||
int online = event.getOnlinePlayers();
|
||||
int max = event.getMaxPlayers();
|
||||
int online = event.onlinePlayers();
|
||||
int max = event.maxPlayers();
|
||||
|
||||
P player = event.createPlayer(
|
||||
plugin.getCore().getPlayerHandler().getCachedPlayer(event.getPlayerIP()),
|
||||
event.getProtocolVersion()
|
||||
plugin.core().playerHandler().getCachedPlayer(event.playerIP()),
|
||||
event.protocolVersion()
|
||||
);
|
||||
GenericServer server = event.createGenericServer(online, max, host);
|
||||
GenericServer server = event.createServer(online, max, host);
|
||||
|
||||
ServerListProfile profile = ProfileManager.resolveProfile(plugin.getCore(), player, server);
|
||||
ServerListProfile profile = ProfileManager.resolveProfile(plugin.core(), player, server);
|
||||
|
||||
if(profile == null){
|
||||
logger.debugWarn(PingEventHandler.class, "Server List Profile couldn't be resolved properly. Cancelling event handling...");
|
||||
@@ -93,11 +93,12 @@ public class PingEventHandler{
|
||||
String onlinePlayers = ComponentParser.text(entry.onlinePlayersCount())
|
||||
.modifyText(text -> StringReplacer.replace(text, player, server))
|
||||
.modifyText(text -> event.parsePAPIPlaceholders(text, player))
|
||||
.applyMMTags(event.plugin())
|
||||
.toString();
|
||||
|
||||
try{
|
||||
online = onlinePlayers == null ? online : Integer.parseInt(onlinePlayers);
|
||||
event.setOnlinePlayers(online);
|
||||
event.onlinePlayers(online);
|
||||
}catch(NumberFormatException ex){
|
||||
logger.warn("Option 'playerCount -> onlinePlayers -> amount' is not a valid Number!");
|
||||
}
|
||||
@@ -110,13 +111,14 @@ public class PingEventHandler{
|
||||
String extraPlayers = ComponentParser.text(entry.extraPlayersCount())
|
||||
.modifyText(text -> StringReplacer.replace(text, player, server))
|
||||
.modifyText(text -> event.parsePAPIPlaceholders(text, player))
|
||||
.applyMMTags(event.plugin())
|
||||
.toString();
|
||||
|
||||
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);
|
||||
event.maxPlayers(max);
|
||||
}catch(NumberFormatException ex){
|
||||
logger.warn("Option 'playerCount -> extraPlayers -> amount' is not a valid Number!");
|
||||
}
|
||||
@@ -127,19 +129,20 @@ public class PingEventHandler{
|
||||
String maxPlayers = ComponentParser.text(entry.maxPlayersCount())
|
||||
.modifyText(text -> StringReplacer.replace(text, player, server))
|
||||
.modifyText(text -> event.parsePAPIPlaceholders(text, player))
|
||||
.applyMMTags(event.plugin())
|
||||
.toString();
|
||||
|
||||
try{
|
||||
max = maxPlayers == null ? 0 : Integer.parseInt(maxPlayers);
|
||||
|
||||
logger.debug(PingEventHandler.class, "'playerCount -> maxPlayers -> amount' is a valid number. Applying it...");
|
||||
event.setMaxPlayers(max);
|
||||
event.maxPlayers(max);
|
||||
}catch(NumberFormatException ex){
|
||||
logger.warn("Option 'playerCount -> maxPlayers -> amount' is not a valid Number!");
|
||||
}
|
||||
}
|
||||
|
||||
GenericServer finalServer = event.createGenericServer(online, max, host);
|
||||
GenericServer finalServer = event.createServer(online, max, host);
|
||||
|
||||
if(ProfileManager.checkOption(entry.motd()) && ignoreMaintenance(event, "motd")){
|
||||
logger.debug(PingEventHandler.class, "'motd' option present. Applying ['%s']...", String.join("', '", entry.motd()));
|
||||
@@ -148,12 +151,13 @@ public class PingEventHandler{
|
||||
.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))
|
||||
.modifyText(text -> plugin.core().textCenterUtil().getCenteredText(text))
|
||||
.applyMMTags(event.plugin())
|
||||
.toComponent()
|
||||
)
|
||||
.toList();
|
||||
|
||||
event.setMotd(Component.join(JoinConfiguration.separator(Component.newline()), motd));
|
||||
event.motd(Component.join(JoinConfiguration.separator(Component.newline()), motd));
|
||||
}
|
||||
|
||||
boolean hidePlayers = ProfileManager.checkOption(entry.hidePlayersEnabled());
|
||||
@@ -167,10 +171,11 @@ public class PingEventHandler{
|
||||
if(ProfileManager.checkOption(entry.playerCountText()) && !hidePlayers && ignoreMaintenance(event, "playerCountText")){
|
||||
logger.debug(PingEventHandler.class, "'playerCount -> text' option set. Applying '%s'...", entry.playerCountText());
|
||||
|
||||
event.setPlayerCount(
|
||||
event.playerCount(
|
||||
ComponentParser.text(entry.playerCountText())
|
||||
.modifyText(text -> StringReplacer.replace(text, player, finalServer))
|
||||
.modifyText(text -> event.parsePAPIPlaceholders(text, player))
|
||||
.applyMMTags(event.plugin())
|
||||
.toString()
|
||||
);
|
||||
}
|
||||
@@ -178,13 +183,13 @@ public class PingEventHandler{
|
||||
boolean hidePlayersHover = ProfileManager.checkOption(entry.hidePlayersHoverEnabled());
|
||||
if(hidePlayersHover){
|
||||
logger.debug(PingEventHandler.class, "'playerCount -> hidePlayersHover' option set. Hiding Player Hover...");
|
||||
event.setPlayersHidden();
|
||||
event.playersHidden();
|
||||
}
|
||||
|
||||
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);
|
||||
event.players(entry.players(), player, server);
|
||||
}
|
||||
|
||||
if(ProfileManager.checkOption(entry.favicon()) && ignoreMaintenance(event, "favicon")){
|
||||
@@ -195,16 +200,16 @@ public class PingEventHandler{
|
||||
.modify(text -> event.parsePAPIPlaceholders(text, player))
|
||||
.asString();
|
||||
|
||||
F favicon = plugin.getFaviconHandler().favicon(faviconString);
|
||||
F favicon = plugin.faviconHandler().favicon(faviconString);
|
||||
|
||||
if(favicon == null){
|
||||
logger.debugWarn(PingEventHandler.class, "Favicon was invalid or not yet resolved! Using default favicon of Server/Proxy...");
|
||||
|
||||
event.setDefaultFavicon();
|
||||
event.defaultFavicon();
|
||||
}else{
|
||||
logger.debug(PingEventHandler.class, "Applying favicon...");
|
||||
|
||||
event.setFavicon(favicon);
|
||||
event.favicon(favicon);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,6 +223,6 @@ public class PingEventHandler{
|
||||
if(!event.isMaintenanceModeActive())
|
||||
return true;
|
||||
|
||||
return !event.getPlugin().getCore().getFileHandler().getBool(true, "disableDuringMaintenance", option);
|
||||
return !event.plugin().core().fileHandler().getBool(true, "disableDuringMaintenance", option);
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,8 @@ public class ConfigMigrator{
|
||||
public static ConfigurationTransformation.Versioned create(){
|
||||
return ConfigurationTransformation.versionedBuilder()
|
||||
.versionKey("configVersion")
|
||||
.addVersion(LATEST, eightToNine())
|
||||
.addVersion(LATEST, nineToTen())
|
||||
.addVersion(9, eightToNine())
|
||||
.addVersion(8, sevenToEight())
|
||||
.addVersion(7, sixToSeven())
|
||||
.addVersion(6, fiveToSix())
|
||||
@@ -57,6 +58,12 @@ public class ConfigMigrator{
|
||||
.build();
|
||||
}
|
||||
|
||||
public static ConfigurationTransformation nineToTen(){
|
||||
return ConfigurationTransformation.builder()
|
||||
.addAction(NodePath.path("faviconStrategy"), TransformAction.rename("faviconResizeStrategy"))
|
||||
.build();
|
||||
}
|
||||
|
||||
public static ConfigurationTransformation eightToNine(){
|
||||
return ConfigurationTransformation.builder()
|
||||
.addAction(NodePath.path(), (path, value) -> {
|
||||
|
||||
@@ -32,6 +32,7 @@ import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
|
||||
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileSerializer;
|
||||
import org.spongepowered.configurate.ConfigurateException;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
import org.spongepowered.configurate.yaml.NodeStyle;
|
||||
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
|
||||
|
||||
@@ -46,6 +47,7 @@ import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class FileHandler{
|
||||
|
||||
@@ -61,18 +63,27 @@ public class FileHandler{
|
||||
|
||||
public FileHandler(AdvancedServerList<?> core){
|
||||
this.plugin = core;
|
||||
this.logger = core.getPlugin().getPluginLogger();
|
||||
this.logger = core.plugin().pluginLogger();
|
||||
|
||||
this.config = core.getPlugin().getFolderPath().resolve("config.yml");
|
||||
this.profilesFolder = core.getPlugin().getFolderPath().resolve("profiles");
|
||||
this.config = core.plugin().folderPath().resolve("config.yml");
|
||||
this.profilesFolder = core.plugin().folderPath().resolve("profiles");
|
||||
}
|
||||
|
||||
public List<ServerListProfile> getProfiles(){
|
||||
public List<ServerListProfile> profiles(){
|
||||
return profiles;
|
||||
}
|
||||
|
||||
public ServerListProfile profile(String file){
|
||||
for(ServerListProfile profile : profiles){
|
||||
if(profile.file().equalsIgnoreCase(file))
|
||||
return profile;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean loadConfig(){
|
||||
File folder = plugin.getPlugin().getFolderPath().toFile();
|
||||
File folder = plugin.plugin().folderPath().toFile();
|
||||
if(!folder.exists() && !folder.mkdirs()){
|
||||
logger.warn("Couldn't create folder for plugin. Is it missing Write permissions?");
|
||||
return false;
|
||||
@@ -106,6 +117,48 @@ public class FileHandler{
|
||||
}
|
||||
}
|
||||
|
||||
public boolean saveProfile(String file, int priority, String condition, List<ProfileEntry> profiles, ProfileEntry defaultProfile){
|
||||
String filename = file.toLowerCase(Locale.ROOT);
|
||||
Path filePath = profilesFolder.resolve(filename.endsWith(".yml") ? filename : filename + ".yml");
|
||||
if(!Files.exists(filePath)){
|
||||
logger.warn("Cannot find profile with file name '<white>%s</white>'", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
YamlConfigurationLoader loader = YamlConfigurationLoader.builder()
|
||||
.defaultOptions(opts -> opts.serializers(build -> build.register(ProfileEntry.class, ProfileSerializer.INSTANCE)))
|
||||
.path(filePath)
|
||||
.nodeStyle(NodeStyle.BLOCK)
|
||||
.build();
|
||||
|
||||
ConfigurationNode node;
|
||||
try{
|
||||
node = loader.load();
|
||||
}catch(IOException ex){
|
||||
logger.warn("Encountered an IOException while loading file '<white>%s</white>'", ex, filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(node == null)
|
||||
return false;
|
||||
|
||||
try{
|
||||
node.node("priority").set(priority);
|
||||
node.node("condition").set(condition);
|
||||
node.node("profiles").setList(ProfileEntry.class, profiles);
|
||||
node.set(ProfileEntry.class, defaultProfile);
|
||||
|
||||
loader.save(node);
|
||||
return true;
|
||||
}catch(SerializationException ex){
|
||||
logger.warn("Encountered a SerializationException while saving file '<white>%s</white>'", ex, filename);
|
||||
return false;
|
||||
}catch(IOException ex){
|
||||
logger.warn("Encountered an IOException while saving file '<white>%s</white>'", ex, filename);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean createFile(String name){
|
||||
if(Files.notExists(profilesFolder) && profilesFolder.toFile().mkdirs()){
|
||||
logger.debugSuccess(FileHandler.class, "Successfully created profiles folder.");
|
||||
@@ -219,7 +272,7 @@ public class FileHandler{
|
||||
private boolean makeBackup(){
|
||||
logger.info("[-] Making backup of old config.yml...");
|
||||
|
||||
File backups = plugin.getPlugin().getFolderPath().resolve("backups").toFile();
|
||||
File backups = plugin.plugin().folderPath().resolve("backups").toFile();
|
||||
if(!backups.exists() && !backups.mkdirs()){
|
||||
logger.failure("Cannot create backups folder for migration!");
|
||||
return false;
|
||||
|
||||
+18
-9
@@ -26,8 +26,11 @@
|
||||
package ch.andre601.advancedserverlist.core.interfaces.core;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.dialogs.IDialog;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.dialogs.IDialogList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
|
||||
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
|
||||
import ch.andre601.advancedserverlist.core.profiles.handlers.FaviconHandler;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
|
||||
@@ -48,28 +51,34 @@ public interface PluginCore<F>{
|
||||
|
||||
void startScheduler();
|
||||
|
||||
AdvancedServerList<F> getCore();
|
||||
AdvancedServerList<F> core();
|
||||
|
||||
Path getFolderPath();
|
||||
Path folderPath();
|
||||
|
||||
PluginLogger getPluginLogger();
|
||||
PluginLogger pluginLogger();
|
||||
|
||||
FaviconHandler<F> getFaviconHandler();
|
||||
FaviconHandler<F> faviconHandler();
|
||||
|
||||
CommandManager<CmdSender> getCommandManager();
|
||||
CommandManager<CmdSender> commandManager();
|
||||
|
||||
String getPlatformInfo();
|
||||
String platformInfo();
|
||||
|
||||
String getLoader();
|
||||
String loader();
|
||||
|
||||
boolean isPluginEnabled(String plugin);
|
||||
|
||||
boolean isDialogsSupported();
|
||||
|
||||
F createFavicon(BufferedImage image) throws Exception;
|
||||
|
||||
IDialogList.IDialogListBuilder createDialogListBuilder(String title);
|
||||
|
||||
IDialog.IDialogBuilder createDialogBuilder(String title, ServerListProfile profile, int profilesPosition);
|
||||
|
||||
default boolean isDebugEnabled(){
|
||||
if(getCore() == null)
|
||||
if(core() == null)
|
||||
return false;
|
||||
|
||||
return getCore().getFileHandler().getBoolean("debug");
|
||||
return core().fileHandler().getBoolean("debug");
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package ch.andre601.advancedserverlist.core.interfaces.dialogs;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.NullBool;
|
||||
import ch.andre601.advancedserverlist.core.commands.CmdProfiles;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IDialog<T>{
|
||||
T createDialog();
|
||||
|
||||
interface IDialogBuilder{
|
||||
IDialogBuilder appendBody(String body);
|
||||
|
||||
IDialogBuilder appendTextInput(CmdProfiles.ProfileOption option, String title, String initValue, int maxLength);
|
||||
|
||||
IDialogBuilder appendTextbox(CmdProfiles.ProfileOption option, String title, List<String> initValue, int maxLength, int rows);
|
||||
|
||||
IDialogBuilder appendNumberRange(CmdProfiles.ProfileOption option, String title, int initValue);
|
||||
|
||||
IDialogBuilder appendBoolean(CmdProfiles.ProfileOption option, String title, NullBool initValue);
|
||||
|
||||
IDialog<?> build();
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package ch.andre601.advancedserverlist.core.interfaces.dialogs;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
|
||||
|
||||
public interface IDialogList{
|
||||
|
||||
void show(CmdSender sender);
|
||||
|
||||
interface IDialogListBuilder{
|
||||
IDialogListBuilder appendBody(String body);
|
||||
|
||||
IDialogListBuilder appendDialog(IDialog<?> dialog);
|
||||
|
||||
IDialogList build();
|
||||
}
|
||||
}
|
||||
+15
-15
@@ -40,23 +40,23 @@ public interface GenericEventWrapper<F, P extends GenericPlayer>{
|
||||
|
||||
GenericServerListEvent callEvent(ProfileEntry entry);
|
||||
|
||||
void setMaxPlayers(int maxPlayers);
|
||||
void maxPlayers(int maxPlayers);
|
||||
|
||||
void setOnlinePlayers(int onlinePlayers);
|
||||
void onlinePlayers(int onlinePlayers);
|
||||
|
||||
void setMotd(Component component);
|
||||
void motd(Component component);
|
||||
|
||||
void hidePlayers();
|
||||
|
||||
void setPlayerCount(String name);
|
||||
void playerCount(String name);
|
||||
|
||||
void setPlayers(List<String> players, P player, GenericServer server);
|
||||
void players(List<String> players, P player, GenericServer server);
|
||||
|
||||
void setPlayersHidden();
|
||||
void playersHidden();
|
||||
|
||||
void setFavicon(F favicon);
|
||||
void favicon(F favicon);
|
||||
|
||||
void setDefaultFavicon();
|
||||
void defaultFavicon();
|
||||
|
||||
void updateEvent();
|
||||
|
||||
@@ -64,23 +64,23 @@ public interface GenericEventWrapper<F, P extends GenericPlayer>{
|
||||
|
||||
boolean isMaintenanceModeActive();
|
||||
|
||||
int getProtocolVersion();
|
||||
int protocolVersion();
|
||||
|
||||
int getOnlinePlayers();
|
||||
int onlinePlayers();
|
||||
|
||||
int getMaxPlayers();
|
||||
int maxPlayers();
|
||||
|
||||
String getPlayerIP();
|
||||
String playerIP();
|
||||
|
||||
String parsePAPIPlaceholders(String text, P player);
|
||||
|
||||
String getVirtualHost();
|
||||
String virtualHost();
|
||||
|
||||
PluginCore<F> getPlugin();
|
||||
PluginCore<F> plugin();
|
||||
|
||||
P createPlayer(CachedPlayer player, int protocol);
|
||||
|
||||
GenericServer createGenericServer(int playersOnline, int playersMax, String host);
|
||||
GenericServer createServer(int playersOnline, int playersMax, String host);
|
||||
|
||||
default String resolveHost(InetSocketAddress address){
|
||||
return address == null ? null : address.getHostString();
|
||||
|
||||
+9
-7
@@ -49,12 +49,14 @@ 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");
|
||||
sender.sendMsg("Loading Configurate-Hocon library. This may take a while...");
|
||||
core.plugin().downloadLibrary("org.spongepowered", "configurate-hocon", "4.1.2");
|
||||
sender.sendMsg("<green>Library loaded!");
|
||||
|
||||
PluginLogger logger = core.getPlugin().getPluginLogger();
|
||||
String folder = core.getPlugin().getLoader().equals("velocity") ? "minimotd-velocity" : "MiniMOTD";
|
||||
PluginLogger logger = core.plugin().pluginLogger();
|
||||
String folder = core.plugin().loader().equals("velocity") ? "minimotd-velocity" : "MiniMOTD";
|
||||
|
||||
Path mainConf = core.getPlugin().getFolderPath().getParent().resolve(folder).resolve("main.conf");
|
||||
Path mainConf = core.plugin().folderPath().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.");
|
||||
@@ -98,7 +100,7 @@ public class MiniMOTDConfigMigrator{
|
||||
|
||||
if(config.motdEnabled()){
|
||||
if(config.motds().size() == 1){
|
||||
applyMotd(profileBuilder, config.motds().get(0));
|
||||
applyMotd(profileBuilder, config.motds().getFirst());
|
||||
}else
|
||||
if(config.motds().size() > 1){
|
||||
for(int i = 0; i < config.motds().size(); i++){
|
||||
@@ -109,7 +111,7 @@ public class MiniMOTDConfigMigrator{
|
||||
|
||||
if(config.iconEnabled()){
|
||||
if(config.motds().size() == 1){
|
||||
MiniMOTDConfig.Motd motd = config.motds().get(0);
|
||||
MiniMOTDConfig.Motd motd = config.motds().getFirst();
|
||||
if(!motd.icon().isEmpty()){
|
||||
profileBuilder.favicon(motd.icon());
|
||||
}
|
||||
@@ -152,7 +154,7 @@ public class MiniMOTDConfigMigrator{
|
||||
return false;
|
||||
}
|
||||
|
||||
Path profile = core.getPlugin().getFolderPath().resolve("profiles").resolve("minimotd_migrated.yml");
|
||||
Path profile = core.plugin().folderPath().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.");
|
||||
|
||||
+4
-4
@@ -99,7 +99,7 @@ public class SLPConfigMigrator{
|
||||
|
||||
public static int migrate(AdvancedServerList<?> core, CmdSender sender){
|
||||
ServerListPlusCore slpCore = ServerListPlusCore.getInstance();
|
||||
PluginLogger logger = core.getPlugin().getPluginLogger();
|
||||
PluginLogger logger = core.plugin().pluginLogger();
|
||||
if(slpCore == null){
|
||||
logger.warn("[<white>Migrator - ServerListPlus</white>] Cannot migrate ServerListPlus config. ServerListPlus is not active!");
|
||||
return 0;
|
||||
@@ -128,7 +128,7 @@ public class SLPConfigMigrator{
|
||||
}
|
||||
|
||||
private static int parseConf(AdvancedServerList<?> core, CmdSender sender, PersonalizedStatusConf.StatusConf conf, Type type){
|
||||
PluginLogger logger = core.getPlugin().getPluginLogger();
|
||||
PluginLogger logger = core.plugin().pluginLogger();
|
||||
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...");
|
||||
@@ -176,7 +176,7 @@ public class SLPConfigMigrator{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Path profile = core.getPlugin().getFolderPath().resolve("profiles").resolve(type.getFile());
|
||||
Path profile = core.plugin().folderPath().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());
|
||||
@@ -223,7 +223,7 @@ public class SLPConfigMigrator{
|
||||
|
||||
if(type == Type.PERSONALIZED){
|
||||
node.node("condition")
|
||||
.set("${player name} != \"" + core.getFileHandler().getString("Anonymous", "unknownPlayer", "name") + "\"");
|
||||
.set("${player name} != \"" + core.fileHandler().getString("Anonymous", "unknownPlayer", "name") + "\"");
|
||||
}else
|
||||
if(type == Type.BANNED){
|
||||
node.node("condition")
|
||||
|
||||
@@ -25,8 +25,11 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.core.parsing;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.compat.miniplaceholders.MiniPlaceholdersUtil;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
|
||||
import java.util.function.Function;
|
||||
@@ -61,6 +64,17 @@ public class ComponentParser{
|
||||
return this;
|
||||
}
|
||||
|
||||
public ComponentParser applyMMTags(PluginCore<?> plugin){
|
||||
if(!plugin.isPluginEnabled("MiniPlaceholders"))
|
||||
return this;
|
||||
|
||||
TagResolver resolver = MiniPlaceholdersUtil.tagResolvers();
|
||||
Component component = mm.deserialize(this.text, resolver);
|
||||
|
||||
this.text = mm.serialize(component);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Component toComponent(){
|
||||
return mm.deserialize(text);
|
||||
}
|
||||
|
||||
@@ -77,8 +77,8 @@ public class TextCenterUtil{
|
||||
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.");
|
||||
plugin.plugin().pluginLogger().warn("Internal char-widths.json.gz couldn't be retrieved.");
|
||||
plugin.plugin().pluginLogger().warn("The <center> Placeholder won't work.");
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
@@ -87,9 +87,9 @@ public class TextCenterUtil{
|
||||
|
||||
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());
|
||||
plugin.plugin().pluginLogger().warn("Encountered IOException while loading font widths.");
|
||||
plugin.plugin().pluginLogger().warn("The <center> Placeholder won't work.");
|
||||
plugin.plugin().pluginLogger().warn("Cause: <white>%s</white>", ex.getMessage());
|
||||
return new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
package ch.andre601.advancedserverlist.core.placeholders;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class DatePlaceholder extends PlaceholderProvider{
|
||||
|
||||
public DatePlaceholder(){
|
||||
super("date");
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String parsePlaceholder(@NonNull String placeholder, @NonNull GenericPlayer player, @NonNull GenericServer server){
|
||||
String[] args = placeholder.split("\\s+");
|
||||
|
||||
return switch(args[0]){
|
||||
case "current" -> {
|
||||
String format = "dd/MM/yyyy";
|
||||
if(args.length > 1){
|
||||
format = format(Arrays.copyOfRange(args, 1, args.length));
|
||||
}
|
||||
|
||||
try{
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat(format);
|
||||
yield dateFormat.format(new Date());
|
||||
}catch(IllegalArgumentException ex){
|
||||
yield "ERR: Invalid Date pattern " + format;
|
||||
}
|
||||
}
|
||||
case "isBefore" -> compareDates(args, integer -> integer < 0);
|
||||
case "isExactly" -> compareDates(args, integer -> integer == 0);
|
||||
case "isAfter" -> compareDates(args, integer -> integer > 0);
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
private String format(String... args){
|
||||
if(args.length == 0)
|
||||
return "dd/MM/yyyy";
|
||||
|
||||
String format = String.join(" ", args);
|
||||
if(format.trim().isEmpty()){
|
||||
return "dd/MM/yyyy";
|
||||
}else{
|
||||
return format.trim();
|
||||
}
|
||||
}
|
||||
|
||||
private String compareDates(String[] args, Function<Integer, Boolean> function){
|
||||
if(args.length == 1)
|
||||
return "ERR: No Date provided!";
|
||||
|
||||
String targetDateStr = args[1];
|
||||
String format = "dd/MM/yyyy";
|
||||
if(args.length > 2){
|
||||
format = format(Arrays.copyOfRange(args, 2, args.length));
|
||||
}
|
||||
|
||||
SimpleDateFormat dateFormat;
|
||||
try{
|
||||
dateFormat = new SimpleDateFormat(format);
|
||||
Date targetDate = dateFormat.parse(targetDateStr);
|
||||
int diff = new Date().compareTo(targetDate);
|
||||
|
||||
return String.valueOf(function.apply(diff));
|
||||
}catch(IllegalArgumentException ex){
|
||||
return "ERR: Invalid Date format provided!";
|
||||
}catch(ParseException ex){
|
||||
return "ERR: Received invalid Date " + targetDateStr;
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
-3
@@ -46,9 +46,18 @@ public record ServerListProfile(int priority, String condition, ProfileEntry def
|
||||
return true;
|
||||
|
||||
ParseWarnCollector collector = new ParseWarnCollector(condition);
|
||||
PluginLogger logger = core.getPlugin().getPluginLogger();
|
||||
PluginLogger logger = core.plugin().pluginLogger();
|
||||
|
||||
boolean result = core.getParser().evaluate(condition, player, server, collector);
|
||||
boolean result;
|
||||
try{
|
||||
result = core.parser().compileToBoolean(condition, collector, player, server);
|
||||
}catch(Exception ex){
|
||||
logger.warn("Encountered an Exception while parsing condition '%s'. Cause: %s", condition, ex.getMessage());
|
||||
if(core.fileHandler().getBool(false, "debug"))
|
||||
logger.warn("Stacktrace:", ex);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if(collector.hasWarnings()){
|
||||
logger.warn("Encountered <white>%d</white> Error(s) while parsing condition for file '<white>%s</white>':", collector.getWarnings().size(), file);
|
||||
@@ -70,7 +79,7 @@ public record ServerListProfile(int priority, String condition, ProfileEntry def
|
||||
}
|
||||
|
||||
if(profiles.size() == 1)
|
||||
return profiles.get(0); // No need to run a random for 1 profile.
|
||||
return profiles.getFirst(); // No need to run a random for 1 profile.
|
||||
|
||||
synchronized(random){
|
||||
return profiles.get(random.nextInt(profiles.size()));
|
||||
|
||||
-82
@@ -1,82 +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.core.profiles.conditions;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.reader.PlaceholderTokenReader;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.reader.PlaceholderValueReader;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens.CustomExpressionTokenizer;
|
||||
import ch.andre601.expressionparser.ExpressionParserEngine;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
import ch.andre601.expressionparser.operator.Operator;
|
||||
import ch.andre601.expressionparser.parsers.ExpressionTemplateParser;
|
||||
import ch.andre601.expressionparser.parsers.ValueReader;
|
||||
import ch.andre601.expressionparser.templates.ExpressionTemplate;
|
||||
import ch.andre601.expressionparser.tokens.Token;
|
||||
import ch.andre601.expressionparser.tokens.readers.TokenReader;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ProfileConditionParser implements ExpressionParserEngine{
|
||||
|
||||
private final CustomExpressionTokenizer tokenizer;
|
||||
private final ExpressionTemplateParser parser;
|
||||
|
||||
private ProfileConditionParser(List<TokenReader> tokenReaders, ImmutableMap<Token, Operator> operators, ImmutableList<ValueReader> valueReaders){
|
||||
this.tokenizer = new CustomExpressionTokenizer(tokenReaders);
|
||||
this.parser = new ExpressionTemplateParser(operators, valueReaders);
|
||||
}
|
||||
|
||||
public static ProfileConditionParser create(){
|
||||
return new ProfileConditionParserBuilder().addDefaults()
|
||||
.addTokenReader(new PlaceholderTokenReader(-20))
|
||||
.addValueReader(new PlaceholderValueReader())
|
||||
.build();
|
||||
}
|
||||
|
||||
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
|
||||
public ExpressionTemplate compile(String s, ParseWarnCollector parseWarnCollector){
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class ProfileConditionParserBuilder extends ExpressionParserEngine.Builder<ProfileConditionParser>{
|
||||
@Override
|
||||
public ProfileConditionParser build(){
|
||||
return new ProfileConditionParser(this.getTokenReaders(), ImmutableMap.copyOf(this.getOperators()), ImmutableList.copyOf(this.getValueReaders()));
|
||||
}
|
||||
}
|
||||
}
|
||||
-48
@@ -1,48 +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.core.profiles.conditions.placeholders.reader;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
import ch.andre601.expressionparser.tokens.Token;
|
||||
import ch.andre601.expressionparser.tokens.readers.TokenReader;
|
||||
|
||||
import java.text.ParsePosition;
|
||||
|
||||
public abstract class CustomTokenReader extends TokenReader{
|
||||
|
||||
public CustomTokenReader(int priority){
|
||||
super(priority);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Token read(String text, ParsePosition position, ParseWarnCollector collector){
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract Token read(String text, ParsePosition position, GenericPlayer player, GenericServer server, ParseWarnCollector collector);
|
||||
}
|
||||
-92
@@ -1,92 +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.core.profiles.conditions.placeholders.tokens;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.reader.CustomTokenReader;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
import ch.andre601.expressionparser.tokens.Token;
|
||||
import ch.andre601.expressionparser.tokens.readers.TokenReader;
|
||||
import com.google.common.collect.Ordering;
|
||||
|
||||
import java.text.ParsePosition;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class CustomExpressionTokenizer{
|
||||
|
||||
private static final Ordering<TokenReader> TOKEN_READER_ORDERING = Ordering.from(Comparator.comparingInt(TokenReader::getPriority)).reverse();
|
||||
|
||||
private final List<TokenReader> tokenReaders;
|
||||
|
||||
public CustomExpressionTokenizer(Iterable<TokenReader> tokenReaders){
|
||||
this.tokenReaders = TOKEN_READER_ORDERING.immutableSortedCopy(tokenReaders);
|
||||
}
|
||||
|
||||
public List<Token> parse(String text, GenericPlayer player, GenericServer server, ParseWarnCollector collector){
|
||||
ParsePosition position = new ParsePosition(0);
|
||||
|
||||
List<Token> tokens = new LinkedList<>();
|
||||
|
||||
next_token:
|
||||
while(true){
|
||||
while(position.getIndex() < text.length() && Character.isWhitespace(text.charAt(position.getIndex())))
|
||||
position.setIndex(position.getIndex() + 1);
|
||||
|
||||
if(position.getIndex() >= text.length())
|
||||
break;
|
||||
|
||||
for(TokenReader tokenReader : tokenReaders){
|
||||
Token token;
|
||||
if(tokenReader instanceof CustomTokenReader customTokenReader){
|
||||
if(null != (token = customTokenReader.read(text, position, player, server, collector))){
|
||||
tokens.add(token);
|
||||
continue next_token;
|
||||
}
|
||||
}else{
|
||||
if(null != (token = tokenReader.read(text, position, collector))){
|
||||
tokens.add(token);
|
||||
continue next_token;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
}
|
||||
+25
-6
@@ -23,27 +23,46 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.reader;
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions.reader;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens.PlaceholderToken;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.tokens.PlaceholderToken;
|
||||
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
import ch.andre601.expressionparser.tokens.Token;
|
||||
import ch.andre601.expressionparser.tokens.readers.TokenReader;
|
||||
|
||||
import java.text.ParsePosition;
|
||||
|
||||
public class PlaceholderTokenReader extends CustomTokenReader{
|
||||
public class PlaceholderTokenReader extends TokenReader{
|
||||
|
||||
public PlaceholderTokenReader(int priority){
|
||||
super(priority);
|
||||
public PlaceholderTokenReader(){
|
||||
super(-20);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Token read(String text, ParsePosition position, GenericPlayer player, GenericServer server, ParseWarnCollector collector){
|
||||
public Token read(String text, ParsePosition position, ParseWarnCollector collector, Object... args){
|
||||
GenericPlayer player = null;
|
||||
GenericServer server = null;
|
||||
|
||||
for(Object arg : args){
|
||||
if(arg instanceof GenericPlayer pl){
|
||||
player = pl;
|
||||
}else
|
||||
if(arg instanceof GenericServer srv){
|
||||
server = srv;
|
||||
}
|
||||
}
|
||||
|
||||
if(player == null || server == null){
|
||||
collector.appendWarning(position.getIndex(), "Received null GenericPlayer or GenericServer instance.");
|
||||
return null;
|
||||
}
|
||||
|
||||
if(position.getIndex() + 1 < text.length() && text.charAt(position.getIndex()) == '$' && text.charAt(position.getIndex() + 1) == '{'){
|
||||
position.setIndex(position.getIndex() + 2);
|
||||
|
||||
return new PlaceholderToken(StringReplacer.parsePlaceholder(text, position, player, server, collector));
|
||||
}
|
||||
return null;
|
||||
+4
-4
@@ -23,9 +23,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.reader;
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions.reader;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens.PlaceholderToken;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.tokens.PlaceholderToken;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
import ch.andre601.expressionparser.parsers.ExpressionTemplateParser;
|
||||
import ch.andre601.expressionparser.parsers.ValueReader;
|
||||
@@ -37,8 +37,8 @@ import java.util.List;
|
||||
public class PlaceholderValueReader extends ValueReader{
|
||||
@Override
|
||||
public ExpressionTemplate read(ExpressionTemplateParser parser, List<Token> tokens, ParseWarnCollector collector){
|
||||
if(tokens.get(0) instanceof PlaceholderToken){
|
||||
PlaceholderToken token = (PlaceholderToken)tokens.remove(0);
|
||||
if(tokens.getFirst() instanceof PlaceholderToken){
|
||||
PlaceholderToken token = (PlaceholderToken)tokens.removeFirst();
|
||||
return token.getValue();
|
||||
}
|
||||
return null;
|
||||
+1
-1
@@ -23,7 +23,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens;
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions.tokens;
|
||||
|
||||
import ch.andre601.expressionparser.expressions.ToBooleanExpression;
|
||||
import ch.andre601.expressionparser.expressions.ToDoubleExpression;
|
||||
+49
-16
@@ -38,10 +38,10 @@ public class FaviconHandler<F>{
|
||||
|
||||
public FaviconHandler(AdvancedServerList<F> core){
|
||||
this.core = core;
|
||||
this.logger = core.getPlugin().getPluginLogger();
|
||||
this.logger = core.plugin().pluginLogger();
|
||||
this.faviconThreadPool = createThreadPool();
|
||||
this.faviconCache = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(core.getFileHandler().getLong(1, 1, "faviconCacheTime"), TimeUnit.MINUTES)
|
||||
.expireAfterWrite(core.fileHandler().getLong(1, 1, "faviconCacheTime"), TimeUnit.MINUTES)
|
||||
.build();
|
||||
|
||||
loadLocalFavicons();
|
||||
@@ -110,6 +110,7 @@ public class FaviconHandler<F>{
|
||||
|
||||
public void cleanCache(){
|
||||
localFavicons.clear();
|
||||
faviconCache.invalidateAll();
|
||||
loadLocalFavicons();
|
||||
}
|
||||
|
||||
@@ -118,7 +119,7 @@ public class FaviconHandler<F>{
|
||||
BufferedImage image = new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D graphics = image.createGraphics();
|
||||
|
||||
String strategy = core.getFileHandler().getString("resize", "faviconStrategy");
|
||||
String strategy = core.fileHandler().getString("resize", "faviconStrategy");
|
||||
int layer = 0;
|
||||
for(BufferedImage img : images){
|
||||
layer++;
|
||||
@@ -172,7 +173,8 @@ public class FaviconHandler<F>{
|
||||
}else
|
||||
if(input.toLowerCase(Locale.ROOT).endsWith(".png")){
|
||||
logger.debug(FaviconHandler.class, "Returning local Favicon '%s'...", input);
|
||||
return localFavicons.get(input.toLowerCase(Locale.ROOT)).image();
|
||||
FaviconPair<F> pair = localFavicons.get(input.toLowerCase(Locale.ROOT));
|
||||
return pair == null ? null : pair.image();
|
||||
}else{
|
||||
logger.debug(FaviconHandler.class, "Handling Player Name/UUID '%s'...", input);
|
||||
return fromURL("https://mc-heads.net/avatar/" + input + "/64");
|
||||
@@ -200,7 +202,7 @@ public class FaviconHandler<F>{
|
||||
|
||||
logger.info("[-] Loading local images as Favicons...");
|
||||
|
||||
Path folder = core.getPlugin().getFolderPath().resolve("favicons");
|
||||
Path folder = core.plugin().folderPath().resolve("favicons");
|
||||
if(!Files.exists(folder)){
|
||||
try{
|
||||
Files.createDirectories(folder);
|
||||
@@ -218,7 +220,11 @@ public class FaviconHandler<F>{
|
||||
|
||||
logger.success("Loaded <white>%s</white> local Favicon(s).", localFavicons.size());
|
||||
}catch(IOException ex){
|
||||
logger.warn("Encountered IOException while loading local favicons.", ex);
|
||||
if(core.fileHandler().getBool(false, "debug")){
|
||||
logger.warn("Encountered IOException while loading local favicons.", ex);
|
||||
}else{
|
||||
logger.warn("Encountered IOException while loading local favicons. Reason: %s", ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,15 +234,23 @@ public class FaviconHandler<F>{
|
||||
if(image == null)
|
||||
return;
|
||||
|
||||
F favicon = core.getPlugin().createFavicon(image);
|
||||
F favicon = core.plugin().createFavicon(image);
|
||||
if(favicon == null)
|
||||
return;
|
||||
|
||||
localFavicons.put(path.getFileName().toString().toLowerCase(Locale.ROOT), new FaviconPair<>(image, favicon));
|
||||
}catch(IOException ex){
|
||||
logger.warn("Encountered IOException while creating a Favicon from '%s'.", ex, path.getFileName().toString());
|
||||
if(core.fileHandler().getBool(false, "debug")){
|
||||
logger.warn("Encountered IOException while creating a Favicon from '%s'.", ex, path.getFileName().toString());
|
||||
}else{
|
||||
logger.warn("Encountered IOException while creating a Favicon from '%s'. Reason: %s", path.getFileName().toString(), ex.getMessage());
|
||||
}
|
||||
}catch(Exception ex){
|
||||
logger.warn("Encountered an Exceotion while creating a Favicon from '%s'.", ex, path.getFileName().toString());
|
||||
if(core.fileHandler().getBool(false, "debug")){
|
||||
logger.warn("Encountered Exception while creating a Favicon from '%s'.", ex, path.getFileName().toString());
|
||||
}else{
|
||||
logger.warn("Encountered Exception while creating a Favicon from '%s'. Reason: %s", path.getFileName().toString(), ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,20 +259,35 @@ public class FaviconHandler<F>{
|
||||
logger.debug(FaviconHandler.class, "Creating request for URL '%s'...", url);
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(new URI(url))
|
||||
.header("User-Agent", "AdvancedServerList-" + core.getPlugin().getLoader() + "/" + core.getVersion())
|
||||
.header("User-Agent", "AdvancedServerList-" + core.plugin().loader() + "/" + core.version())
|
||||
.build();
|
||||
|
||||
try(InputStream stream = client.send(request, HttpResponse.BodyHandlers.ofInputStream()).body()){
|
||||
return createBufferedImage(stream);
|
||||
}catch(IOException ex){
|
||||
logger.warn("Encountered IOException while performing a web request for '%s'.", ex, url);
|
||||
if(core.fileHandler().getBool(false, "debug")){
|
||||
logger.warn("Encountered IOException while performing a web request for '%s'.", ex, url);
|
||||
}else{
|
||||
logger.warn("Encountered IOException while performing a web request for '%'. Reason: %s", url, ex.getMessage());
|
||||
}
|
||||
|
||||
return null;
|
||||
}catch(InterruptedException ex){
|
||||
logger.warn("Encountered an InterruptedException while performing a web request for '%s'.", ex, url);
|
||||
if(core.fileHandler().getBool(false, "debug")){
|
||||
logger.warn("Encountered an InterruptedException while performing a web request for '%s'.", ex, url);
|
||||
}else{
|
||||
logger.warn("Encountered an InterruptedException while performing a web request for '%s'. Reason: %s", url, ex.getMessage());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}catch(URISyntaxException ex){
|
||||
logger.warn("Received URISyntaxException for URL '%s'", ex, url);
|
||||
if(core.fileHandler().getBool(false, "debug")){
|
||||
logger.warn("Encountered an URISyntaxException while performing a web request for '%s'.", ex, url);
|
||||
}else{
|
||||
logger.warn("Encountered an URISyntaxException while performing a web request for '%s'. Reason: %s", url, ex.getMessage());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -282,7 +311,7 @@ public class FaviconHandler<F>{
|
||||
BufferedImage image = new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D graphics = image.createGraphics();
|
||||
|
||||
String resizeMode = core.getFileHandler().getString("resize", "faviconStrategy");
|
||||
String resizeMode = core.fileHandler().getString("resize", "faviconStrategy");
|
||||
switch(resizeMode.toLowerCase(Locale.ROOT)){
|
||||
case "center" -> {
|
||||
int height = original.getHeight();
|
||||
@@ -316,9 +345,13 @@ public class FaviconHandler<F>{
|
||||
|
||||
private F createFavicon(BufferedImage image){
|
||||
try{
|
||||
return core.getPlugin().createFavicon(image);
|
||||
return core.plugin().createFavicon(image);
|
||||
}catch(Exception ex){
|
||||
logger.warn("Encountered an Exception while trying to create a Favicon instance.", ex);
|
||||
if(core.fileHandler().getBool(false, "debug")){
|
||||
logger.warn("Encountered an Exception while trying to create a Favicon instance.", ex);
|
||||
}else{
|
||||
logger.warn("Encountered an Exception while trying to create a Favicon instance. Reason: %s", ex.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+8
-8
@@ -61,8 +61,8 @@ public class PlayerHandler{
|
||||
|
||||
public PlayerHandler(AdvancedServerList<?> core){
|
||||
this.core = core;
|
||||
this.logger = core.getPlugin().getPluginLogger();
|
||||
this.cache = core.getPlugin().getFolderPath().resolve("playercache.json");
|
||||
this.logger = core.plugin().pluginLogger();
|
||||
this.cache = core.plugin().folderPath().resolve("playercache.json");
|
||||
}
|
||||
|
||||
public void load(){
|
||||
@@ -71,7 +71,7 @@ public class PlayerHandler{
|
||||
return;
|
||||
}
|
||||
|
||||
if(core.getFileHandler().getBoolean("disableCache")){
|
||||
if(core.fileHandler().getBoolean("disableCache")){
|
||||
logger.info("'disableCache' is set to true. Skipping playercache.json loading...");
|
||||
return;
|
||||
}
|
||||
@@ -103,7 +103,7 @@ public class PlayerHandler{
|
||||
return;
|
||||
}
|
||||
|
||||
if(core.getFileHandler().getBoolean("disableCache")){
|
||||
if(core.fileHandler().getBoolean("disableCache")){
|
||||
logger.debug(PlayerHandler.class, "[-] 'disable_cache' is set to true. Not saving cached players.");
|
||||
return;
|
||||
}
|
||||
@@ -117,14 +117,14 @@ public class PlayerHandler{
|
||||
}
|
||||
|
||||
public void addPlayer(String ip, String name, UUID uuid){
|
||||
if(contains(ip) || core.getFileHandler().getBoolean("disableCache"))
|
||||
if(contains(ip) || core.fileHandler().getBoolean("disableCache"))
|
||||
return;
|
||||
|
||||
cachedPlayers.add(new CachedPlayer(ip, name, uuid));
|
||||
}
|
||||
|
||||
public CachedPlayer getCachedPlayer(String key){
|
||||
if(!contains(key) || core.getFileHandler().getBoolean("disableCache"))
|
||||
if(!contains(key) || core.fileHandler().getBoolean("disableCache"))
|
||||
return getDefaultPlayer();
|
||||
|
||||
for(CachedPlayer player : cachedPlayers){
|
||||
@@ -164,8 +164,8 @@ public class PlayerHandler{
|
||||
|
||||
return (defaultPlayer = new CachedPlayer(
|
||||
"0.0.0.0",
|
||||
core.getFileHandler().getString("Anonymous", "unknownPlayer", "name"),
|
||||
convertToUUID(core.getFileHandler().getString(defaultUUID.toString(), "unknownPlayer", "uuid"))
|
||||
core.fileHandler().getString("Anonymous", "unknownPlayer", "name"),
|
||||
convertToUUID(core.fileHandler().getString(defaultUUID.toString(), "unknownPlayer", "uuid"))
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -78,7 +78,7 @@ public class ProfileManager{
|
||||
}
|
||||
|
||||
public static ServerListProfile resolveProfile(AdvancedServerList<?> core, GenericPlayer player, GenericServer server){
|
||||
for(ServerListProfile profile : core.getFileHandler().getProfiles()){
|
||||
for(ServerListProfile profile : core.fileHandler().profiles()){
|
||||
if(profile.isInvalidProfile())
|
||||
continue;
|
||||
|
||||
|
||||
+2
-2
@@ -30,7 +30,7 @@ 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;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens.PlaceholderToken;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.tokens.PlaceholderToken;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
|
||||
import java.text.ParsePosition;
|
||||
@@ -68,7 +68,7 @@ public class StringReplacer{
|
||||
}
|
||||
|
||||
private static String parsePlaceholder0(String input, ParsePosition position, GenericPlayer player, GenericServer server, ParseWarnCollector collector){
|
||||
AdvancedServerListAPI api = AdvancedServerList.getApi();
|
||||
AdvancedServerListAPI api = AdvancedServerList.api();
|
||||
int index = position.getIndex();
|
||||
|
||||
StringBuilder identifier = new StringBuilder();
|
||||
|
||||
@@ -77,7 +77,7 @@ faviconCacheTime: 1
|
||||
#
|
||||
# Setting any not listed option or leaving this blank/removing it sets the option to resize.
|
||||
#
|
||||
faviconStrategy: 'resize'
|
||||
faviconResizeStrategy: 'resize'
|
||||
|
||||
#
|
||||
# Options to disable while the Maintenance Plugin is present and Maintenance Mode is active.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Set the priority of this profile.
|
||||
# If there are multiple profiles (files) will they be sorted by priority, starting with highest.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#priority
|
||||
# Read more: https://asl.andre601.ch/profiles/options/priority/
|
||||
#
|
||||
priority: 0
|
||||
|
||||
@@ -14,7 +14,7 @@ priority: 0
|
||||
#
|
||||
# Removing the condition option or setting it to an empty String will be treated as a true condition being returned.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#condition
|
||||
# Read more: https://asl.andre601.ch/profiles/options/condition
|
||||
#
|
||||
condition: ''
|
||||
|
||||
@@ -30,7 +30,7 @@ condition: ''
|
||||
#
|
||||
# When not present or empty (profiles: []), no profiles will be used and global options from the file will be used instead.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#profiles
|
||||
# Read more: https://asl.andre601.ch/profiles/options/profiles
|
||||
#
|
||||
profiles:
|
||||
- motd: ['<aqua>Line A', '<gold>Line B']
|
||||
@@ -50,7 +50,7 @@ profiles:
|
||||
#
|
||||
# When not present or empty (motd: []), no MOTD will be set.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#motd
|
||||
# Read more: https://asl.andre601.ch/profiles/options/motd
|
||||
#
|
||||
motd:
|
||||
- '<grey>First Line'
|
||||
@@ -71,7 +71,7 @@ motd:
|
||||
#
|
||||
# If not present or empty (favicon: ''), defaults to not modifying the favicon.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#favicon
|
||||
# Read more: https://asl.andre601.ch/profiles/options/favicon
|
||||
#
|
||||
# "The favicon isn't showing!"
|
||||
# This is a side effect of using either URLs or player names/UUIDs for the favicon.
|
||||
@@ -87,7 +87,7 @@ favicon: ''
|
||||
#
|
||||
# Contains options for modifying the player count (Text displaying <online>/<max>).
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#playercount
|
||||
# Read more: https://asl.andre601.ch/profiles/options/playercount
|
||||
#
|
||||
playerCount:
|
||||
#
|
||||
@@ -97,7 +97,7 @@ playerCount:
|
||||
#
|
||||
# If not present, defaults to false.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#hideplayers
|
||||
# Read more: https://asl.andre601.ch/profiles/options/playercount/hideplayers
|
||||
#
|
||||
hidePlayers: false
|
||||
#
|
||||
@@ -106,7 +106,7 @@ playerCount:
|
||||
#
|
||||
# If not present, defaults to false.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#hideplayershover
|
||||
# Read more: https://asl.andre601.ch/profiles/options/playercount/hideplayershover
|
||||
#
|
||||
hidePlayersHover: false
|
||||
#
|
||||
@@ -116,7 +116,7 @@ playerCount:
|
||||
#
|
||||
# If not present or empty (hover: []), defaults to not modifying the hover.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#hover
|
||||
# Read more: https://asl.andre601.ch/profiles/options/playercount/hover
|
||||
#
|
||||
hover:
|
||||
- '<aqua>Line 1'
|
||||
@@ -130,7 +130,7 @@ playerCount:
|
||||
#
|
||||
# If not present or empty (text: ''), defaults to not modifying the text.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#text
|
||||
# Read more: https://asl.andre601.ch/profiles/options/playercount/text
|
||||
#
|
||||
text: ''
|
||||
#
|
||||
@@ -139,7 +139,7 @@ playerCount:
|
||||
#
|
||||
# Using this feature will modify the ${server playersMax} placeholder, except for usage in the condition option.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#extraplayers
|
||||
# Read more: https://asl.andre601.ch/profiles/options/playercount/extraplayers
|
||||
#
|
||||
extraPlayers:
|
||||
#
|
||||
@@ -149,7 +149,7 @@ playerCount:
|
||||
#
|
||||
# If not present, defaults to false.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#extraplayers-enabled
|
||||
# Read more: https://asl.andre601.ch/profiles/options/playercount/extraplayers#enabled
|
||||
#
|
||||
enabled: false
|
||||
#
|
||||
@@ -161,7 +161,7 @@ playerCount:
|
||||
#
|
||||
# If not present, defaults to 0.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#extraplayers-amount
|
||||
# Read more: https://asl.andre601.ch/profiles/options/playercount/extraplayers#amount
|
||||
#
|
||||
amount: 0
|
||||
#
|
||||
@@ -169,7 +169,7 @@ playerCount:
|
||||
#
|
||||
# Using this feature will modify the ${server playersMax} placeholder, except for usage in the condition option.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#maxplayers
|
||||
# Read more: https://asl.andre601.ch/profiles/options/playercount/maxplayers
|
||||
#
|
||||
maxPlayers:
|
||||
#
|
||||
@@ -178,7 +178,7 @@ playerCount:
|
||||
#
|
||||
# If not present, defaults to false.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#maxplayers-enabled
|
||||
# Read more: https://asl.andre601.ch/profiles/options/playercount/maxplayers#enabled
|
||||
#
|
||||
enabled: false
|
||||
#
|
||||
@@ -187,13 +187,13 @@ playerCount:
|
||||
#
|
||||
# If not present, defaults to 0.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#maxplayers-amount
|
||||
# Read more: https://asl.andre601.ch/profiles/options/playercount/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
|
||||
# Read more: https://asl.andre601.ch/profiles/options/playercount/onlineplayers
|
||||
#
|
||||
onlinePlayers:
|
||||
#
|
||||
@@ -202,7 +202,7 @@ playerCount:
|
||||
#
|
||||
# If not present, defaults to false.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#onlineplayers-enabled
|
||||
# Read more: https://asl.andre601.ch/profiles/options/playercount/onlineplayers#enabled
|
||||
#
|
||||
enabled: false
|
||||
#
|
||||
@@ -211,6 +211,6 @@ playerCount:
|
||||
#
|
||||
# If not present, defaults to current online player count.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#onlineplayers-amount
|
||||
# Read more: https://asl.andre601.ch/profiles/options/playercount/onlineplayers#amount
|
||||
#
|
||||
amount: 0
|
||||
@@ -25,27 +25,35 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.core;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.ProfileConditionParser;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.expressionparser.DefaultExpressionParserEngine;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class ExpressionParserTests{
|
||||
|
||||
private final ProfileConditionParser parser = ProfileConditionParser.create();
|
||||
private final DefaultExpressionParserEngine parser = DefaultExpressionParserEngine.createDefault();
|
||||
private final DummyPluginLogger logger = new DummyPluginLogger();
|
||||
private final Map<String, Boolean> testValuesMap = getTestMap();
|
||||
|
||||
private final TestPlayer player = new TestPlayer();
|
||||
private final TestServer server = new TestServer();
|
||||
|
||||
@Test
|
||||
public void testBasicExpressionResults(){
|
||||
for(Map.Entry<String, Boolean> values : testValuesMap.entrySet()){
|
||||
logger.info("TEST[expression=\"%s\", expected=%b]", values.getKey(), values.getValue());
|
||||
|
||||
ParseWarnCollector collector = new ParseWarnCollector(values.getKey());
|
||||
boolean result = parser.evaluate(values.getKey(), null, null, collector);
|
||||
boolean result = parser.compileToBoolean(values.getKey(), collector, player, server);
|
||||
|
||||
logger.info("Result (Output, Expected?): %b, %b", result, (result == values.getValue()));
|
||||
assertEquals(result, values.getValue());
|
||||
@@ -66,4 +74,38 @@ public class ExpressionParserTests{
|
||||
"false or 100 < 10", false
|
||||
);
|
||||
}
|
||||
|
||||
private static class TestPlayer implements GenericPlayer{
|
||||
@Override
|
||||
public @NonNull String getName(){
|
||||
return "Lorem";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtocol(){
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull UUID getUUID(){
|
||||
return UUID.randomUUID();
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestServer implements GenericServer{
|
||||
@Override
|
||||
public int getPlayersOnline(){
|
||||
return 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPlayersMax(){
|
||||
return 20;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getHost(){
|
||||
return "play.example.com";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block announce %}
|
||||
<span class="twemoji">{% include ".icons/octicons/paintbrush-24.svg" %}</span>
|
||||
The <a href="/profiles">Profiles page</a> received a huge restructuring!
|
||||
<span data-md-component="download-countdown"></span>
|
||||
{% endblock %}
|
||||
@@ -1,6 +1,6 @@
|
||||
[discord]: https://discord.gg/MyPTjpsgGH
|
||||
|
||||
[placeholderapi]: https://hangar.papermc.io/HelpChat/PlaceholderAPI
|
||||
[placeholderapi]: https://modrinth.com/plugin/PlaceholderAPI
|
||||
[viaversion]: https://hangar.papermc.io/ViaVersion/ViaVersion
|
||||
[papiproxybridge]: https://hangar.papermc.io/William278/PAPIProxyBridge
|
||||
[maintenance]: https://hangar.papermc.io/kennytv/Maintenance
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
---
|
||||
icon: octicons/checklist-24
|
||||
---
|
||||
# LuckPerms Addon
|
||||
|
||||
The LuckPerms addon provides placeholders to return values from LuckPerms for a specific player.
|
||||
This can be a players primary group, whether they have a specific group or whether they have a specific permission.
|
||||
|
||||
/// note
|
||||
The Userdata retrieval is done asynchronously by LuckPerms.
|
||||
However, this addon forces the thread for this to be blocked, which can cause lag, if done on the main thread.
|
||||
|
||||
This was done due to possible downsides and issues with trying to keep it async and block-free.
|
||||
To mitigate possible lag is the retrieved user data cached for 1 minute before being discarded.
|
||||
///
|
||||
|
||||
## Placeholders
|
||||
|
||||
**Supported Platforms:**
|
||||
|
||||
<!-- icon:all -->
|
||||
|
||||
| Placeholder | Description |
|
||||
|-------------------------------------------|-----------------------------------------------------------------------------------------------------------------|
|
||||
| `${luckperms hasGroup <group>}` | Returns whether the player has the specified group or not. |
|
||||
| `${luckperms hasPermission <permission>}` | Returns whether the player has the specified permission.<br/>No permission or one set to `false` returns false. |
|
||||
| `${luckperms primaryGroup}` | Gives the name of the primary group the player has. |
|
||||
|
||||
/// details | Example
|
||||
type: example
|
||||
|
||||
```yaml title="is_admin.yml
|
||||
priority: 1
|
||||
condition: "${luckperms hasGroup admin}"
|
||||
|
||||
motd:
|
||||
- "<yellow>Welcome Admin!"
|
||||
```
|
||||
///
|
||||
@@ -19,6 +19,12 @@ These Addons are made by Andre601 and available together with the plugin downloa
|
||||
|
||||
Addon for different Punishment plugins such as AdvancedBan, that add new placeholders to use in AdvancedServerList.
|
||||
|
||||
- [**LuckPerms**](first-party/luckperms.md)
|
||||
|
||||
----
|
||||
|
||||
Addon for adding LuckPerms-related placeholders to use in conditions.
|
||||
|
||||
</div>
|
||||
|
||||
## Third-party
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
document$.subscribe(async () => {
|
||||
const count = document.querySelector('[data-md-component="download-countdown"]');
|
||||
|
||||
async function applyCount(downloads) {
|
||||
const remaining = 100_000 - downloads;
|
||||
const formatted = new Intl.NumberFormat().format(remaining);
|
||||
|
||||
var link = document.createElement('a');
|
||||
var linkText = document.createTextNode("Soon at 100k downloads...");
|
||||
|
||||
if (remaining <= 0) {
|
||||
count.className = "rainbow";
|
||||
count.innerText = "Thank you for 100 THOUSAND downloads!";
|
||||
return;
|
||||
} else if (remaining == 1) {
|
||||
linkText = document.createTextNode("1 download remaining...");
|
||||
} else {
|
||||
linkText = document.createTextNode(`${formatted} downloads remaining...`)
|
||||
}
|
||||
|
||||
link.appendChild(linkText);
|
||||
link.title = "Visit Modrinth";
|
||||
link.href = "https://modrinth.com/plugin/advancedserverlist";
|
||||
link.target = "_blank";
|
||||
link.rel = "nofollow";
|
||||
|
||||
count.appendChild(link);
|
||||
}
|
||||
|
||||
async function fetchDownloads() {
|
||||
const data = await fetch('https://api.modrinth.com/v3/project/advancedserverlist')
|
||||
.then(_ => _.json());
|
||||
|
||||
const downloads = data.downloads
|
||||
|
||||
if (downloads != null) {
|
||||
__md_set("__downloads_count", downloads, sessionStorage);
|
||||
applyCount(downloads)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const cached = __md_get("__downloads_count", sessionStorage);
|
||||
if (cached != null) {
|
||||
applyCount(cached);
|
||||
} else {
|
||||
fetchDownloads();
|
||||
}
|
||||
})
|
||||
@@ -61,4 +61,86 @@
|
||||
padding: .5em;
|
||||
line-height: 0;
|
||||
color: var(--md-default-fg-color);
|
||||
}
|
||||
|
||||
/* Animations */
|
||||
@keyframes balloon {
|
||||
0% {
|
||||
transform: translate(0rem, 0rem) rotate(0deg) scale(2);
|
||||
}
|
||||
10% {
|
||||
transform: translate(0.05rem, -0.08rem) rotate(2deg) scale(1.95);
|
||||
}
|
||||
20% {
|
||||
transform: translate(-0.07rem, 0.06rem) rotate(-3deg) scale(2);
|
||||
}
|
||||
30% {
|
||||
transform: translate(0.1rem, -0.02rem) rotate(1.5deg) scale(2.05);
|
||||
}
|
||||
40% {
|
||||
transform: translate(-0.06rem, -0.1rem) rotate(-2deg) scale(1.95);
|
||||
}
|
||||
50% {
|
||||
transform: translate(0.02rem, 0.08rem) rotate(3deg) scale(2);
|
||||
}
|
||||
60% {
|
||||
transform: translate(-0.1rem, -0.01rem) rotate(-1deg) scale(2.05);
|
||||
}
|
||||
70% {
|
||||
transform: translate(0.08rem, 0.04rem) rotate(2.5deg) scale(1.95);
|
||||
}
|
||||
80% {
|
||||
transform: translate(-0.03rem, -0.07rem) rotate(-2.5deg) scale(2);
|
||||
}
|
||||
90% {
|
||||
transform: translate(0.06rem, 0.03rem) rotate(1deg) scale(2.05);
|
||||
}
|
||||
100% {
|
||||
transform: translate(0rem, 0rem) rotate(0deg) scale(2);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rainbow {
|
||||
0% {
|
||||
color: #ff6b6b;
|
||||
}
|
||||
10% {
|
||||
color: #ffcc70;
|
||||
}
|
||||
20% {
|
||||
color: #f7f48b;
|
||||
}
|
||||
30% {
|
||||
color: #caffbf;
|
||||
}
|
||||
40% {
|
||||
color: #9bf6ff;
|
||||
}
|
||||
50% {
|
||||
color: #a0c4ff;
|
||||
}
|
||||
60% {
|
||||
color: #bdb2ff;
|
||||
}
|
||||
70% {
|
||||
color: #ffc6ff;
|
||||
}
|
||||
80% {
|
||||
color: #ffadad;
|
||||
}
|
||||
90% {
|
||||
color: #ffd6a5;
|
||||
}
|
||||
100% {
|
||||
color: #ff6b6b;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.balloon {
|
||||
animation: 20s ease-in-out infinite balloon;
|
||||
}
|
||||
|
||||
.rainbow {
|
||||
animation: 10s ease-in-out infinite rainbow;
|
||||
}
|
||||
@@ -11,4 +11,4 @@ title: /asl clearcache
|
||||
- `advancedserverlist.command.clearcache`
|
||||
///
|
||||
|
||||
Resets the current Favicon and Player cache.
|
||||
Clears currently loaded favicons and the player cache and loads local favicons again.
|
||||
@@ -2,7 +2,7 @@
|
||||
title: /asl profiles
|
||||
---
|
||||
|
||||
# `/asl profiles add <profile>`<br>`/asl profiles copy <profile> <name>`<br>`/asl profiles info <profile>`<br>`/asl profiles list`<br>`/asl profiles set <profile> <option> [value]`
|
||||
# `/asl profiles add <profile>`<br>`/asl profiles copy <profile> <name>`<br>`/asl profiles edit <profile>`<br>`/asl profiles info <profile>`<br>`/asl profiles list`<br>`/asl profiles set <profile> <option> [value]`
|
||||
|
||||
/// info |
|
||||
**Permissions:**
|
||||
@@ -56,6 +56,27 @@ Creates a new profile using default values.
|
||||
Creates a copy from the provided profile.
|
||||
[`/asl reload`](reload.md) needs to be executed to load the new profile.
|
||||
|
||||
## `/asl profiles edit <profile>` { #edit }
|
||||
|
||||
/// info |
|
||||
**Permissions:**
|
||||
|
||||
- `advancedserverlist.admin`
|
||||
- `advancedserverlist.command.profiles`
|
||||
- `advancedserverlist.command.profiles.edit`
|
||||
|
||||
**Arguments:**
|
||||
|
||||
- `<profile>` - Name of the profile to edit.
|
||||
///
|
||||
|
||||
Opens a Dialog to edit the specified Profile.
|
||||
The first Dialog allows you to select either the primary settings or the individual `profiles` with each option allowing you to edit their values according to what they support.
|
||||
|
||||
/// warning
|
||||
This Feature only works for `v5.7.0-b1` and newer of AdvancedServerList and only for Paper 1.21.7 Builds 17 and newer due to lack of API in older versions.
|
||||
///
|
||||
|
||||
## `/asl profiles info <profile>` { #info }
|
||||
|
||||
/// info |
|
||||
|
||||
@@ -90,7 +90,7 @@ The plugin also supports these additional plugins. They are all optional.
|
||||
**Supported on:**
|
||||
<!-- icon:all -->
|
||||
|
||||
- [**BanPlugins Addon**][addon]
|
||||
- [**BanPlugins Addon**][banplugins-addon]
|
||||
|
||||
----
|
||||
|
||||
@@ -98,11 +98,23 @@ The plugin also supports these additional plugins. They are all optional.
|
||||
|
||||
----
|
||||
|
||||
**Supported on:**
|
||||
<!-- icon:all -->
|
||||
|
||||
- [**LuckPerms Addon**][luckperms-addon]
|
||||
|
||||
----
|
||||
|
||||
Official Add-on for AdvancedServerList that adds placeholders for LuckPerms.
|
||||
|
||||
----
|
||||
|
||||
**Supported on:**
|
||||
<!-- icon:all -->
|
||||
///
|
||||
|
||||
[addon]: ../addons/first-party/banplugins.md
|
||||
[banplugins-addon]: ../addons/first-party/banplugins.md
|
||||
[luckperms-addon]: ../addons/first-party/luckperms.md
|
||||
|
||||
## 2. Installation { #installation }
|
||||
|
||||
@@ -461,7 +473,7 @@ faviconCacheTime: 1
|
||||
#
|
||||
# Setting any not listed option or leaving this blank/removing it sets the option to resize.
|
||||
#
|
||||
faviconStrategy: 'resize'
|
||||
faviconResizeStrategy: 'resize'
|
||||
|
||||
#
|
||||
# Options to disable while the Maintenance Plugin is present and Maintenance Mode is active.
|
||||
@@ -531,7 +543,7 @@ 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.
|
||||
#
|
||||
configVersion: 9
|
||||
configVersion: 10
|
||||
```
|
||||
///
|
||||
|
||||
|
||||
@@ -42,6 +42,13 @@ The mode used is set in the `faviconStrategy` option in the `config.yml` and can
|
||||
|
||||
Please note that the actual favicon displayed will always be 64x64 pixels, even if the image(s) depicted in it aren't.
|
||||
|
||||
## Updating local Images
|
||||
|
||||
Local favicons (images in the `favicons` folder) are only loaded during the plugin's startup.
|
||||
If you would like to add new images to be used, you have to execute [`/asl clearcache`](../../commands/clearcache.md) to add them.
|
||||
|
||||
Note that this will also clear any dynamically created Favicons, requiring them to be created again.
|
||||
|
||||
## Example
|
||||
|
||||
```yaml
|
||||
|
||||
@@ -74,6 +74,22 @@ These placeholders require the [Maintenance](https://hangar.papermc.io/kennytv/M
|
||||
|-------------------------------------|----------------------------------------------------------------|
|
||||
| `${maintenance maintenanceEnabled}` | Returns whether the Global maintenance mode is enabled or not. |
|
||||
|
||||
### Date
|
||||
|
||||
These placeholders can be used to get the current date or compare it with another.
|
||||
|
||||
| Placeholder | Description |
|
||||
|---------------------------|---------------------------------------------------------------------------------------------------------------------------|
|
||||
| `${date current}` | Returns the current date. |
|
||||
| `${date isBefore <date>}` | Returns, whether the current date is before the specified one. The specified date needs to match the date pattern used. |
|
||||
| `${date isExact <date>}` | Returns, whether the current date is equal to the specified one. The specified date needs to match the date pattern used. |
|
||||
| `${date isAfter <date>}` | Returns, whether the current date is after the specified one. The specified date needs to match the date pattern used. |
|
||||
|
||||
/// note
|
||||
Each placeholder accepts an optional date pattern that follows Java's SimpleDateFormat structure.
|
||||
If none is provided does each default to `dd/MM/yyyy`
|
||||
///
|
||||
|
||||
## Adding your own Placeholders
|
||||
|
||||
Thanks to the API of AdvancedServerList are you able to add your own Placeholders that can be used using the `${identifier value}` pattern.
|
||||
@@ -112,4 +128,14 @@ Placeholders from PlaceholderAPI Expansions can be used in AdvancedServerList us
|
||||
PlaceholderAPI placeholders can be used both on the Server (Paper) and on the proxy (BungeeCord, Velocity) version of AdvancedServerList.
|
||||
However, the Proxy version requires the usage of [PAPIProxyBridge] to function properly.
|
||||
|
||||
Placeholders can also not be used within the [`condition`](options/condition.md) option of a Server List Profile.
|
||||
Placeholders can also not be used within the [`condition`](options/condition.md) option of a Server List Profile.
|
||||
|
||||
## MiniPlaceholders
|
||||
|
||||
/// info | New since `v5.7.0`
|
||||
///
|
||||
|
||||
Placeholders provided through [MiniPlaceholders](https://modrinth.com/plugin/miniplaceholders) are supported for all text options except [`condition`](options/condition.md).
|
||||
|
||||
Note that due to various limitations, only the `global` placeholders/tags - meaning ones that do not require a player - will work.
|
||||
Support also only works for Paper and Velocity.
|
||||
+5
-5
@@ -78,7 +78,7 @@
|
||||
<dependency>
|
||||
<groupId>io.papermc.paper</groupId>
|
||||
<artifactId>paper-api</artifactId>
|
||||
<version>1.21.4-R0.1-SNAPSHOT</version>
|
||||
<version>[26.1.2.build,)</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
<dependency>
|
||||
<groupId>org.bstats</groupId>
|
||||
<artifactId>bstats-bukkit</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<version>3.2.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -94,13 +94,13 @@
|
||||
<dependency>
|
||||
<groupId>me.clip</groupId>
|
||||
<artifactId>placeholderapi</artifactId>
|
||||
<version>2.11.6</version>
|
||||
<version>2.12.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.viaversion</groupId>
|
||||
<artifactId>viaversion-api</artifactId>
|
||||
<version>5.4.0</version>
|
||||
<version>5.10.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.6.0</version>
|
||||
<version>3.6.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
|
||||
@@ -26,11 +26,16 @@
|
||||
package ch.andre601.advancedserverlist.paper;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.dialogs.IDialog;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.dialogs.IDialogList;
|
||||
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.ServerListProfile;
|
||||
import ch.andre601.advancedserverlist.core.profiles.handlers.FaviconHandler;
|
||||
import ch.andre601.advancedserverlist.paper.commands.PaperCommandManagerInterface;
|
||||
import ch.andre601.advancedserverlist.paper.dialogs.PaperDialog;
|
||||
import ch.andre601.advancedserverlist.paper.dialogs.PaperDialogList;
|
||||
import ch.andre601.advancedserverlist.paper.listeners.ServerLoadEventListener;
|
||||
import ch.andre601.advancedserverlist.paper.logging.PaperLogger;
|
||||
import ch.andre601.advancedserverlist.paper.objects.WorldCache;
|
||||
@@ -95,7 +100,7 @@ public class PaperCore extends JavaPlugin implements PluginCore<CachedServerIcon
|
||||
if(worldCache != null)
|
||||
worldCache = null;
|
||||
|
||||
getCore().disable();
|
||||
core().disable();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -106,7 +111,7 @@ public class PaperCore extends JavaPlugin implements PluginCore<CachedServerIcon
|
||||
@Override
|
||||
public void loadMetrics(){
|
||||
new Metrics(this, 15584).addCustomChart(new SimplePie("profiles",
|
||||
() -> String.valueOf(core.getFileHandler().getProfiles().size())
|
||||
() -> String.valueOf(core.fileHandler().profiles().size())
|
||||
));
|
||||
}
|
||||
|
||||
@@ -146,22 +151,22 @@ public class PaperCore extends JavaPlugin implements PluginCore<CachedServerIcon
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdvancedServerList<CachedServerIcon> getCore(){
|
||||
public AdvancedServerList<CachedServerIcon> core(){
|
||||
return core;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getFolderPath(){
|
||||
public Path folderPath(){
|
||||
return getDataFolder().toPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginLogger getPluginLogger(){
|
||||
public PluginLogger pluginLogger(){
|
||||
return logger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaviconHandler<CachedServerIcon> getFaviconHandler(){
|
||||
public FaviconHandler<CachedServerIcon> faviconHandler(){
|
||||
if(faviconHandler == null)
|
||||
faviconHandler = new FaviconHandler<>(core);
|
||||
|
||||
@@ -169,23 +174,23 @@ public class PaperCore extends JavaPlugin implements PluginCore<CachedServerIcon
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommandManager<CmdSender> getCommandManager(){
|
||||
public CommandManager<CmdSender> commandManager(){
|
||||
return commandHandler.commandHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlatformInfo(){
|
||||
public String platformInfo(){
|
||||
try{
|
||||
Class.forName("io.papermc.paper.ServerBuildInfo");
|
||||
return getNewVersion();
|
||||
return buildInfo();
|
||||
}catch(ClassNotFoundException ignored){
|
||||
// Old Paper versions (Before 16th of May 2024)
|
||||
return getOldVersion();
|
||||
return version();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLoader(){
|
||||
public String loader(){
|
||||
return "paper";
|
||||
}
|
||||
|
||||
@@ -194,19 +199,39 @@ public class PaperCore extends JavaPlugin implements PluginCore<CachedServerIcon
|
||||
return Bukkit.getPluginManager().isPluginEnabled(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDialogsSupported(){
|
||||
try{
|
||||
Class.forName("io.papermc.paper.dialog.Dialog");
|
||||
return true;
|
||||
}catch(ClassNotFoundException ignored){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CachedServerIcon createFavicon(BufferedImage image) throws Exception{
|
||||
return Bukkit.loadServerIcon(image);
|
||||
}
|
||||
|
||||
public WorldCache getWorldCache(){
|
||||
@Override
|
||||
public IDialogList.IDialogListBuilder createDialogListBuilder(String title){
|
||||
return PaperDialogList.PaperDialogListBuilder.create(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IDialog.IDialogBuilder createDialogBuilder(String title, ServerListProfile profile, int profilesPosition){
|
||||
return PaperDialog.PaperDialogBuilder.create(core(), title, profile, profilesPosition);
|
||||
}
|
||||
|
||||
public WorldCache worldCache(){
|
||||
if(worldCache != null)
|
||||
return worldCache;
|
||||
|
||||
return (worldCache = new WorldCache());
|
||||
}
|
||||
|
||||
public int getPlayersOnline(World world){
|
||||
public int playersOnline(World world){
|
||||
List<? extends Player> players = new ArrayList<>(world == null ? getServer().getOnlinePlayers() : world.getPlayers());
|
||||
|
||||
players.removeIf(player -> {
|
||||
@@ -221,7 +246,7 @@ public class PaperCore extends JavaPlugin implements PluginCore<CachedServerIcon
|
||||
return players.size();
|
||||
}
|
||||
|
||||
private String getNewVersion(){
|
||||
private String buildInfo(){
|
||||
ServerBuildInfo info = ServerBuildInfo.buildInfo();
|
||||
|
||||
String name = info.brandName();
|
||||
@@ -235,20 +260,20 @@ public class PaperCore extends JavaPlugin implements PluginCore<CachedServerIcon
|
||||
return String.format("%s (ID: %s, Version: %s, Build: %d)", name, id, version, build.getAsInt());
|
||||
}
|
||||
|
||||
private String getOldVersion(){
|
||||
private String version(){
|
||||
return getServer().getName() + " " + getServer().getVersion();
|
||||
}
|
||||
|
||||
private void printOutdatedPaper(){
|
||||
getPluginLogger().warn("================================================================");
|
||||
getPluginLogger().warn("OUTDATED PAPER VERSION DETECTED!");
|
||||
getPluginLogger().warn("");
|
||||
getPluginLogger().warn("AdvancedServerList detected an outdated Paper version.");
|
||||
getPluginLogger().warn("The plugin requires at least 1.20.6 of Paper due to required");
|
||||
getPluginLogger().warn("classes only existing within this version onwards.");
|
||||
getPluginLogger().warn("");
|
||||
getPluginLogger().warn("Please use at least Paper 1.20.6 or downgrade AdvancedServerList");
|
||||
getPluginLogger().warn("to v5.4.1.");
|
||||
getPluginLogger().warn("================================================================");
|
||||
pluginLogger().warn("================================================================");
|
||||
pluginLogger().warn("OUTDATED PAPER VERSION DETECTED!");
|
||||
pluginLogger().warn("");
|
||||
pluginLogger().warn("AdvancedServerList detected an outdated Paper version.");
|
||||
pluginLogger().warn("The plugin requires at least 1.20.6 of Paper due to required");
|
||||
pluginLogger().warn("classes only existing within this version onwards.");
|
||||
pluginLogger().warn("");
|
||||
pluginLogger().warn("Please use at least Paper 1.20.6 or downgrade AdvancedServerList");
|
||||
pluginLogger().warn("to v5.4.1.");
|
||||
pluginLogger().warn("================================================================");
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -32,7 +32,6 @@ import net.kyori.adventure.audience.Audience;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
public class PaperCmdSender implements CmdSender{
|
||||
|
||||
private final CommandSender sender;
|
||||
@@ -70,7 +69,7 @@ public class PaperCmdSender implements CmdSender{
|
||||
return sender;
|
||||
}
|
||||
|
||||
public CommandSourceStack getCommandSourceStack(){
|
||||
public CommandSourceStack commandSourceStack(){
|
||||
return commandSourceStack;
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -33,7 +33,6 @@ import org.incendo.cloud.SenderMapper;
|
||||
import org.incendo.cloud.execution.ExecutionCoordinator;
|
||||
import org.incendo.cloud.paper.PaperCommandManager;
|
||||
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
public class PaperCommandManagerInterface implements CommandManagerInterface<CommandSourceStack>{
|
||||
|
||||
private final PaperCore plugin;
|
||||
@@ -45,7 +44,7 @@ public class PaperCommandManagerInterface implements CommandManagerInterface<Com
|
||||
@Override
|
||||
public CommandManager<CmdSender> commandHandler(){
|
||||
return PaperCommandManager.builder(senderMapper())
|
||||
.executionCoordinator(ExecutionCoordinator.asyncCoordinator())
|
||||
.executionCoordinator(ExecutionCoordinator.simpleCoordinator())
|
||||
.buildOnEnable(plugin);
|
||||
}
|
||||
|
||||
@@ -53,7 +52,7 @@ public class PaperCommandManagerInterface implements CommandManagerInterface<Com
|
||||
public SenderMapper<CommandSourceStack, CmdSender> senderMapper(){
|
||||
return SenderMapper.create(
|
||||
PaperCmdSender::new,
|
||||
sender -> ((PaperCmdSender)sender).getCommandSourceStack()
|
||||
sender -> ((PaperCmdSender)sender).commandSourceStack()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
package ch.andre601.advancedserverlist.paper.dialogs;
|
||||
|
||||
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.commands.CmdProfiles;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.dialogs.IDialog;
|
||||
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
|
||||
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
|
||||
import io.papermc.paper.dialog.Dialog;
|
||||
import io.papermc.paper.dialog.DialogResponseView;
|
||||
import io.papermc.paper.registry.data.dialog.ActionButton;
|
||||
import io.papermc.paper.registry.data.dialog.DialogBase;
|
||||
import io.papermc.paper.registry.data.dialog.action.DialogAction;
|
||||
import io.papermc.paper.registry.data.dialog.body.DialogBody;
|
||||
import io.papermc.paper.registry.data.dialog.input.DialogInput;
|
||||
import io.papermc.paper.registry.data.dialog.input.TextDialogInput;
|
||||
import io.papermc.paper.registry.data.dialog.type.DialogType;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.ClickCallback;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
public class PaperDialog implements IDialog<Dialog>{
|
||||
|
||||
private final AdvancedServerList<?> core;
|
||||
private final String title;
|
||||
private final ServerListProfile profile;
|
||||
private final int profilesPosition;
|
||||
private final List<DialogBody> bodies;
|
||||
private final List<DialogInput> inputs;
|
||||
|
||||
private PaperDialog(AdvancedServerList<?> core, String title, ServerListProfile profile, int profilesPosition, List<DialogBody> bodies, List<DialogInput> inputs){
|
||||
this.core = core;
|
||||
this.title = title;
|
||||
this.profile = profile;
|
||||
this.profilesPosition = profilesPosition;
|
||||
this.bodies = bodies;
|
||||
this.inputs = inputs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog createDialog(){
|
||||
return Dialog.create(
|
||||
factory -> factory.empty().base(
|
||||
DialogBase.builder(ComponentParser.text(title).toComponent())
|
||||
.body(bodies)
|
||||
.inputs(inputs)
|
||||
.afterAction(DialogBase.DialogAfterAction.NONE)
|
||||
.pause(false)
|
||||
.build()
|
||||
).type(DialogType.confirmation(
|
||||
ActionButton.builder(ComponentParser.text("<green>Save changes").toComponent())
|
||||
.tooltip(ComponentParser.text("""
|
||||
<grey>Saves your changes made in this Dialog.
|
||||
<grey>Applying changes requires the use of <aqua>/asl reload""").toComponent())
|
||||
.action(
|
||||
DialogAction.customClick(
|
||||
(view, audience) -> handle(audience, view, profile, profilesPosition),
|
||||
ClickCallback.Options.builder().build()
|
||||
)
|
||||
)
|
||||
.build(),
|
||||
ActionButton.builder(ComponentParser.text("Back...").toComponent())
|
||||
.tooltip(ComponentParser.text("""
|
||||
<grey>Returns you to the main Dialog Screen.
|
||||
<grey>Any unsaved changes will be <red>lost</red>!
|
||||
|
||||
<grey>Click the <green>Save changes</green> button to save your changes.""").toComponent())
|
||||
.action(DialogAction.staticAction(ClickEvent.runCommand("/asl profiles edit " + profile.file())))
|
||||
.build()
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
private void handle(Audience audience, DialogResponseView view, ServerListProfile slp, int profilesPosition){
|
||||
Float priority = view.getFloat(CmdProfiles.ProfileOption.PRIORITY.toDialogKey());
|
||||
String condition = view.getText(CmdProfiles.ProfileOption.CONDITION.toDialogKey());
|
||||
|
||||
String motd = view.getText(CmdProfiles.ProfileOption.MOTD.toDialogKey());
|
||||
String favicon = view.getText(CmdProfiles.ProfileOption.FAVICON.toDialogKey());
|
||||
|
||||
NullBool hidePlayers = NullBool.resolve(view.getBoolean(CmdProfiles.ProfileOption.PLAYERCOUNT_HIDEPLAYERS.toDialogKey()));
|
||||
NullBool hidePlayersHover = NullBool.resolve(view.getBoolean(CmdProfiles.ProfileOption.PLAYERCOUNT_HIDEPLAYERSHOVER.toDialogKey()));
|
||||
|
||||
String hover = view.getText(CmdProfiles.ProfileOption.PLAYERCOUNT_HOVER.toDialogKey());
|
||||
String playerCountText = view.getText(CmdProfiles.ProfileOption.PLAYERCOUNT_TEXT.toDialogKey());
|
||||
|
||||
NullBool extraPlayersEnabled = NullBool.resolve(view.getBoolean(CmdProfiles.ProfileOption.PLAYERCOUNT_EXTRAPLAYERS_ENABLED.toDialogKey()));
|
||||
String extraPlayersCount = view.getText(CmdProfiles.ProfileOption.PLAYERCOUNT_EXTRAPLAYERS_AMOUNT.toDialogKey());
|
||||
|
||||
NullBool maxPlayersEnabled = NullBool.resolve(view.getBoolean(CmdProfiles.ProfileOption.PLAYERCOUNT_MAXPLAYERS_ENABLED.toDialogKey()));
|
||||
String maxPlayersCount = view.getText(CmdProfiles.ProfileOption.PLAYERCOUNT_MAXPLAYERS_AMOUNT.toDialogKey());
|
||||
|
||||
NullBool onlinePlayersEnabled = NullBool.resolve(view.getBoolean(CmdProfiles.ProfileOption.PLAYERCOUNT_ONLINEPLAYERS_ENABLED.toDialogKey()));
|
||||
String onlinePlayersCount = view.getText(CmdProfiles.ProfileOption.PLAYERCOUNT_ONLINEPLAYERS_AMOUNT.toDialogKey());
|
||||
|
||||
ProfileEntry.Builder builder = ProfileEntry.empty().builder();
|
||||
if(motd != null && !motd.isEmpty())
|
||||
builder.motd(List.of(motd.split("\n")));
|
||||
|
||||
if(favicon != null && !favicon.isEmpty())
|
||||
builder.favicon(favicon);
|
||||
|
||||
builder.hidePlayersEnabled(hidePlayers);
|
||||
builder.hidePlayersHoverEnabled(hidePlayersHover);
|
||||
|
||||
if(hover != null && !hover.isEmpty())
|
||||
builder.players(List.of(hover.split("\n")));
|
||||
|
||||
if(playerCountText != null && !playerCountText.isEmpty())
|
||||
builder.playerCountText(playerCountText);
|
||||
|
||||
builder.extraPlayersEnabled(extraPlayersEnabled);
|
||||
if(extraPlayersCount != null && !extraPlayersCount.isEmpty())
|
||||
builder.extraPlayersCount(extraPlayersCount);
|
||||
|
||||
builder.maxPlayersEnabled(maxPlayersEnabled);
|
||||
if(maxPlayersCount != null && !maxPlayersCount.isEmpty())
|
||||
builder.maxPlayersCount(maxPlayersCount);
|
||||
|
||||
builder.onlinePlayersEnabled(onlinePlayersEnabled);
|
||||
if(onlinePlayersCount != null && !onlinePlayersCount.isEmpty())
|
||||
builder.onlinePlayersCount(onlinePlayersCount);
|
||||
|
||||
ProfileEntry entry = slp.defaultProfile();
|
||||
List<ProfileEntry> entries = slp.profiles();
|
||||
|
||||
if(profilesPosition >= 0){
|
||||
if(profilesPosition >= entries.size()){
|
||||
entries.add(builder.build());
|
||||
}else{
|
||||
entries.set(profilesPosition, builder.build());
|
||||
}
|
||||
}else{
|
||||
entry = builder.build();
|
||||
}
|
||||
|
||||
float newPriority = priority == null ? slp.priority() : priority;
|
||||
|
||||
if(core.fileHandler().saveProfile(slp.file(), (int)newPriority, condition, entries, entry)){
|
||||
audience.sendMessage(ComponentParser.textFormatted(
|
||||
"<grey>[<aqua>ASL</aqua>] <green>Successfully saved changes for <white>%s</white>!",
|
||||
slp.file()
|
||||
).toComponent());
|
||||
}else{
|
||||
audience.sendMessage(ComponentParser.textFormatted(
|
||||
"<grey>[<red>ASL</red>] <red>Error while saving changes for <white>%s</white>! See console for details.",
|
||||
slp.file()
|
||||
).toComponent());
|
||||
}
|
||||
}
|
||||
|
||||
public static class PaperDialogBuilder implements IDialogBuilder{
|
||||
|
||||
public static PaperDialogBuilder create(AdvancedServerList<?> core, String title, ServerListProfile profile, int profilesPosition){
|
||||
return new PaperDialogBuilder(core, title, profile, profilesPosition);
|
||||
}
|
||||
|
||||
private final AdvancedServerList<?> core;
|
||||
private final String title;
|
||||
private final ServerListProfile profile;
|
||||
private final int profilesPosition;
|
||||
private final List<DialogBody> bodies = new ArrayList<>();
|
||||
private final List<DialogInput> inputs = new ArrayList<>();
|
||||
|
||||
private PaperDialogBuilder(AdvancedServerList<?> core, String title, ServerListProfile profile, int profilesPosition){
|
||||
this.core = core;
|
||||
this.title = title;
|
||||
this.profile = profile;
|
||||
this.profilesPosition = profilesPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperDialogBuilder appendBody(String body){
|
||||
this.bodies.add(DialogBody.plainMessage(ComponentParser.text(body).toComponent()));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperDialogBuilder appendTextInput(CmdProfiles.ProfileOption option, String title, String initValue, int maxLength){
|
||||
this.inputs.add(DialogInput.text(option.toDialogKey(), Component.text(title))
|
||||
.initial(initValue == null ? "" : initValue)
|
||||
.maxLength(maxLength)
|
||||
.build()
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperDialogBuilder appendTextbox(CmdProfiles.ProfileOption option, String title, List<String> initValue, int maxLength, int rows){
|
||||
this.inputs.add(DialogInput.text(option.toDialogKey(), Component.text(title))
|
||||
.initial(initValue == null ? "" : String.join("\n", initValue))
|
||||
.maxLength(maxLength)
|
||||
.multiline(TextDialogInput.MultilineOptions.create(rows, null))
|
||||
.build()
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperDialogBuilder appendNumberRange(CmdProfiles.ProfileOption option, String title, int initValue){
|
||||
float minValue = Math.min((float)initValue, -100.0F);
|
||||
float maxValue = Math.max((float)initValue, 100.0F);
|
||||
|
||||
this.inputs.add(DialogInput.numberRange(option.toDialogKey(), Component.text(title), minValue, maxValue)
|
||||
.step(1.0F)
|
||||
.initial((float)initValue)
|
||||
.build()
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperDialogBuilder appendBoolean(CmdProfiles.ProfileOption option, String title, NullBool initValue){
|
||||
this.inputs.add(DialogInput.bool(option.toDialogKey(), Component.text(title))
|
||||
.initial(initValue.getOrDefault(false))
|
||||
.build()
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperDialog build(){
|
||||
return new PaperDialog(core, title, profile, profilesPosition, bodies, inputs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package ch.andre601.advancedserverlist.paper.dialogs;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.interfaces.dialogs.IDialog;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.dialogs.IDialogList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
|
||||
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
|
||||
import io.papermc.paper.dialog.Dialog;
|
||||
import io.papermc.paper.registry.RegistryKey;
|
||||
import io.papermc.paper.registry.data.dialog.DialogBase;
|
||||
import io.papermc.paper.registry.data.dialog.body.DialogBody;
|
||||
import io.papermc.paper.registry.data.dialog.type.DialogType;
|
||||
import io.papermc.paper.registry.set.RegistrySet;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PaperDialogList implements IDialogList{
|
||||
|
||||
private final String title;
|
||||
private final List<String> bodies;
|
||||
private final List<IDialog<?>> dialogs;
|
||||
|
||||
protected PaperDialogList(String title, List<String> bodies, List<IDialog<?>> dialogs){
|
||||
this.title = title;
|
||||
this.bodies = bodies;
|
||||
this.dialogs = dialogs;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
public void show(CmdSender sender){
|
||||
List<DialogBody> dialogBodies = bodies.stream()
|
||||
.<DialogBody>map(text -> DialogBody.plainMessage(ComponentParser.text(text).toComponent()))
|
||||
.toList();
|
||||
List<Dialog> paperDialogs = dialogs.stream()
|
||||
.filter(dialog -> dialog instanceof PaperDialog)
|
||||
.map(dialog -> (PaperDialog)dialog)
|
||||
.map(PaperDialog::createDialog)
|
||||
.toList();
|
||||
|
||||
DialogBase.Builder builder = DialogBase.builder(Component.text(title))
|
||||
.body(dialogBodies);
|
||||
|
||||
RegistrySet<Dialog> dialogRegistry = RegistrySet.valueSet(RegistryKey.DIALOG, paperDialogs);
|
||||
|
||||
Dialog dialog = Dialog.create(
|
||||
factory -> factory.empty().base(builder.build())
|
||||
.type(DialogType.dialogList(dialogRegistry).columns(3).build())
|
||||
);
|
||||
|
||||
sender.audience().showDialog(dialog);
|
||||
}
|
||||
|
||||
public static class PaperDialogListBuilder implements IDialogListBuilder{
|
||||
|
||||
public static PaperDialogListBuilder create(String title){
|
||||
return new PaperDialogListBuilder(title);
|
||||
}
|
||||
|
||||
private final String title;
|
||||
private final List<String> bodies = new ArrayList<>();
|
||||
private final List<IDialog<?>> dialogs = new ArrayList<>();
|
||||
|
||||
private PaperDialogListBuilder(String title){
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperDialogListBuilder appendBody(String body){
|
||||
this.bodies.add(body);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperDialogListBuilder appendDialog(IDialog<?> dialog){
|
||||
this.dialogs.add(dialog);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaperDialogList build(){
|
||||
return new PaperDialogList(this.title, this.bodies, this.dialogs);
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
-35
@@ -35,11 +35,9 @@ import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
|
||||
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
|
||||
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
|
||||
import ch.andre601.advancedserverlist.paper.PaperCore;
|
||||
import ch.andre601.advancedserverlist.paper.objects.FakePlayerProfile;
|
||||
import ch.andre601.advancedserverlist.paper.objects.impl.PaperPlayerImpl;
|
||||
import ch.andre601.advancedserverlist.paper.objects.impl.PaperServerImpl;
|
||||
import com.destroystokyo.paper.event.server.PaperServerListPingEvent;
|
||||
import com.destroystokyo.paper.profile.PlayerProfile;
|
||||
import me.clip.placeholderapi.PlaceholderAPI;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Bukkit;
|
||||
@@ -70,17 +68,17 @@ public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon,
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxPlayers(int maxPlayers){
|
||||
public void maxPlayers(int maxPlayers){
|
||||
event.setMaxPlayers(maxPlayers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnlinePlayers(int onlinePlayers){
|
||||
public void onlinePlayers(int onlinePlayers){
|
||||
event.setNumPlayers(onlinePlayers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMotd(Component component){
|
||||
public void motd(Component component){
|
||||
event.motd(component);
|
||||
}
|
||||
|
||||
@@ -90,39 +88,38 @@ public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon,
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerCount(String name){
|
||||
public void playerCount(String name){
|
||||
event.setVersion(name);
|
||||
event.setProtocolVersion(-1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayers(List<String> lines, PaperPlayerImpl player, GenericServer server){
|
||||
public void players(List<String> lines, PaperPlayerImpl player, GenericServer server){
|
||||
try{
|
||||
Class.forName("com.destroystokyo.paper.event.server.PaperServerListPingEvent$ListedPlayerInfo");
|
||||
setListedPlayers(lines, player, server);
|
||||
}catch(ClassNotFoundException ex){
|
||||
// Version before latest 1.20.6 builds(?)
|
||||
setPlayerSample(lines, player, server);
|
||||
plugin.pluginLogger().warn("playerCount -> hover is not supported on this Paper Version!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayersHidden(){
|
||||
public void playersHidden(){
|
||||
try{
|
||||
Class.forName("com.destroystokyo.paper.event.server.PaperServerListPingEvent$ListedPlayerInfo");
|
||||
clearListedPlayers();
|
||||
}catch(ClassNotFoundException ex){
|
||||
clearPlayerSample();
|
||||
plugin.pluginLogger().warn("playerCount -> hidePlayers is not supported on this Paper Version!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFavicon(CachedServerIcon favicon){
|
||||
public void favicon(CachedServerIcon favicon){
|
||||
event.setServerIcon(favicon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultFavicon(){
|
||||
public void defaultFavicon(){
|
||||
event.setServerIcon(event.getServerIcon());
|
||||
}
|
||||
|
||||
@@ -145,22 +142,22 @@ public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon,
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtocolVersion(){
|
||||
public int protocolVersion(){
|
||||
return event.getClient().getProtocolVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOnlinePlayers(){
|
||||
return plugin.getPlayersOnline(null);
|
||||
public int onlinePlayers(){
|
||||
return plugin.playersOnline(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxPlayers(){
|
||||
public int maxPlayers(){
|
||||
return event.getMaxPlayers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlayerIP(){
|
||||
public String playerIP(){
|
||||
return event.getClient().getAddress().getHostString();
|
||||
}
|
||||
|
||||
@@ -173,12 +170,12 @@ public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon,
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVirtualHost(){
|
||||
public String virtualHost(){
|
||||
return this.resolveHost(event.getClient().getVirtualHost());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginCore<CachedServerIcon> getPlugin(){
|
||||
public PluginCore<CachedServerIcon> plugin(){
|
||||
return plugin;
|
||||
}
|
||||
|
||||
@@ -190,8 +187,8 @@ public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon,
|
||||
}
|
||||
|
||||
@Override
|
||||
public GenericServer createGenericServer(int playersOnline, int playersMax, String host){
|
||||
return new PaperServerImpl(plugin.getWorldCache().worlds(), playersOnline, playersMax, host);
|
||||
public GenericServer createServer(int playersOnline, int playersMax, String host){
|
||||
return new PaperServerImpl(plugin.worldCache().worlds(), playersOnline, playersMax, host);
|
||||
}
|
||||
|
||||
private void clearListedPlayers(){
|
||||
@@ -206,25 +203,13 @@ public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon,
|
||||
event.getListedPlayers().addAll(playerList);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"Deprecation", "removal"})
|
||||
private void clearPlayerSample(){
|
||||
event.getPlayerSample().clear();
|
||||
}
|
||||
|
||||
@SuppressWarnings({"Deprecation", "removal"})
|
||||
private void setPlayerSample(List<String> lines, PaperPlayerImpl player, GenericServer server){
|
||||
clearPlayerSample();
|
||||
List<PlayerProfile> playerProfiles = getPlayerList(lines, player, server, FakePlayerProfile::create);
|
||||
|
||||
event.getPlayerSample().addAll(playerProfiles);
|
||||
}
|
||||
|
||||
private <T> List<T> getPlayerList(List<String> lines, PaperPlayerImpl player, GenericServer server, Function<String, T> function){
|
||||
List<T> playerList = new ArrayList<>(lines.size());
|
||||
for(String line : lines){
|
||||
String parsed = ComponentParser.text(line)
|
||||
.modifyText(text -> StringReplacer.replace(text, player, server))
|
||||
.modifyText(text -> parsePAPIPlaceholders(text, player))
|
||||
.applyMMTags(plugin())
|
||||
.toString();
|
||||
|
||||
playerList.add(function.apply(parsed));
|
||||
|
||||
+3
-3
@@ -51,15 +51,15 @@ public class PlayerJoinEventListener implements Listener{
|
||||
return;
|
||||
|
||||
Player player = event.getPlayer();
|
||||
plugin.getCore().getPlayerHandler().addPlayer(address.getHostString(), player.getName(), player.getUniqueId());
|
||||
plugin.core().playerHandler().addPlayer(address.getHostString(), player.getName(), player.getUniqueId());
|
||||
|
||||
if(player.hasPermission("advancedserverlist.admin") || player.hasPermission("advancedserverlist.updatecheck")){
|
||||
if(plugin.getCore().getUpdateChecker() == null)
|
||||
if(plugin.core().updateChecker() == null)
|
||||
return;
|
||||
|
||||
PaperCmdSender sender = new PaperCmdSender(player);
|
||||
|
||||
plugin.getCore().getUpdateChecker().performCachedUpdateCheck(sender);
|
||||
plugin.core().updateChecker().performCachedUpdateCheck(sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
-1
@@ -29,7 +29,6 @@ import ch.andre601.advancedserverlist.api.bukkit.events.PreServerListSetEvent;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
|
||||
public class PreServerListSetEventImpl extends PreServerListSetEvent{
|
||||
|
||||
public PreServerListSetEventImpl(ProfileEntry entry){
|
||||
super(entry);
|
||||
}
|
||||
|
||||
+11
-11
@@ -47,21 +47,21 @@ public class ServerLoadEventListener implements Listener{
|
||||
new WorldEventsListener(plugin);
|
||||
|
||||
// Load currently loaded worlds into the WorldCache
|
||||
Bukkit.getWorlds().forEach(world -> plugin.getWorldCache().addWorld(world));
|
||||
Bukkit.getWorlds().forEach(world -> plugin.worldCache().addWorld(world));
|
||||
|
||||
// Print a warning if server load was after a reload.
|
||||
if(event.getType() != ServerLoadEvent.LoadType.RELOAD)
|
||||
return;
|
||||
|
||||
plugin.getPluginLogger().warn("======================================================================================");
|
||||
plugin.getPluginLogger().warn("SERVER RELOAD DETECTED!");
|
||||
plugin.getPluginLogger().warn("");
|
||||
plugin.getPluginLogger().warn("A server reload has been detected by AdvancedServerList, meaning either the /reload");
|
||||
plugin.getPluginLogger().warn("command or Bukkit.reload() was executed.");
|
||||
plugin.getPluginLogger().warn("");
|
||||
plugin.getPluginLogger().warn("YOU WILL GET NO SUPPORT FOR THE PLUGIN FOR ANY ISSUES YOU ENCOUNTER AFTER A SERVER");
|
||||
plugin.getPluginLogger().warn("RELOAD!");
|
||||
plugin.getPluginLogger().warn("ALWAYS RESTART YOUR SERVER. NEVER RELOAD IT!");
|
||||
plugin.getPluginLogger().warn("======================================================================================");
|
||||
plugin.pluginLogger().warn("======================================================================================");
|
||||
plugin.pluginLogger().warn("SERVER RELOAD DETECTED!");
|
||||
plugin.pluginLogger().warn("");
|
||||
plugin.pluginLogger().warn("A server reload has been detected by AdvancedServerList, meaning either the /reload");
|
||||
plugin.pluginLogger().warn("command or Bukkit.reload() was executed.");
|
||||
plugin.pluginLogger().warn("");
|
||||
plugin.pluginLogger().warn("YOU WILL GET NO SUPPORT FOR THE PLUGIN FOR ANY ISSUES YOU ENCOUNTER AFTER A SERVER");
|
||||
plugin.pluginLogger().warn("RELOAD!");
|
||||
plugin.pluginLogger().warn("ALWAYS RESTART YOUR SERVER. NEVER RELOAD IT!");
|
||||
plugin.pluginLogger().warn("======================================================================================");
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -41,11 +41,11 @@ public class WorldEventsListener implements Listener{
|
||||
|
||||
@EventHandler
|
||||
public void onWorldLoad(WorldLoadEvent event){
|
||||
plugin.getWorldCache().addWorld(event.getWorld());
|
||||
plugin.worldCache().addWorld(event.getWorld());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onWorldUnload(WorldUnloadEvent event){
|
||||
plugin.getWorldCache().removeWorld(event.getWorld().getName());
|
||||
plugin.worldCache().removeWorld(event.getWorld().getName());
|
||||
}
|
||||
}
|
||||
-208
@@ -1,208 +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.paper.objects;
|
||||
|
||||
import com.destroystokyo.paper.profile.PlayerProfile;
|
||||
import com.destroystokyo.paper.profile.ProfileProperty;
|
||||
import org.bukkit.profile.PlayerTextures;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public record FakePlayerProfile(String name, UUID uuid) implements PlayerProfile{
|
||||
|
||||
public static FakePlayerProfile create(String name){
|
||||
return new FakePlayerProfile(name, UUID.randomUUID());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable UUID getUniqueId(){
|
||||
return uuid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getName(){
|
||||
return name();
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
@Override
|
||||
public @NotNull String setName(@Nullable String name){
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable UUID getId(){
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
@Override
|
||||
public @Nullable UUID setId(@Nullable UUID uuid){
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull PlayerTextures getTextures(){
|
||||
return new FakePlayerTextures();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTextures(@Nullable PlayerTextures textures){
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Set<ProfileProperty> getProperties(){
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasProperty(@Nullable String property){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProperty(@NotNull ProfileProperty property){
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProperties(@NotNull Collection<ProfileProperty> properties){
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeProperty(@Nullable String property){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearProperties(){
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isComplete(){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean completeFromCache(){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean completeFromCache(boolean onlineMode){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean completeFromCache(boolean lookupUUID, boolean onlineMode){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean complete(boolean textures){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean complete(boolean textures, boolean onlineMode){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull CompletableFuture<PlayerProfile> update(){
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.bukkit.profile.@NotNull PlayerProfile clone(){
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Map<String, Object> serialize(){
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
private record FakePlayerTextures() implements PlayerTextures{
|
||||
|
||||
@Override
|
||||
public boolean isEmpty(){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear(){
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable URL getSkin(){
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkin(@Nullable URL skinUrl){
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkin(@Nullable URL skinUrl, @Nullable SkinModel skinModel){
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull SkinModel getSkinModel(){
|
||||
return SkinModel.CLASSIC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable URL getCape(){
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCape(@Nullable URL capeUrl){
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimestamp(){
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSigned(){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-3
@@ -28,14 +28,17 @@ package ch.andre601.advancedserverlist.paper.objects.impl;
|
||||
import ch.andre601.advancedserverlist.api.bukkit.objects.BukkitPlayer;
|
||||
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public record PaperPlayerImpl(OfflinePlayer player, CachedPlayer cachedPlayer, int protocol) implements BukkitPlayer{
|
||||
@NullMarked
|
||||
public record PaperPlayerImpl(@Nullable OfflinePlayer player, CachedPlayer cachedPlayer, int protocol) implements BukkitPlayer{
|
||||
|
||||
@Override
|
||||
public String getName(){
|
||||
return player == null ? cachedPlayer.name() : player.getName();
|
||||
return player == null || player.getName() == null ? cachedPlayer.name() : player.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -49,7 +52,7 @@ public record PaperPlayerImpl(OfflinePlayer player, CachedPlayer cachedPlayer, i
|
||||
}
|
||||
|
||||
@Override
|
||||
public OfflinePlayer getPlayer(){
|
||||
public @Nullable OfflinePlayer getPlayer(){
|
||||
return player;
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -27,12 +27,13 @@ package ch.andre601.advancedserverlist.paper.objects.impl;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.bukkit.objects.BukkitServer;
|
||||
import org.bukkit.World;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public record PaperServerImpl(Map<String, World> worlds, int playersOnline, int playersMax, String host) implements BukkitServer {
|
||||
@Override
|
||||
public Map<String, World> getWorlds(){
|
||||
public @NonNull Map<String, World> getWorlds(){
|
||||
return worlds;
|
||||
}
|
||||
|
||||
|
||||
+11
-11
@@ -41,7 +41,7 @@ import me.clip.placeholderapi.PlaceholderAPI;
|
||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -58,18 +58,18 @@ public class PAPIPlaceholders extends PlaceholderExpansion{
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getIdentifier(){
|
||||
public @NonNull String getIdentifier(){
|
||||
return "asl";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getAuthor(){
|
||||
public @NonNull String getAuthor(){
|
||||
return "Andre601";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getVersion(){
|
||||
return plugin.getCore().getVersion();
|
||||
public @NonNull String getVersion(){
|
||||
return plugin.core().version();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -78,18 +78,18 @@ public class PAPIPlaceholders extends PlaceholderExpansion{
|
||||
}
|
||||
|
||||
@Override
|
||||
public String onPlaceholderRequest(Player pl, @NotNull String identifier){
|
||||
public String onPlaceholderRequest(Player pl, @NonNull String identifier){
|
||||
String host = pl.getVirtualHost() == null ? null : pl.getVirtualHost().getHostString();
|
||||
CachedPlayer cached = plugin.getCore().getPlayerHandler().getCachedPlayer(pl.getUniqueId());
|
||||
CachedPlayer cached = plugin.core().playerHandler().getCachedPlayer(pl.getUniqueId());
|
||||
|
||||
int protocol = resolveProtocol(pl);
|
||||
int online = Bukkit.getOnlinePlayers().size();
|
||||
int max = Bukkit.getMaxPlayers();
|
||||
|
||||
BukkitServer server = new PaperServerImpl(plugin.getWorldCache().worlds(), online, max, host);
|
||||
BukkitServer server = new PaperServerImpl(plugin.worldCache().worlds(), online, max, host);
|
||||
BukkitPlayer player = new PaperPlayerImpl(pl, cached, protocol);
|
||||
|
||||
ServerListProfile profile = ProfileManager.resolveProfile(plugin.getCore(), player, server);
|
||||
ServerListProfile profile = ProfileManager.resolveProfile(plugin.core(), player, server);
|
||||
if(profile == null)
|
||||
return null;
|
||||
|
||||
@@ -113,7 +113,7 @@ public class PAPIPlaceholders extends PlaceholderExpansion{
|
||||
max = online + (extraPlayers == null ? 0 : extraPlayers);
|
||||
}
|
||||
|
||||
BukkitServer finalServer = new PaperServerImpl(plugin.getWorldCache().worlds(), online, max, host);
|
||||
BukkitServer finalServer = new PaperServerImpl(plugin.worldCache().worlds(), online, max, host);
|
||||
return switch(identifier.toLowerCase(Locale.ROOT)){
|
||||
case "favicon" -> getOption(entry.favicon(), pl, player, finalServer);
|
||||
case "motd" -> getOption(entry.motd(), pl, player, finalServer, true);
|
||||
@@ -155,7 +155,7 @@ public class PAPIPlaceholders extends PlaceholderExpansion{
|
||||
.modifyText(text -> PlaceholderAPI.setPlaceholders(pl, text))
|
||||
.modifyText(text -> {
|
||||
if(isMotd)
|
||||
return plugin.getCore().getTextCenterUtil().getCenteredText(text);
|
||||
return plugin.core().textCenterUtil().getCenteredText(text);
|
||||
|
||||
return text;
|
||||
})
|
||||
|
||||
+4
-1
@@ -29,7 +29,10 @@ import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.paper.objects.impl.PaperPlayerImpl;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@NullMarked
|
||||
public class PaperPlayerPlaceholders extends PlaceholderProvider{
|
||||
|
||||
public PaperPlayerPlaceholders(){
|
||||
@@ -37,7 +40,7 @@ public class PaperPlayerPlaceholders extends PlaceholderProvider{
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
|
||||
public @Nullable String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
|
||||
if(!(player instanceof PaperPlayerImpl paperPlayer))
|
||||
return null;
|
||||
|
||||
|
||||
Loaded 100 of 124 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user