mirror of
https://codeberg.org/Andre601/AdvancedServerList.git
synced 2026-11-05 17:02:34 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
323614d8c5 | ||
|
|
264dedca34 | ||
|
|
ce26decb7d | ||
|
|
37085e82f0 | ||
|
|
041430e842 | ||
|
|
6762cbc245 | ||
|
|
917d3640f0 | ||
|
|
0cece71f37 | ||
|
|
d9c9f30cea | ||
|
|
dcb119df96 | ||
|
|
78ae7fbcb2 | ||
|
|
1545aad32d | ||
|
|
035d485561 | ||
|
|
f34a1ad2e4 | ||
|
|
5ceef81927 | ||
|
|
6315f74312 | ||
|
|
086a45593b | ||
|
|
1095166155 | ||
|
|
bf89a7cb12 | ||
|
|
729b671c5a | ||
|
|
380791cd45 | ||
|
|
ca80083414 | ||
|
|
ee7fa16514 | ||
|
|
c86a3d4101 | ||
|
|
6fd6a8fe38 | ||
|
|
b05b38e0e8 | ||
|
|
d55298d61b | ||
|
|
37ccf7176c | ||
|
|
868c93ac09 | ||
|
|
f927e836f5 | ||
|
|
2172628985 | ||
|
|
628b1763da | ||
|
|
bbe5fea132 | ||
|
|
8b555a8f53 | ||
|
|
a5ca6fb53e | ||
|
|
164a4823e8 | ||
|
|
352191695a | ||
|
|
b2235e1d8b | ||
|
|
324b6d6f82 | ||
|
|
fd6e2e736f | ||
|
|
efd5164b8e | ||
|
|
cdb86ae83f | ||
|
|
90c02da02e | ||
|
|
53d56c5891 | ||
|
|
7dd02fa0e5 | ||
|
|
e02b944181 | ||
|
|
299eff1b0d | ||
|
|
aa24ab336b | ||
|
|
a8b9e69e30 | ||
|
|
065c9abf9c | ||
|
|
bdc9668b29 | ||
|
|
7d1abdd2b2 | ||
|
|
667c642708 | ||
|
|
79b13ceab6 | ||
|
|
169f560b2c | ||
|
|
7e8c41c27a | ||
|
|
973966c844 | ||
|
|
eee90cc02f | ||
|
|
ecf052b955 | ||
|
|
a791c86df0 | ||
|
|
63d0b0ac62 | ||
|
|
c46bc37818 | ||
|
|
268d5b84c9 | ||
|
|
0c63abfac8 | ||
|
|
35ca151424 | ||
|
|
e28800f72f | ||
|
|
8232357aba | ||
|
|
eae7f1117c | ||
|
|
d25053b285 | ||
|
|
57273bd265 | ||
|
|
9cf694a7d6 | ||
|
|
5bc0c7b843 | ||
|
|
1c48fd61bc | ||
|
|
8e622b4038 | ||
|
|
35e37bca2e | ||
|
|
cdb508994f | ||
|
|
1113c41379 | ||
|
|
d186ca82a2 | ||
|
|
5cda9e819b | ||
|
|
fe5a73440b | ||
|
|
a91e839f8c | ||
|
|
d4668e0e76 | ||
|
|
305f3452c4 | ||
|
|
fec3361fd7 | ||
|
|
f0861ffa6a | ||
|
|
cfca3f72dc | ||
|
|
aca83e8350 | ||
|
|
8383c8b97f | ||
|
|
3d1ddaa782 | ||
|
|
1d615e252f | ||
|
|
310e72d048 | ||
|
|
2754bf13aa | ||
|
|
9ff5fcdaa7 | ||
|
|
0ba7ed6ece | ||
|
|
2d8c774401 | ||
|
|
f68be63f64 | ||
|
|
2695b393d8 | ||
|
|
55821d2edf | ||
|
|
b64e32503e | ||
|
|
c5ab9b118f | ||
|
|
6cc54349b5 | ||
|
|
98d2de975e | ||
|
|
6d1c118660 | ||
|
|
49e5b195ec | ||
|
|
c92611e7f8 | ||
|
|
233414c45c | ||
|
|
c0629e10bc | ||
|
|
621eb7c489 | ||
|
|
38e16f1d4b | ||
|
|
2e61531079 | ||
|
|
5cf295d4c5 | ||
|
|
24d5865a57 | ||
|
|
03c5e7d9d0 | ||
|
|
7874fcf265 | ||
|
|
3e9070ebf9 | ||
|
|
478fa88a97 | ||
|
|
346f94decc | ||
|
|
f5e8a7e460 | ||
|
|
3cb470a086 | ||
|
|
348ecce315 | ||
|
|
78463bca4f | ||
|
|
a6bde40f30 | ||
|
|
45fa7b5d69 | ||
|
|
1f52ff39d1 | ||
|
|
bc66d925ff | ||
|
|
41f8f6b29d | ||
|
|
e032b2cc7f | ||
|
|
7c6d4a3840 | ||
|
|
2f2095237d | ||
|
|
2a20af1f9a | ||
|
|
c424c5abd5 | ||
|
|
101fc593d2 | ||
|
|
cb9e65105e | ||
|
|
9b95bb1222 | ||
|
|
2b01ed9725 | ||
|
|
9b77a1274d | ||
|
|
18d5cca185 | ||
|
|
d5b604c1d0 | ||
|
|
e9b4ccbb93 | ||
|
|
a14f8c961f | ||
|
|
ba311f42c4 | ||
|
|
1b5379d54b | ||
|
|
03a1908ca6 | ||
|
|
f9574d2f83 | ||
|
|
7e45439dfe | ||
|
|
2a8b4ed640 | ||
|
|
86c053e445 | ||
|
|
7eba04bb9a | ||
|
|
b4ac677f67 | ||
|
|
989d44cc5e | ||
|
|
9821875e7a | ||
|
|
07e3b6702b | ||
|
|
31889fbd9c | ||
|
|
87a089a0fa | ||
|
|
88b91e8859 | ||
|
|
f8097e3c72 | ||
|
|
e237c990d8 | ||
|
|
21c0ba975c | ||
|
|
642ce922c3 | ||
|
|
6e5466aacf | ||
|
|
e6635cd844 | ||
|
|
229ab60c57 | ||
|
|
483daee999 | ||
|
|
31ffcd7f7b | ||
|
|
e5139cc00d | ||
|
|
9b1b95b27a | ||
|
|
88d3ceeaf3 | ||
|
|
f74f2f337c | ||
|
|
87b35f240e | ||
|
|
fc861ea304 | ||
|
|
927971ca12 | ||
|
|
0ecb8383e3 | ||
|
|
9c3b2220d5 | ||
|
|
46e15441fd | ||
|
|
2d2a1ca805 | ||
|
|
c577264e1d | ||
|
|
27c3972ab0 | ||
|
|
e4c90730ba | ||
|
|
0694e08399 | ||
|
|
2fefa966dd | ||
|
|
a57cf3df17 | ||
|
|
1ae7260cf3 | ||
|
|
8459eee57d | ||
|
|
f5cebf42ab | ||
|
|
731bdeba7d | ||
|
|
d14cda243a | ||
|
|
0a98aad138 | ||
|
|
1249a08264 | ||
|
|
c0414a5962 | ||
|
|
9cc4d4bb36 | ||
|
|
338358a2ab | ||
|
|
805ba83bb6 | ||
|
|
0f646a8f8d | ||
|
|
2519f09f6f | ||
|
|
60bca9e3d7 | ||
|
|
da8f72fc50 | ||
|
|
c42d4b8967 | ||
|
|
0110854ae4 | ||
|
|
d6d5952cbc | ||
|
|
f9d961cae7 | ||
|
|
a387feea23 | ||
|
|
359c58163b | ||
|
|
0892f5cd1d | ||
|
|
452a7e6dcf | ||
|
|
162dd10a73 | ||
|
|
35120c5364 | ||
|
|
6c828171d2 | ||
|
|
dcc51f8458 | ||
|
|
1287ca62fe | ||
|
|
1ff439fa95 | ||
|
|
ed0f832b2f | ||
|
|
b8e6b2acc6 | ||
|
|
fba32c91c5 | ||
|
|
6505ded12b | ||
|
|
53088affcb | ||
|
|
9c030764fa | ||
|
|
d5d58f1eea | ||
|
|
7181092821 | ||
|
|
fc5ee4f242 | ||
|
|
6e74c4fb14 | ||
|
|
f6a27342e6 | ||
|
|
38b50df2c9 | ||
|
|
db93816e55 | ||
|
|
244c2440fc | ||
|
|
8e2c644669 | ||
|
|
a68809ab31 | ||
|
|
4b4fd80abe | ||
|
|
48ea128267 | ||
|
|
68e5795618 | ||
|
|
1aa20e4196 | ||
|
|
6db25c8f9c | ||
|
|
0ef3db752d | ||
|
|
1a26f5ad34 | ||
|
|
17a5574be7 | ||
|
|
c7bfb8a736 | ||
|
|
7a756c3b98 | ||
|
|
1539e1c3c0 | ||
|
|
a86872c021 | ||
|
|
7d12499f39 | ||
|
|
455434b5f3 | ||
|
|
b66251ab20 | ||
|
|
4a1dfa5cb4 | ||
|
|
1efd65e16c | ||
|
|
908da9cd32 | ||
|
|
e8a30c6ef7 | ||
|
|
df164c104f | ||
|
|
acdf6f6e9a | ||
|
|
f52a63a8f1 | ||
|
|
6a92cb3a16 | ||
|
|
1175451753 | ||
|
|
5c4130411b | ||
|
|
05727eeec5 | ||
|
|
10af949abc | ||
|
|
9851347e74 | ||
|
|
c3e01c8b9c | ||
|
|
a646d9e998 | ||
|
|
3c50a30d4a | ||
|
|
4328ad6b44 | ||
|
|
34b0555508 | ||
|
|
c92cd0058b | ||
|
|
2cfe8b8a27 | ||
|
|
6530fed704 | ||
|
|
7efb203e7b | ||
|
|
1a34376100 | ||
|
|
ec1aa5b393 | ||
|
|
9683d3c001 | ||
|
|
db60545fcc | ||
|
|
392495ef63 | ||
|
|
903764b234 | ||
|
|
72329ed1e4 | ||
|
|
c516b56053 | ||
|
|
5e4295fbfb | ||
|
|
b140c0aa32 | ||
|
|
8f7b293541 | ||
|
|
6f878164c5 | ||
|
|
a16801ff56 | ||
|
|
65a89cf762 | ||
|
|
27d4ada179 | ||
|
|
574edfb246 | ||
|
|
7b7aad9d4e | ||
|
|
c5c9ed8109 | ||
|
|
58fea4090d | ||
|
|
cd0aad6ec1 | ||
|
|
fa45844434 | ||
|
|
c4e2a144b5 | ||
|
|
7fe93c7021 | ||
|
|
1d413a5c2a | ||
|
|
51db52dbdd | ||
|
|
4ade528188 | ||
|
|
64ba48a7c7 | ||
|
|
ac4edb2b97 | ||
|
|
3ea000c98b | ||
|
|
746bef13e1 | ||
|
|
355ab73546 | ||
|
|
67170c70e0 | ||
|
|
f99c2df4e8 | ||
|
|
212ec04fb8 | ||
|
|
89c6089101 | ||
|
|
87bce39d9a | ||
|
|
18900547a0 |
No files matched your search
@@ -0,0 +1,37 @@
|
||||
name: Pull Request
|
||||
description: Create a new Pull request
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |-
|
||||
Thank you for creating a Pull request!
|
||||
|
||||
Please be sure to fill out this template with all requested information to ensure it being valid and not being closed unmerged.
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Type
|
||||
description: What kind of Pull request is this?
|
||||
options:
|
||||
- Enhancement
|
||||
- Bugfix
|
||||
- Documentation
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Breaking Change?
|
||||
description: |-
|
||||
Is this a breaking change?
|
||||
A breaking change means that it becomes incompatible with previous server/proxy versions or plugin versions.
|
||||
options:
|
||||
- Yes
|
||||
- No
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Description
|
||||
description: Provide a detailed description of what this Pull request is doing. Link any issues this Pull request may fix/close.
|
||||
validations:
|
||||
required: true
|
||||
@@ -1,8 +1,8 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Discord Server
|
||||
about: Ask questions about the plugin in the `#advancedserverlist` channel.
|
||||
url: https://discord.gg/6dazXp6
|
||||
about: Ask questions about the plugin in the `advancedserverlist` category of the M.O.S.S. Discord.
|
||||
url: https://discord.gg/MyPTjpsgGH
|
||||
- name: Wiki
|
||||
about: Check the Wiki for explanations about the features and examples.
|
||||
url: https://docs.andre601.ch/AdvancedServerList
|
||||
url: https://asl.andre601.ch
|
||||
@@ -80,7 +80,7 @@ Spanish Video by Ajneb97
|
||||
</a>
|
||||
|
||||
## Support
|
||||
<a href="https://discord.gg/6dazXp6" target="_blank">
|
||||
<a href="https://discord.gg/MyPTjpsgGH" target="_blank">
|
||||
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact-minimal/social/discord-singular_vector.svg&w=64" alt="discord" title="Join my Discord Server">
|
||||
</a>
|
||||
<a href="https://app.revolt.chat/invite/74TpERXA" target="_blank">
|
||||
|
||||
@@ -24,11 +24,11 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python 3.7
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.x
|
||||
- name: Create/Get Cache
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
key: ${{ github.ref }}
|
||||
path: .cache
|
||||
@@ -39,11 +39,11 @@ jobs:
|
||||
- name: Build docs
|
||||
run: mkdocs build
|
||||
- name: Configure GitHub Pages
|
||||
uses: actions/configure-pages@v3
|
||||
uses: actions/configure-pages@v5
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v2
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: 'site/'
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v2
|
||||
uses: actions/deploy-pages@v4
|
||||
@@ -0,0 +1,63 @@
|
||||
when:
|
||||
- event: pull_request
|
||||
path:
|
||||
include: ['.woodpecker/pr_preview.yml', 'requirements.txt', 'mkdocs.yml', 'docs/**']
|
||||
|
||||
variables:
|
||||
setup_git: &setup_git
|
||||
- apk add git
|
||||
- git config --global user.email "andre@andre601.ch"
|
||||
- git config --global user.name "ASL Docs Builder"
|
||||
|
||||
steps:
|
||||
cloneTargetRepo:
|
||||
image: alpine:3.18.4
|
||||
commands:
|
||||
- chmod -R a+w .
|
||||
- <<: *setup_git
|
||||
- git clone https://codeberg.org/Andre601/asl-docs.git site
|
||||
- chmod -R a+w site
|
||||
- cd site
|
||||
- git switch pr-${CI_COMMIT_PULL_REQUEST} 2>/dev/null || git switch -c pr-${CI_COMMIT_PULL_REQUEST}
|
||||
buildDocs:
|
||||
image: woodpeckerci/plugin-mkdocs:latest
|
||||
settings:
|
||||
pip_install_file: requirements.txt
|
||||
commitAndPush:
|
||||
image: alpine:3.18.4
|
||||
secrets:
|
||||
- bot_token
|
||||
commands:
|
||||
- <<: *setup_git
|
||||
- mv domains site/.domains
|
||||
- cd site
|
||||
- git remote add upstream https://$BOT_TOKEN@codeberg.org/Andre601/asl-docs.git
|
||||
- git add --all
|
||||
- git commit -m "Update Preview for PR ${CI_COMMIT_PULL_REQUEST} ($( env TZ=Europe/Zurich date +"%d.%m.%Y %Z" )) [SKIP CI]"
|
||||
- git push --set-upstream upstream pr-${CI_COMMIT_PULL_REQUEST} -f
|
||||
commentOnSuccess:
|
||||
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://asl.andre601.ch/@pr-${CI_COMMIT_PULL_REQUEST} |
|
||||
commentOnFailure:
|
||||
image: mcs94/gitea-comment
|
||||
when:
|
||||
- status: ['failure']
|
||||
settings:
|
||||
gitea_address: https://codeberg.org
|
||||
gitea_token:
|
||||
from_secret: BOT_TOKEN
|
||||
comment: |-
|
||||
Issue while creating Pull request preview.
|
||||
Please check the CI logs for any reasons: ${CI_PIPELINE_URL}
|
||||
@@ -4,14 +4,14 @@ when:
|
||||
|
||||
steps:
|
||||
createFiles:
|
||||
image: maven:3.9.5-eclipse-temurin-17
|
||||
image: maven:3.9.6-eclipse-temurin-17
|
||||
secrets:
|
||||
- source: cb_token
|
||||
target: codeberg_api_token
|
||||
- source: modrinth_api_token
|
||||
target: modrinth_api_token
|
||||
- source: hangar_api_token
|
||||
target: hangar_api_token
|
||||
- modrinth_api_token
|
||||
- hangar_api_token
|
||||
- discord_webhook_url
|
||||
environment:
|
||||
CODEBERG_API_TOKEN:
|
||||
from_secret: cb_token
|
||||
commands:
|
||||
# Create the jar files.
|
||||
- mvn clean install
|
||||
@@ -20,7 +20,7 @@ steps:
|
||||
- mv VersionUploader.jar ../../
|
||||
- cd ../../
|
||||
# Execute Jar file
|
||||
- java -jar VersionUploader.jar --modrinth
|
||||
- java -jar VersionUploader.jar --all
|
||||
uploadToCodeberg:
|
||||
image: woodpeckerci/plugin-gitea-release
|
||||
settings:
|
||||
@@ -29,5 +29,16 @@ steps:
|
||||
- "bungeecord/target/AdvancedServerList-*.jar"
|
||||
- "paper/target/AdvancedServerList-*.jar"
|
||||
- "velocity/target/AdvancedServerList-*.jar"
|
||||
- "addons/banplugins/target/AdvancedServerList-*.jar"
|
||||
api_key:
|
||||
from_secret: CB_TOKEN
|
||||
from_secret: cb_token
|
||||
postOnMastodon:
|
||||
image: woodpeckerci/plugin-mastodon-post
|
||||
when:
|
||||
- status: ['success']
|
||||
settings:
|
||||
server_url: https://blobfox.coffee
|
||||
access_token:
|
||||
from_secret: mastodon_token
|
||||
status: '${CI_COMMIT_TAG} of #AdvancedServerList has been released and can be found on Modrinth (https://modrinth.com/plugin/AdvancedServerList), Hangar (https://hangar.papermc.io/Andre_601/AdvancedServerList) and Codeberg (https://codeberg.org/Andre601/AdvancedServerList).'
|
||||
visibility: public
|
||||
@@ -1,8 +1,8 @@
|
||||
when:
|
||||
- branch: master
|
||||
- branch: '${CI_REPO_DEFAULT_BRANCH}'
|
||||
event: push
|
||||
path:
|
||||
include: ['requirements.txt', 'mkdocs.yml', 'docs/**']
|
||||
include: ['.woodpecker/publish_docs.yml', 'requirements.txt', 'mkdocs.yml', 'docs/**']
|
||||
|
||||
variables:
|
||||
setup_git: &setup_git
|
||||
@@ -16,7 +16,7 @@ steps:
|
||||
commands:
|
||||
- chmod -R a+w .
|
||||
- <<: *setup_git
|
||||
- git clone -b pages https://codeberg.org/Andre601/AdvancedServerList.git site
|
||||
- git clone -b pages https://codeberg.org/Andre601/asl-docs site
|
||||
- chmod -R a+w site
|
||||
buildDocs:
|
||||
image: woodpeckerci/plugin-mkdocs:latest
|
||||
@@ -25,12 +25,12 @@ steps:
|
||||
commitAndPush:
|
||||
image: alpine:3.18.4
|
||||
secrets:
|
||||
- cb_token
|
||||
- bot_token
|
||||
commands:
|
||||
- <<: *setup_git
|
||||
- mv domains site/.domains
|
||||
- cd site
|
||||
- git remote set-url origin https://$CB_TOKEN@codeberg.org/Andre601/AdvancedServerList.git
|
||||
- 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
|
||||
@@ -1,6 +1,6 @@
|
||||
# AdvancedServerList
|
||||
|
||||
AdvancedServerList is a plugin that allowys you to customize your server's MOTD, favicon, Player count text and player count hover displayed in a player's multiplayer server list based on conditions and priorities.
|
||||
AdvancedServerList is a plugin that allows you to customize your server's MOTD, favicon, Player count text and player count hover displayed in a player's multiplayer server list based on conditions and priorities.
|
||||
|
||||
## Downloads
|
||||
|
||||
@@ -8,11 +8,9 @@ AdvancedServerList is a plugin that allowys you to customize your server's MOTD,
|
||||
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact/available/modrinth_vector.svg" height="46" alt="modrinth" title="Available on Modrinth">
|
||||
</a>
|
||||
<br>
|
||||
<!--
|
||||
<a href="https://hangar.papermc.io/Andre_601/AdvancedServerList" target="_blank">
|
||||
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact/available/hangar_vector.svg" height="46" alt="hangar" title="Available on Hangar">
|
||||
</a>
|
||||
-->
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
@@ -30,29 +28,33 @@ AdvancedServerList is a plugin that allowys you to customize your server's MOTD,
|
||||
</a>
|
||||
|
||||
## What is a Server List Profile?
|
||||
|
||||
A Server List Profile refers to a YAML file located in the plugin's `profiles` directory.
|
||||
It allows you to configure specific aspects of the server display in the MC-Client's multiplayer server list, such as the MOTD, player count text, player count hover or Favicon.
|
||||
|
||||
> [*Read More*][profiles]
|
||||
|
||||
### Conditions
|
||||
Thanks to conditions can you determine when a profile should be displayed in the player’s server list, to allow displaying specific text (i.e. a warning when they are using an outdated version).
|
||||
|
||||
When multiple profiles exist that have valid conditions will the one with the highest priority (Higher number = higher priority) be selected. Having no conditions makes the profile automatically return true.
|
||||
Thanks to conditions can you determine when a profile should be displayed in the player's server list, to allow displaying specific text (i.e. a warning when they are using an outdated version).
|
||||
|
||||
When multiple profiles exist that have valid conditions will the one with the highest priority (Higher number = higher priority) be selected. Having no conditions makes it automatically true.
|
||||
|
||||
> [*Read More*][conditions]
|
||||
|
||||
### Placeholders
|
||||
|
||||
Placeholders can be used within conditions to further customize them. They can also be used in any other text option to display their respective values.
|
||||
The format is `${<target> <identifier>}` which was adopted from BungeeTabListPlus. Depending on what platform you use the plugin on are only specific placeholders available.
|
||||
|
||||
When using the SpigotMC/PaperMC version, or while PAPIProxyBridge is installed on your proxy, can you also use placeholders from [PlaceholderAPI][placeholderapi] using its `%<identifier>_<values>%` placeholder format. PlaceholderAPI needs to be installed for that.
|
||||
When using the SpigotMC/PaperMC version, or while [PAPIProxyBridge][papiproxybridge] is installed on your proxy, can you also use placeholders from [PlaceholderAPI][placeholderapi] using its `%<identifier>_<values>%` placeholder format. PlaceholderAPI needs to be installed on the server (not proxy) for that.
|
||||
|
||||
If you're a plugin dev can you even add your own custom placeholders through AdvancedServerList's own API.
|
||||
|
||||
> [*Read More*][placeholders]
|
||||
|
||||
### Formatting
|
||||
|
||||
The plugin uses the MiniMessage format for a consistent, easy way of formatting your text.
|
||||
Only certain options are usable for each option. As an example does motd support HEX colours and gradients, while the other options only support default colour codes.
|
||||
|
||||
@@ -86,7 +88,7 @@ You can disable this in the global bStats config file located in `/plugins/bstat
|
||||
|
||||
## Support
|
||||
|
||||
<a href="https://discord.gg/6dazXp6" target="_blank">
|
||||
<a href="https://discord.gg/MyPTjpsgGH" target="_blank">
|
||||
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact-minimal/social/discord-singular_vector.svg" height="64" alt="discord" title="Join my Discord Server">
|
||||
</a>
|
||||
<a href="https://app.revolt.chat/invite/74TpERXA" target="_blank">
|
||||
@@ -98,7 +100,7 @@ You can disable this in the global bStats config file located in `/plugins/bstat
|
||||
|
||||
<!-- Links -->
|
||||
[profiles]: https://asl.andre601.ch/profiles/
|
||||
[conditions]: https://asl.andre601.ch/profiles/#conditions
|
||||
[conditions]: https://asl.andre601.ch/profiles/#condition
|
||||
[placeholders]: https://asl.andre601.ch/profiles/placeholders/
|
||||
[minimessage]: https://asl.andre601.ch/profiles/formatting/
|
||||
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ MIT License
|
||||
~
|
||||
~ Copyright (c) 2022-2024 Andre_601
|
||||
~
|
||||
~ Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
~ of this software and associated documentation files (the "Software"), to deal
|
||||
~ in the Software without restriction, including without limitation the rights
|
||||
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
~ copies of the Software, and to permit persons to whom the Software is
|
||||
~ furnished to do so, subject to the following conditions:
|
||||
~
|
||||
~ The above copyright notice and this permission notice shall be included in all
|
||||
~ copies or substantial portions of the Software.
|
||||
~
|
||||
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
~ SOFTWARE.
|
||||
~
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>parent</artifactId>
|
||||
<groupId>ch.andre601.advancedserverlist</groupId>
|
||||
<version>parent</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>banplugins</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>${plugin.version}</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>16</maven.compiler.source>
|
||||
<maven.compiler.target>16</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>sonatype</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>papermc</id>
|
||||
<url>https://papermc.io/repo/repository/maven-public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>libertybans</id>
|
||||
<url>https://mvn-repo.arim.space/affero-gpl3/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<!-- Proxy/Server -->
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>1.20-R0.2</version>
|
||||
<type>jar</type>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>1.20-R0.2</version>
|
||||
<type>javadoc</type>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.papermc.paper</groupId>
|
||||
<artifactId>paper-api</artifactId>
|
||||
<version>1.20-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.velocitypowered</groupId>
|
||||
<artifactId>velocity-api</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Plugin APIs -->
|
||||
<dependency>
|
||||
<groupId>com.github.DevLeoko</groupId>
|
||||
<artifactId>AdvancedBan</artifactId>
|
||||
<version>v2.3.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>space.arim.libertybans</groupId>
|
||||
<artifactId>bans-api</artifactId>
|
||||
<version>1.1.0-RC1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.andre601.asl-api</groupId>
|
||||
<artifactId>api</artifactId>
|
||||
<version>${api.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>AdvancedServerList-BanPlugins-Addon-${plugin.version}</finalName>
|
||||
<resources>
|
||||
<resource>
|
||||
<filtering>true</filtering>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.13.0</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.banplugins.bungeecord;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.banplugins.placeholders.AdvancedBanPlaceholders;
|
||||
import ch.andre601.advancedserverlist.banplugins.placeholders.LibertyBansPlaceholders;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public enum BungeeCordBanPlugins{
|
||||
|
||||
ADVANCED_BAN("AdvancedBan", new AdvancedBanPlaceholders()),
|
||||
LIBERTY_BANS("LibertyBans", new LibertyBansPlaceholders());
|
||||
|
||||
private final String plugin;
|
||||
private final PlaceholderProvider placeholderProvider;
|
||||
|
||||
BungeeCordBanPlugins(String plugin, PlaceholderProvider placeholderProvider){
|
||||
this.plugin = plugin;
|
||||
this.placeholderProvider = placeholderProvider;
|
||||
}
|
||||
|
||||
public static Map<String, PlaceholderProvider> getBanPlugins(){
|
||||
Map<String, PlaceholderProvider> content = new HashMap<>();
|
||||
|
||||
for(BungeeCordBanPlugins bungeeCordBanPlugins : BungeeCordBanPlugins.values()){
|
||||
content.put(bungeeCordBanPlugins.plugin, bungeeCordBanPlugins.placeholderProvider);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.banplugins.bungeecord;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.AdvancedServerListAPI;
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class BungeeCordBanPluginsAddon extends Plugin{
|
||||
|
||||
@Override
|
||||
public void onEnable(){
|
||||
if(getProxy().getPluginManager().getPlugin("AdvancedServerList") == null){
|
||||
getLogger().warning("AdvancedServerList is not enabled. This plugin requires it to function!");
|
||||
return;
|
||||
}
|
||||
|
||||
int loadedPlaceholders = loadPlaceholderProviders();
|
||||
if(loadedPlaceholders == 0){
|
||||
getLogger().warning("No compatible Ban plugin was found to register placeholders for.");
|
||||
}else{
|
||||
getLogger().info("Loaded " + loadedPlaceholders + " Placeholder Set(s) for AdvancedServerList!");
|
||||
}
|
||||
}
|
||||
|
||||
private int loadPlaceholderProviders(){
|
||||
int loaded = 0;
|
||||
Map<String, PlaceholderProvider> banPlugins = BungeeCordBanPlugins.getBanPlugins();
|
||||
AdvancedServerListAPI api = AdvancedServerListAPI.get();
|
||||
|
||||
for(Map.Entry<String, PlaceholderProvider> entry : banPlugins.entrySet()){
|
||||
if(getProxy().getPluginManager().getPlugin(entry.getKey()) != null){
|
||||
getLogger().info("Registering Placeholders for " + entry.getKey() + "...");
|
||||
api.addPlaceholderProvider(entry.getValue());
|
||||
getLogger().info("Placeholder successfully registered!");
|
||||
|
||||
loaded++;
|
||||
}
|
||||
}
|
||||
|
||||
return loaded;
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.banplugins.paper;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.banplugins.placeholders.AdvancedBanPlaceholders;
|
||||
import ch.andre601.advancedserverlist.banplugins.placeholders.LibertyBansPlaceholders;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public enum PaperBanPlugins{
|
||||
|
||||
ADVANCED_BAN("AdvancedBan", new AdvancedBanPlaceholders()),
|
||||
LIBERTY_BANS("LibertyBans", new LibertyBansPlaceholders());
|
||||
|
||||
private final String plugin;
|
||||
private final PlaceholderProvider placeholderProvider;
|
||||
|
||||
PaperBanPlugins(String plugin, PlaceholderProvider placeholderProvider){
|
||||
this.plugin = plugin;
|
||||
this.placeholderProvider = placeholderProvider;
|
||||
}
|
||||
|
||||
public static Map<String, PlaceholderProvider> getBanPlugins(){
|
||||
Map<String, PlaceholderProvider> content = new HashMap<>();
|
||||
|
||||
for(PaperBanPlugins paperBanPlugins : PaperBanPlugins.values()){
|
||||
content.put(paperBanPlugins.plugin, paperBanPlugins.placeholderProvider);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.banplugins.paper;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.AdvancedServerListAPI;
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class PaperBanPluginsAddon extends JavaPlugin{
|
||||
|
||||
@Override
|
||||
public void onEnable(){
|
||||
if(!getServer().getPluginManager().isPluginEnabled("AdvancedServerList")){
|
||||
getLogger().warning("AdvancedServerList is not enabled. This plugin requires it to function!");
|
||||
getServer().getPluginManager().disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
|
||||
int loadedPlaceholders = loadPlaceholderProviders();
|
||||
if(loadedPlaceholders == 0){
|
||||
getLogger().warning("No compatible Ban plugin was found to register placeholders for. Disabling plugin...");
|
||||
|
||||
getServer().getPluginManager().disablePlugin(this);
|
||||
}else{
|
||||
getLogger().info("Loaded " + loadedPlaceholders + " Placeholder Set(s) for AdvancedServerList!");
|
||||
}
|
||||
}
|
||||
|
||||
private int loadPlaceholderProviders(){
|
||||
int loaded = 0;
|
||||
Map<String, PlaceholderProvider> banPlugins = PaperBanPlugins.getBanPlugins();
|
||||
AdvancedServerListAPI api = AdvancedServerListAPI.get();
|
||||
|
||||
for(Map.Entry<String, PlaceholderProvider> entry : banPlugins.entrySet()){
|
||||
if(getServer().getPluginManager().isPluginEnabled(entry.getKey())){
|
||||
getLogger().info("Registering Placeholders for " + entry.getKey() + "...");
|
||||
api.addPlaceholderProvider(entry.getValue());
|
||||
getLogger().info("Placeholder successfully registered!");
|
||||
|
||||
loaded++;
|
||||
}
|
||||
}
|
||||
|
||||
return loaded;
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.banplugins.placeholders;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.banplugins.providers.AdvancedBanProvider;
|
||||
|
||||
public class AdvancedBanPlaceholders extends PlaceholderProvider{
|
||||
|
||||
private final AdvancedBanProvider provider = new AdvancedBanProvider();
|
||||
|
||||
public AdvancedBanPlaceholders(){
|
||||
super("advancedban");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
|
||||
String[] args = placeholder.split("\\s", 2);
|
||||
|
||||
return switch(args[0]) {
|
||||
// Mute-related placeholders
|
||||
case "isMuted" -> String.valueOf(provider.muted(player));
|
||||
case "muteReason" -> provider.muteReason(player);
|
||||
case "muteDuration" -> {
|
||||
if(args.length == 1)
|
||||
yield provider.muteDuration(player);
|
||||
|
||||
boolean fromStart = Boolean.getBoolean(args[1]);
|
||||
yield provider.muteDuration(player, fromStart);
|
||||
}
|
||||
case "muteExpiration" -> {
|
||||
if(args.length == 1)
|
||||
yield provider.muteExpirationDate(player);
|
||||
|
||||
yield provider.banExpirationDate(player, args[1]);
|
||||
}
|
||||
|
||||
// Ban-related placeholders
|
||||
case "isBanned" -> String.valueOf(provider.banned(player));
|
||||
case "banReason" -> provider.banReason(player);
|
||||
case "banDuration" -> {
|
||||
if(args.length == 1)
|
||||
yield provider.banDuration(player);
|
||||
|
||||
boolean fromStart = Boolean.getBoolean(args[1]);
|
||||
yield provider.banDuration(player, fromStart);
|
||||
}
|
||||
case "banExpiration" -> {
|
||||
if(args.length == 1)
|
||||
yield provider.banExpirationDate(player);
|
||||
|
||||
yield provider.banExpirationDate(player, args[1]);
|
||||
}
|
||||
|
||||
// Unknown/Invalid placeholder.
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.banplugins.placeholders;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.banplugins.providers.LibertyBansProvider;
|
||||
|
||||
public class LibertyBansPlaceholders extends PlaceholderProvider{
|
||||
|
||||
private final LibertyBansProvider provider = LibertyBansProvider.create();
|
||||
|
||||
public LibertyBansPlaceholders(){
|
||||
super("libertybans");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
|
||||
String[] args = placeholder.split("\\s", 2);
|
||||
|
||||
return switch(args[0]){
|
||||
// Mute-related placeholders
|
||||
case "isMuted" -> String.valueOf(provider.muted(player));
|
||||
case "muteReason" -> provider.muteReason(player);
|
||||
case "muteExpiration" -> {
|
||||
if(args.length == 1)
|
||||
yield provider.muteExpirationDate(player);
|
||||
|
||||
yield provider.muteExpirationDate(player, args[1]);
|
||||
}
|
||||
|
||||
// Ban-related placeholders
|
||||
case "isBanned" -> String.valueOf(provider.banned(player));
|
||||
case "banReason" -> provider.banReason(player);
|
||||
case "banExpiration" -> {
|
||||
if(args.length == 1)
|
||||
yield provider.banExpirationDate(player);
|
||||
|
||||
yield provider.banExpirationDate(player, args[1]);
|
||||
}
|
||||
|
||||
// Unknown/Invalid placeholder
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
}
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.banplugins.providers;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.primitives.UnsignedLongs;
|
||||
import me.leoko.advancedban.manager.PunishmentManager;
|
||||
import me.leoko.advancedban.utils.Punishment;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
public class AdvancedBanProvider implements PunishmentProvider{
|
||||
|
||||
private static PunishmentManager getAPI(){
|
||||
return PunishmentManager.get();
|
||||
}
|
||||
|
||||
private static String noDashesUUID(UUID uuid){
|
||||
return hexString(uuid.getMostSignificantBits()) + hexString(uuid.getLeastSignificantBits());
|
||||
}
|
||||
|
||||
private static Punishment mute(GenericPlayer player){
|
||||
return getAPI().getMute(noDashesUUID(player.getUUID()));
|
||||
}
|
||||
|
||||
private static Punishment ban(GenericPlayer player){
|
||||
return getAPI().getBan(noDashesUUID(player.getUUID()));
|
||||
}
|
||||
|
||||
private static String hexString(long unsigned){
|
||||
return Strings.padStart(UnsignedLongs.toString(unsigned, 16), 16, '0');
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean muted(GenericPlayer player){
|
||||
return getAPI().isMuted(noDashesUUID(player.getUUID()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean banned(GenericPlayer player){
|
||||
return getAPI().isBanned(noDashesUUID(player.getUUID()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String muteReason(GenericPlayer player){
|
||||
Punishment mute = mute(player);
|
||||
if(mute == null)
|
||||
return null;
|
||||
|
||||
return mute.getReason();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String banReason(GenericPlayer player){
|
||||
Punishment ban = ban(player);
|
||||
if(ban == null)
|
||||
return null;
|
||||
|
||||
return ban.getReason();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String muteDuration(GenericPlayer player){
|
||||
return muteDuration(player, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String banDuration(GenericPlayer player){
|
||||
return banDuration(player, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String muteExpirationDate(GenericPlayer player, String pattern){
|
||||
Punishment mute = mute(player);
|
||||
if(mute == null)
|
||||
return null;
|
||||
|
||||
long end = mute.getEnd();
|
||||
if(end < 0L)
|
||||
return "never";
|
||||
|
||||
return this.returnDate(pattern, end);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String banExpirationDate(GenericPlayer player, String pattern){
|
||||
Punishment ban = ban(player);
|
||||
if(ban == null)
|
||||
return null;
|
||||
|
||||
long end = ban.getEnd();
|
||||
if(end < 0L)
|
||||
return "never";
|
||||
|
||||
return this.returnDate(pattern, end);
|
||||
}
|
||||
|
||||
public String muteDuration(GenericPlayer player, boolean fromStart){
|
||||
Punishment mute = mute(player);
|
||||
if(mute == null)
|
||||
return null;
|
||||
|
||||
return mute.getDuration(fromStart);
|
||||
}
|
||||
|
||||
public String banDuration(GenericPlayer player, boolean fromStart){
|
||||
Punishment ban = ban(player);
|
||||
if(ban == null)
|
||||
return null;
|
||||
|
||||
return ban.getDuration(fromStart);
|
||||
}
|
||||
}
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.banplugins.providers;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import space.arim.libertybans.api.LibertyBans;
|
||||
import space.arim.libertybans.api.PunishmentType;
|
||||
import space.arim.libertybans.api.punish.Punishment;
|
||||
import space.arim.libertybans.api.user.KnownAccount;
|
||||
import space.arim.omnibus.Omnibus;
|
||||
import space.arim.omnibus.OmnibusProvider;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class LibertyBansProvider implements PunishmentProvider{
|
||||
private final LibertyBans libertyBans;
|
||||
|
||||
private LibertyBansProvider(LibertyBans libertyBans){
|
||||
this.libertyBans = libertyBans;
|
||||
}
|
||||
|
||||
public static LibertyBansProvider create(){
|
||||
Omnibus omnibus = OmnibusProvider.getOmnibus();
|
||||
LibertyBans libertyBans = omnibus.getRegistry().getProvider(LibertyBans.class).orElseThrow();
|
||||
|
||||
return new LibertyBansProvider(libertyBans);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean muted(GenericPlayer player){
|
||||
return punishment(player.getUUID(), PunishmentType.MUTE) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean banned(GenericPlayer player){
|
||||
return punishment(player.getUUID(), PunishmentType.BAN) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String muteReason(GenericPlayer player){
|
||||
Punishment mute = punishment(player.getUUID(), PunishmentType.MUTE);
|
||||
if(mute == null)
|
||||
return null;
|
||||
|
||||
return mute.getReason();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String banReason(GenericPlayer player){
|
||||
Punishment ban = punishment(player.getUUID(), PunishmentType.BAN);
|
||||
if(ban == null)
|
||||
return null;
|
||||
|
||||
return ban.getReason();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String muteDuration(GenericPlayer player){
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String banDuration(GenericPlayer player){
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String muteExpirationDate(GenericPlayer player, String pattern){
|
||||
Punishment mute = punishment(player.getUUID(), PunishmentType.MUTE);
|
||||
if(mute == null)
|
||||
return null;
|
||||
|
||||
if(mute.isPermanent())
|
||||
return "never";
|
||||
|
||||
return this.returnDate(pattern, mute.getEndDate().toEpochMilli());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String banExpirationDate(GenericPlayer player, String pattern){
|
||||
Punishment ban = punishment(player.getUUID(), PunishmentType.BAN);
|
||||
if(ban == null)
|
||||
return null;
|
||||
|
||||
if(ban.isPermanent())
|
||||
return "never";
|
||||
|
||||
return this.returnDate(pattern, ban.getEndDate().toEpochMilli());
|
||||
}
|
||||
|
||||
private Punishment punishment(UUID uuid, PunishmentType type){
|
||||
List<? extends KnownAccount> accounts = libertyBans.getAccountSupervisor()
|
||||
.findAccountsMatching(uuid)
|
||||
.join();
|
||||
|
||||
if(accounts.isEmpty())
|
||||
return null;
|
||||
|
||||
KnownAccount sorted = Collections.max(accounts, Comparator.comparing(KnownAccount::recorded));
|
||||
|
||||
return libertyBans.getSelector()
|
||||
.selectionByApplicabilityBuilder(sorted.uuid(), sorted.address())
|
||||
.type(type)
|
||||
.build()
|
||||
.getFirstSpecificPunishment()
|
||||
.toCompletableFuture()
|
||||
.join()
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.banplugins.providers;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
public interface PunishmentProvider{
|
||||
|
||||
boolean muted(GenericPlayer player);
|
||||
|
||||
boolean banned(GenericPlayer player);
|
||||
|
||||
String muteReason(GenericPlayer player);
|
||||
|
||||
String banReason(GenericPlayer player);
|
||||
|
||||
String muteDuration(GenericPlayer player);
|
||||
|
||||
String banDuration(GenericPlayer player);
|
||||
|
||||
default String muteExpirationDate(GenericPlayer player){
|
||||
return muteExpirationDate(player, "dd, MMM yyyy HH:mm:ss");
|
||||
}
|
||||
|
||||
String muteExpirationDate(GenericPlayer player, String pattern);
|
||||
|
||||
default String banExpirationDate(GenericPlayer player){
|
||||
return banExpirationDate(player, "dd, MMM yyyy HH:mm:ss");
|
||||
}
|
||||
|
||||
String banExpirationDate(GenericPlayer player, String pattern);
|
||||
|
||||
default String returnDate(String pattern, long end){
|
||||
Date date = new Date(end);
|
||||
try{
|
||||
return new SimpleDateFormat(pattern).format(date);
|
||||
}catch(IllegalArgumentException ex){
|
||||
return new SimpleDateFormat("dd, MMM yyyy HH:mm:ss").format(date);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.banplugins.velocity;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.banplugins.paper.PaperBanPlugins;
|
||||
import ch.andre601.advancedserverlist.banplugins.placeholders.LibertyBansPlaceholders;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public enum VelocityBanPlugins{
|
||||
|
||||
LIBERTY_BANS("libertybans", new LibertyBansPlaceholders());
|
||||
|
||||
private final String plugin;
|
||||
private final PlaceholderProvider placeholderProvider;
|
||||
|
||||
VelocityBanPlugins(String plugin, PlaceholderProvider placeholderProvider){
|
||||
this.plugin = plugin;
|
||||
this.placeholderProvider = placeholderProvider;
|
||||
}
|
||||
|
||||
public static Map<String, PlaceholderProvider> getBanPlugins(){
|
||||
Map<String, PlaceholderProvider> content = new HashMap<>();
|
||||
|
||||
for(VelocityBanPlugins velocityBanPlugins : VelocityBanPlugins.values()){
|
||||
content.put(velocityBanPlugins.plugin, velocityBanPlugins.placeholderProvider);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.banplugins.velocity;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.AdvancedServerListAPI;
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import com.google.inject.Inject;
|
||||
import com.velocitypowered.api.event.Subscribe;
|
||||
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class VelocityBanPluginsAddon{
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger("ASLBanPluginsAddon");
|
||||
|
||||
private final ProxyServer proxy;
|
||||
|
||||
@Inject
|
||||
public VelocityBanPluginsAddon(ProxyServer proxy){
|
||||
this.proxy = proxy;
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void init(ProxyInitializeEvent event){
|
||||
if(proxy.getPluginManager().getPlugin("advancedserverlist") == null){
|
||||
logger.warn("AdvancedServerList is not enabled. This plugin requires it to function!");
|
||||
return;
|
||||
}
|
||||
|
||||
int loadedPlaceholders = loadPlaceholderProviders();
|
||||
if(loadedPlaceholders == 0){
|
||||
logger.warn("No compatible Ban plugin was found to register placeholders for.");
|
||||
}else{
|
||||
logger.info("Loaded {} Placeholder Set(s) for AdvancedServerList!", loadedPlaceholders);
|
||||
}
|
||||
}
|
||||
|
||||
private int loadPlaceholderProviders(){
|
||||
int loaded = 0;
|
||||
Map<String, PlaceholderProvider> banPlugins = VelocityBanPlugins.getBanPlugins();
|
||||
AdvancedServerListAPI api = AdvancedServerListAPI.get();
|
||||
|
||||
for(Map.Entry<String, PlaceholderProvider> entry : banPlugins.entrySet()){
|
||||
if(proxy.getPluginManager().getPlugin(entry.getKey()) != null){
|
||||
logger.info("Registering placeholders for {}...", entry.getKey());
|
||||
api.addPlaceholderProvider(entry.getValue());
|
||||
logger.info("Placeholder successfully registered!");
|
||||
|
||||
loaded++;
|
||||
}
|
||||
}
|
||||
|
||||
return loaded;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
name: 'ASLBanPluginsAddon'
|
||||
author: 'Andre_601'
|
||||
version: '${plugin.version}'
|
||||
description: 'AdvancedBan Add-on for AdvancedServerList to add placeholders to use.'
|
||||
|
||||
softDepends:
|
||||
- AdvancedServerList
|
||||
- AdvancedBan
|
||||
- LibertyBans
|
||||
|
||||
main: 'ch.andre601.advancedserverlist.banplugins.bungeecord.BungeeCordBanPluginsAddon'
|
||||
@@ -0,0 +1,19 @@
|
||||
name: 'ASLBanPluginsAddon'
|
||||
author: 'Andre_601'
|
||||
version: '${plugin.version}'
|
||||
|
||||
main: 'ch.andre601.advancedserverlist.banplugins.paper.AdvancedBanPlaceholders'
|
||||
|
||||
api-version: '1.19'
|
||||
|
||||
dependencies:
|
||||
server:
|
||||
AdvancedServerList:
|
||||
required: false
|
||||
load: BEFORE
|
||||
AdvancedBans:
|
||||
required: false
|
||||
load: BEFORE
|
||||
LibertyBans:
|
||||
required: false
|
||||
load: BEFORE
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"id": "aslbanpluginsaddon",
|
||||
"name": "ASLBanPluginsAddon",
|
||||
"version": "${plugin.version}",
|
||||
"description": "${plugin.description}",
|
||||
"authors": [
|
||||
"Andre_601"
|
||||
],
|
||||
"dependencies": [
|
||||
{
|
||||
"id": "advancedserverlist",
|
||||
"optional": true
|
||||
},
|
||||
{
|
||||
"id": "libertybans",
|
||||
"optional": true
|
||||
}
|
||||
],
|
||||
"main": "ch.andre601.advancedserverlist.banplugins.velocity.VelocityBanPluginsAddon"
|
||||
}
|
||||
+22
-15
@@ -64,55 +64,65 @@
|
||||
<version>${api.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- BungeeCord API -->
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>1.20-R0.1</version>
|
||||
<version>1.20-R0.2</version>
|
||||
<type>jar</type>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>1.20-R0.1</version>
|
||||
<version>1.20-R0.2</version>
|
||||
<type>javadoc</type>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Adventure Library. Needs to be shaded in -->
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-api</artifactId>
|
||||
<version>4.14.0</version>
|
||||
<version>4.16.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-text-minimessage</artifactId>
|
||||
<version>4.14.0</version>
|
||||
<version>4.16.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-platform-bungeecord</artifactId>
|
||||
<version>4.3.1</version>
|
||||
<version>4.3.2</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Metrics -->
|
||||
<dependency>
|
||||
<groupId>org.bstats</groupId>
|
||||
<artifactId>bstats-bungeecord</artifactId>
|
||||
<version>3.0.2</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Configurate -->
|
||||
<dependency>
|
||||
<groupId>org.spongepowered</groupId>
|
||||
<artifactId>configurate-yaml</artifactId>
|
||||
<version>4.1.2</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Plugins -->
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>4.12.0</version>
|
||||
<scope>compile</scope>
|
||||
<groupId>com.github.LeonMangler</groupId>
|
||||
<artifactId>PremiumVanishAPI</artifactId>
|
||||
<version>2.9.0-4</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@@ -128,12 +138,12 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.11.0</version>
|
||||
<version>3.13.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<version>3.5.2</version>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<relocations>
|
||||
@@ -149,16 +159,13 @@
|
||||
<pattern>org.bstats</pattern>
|
||||
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.bstats</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>okhttp3</pattern>
|
||||
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.okhttp3</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>
|
||||
|
||||
+39
-5
@@ -29,28 +29,37 @@ import ch.andre601.advancedserverlist.bungeecord.commands.CmdAdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.bungeecord.listeners.JoinEvent;
|
||||
import ch.andre601.advancedserverlist.bungeecord.listeners.PingEvent;
|
||||
import ch.andre601.advancedserverlist.bungeecord.logging.BungeeLogger;
|
||||
import ch.andre601.advancedserverlist.bungeecord.objects.BungeePlayerPlaceholders;
|
||||
import ch.andre601.advancedserverlist.bungeecord.objects.BungeeServerPlaceholders;
|
||||
import ch.andre601.advancedserverlist.bungeecord.objects.placeholders.BungeePlayerPlaceholders;
|
||||
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.core.PluginCore;
|
||||
import ch.andre601.advancedserverlist.core.profiles.favicon.FaviconHandler;
|
||||
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.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 java.awt.image.BufferedImage;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
|
||||
|
||||
private AdvancedServerList<Favicon> core;
|
||||
private FaviconHandler<Favicon> faviconHandler = null;
|
||||
private final PluginLogger logger = new BungeeLogger(getLogger());
|
||||
private BungeeAudiences audiences = null;
|
||||
private final PluginLogger logger = new BungeeLogger(this);
|
||||
|
||||
@Override
|
||||
public void onEnable(){
|
||||
this.core = AdvancedServerList.init(this, BungeePlayerPlaceholders.init(), BungeeServerPlaceholders.init());
|
||||
this.audiences = BungeeAudiences.create(this);
|
||||
this.core = AdvancedServerList.init(this, BungeePlayerPlaceholders.init(), BungeeServerPlaceholders.init(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -77,12 +86,17 @@ public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadFaviconHandler(AdvancedServerList<Favicon> core){
|
||||
faviconHandler = new FaviconHandler<>(core);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearFaviconCache(){
|
||||
if(faviconHandler == null)
|
||||
return;
|
||||
|
||||
faviconHandler.clearCache();
|
||||
faviconHandler.cleanCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -122,4 +136,24 @@ public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
|
||||
public String getLoader(){
|
||||
return "bungeecord";
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
return players.size();
|
||||
}
|
||||
}
|
||||
+1
-3
@@ -33,16 +33,14 @@ import net.md_5.bungee.api.plugin.Command;
|
||||
public class CmdAdvancedServerList extends Command{
|
||||
|
||||
private final BungeeCordCore plugin;
|
||||
private final BungeeAudiences audiences;
|
||||
|
||||
public CmdAdvancedServerList(BungeeCordCore plugin){
|
||||
super("advancedserverlist", "advancedserverlist.command.asl", "asl");
|
||||
this.plugin = plugin;
|
||||
this.audiences = BungeeAudiences.create(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender, String[] args){
|
||||
plugin.getCore().getCommandHandler().handle(new BungeeCmdSender(sender, audiences), args);
|
||||
plugin.getCore().getCommandHandler().handle(new BungeeCmdSender(sender, plugin.getAudiences()), args);
|
||||
}
|
||||
}
|
||||
+5
-11
@@ -25,12 +25,12 @@
|
||||
|
||||
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.BungeePlayerImpl;
|
||||
import ch.andre601.advancedserverlist.api.events.GenericServerListEvent;
|
||||
import ch.andre601.advancedserverlist.bungeecord.objects.BungeeProxyImpl;
|
||||
import ch.andre601.advancedserverlist.bungeecord.objects.impl.BungeePlayerImpl;
|
||||
import ch.andre601.advancedserverlist.bungeecord.objects.impl.BungeeProxyImpl;
|
||||
import ch.andre601.advancedserverlist.core.events.PingEventHandler;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.events.GenericEventWrapper;
|
||||
@@ -46,7 +46,6 @@ import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.ProxyPingEvent;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -143,12 +142,12 @@ public class BungeeEventWrapper implements GenericEventWrapper<Favicon, BungeePl
|
||||
|
||||
@Override
|
||||
public int getProtocolVersion(){
|
||||
return this.protocol.getProtocol();
|
||||
return event.getConnection().getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOnlinePlayers(){
|
||||
return ping.getPlayers().getOnline();
|
||||
return plugin.getOnlinePlayers(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -205,9 +204,4 @@ public class BungeeEventWrapper implements GenericEventWrapper<Favicon, BungeePl
|
||||
|
||||
return new BungeeProxyImpl(servers, playersOnline, playersMax, host);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Favicon createFavicon(BufferedImage image) throws IllegalArgumentException{
|
||||
return Favicon.create(image);
|
||||
}
|
||||
}
|
||||
+10
-1
@@ -26,6 +26,7 @@
|
||||
package ch.andre601.advancedserverlist.bungeecord.listeners;
|
||||
|
||||
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
|
||||
import ch.andre601.advancedserverlist.bungeecord.commands.BungeeCmdSender;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.PostLoginEvent;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
@@ -34,7 +35,6 @@ import net.md_5.bungee.event.EventHandler;
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
public class JoinEvent implements Listener{
|
||||
|
||||
private final BungeeCordCore plugin;
|
||||
|
||||
public JoinEvent(BungeeCordCore plugin){
|
||||
@@ -48,5 +48,14 @@ public class JoinEvent implements Listener{
|
||||
ProxiedPlayer player = event.getPlayer();
|
||||
|
||||
plugin.getCore().getPlayerHandler().addPlayer(address.getHostString(), player.getName(), player.getUniqueId());
|
||||
|
||||
if(player.hasPermission("advancedserverlist.admin") || player.hasPermission("advancedserverlist.updatecheck")){
|
||||
if(plugin.getAudiences() == null || plugin.getCore().getUpdateChecker() == null)
|
||||
return;
|
||||
|
||||
BungeeCmdSender sender = new BungeeCmdSender(player, plugin.getAudiences());
|
||||
|
||||
plugin.getCore().getUpdateChecker().performeCachedUpdateCheck(sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-3
@@ -25,12 +25,13 @@
|
||||
|
||||
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;
|
||||
import net.md_5.bungee.event.EventPriority;
|
||||
|
||||
public class PingEvent implements Listener{
|
||||
|
||||
@@ -41,8 +42,10 @@ public class PingEvent implements Listener{
|
||||
plugin.getProxy().getPluginManager().registerListener(plugin, this);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOW)
|
||||
@EventHandler(priority = 90) // Maintenance has Event Priority 80, so we need to be AFTER it.
|
||||
public void onProxyPing(ProxyPingEvent event){
|
||||
PingEventHandler.handleEvent(new BungeeEventWrapper(plugin, event));
|
||||
ProfileEntry entry = PingEventHandler.handleEvent(new BungeeEventWrapper(plugin, event));
|
||||
|
||||
plugin.getProxy().getPluginManager().callEvent(new PostServerListSetEvent(entry));
|
||||
}
|
||||
}
|
||||
+17
-2
@@ -25,6 +25,7 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.bungeecord.logging;
|
||||
|
||||
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
|
||||
import java.util.logging.Level;
|
||||
@@ -32,10 +33,24 @@ import java.util.logging.Logger;
|
||||
|
||||
public class BungeeLogger implements PluginLogger{
|
||||
|
||||
private final BungeeCordCore plugin;
|
||||
private final Logger logger;
|
||||
|
||||
public BungeeLogger(Logger logger){
|
||||
this.logger = logger;
|
||||
public BungeeLogger(BungeeCordCore plugin){
|
||||
this.plugin = plugin;
|
||||
this.logger = plugin.getLogger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Class<?> clazz, String msg, Object... args){
|
||||
if(plugin.isDebugEnabled())
|
||||
info("[DEBUG] [" + clazz.getSimpleName() + "] " + msg, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debugWarn(Class<?> clazz, String msg, Object... args){
|
||||
if(plugin.isDebugEnabled())
|
||||
warn("[DEBUG] [" + clazz.getSimpleName() + "] " + msg, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+4
-4
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -23,7 +23,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.bungeecord.objects;
|
||||
package ch.andre601.advancedserverlist.bungeecord.objects.impl;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.players.GenericPlayerImpl;
|
||||
@@ -31,8 +31,8 @@ import ch.andre601.advancedserverlist.core.profiles.players.GenericPlayerImpl;
|
||||
public class BungeePlayerImpl extends GenericPlayerImpl{
|
||||
|
||||
public BungeePlayerImpl(CachedPlayer player, int protocol){
|
||||
this.name = player.getName();
|
||||
this.name = player.name();
|
||||
this.protocol = protocol;
|
||||
this.uuid = player.getUuid();
|
||||
this.uuid = player.uuid();
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -23,7 +23,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.bungeecord.objects;
|
||||
package ch.andre601.advancedserverlist.bungeecord.objects.impl;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.bungeecord.objects.BungeeProxy;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -23,7 +23,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.bungeecord.objects;
|
||||
package ch.andre601.advancedserverlist.bungeecord.objects.placeholders;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
+13
-7
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -23,24 +23,28 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.bungeecord.objects;
|
||||
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 BungeeServerPlaceholders(){
|
||||
private final BungeeCordCore plugin;
|
||||
|
||||
private BungeeServerPlaceholders(BungeeCordCore plugin){
|
||||
super("server");
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public static BungeeServerPlaceholders init(){
|
||||
return new BungeeServerPlaceholders();
|
||||
public static BungeeServerPlaceholders init(BungeeCordCore plugin){
|
||||
return new BungeeServerPlaceholders(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -60,11 +64,11 @@ public class BungeeServerPlaceholders extends PlaceholderProvider{
|
||||
if(serverName.isEmpty())
|
||||
continue;
|
||||
|
||||
ServerInfo info = proxy.getServers().get(serverName);
|
||||
ServerInfo info = proxy.getServers().get(serverName.strip());
|
||||
if(info == null)
|
||||
continue;
|
||||
|
||||
players += info.getPlayers().size();
|
||||
players += plugin.getOnlinePlayers(info);
|
||||
}
|
||||
|
||||
yield String.valueOf(players);
|
||||
@@ -85,6 +89,8 @@ public class BungeeServerPlaceholders extends PlaceholderProvider{
|
||||
|
||||
if(args.length == 2){
|
||||
ServerInfo info = proxy.getServers().get(args[1]);
|
||||
if(info == null)
|
||||
yield null;
|
||||
|
||||
yield String.valueOf(((InetSocketAddress)info.getSocketAddress()).getHostString());
|
||||
}
|
||||
+32
-16
@@ -41,6 +41,7 @@
|
||||
<properties>
|
||||
<maven.compiler.source>16</maven.compiler.source>
|
||||
<maven.compiler.target>16</maven.compiler.target>
|
||||
<plugin.config.version>5</plugin.config.version>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
@@ -56,6 +57,10 @@
|
||||
<id>sonatype</id>
|
||||
<url>https://s01.oss.sonatype.org/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>codeberg</id>
|
||||
<url>https://codeberg.org/api/packages/Andre601/maven/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
@@ -65,42 +70,46 @@
|
||||
<version>${api.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.andre601</groupId>
|
||||
<artifactId>expressionparser</artifactId>
|
||||
<version>1.3.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spongepowered</groupId>
|
||||
<artifactId>configurate-yaml</artifactId>
|
||||
<version>4.1.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- MiniMessage -->
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-api</artifactId>
|
||||
<version>4.14.0</version>
|
||||
<version>4.16.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-text-minimessage</artifactId>
|
||||
<version>4.14.0</version>
|
||||
<version>4.16.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-text-serializer-legacy</artifactId>
|
||||
<version>4.14.0</version>
|
||||
<version>4.16.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Misc -->
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.10.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>4.12.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.unascribed</groupId>
|
||||
<artifactId>flexver-java</artifactId>
|
||||
@@ -110,13 +119,15 @@
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>32.1.3-jre</version>
|
||||
<version>33.1.0-jre</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Plugins -->
|
||||
<dependency>
|
||||
<groupId>net.william278</groupId>
|
||||
<artifactId>papiproxybridge</artifactId>
|
||||
<version>1.4.2</version>
|
||||
<version>1.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -128,9 +139,9 @@
|
||||
|
||||
<!-- Test dependencies -->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.13.2</version>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>5.10.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
@@ -147,12 +158,12 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.11.0</version>
|
||||
<version>3.13.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<version>3.5.2</version>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<filters>
|
||||
@@ -160,6 +171,7 @@
|
||||
<artifact>*:*</artifact>
|
||||
<excludes>
|
||||
<exclude>META-INF/*.SF</exclude>
|
||||
<exclude>META-INF/*.DSA</exclude>
|
||||
<exclude>META-INF/*.RSA</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
@@ -169,6 +181,10 @@
|
||||
<pattern>com.unascribed</pattern>
|
||||
<shadedPattern>ch.andre601.advancedserverlist.core.depends.flexver</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>ch.andre601.expressionparser</pattern>
|
||||
<shadedPattern>ch.andre601.advancedserverlist.core.depends.expressionparser</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
<executions>
|
||||
|
||||
@@ -31,11 +31,11 @@ import ch.andre601.advancedserverlist.core.check.UpdateChecker;
|
||||
import ch.andre601.advancedserverlist.core.commands.CommandHandler;
|
||||
import ch.andre601.advancedserverlist.core.file.FileHandler;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.ProfileConditionParser;
|
||||
import ch.andre601.advancedserverlist.core.profiles.players.PlayerHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
@@ -46,7 +46,8 @@ public class AdvancedServerList<F>{
|
||||
private final FileHandler fileHandler;
|
||||
private final CommandHandler commandHandler;
|
||||
private final PlayerHandler playerHandler;
|
||||
private final AdvancedServerListAPI api = AdvancedServerListAPI.get();
|
||||
private static final AdvancedServerListAPI api = AdvancedServerListAPI.get();
|
||||
private final ProfileConditionParser parser = ProfileConditionParser.create();
|
||||
|
||||
private UpdateChecker updateChecker;
|
||||
|
||||
@@ -58,7 +59,7 @@ public class AdvancedServerList<F>{
|
||||
this.commandHandler = new CommandHandler(this);
|
||||
this.playerHandler = new PlayerHandler(this);
|
||||
|
||||
placeholders.forEach(this.api::addPlaceholderProvider);
|
||||
placeholders.forEach(AdvancedServerList.getApi()::addPlaceholderProvider);
|
||||
|
||||
load();
|
||||
}
|
||||
@@ -87,10 +88,18 @@ public class AdvancedServerList<F>{
|
||||
return version;
|
||||
}
|
||||
|
||||
public AdvancedServerListAPI getApi(){
|
||||
public static AdvancedServerListAPI getApi(){
|
||||
return api;
|
||||
}
|
||||
|
||||
public ProfileConditionParser getParser(){
|
||||
return parser;
|
||||
}
|
||||
|
||||
public UpdateChecker getUpdateChecker(){
|
||||
return updateChecker;
|
||||
}
|
||||
|
||||
public void disable(){
|
||||
getPlugin().getPluginLogger().info("Saving playercache.json file...");
|
||||
getPlayerHandler().save();
|
||||
@@ -136,15 +145,13 @@ public class AdvancedServerList<F>{
|
||||
}
|
||||
|
||||
if(getFileHandler().loadProfiles()){
|
||||
getPlugin().getPluginLogger().info("Successfully loaded " + getFileHandler().getProfiles().size() + " profiles!");
|
||||
getPlugin().getPluginLogger().info("Successfully loaded %d profile(s)!", getFileHandler().getProfiles().size());
|
||||
}else{
|
||||
getPlugin().getPluginLogger().warn("Unable to load profiles! Check previous lines for errors.");
|
||||
return;
|
||||
}
|
||||
|
||||
Path folder = getPlugin().getFolderPath().resolve("favicons");
|
||||
if(!folder.toFile().exists() && folder.toFile().mkdirs())
|
||||
getPlugin().getPluginLogger().info("Successfully created favicons folder.");
|
||||
getPlugin().loadFaviconHandler(this);
|
||||
|
||||
getPlugin().getPluginLogger().info("Loading Commands...");
|
||||
plugin.loadCommands();
|
||||
|
||||
@@ -27,21 +27,21 @@ package ch.andre601.advancedserverlist.core.check;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
|
||||
import com.google.gson.FieldNamingPolicy;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.unascribed.flexver.FlexVerComparator;
|
||||
import io.leangen.geantyref.TypeToken;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
@@ -49,12 +49,10 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class UpdateChecker{
|
||||
|
||||
private final String url = "https://api.modrinth.com/v2/project/advancedserverlist/version?loaders=[\"%s\"]";
|
||||
private final OkHttpClient client = new OkHttpClient();
|
||||
|
||||
private final AdvancedServerList<?> core;
|
||||
private final PluginLogger logger;
|
||||
private final String loader;
|
||||
@SuppressWarnings("FieldCanBeLocal")
|
||||
// 'https://api.modrinth.com/v2/project/advancedserverlist/version?loaders=["%s"]' URL encoded.
|
||||
private final String url = "https://api.modrinth.com/v2/project/advancedserverlist/version?loaders=%%5B%%22%s%%22%%5D";
|
||||
private final HttpClient client = HttpClient.newHttpClient();
|
||||
|
||||
private final Type listType = new TypeToken<ArrayList<ModrinthVersion>>(){}.getType();
|
||||
private final Gson gson = new GsonBuilder()
|
||||
@@ -65,6 +63,12 @@ public class UpdateChecker{
|
||||
|
||||
private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(new UpdateCheckThread());
|
||||
|
||||
private final VersionCache cache = new VersionCache();
|
||||
|
||||
private final AdvancedServerList<?> core;
|
||||
private final PluginLogger logger;
|
||||
private final String loader;
|
||||
|
||||
public UpdateChecker(AdvancedServerList<?> core){
|
||||
this.core = core;
|
||||
this.logger = core.getPlugin().getPluginLogger();
|
||||
@@ -73,42 +77,38 @@ public class UpdateChecker{
|
||||
startUpdateChecker();
|
||||
}
|
||||
|
||||
public void startUpdateChecker(){
|
||||
executor.scheduleAtFixedRate(() -> {
|
||||
logger.info("Checking for a new update...");
|
||||
checkUpdate().whenComplete((version, throwable) -> {
|
||||
if(version == null || throwable != null){
|
||||
logger.warn("Failed to look for any updates. See previous messages for reasons.");
|
||||
return;
|
||||
}
|
||||
public void performeCachedUpdateCheck(CmdSender sender){
|
||||
ModrinthVersion version = cache.get(() -> {
|
||||
try{
|
||||
return performUpdateCheck().join();
|
||||
}catch(Exception ex){
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
int result = version.compare(core.getVersion());
|
||||
switch(result){
|
||||
case -1 -> printUpdateBanner(version.getVersionNumber(), version.getId(), version.isRelease());
|
||||
case 0 -> logger.info("No new update found. You're running the latest version!");
|
||||
case 1 -> logger.info(
|
||||
"Your version (%s) is higher than the latest release (%s). Are you running a dev build?",
|
||||
core.getVersion(), version.getVersionNumber()
|
||||
);
|
||||
}
|
||||
});
|
||||
}, 0L, 12L, TimeUnit.HOURS);
|
||||
if(version == null)
|
||||
return;
|
||||
|
||||
int result = version.compare(core.getVersion());
|
||||
if(result == -1){
|
||||
sender.sendPrefixedMsg("<green>A new version of AdvancedServerList is available!");
|
||||
sender.sendPrefixedMsg("<green>Your version: <white>%s", core.getVersion());
|
||||
sender.sendPrefixedMsg("<green>Modrinth: <white>%s", version.versionNumber());
|
||||
sender.sendPrefixedMsg("<click:open_url:'https://modrinth.com/plugin/advancedserverlist/version/%s'><green>[<white>Download Page</white>]</click>", version.id());
|
||||
}else
|
||||
if(result == 1){
|
||||
sender.sendPrefixedMsg("Your version (<white>%s</white>) seems newer than the latest release on Modrinth (<white>%s</white>)", core.getVersion(), version.versionNumber);
|
||||
sender.sendPrefixedMsg("Are you running a dev-build?");
|
||||
}
|
||||
}
|
||||
|
||||
public void disable(){
|
||||
executor.shutdown();
|
||||
client.dispatcher().executorService().shutdown();
|
||||
try{
|
||||
if(!executor.awaitTermination(1, TimeUnit.SECONDS)){
|
||||
executor.shutdownNow();
|
||||
if(!executor.awaitTermination(1, TimeUnit.SECONDS))
|
||||
logger.warn("Scheduler didn't terminate in time!");
|
||||
}
|
||||
|
||||
if(!client.dispatcher().executorService().awaitTermination(1, TimeUnit.SECONDS)){
|
||||
client.dispatcher().executorService().shutdownNow();
|
||||
if(!client.dispatcher().executorService().awaitTermination(1, TimeUnit.SECONDS))
|
||||
logger.warn("OkHttp's Scheduler didn't terminate in time!");
|
||||
logger.warn("Scheduler did not terminate in time!");
|
||||
}
|
||||
}catch(InterruptedException ex){
|
||||
executor.shutdownNow();
|
||||
@@ -116,108 +116,93 @@ public class UpdateChecker{
|
||||
}
|
||||
}
|
||||
|
||||
private CompletableFuture<ModrinthVersion> checkUpdate(){
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
PluginLogger logger = core.getPlugin().getPluginLogger();
|
||||
if(core.getVersion().equals("UNKNOWN")){
|
||||
logger.warn("Cannot perform Update check! Plugin version couldn't be parsed.");
|
||||
return null;
|
||||
}
|
||||
private void startUpdateChecker(){
|
||||
executor.scheduleAtFixedRate(() -> {
|
||||
logger.info("Looking for an update...");
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.url(String.format(url, loader))
|
||||
performUpdateCheck().whenComplete((version, throwable) -> {
|
||||
if(version == null || throwable != null){
|
||||
logger.warn("Failed to look for any updates. Check previous messages for causes.");
|
||||
return;
|
||||
}
|
||||
|
||||
logger.debug(UpdateChecker.class, "Comparing versions...");
|
||||
|
||||
int result = version.compare(core.getVersion());
|
||||
switch(result){
|
||||
case -1 -> printUpdateBanner(version);
|
||||
case 0 -> logger.info("You are running the latest version!");
|
||||
case 1 -> logger.info(
|
||||
"Your version (%s) seems to be newer than the latest release (%s). Are you running a dev build?",
|
||||
core.getVersion(), version.versionNumber()
|
||||
);
|
||||
}
|
||||
});
|
||||
}, 0L, 12L, TimeUnit.HOURS);
|
||||
}
|
||||
|
||||
private CompletableFuture<ModrinthVersion> performUpdateCheck(){
|
||||
String finalUrl = String.format(url, loader);
|
||||
|
||||
logger.debug(UpdateChecker.class, "Checking '%s' for updates...", finalUrl);
|
||||
|
||||
if(core.getVersion().equals("UNKNOWN")){
|
||||
logger.warn("Cannot perform update check. Plugin version is 'UNKNOWN'!");
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
HttpRequest request;
|
||||
try{
|
||||
request = HttpRequest.newBuilder()
|
||||
.uri(new URI(finalUrl))
|
||||
.header("User-Agent", "AdvancedServerList-" + loader + "/" + core.getVersion())
|
||||
.build();
|
||||
|
||||
try(Response response = client.newCall(request).execute()){
|
||||
if(!response.isSuccessful()){
|
||||
logger.warn("Encountered a non-successful response from Modrinth! Code: %d", response.code());
|
||||
return null;
|
||||
}
|
||||
|
||||
ResponseBody body = response.body();
|
||||
if(body == null){
|
||||
logger.warn("Received an empty Response body from Modrinth!");
|
||||
return null;
|
||||
}
|
||||
|
||||
String responseString = body.string();
|
||||
if(responseString.isEmpty()){
|
||||
logger.warn("Received an empty Response body from Modrinth!");
|
||||
return null;
|
||||
}
|
||||
|
||||
List<ModrinthVersion> list = gson.fromJson(responseString, listType);
|
||||
if(list == null || list.isEmpty()){
|
||||
logger.warn("Couldn't convert JSON Array into a valid list.");
|
||||
return null;
|
||||
}
|
||||
|
||||
ModrinthVersion version = list.get(0);
|
||||
|
||||
if(version.getVersionNumber() == null || version.getVersionNumber().isEmpty()){
|
||||
logger.warn("Cannot check latest version. Received version number was null/empty.");
|
||||
return null;
|
||||
}
|
||||
|
||||
return version;
|
||||
}catch(JsonSyntaxException ex){
|
||||
logger.warn("Encountered invalid JSON from Response body!", ex);
|
||||
}catch(URISyntaxException ex){
|
||||
logger.warn("Cannot perform update check. URL '%s' is not a valid URI.", ex, finalUrl);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
return client.sendAsync(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8))
|
||||
.thenApply(response -> new ArrayList<ModrinthVersion>(gson.fromJson(response.body(), listType)))
|
||||
.thenApply(list -> list.get(0))
|
||||
.exceptionally((throwable) -> {
|
||||
logger.warn("Encountered exception while performing update check!", throwable);
|
||||
return null;
|
||||
}catch(IOException ex){
|
||||
logger.warn("Encountered Exception while checking for an update!", ex);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void printUpdateBanner(String version, String versionId, boolean isRelease){
|
||||
logger.info("==================================================================");
|
||||
logger.info("You are running an outdated version of AdvancedServerList!");
|
||||
logger.info("");
|
||||
logger.info("Your version: %s", core.getVersion());
|
||||
logger.info("Modrinth version: %s", version);
|
||||
logger.info("");
|
||||
private void printUpdateBanner(ModrinthVersion version){
|
||||
logger.warn("==================================================================");
|
||||
logger.warn("You are running an outdated version of AdvancedServerList!");
|
||||
logger.warn("");
|
||||
logger.warn("Your version: %s", core.getVersion());
|
||||
logger.warn("Modrinth: %s", version.versionNumber());
|
||||
logger.warn("");
|
||||
|
||||
if(!isRelease){
|
||||
logger.info("WARNING: This release is an Alpha/Beta! It may contain");
|
||||
logger.info(" breaking changes!");
|
||||
logger.info("");
|
||||
if(!version.isRelease()){
|
||||
logger.warn("WARNING!");
|
||||
logger.warn("This is a %s version and may contain breaking changes and/or bugs!", version.versionType());
|
||||
logger.warn("");
|
||||
}
|
||||
|
||||
logger.info("You can download the latest release from here:");
|
||||
logger.info("https://modrinth.com/plugin/advancedserverlist/version/%s", versionId);
|
||||
logger.info("==================================================================");
|
||||
logger.warn("Download the latest version from here:");
|
||||
logger.warn("https://modrinth.com/plugin/advancedserverlist/version/%s", version.id());
|
||||
logger.warn("==================================================================");
|
||||
}
|
||||
|
||||
public static class ModrinthVersion{
|
||||
@SuppressWarnings("FieldMayBeFinal")
|
||||
private String id;
|
||||
@SuppressWarnings("FieldMayBeFinal")
|
||||
private String versionNumber;
|
||||
@SuppressWarnings("FieldMayBeFinal")
|
||||
private String versionType;
|
||||
|
||||
public ModrinthVersion(String id, String versionNumber, String versionType){
|
||||
this.id = id;
|
||||
this.versionNumber = versionNumber;
|
||||
this.versionType = versionType;
|
||||
}
|
||||
|
||||
public String getId(){
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getVersionNumber(){
|
||||
return versionNumber;
|
||||
}
|
||||
public record ModrinthVersion(String id, String versionNumber, String versionType){
|
||||
|
||||
public boolean isRelease(){
|
||||
return versionType.equals("release");
|
||||
return versionType().equals("release");
|
||||
}
|
||||
|
||||
public int compare(String version){
|
||||
return FlexVerComparator.compare(version, versionNumber);
|
||||
return FlexVerComparator.compare(version, versionNumber());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
return String.format("ModrinthVersion{id=%s,versionNumber=%s,versionType=%s}", id, versionNumber, versionType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.check;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class VersionCache{
|
||||
|
||||
private CachedValue cachedValue = null;
|
||||
|
||||
public VersionCache(){}
|
||||
|
||||
public UpdateChecker.ModrinthVersion get(Supplier<UpdateChecker.ModrinthVersion> supplier){
|
||||
if(cachedValue == null || cachedValue.hasExpired())
|
||||
cachedValue = new CachedValue(System.currentTimeMillis(), supplier.get());
|
||||
|
||||
return cachedValue.version();
|
||||
}
|
||||
|
||||
private record CachedValue(long timestamp, UpdateChecker.ModrinthVersion version){
|
||||
public boolean hasExpired(){
|
||||
return (timestamp < 0L) || System.currentTimeMillis() - timestamp >= 300_000L;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,10 @@ package ch.andre601.advancedserverlist.core.compat.papi;
|
||||
|
||||
import net.william278.papiproxybridge.api.PlaceholderAPI;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
|
||||
+68
-28
@@ -30,9 +30,10 @@ import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.core.compat.maintenance.MaintenanceUtil;
|
||||
import ch.andre601.advancedserverlist.core.compat.papi.PAPIUtil;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.events.GenericEventWrapper;
|
||||
import ch.andre601.advancedserverlist.core.compat.papi.PAPIUtil;
|
||||
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
|
||||
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
|
||||
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileManager;
|
||||
@@ -43,12 +44,18 @@ public class PingEventHandler{
|
||||
private static PAPIUtil papiUtil = null;
|
||||
private static MaintenanceUtil maintenanceUtil = null;
|
||||
|
||||
public static <F, P extends GenericPlayer> void handleEvent(GenericEventWrapper<F, P> event){
|
||||
if(event.isInvalidProtocol() || event.isMaintenanceModeActive())
|
||||
return;
|
||||
public static <F, P extends GenericPlayer> ProfileEntry handleEvent(GenericEventWrapper<F, P> event){
|
||||
event.getPlugin().getPluginLogger().debug(PingEventHandler.class, "Received ping event. Handling it...");
|
||||
if(event.isInvalidProtocol()){
|
||||
event.getPlugin().getPluginLogger().debug(PingEventHandler.class, "Not handling event. Protocol was invalid.");
|
||||
return null;
|
||||
}
|
||||
|
||||
PluginCore<F> plugin = event.getPlugin();
|
||||
String host = event.getVirtualHost();
|
||||
PluginLogger logger = plugin.getPluginLogger();
|
||||
|
||||
logger.debug(PingEventHandler.class, "Protocol valid. Continue handling...");
|
||||
|
||||
int online = event.getOnlinePlayers();
|
||||
int max = event.getMaxPlayers();
|
||||
@@ -61,32 +68,50 @@ public class PingEventHandler{
|
||||
|
||||
ServerListProfile profile = ProfileManager.resolveProfile(plugin.getCore(), player, server);
|
||||
|
||||
if(profile == null)
|
||||
return;
|
||||
if(profile == null){
|
||||
logger.debugWarn(PingEventHandler.class, "Server List Profile couldn't be resolved properly. Cancelling event handling...");
|
||||
return null;
|
||||
}
|
||||
|
||||
logger.debug(PingEventHandler.class, "Received valid Server List Profile. Calling PreServerListSetEvent...");
|
||||
|
||||
GenericServerListEvent e = event.callEvent(ProfileManager.merge(profile));
|
||||
if(e == null || e.isCancelled())
|
||||
return;
|
||||
if(e == null || e.isCancelled()){
|
||||
logger.debug(PingEventHandler.class, "PreServerListSetEvent was cancelled. Stopping ping handling...");
|
||||
return null;
|
||||
}
|
||||
|
||||
logger.debug(PingEventHandler.class, "PreServerListSetEvent completed. Proceeding with ping handling...");
|
||||
|
||||
ProfileEntry entry = e.getEntry();
|
||||
if(entry.isInvalid())
|
||||
return;
|
||||
if(entry.isInvalid()){
|
||||
logger.debugWarn(PingEventHandler.class, "No valid ProfileEntry retrieved. Cancelling ping handling...");
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean extraPlayers = ProfileManager.checkOption(entry.extraPlayersEnabled());
|
||||
|
||||
if(extraPlayers){
|
||||
if(extraPlayers && ignoreMaintenance(event, "extraPlayers")){
|
||||
max = online + (entry.extraPlayersCount() == null ? 0 : entry.extraPlayersCount());
|
||||
|
||||
logger.debug(PingEventHandler.class, "Extra Players enabled. Applying '%d' as max player count...", max);
|
||||
|
||||
event.setMaxPlayers(max);
|
||||
}
|
||||
|
||||
if(ProfileManager.checkOption(entry.maxPlayersEnabled()) && !extraPlayers){
|
||||
if(ProfileManager.checkOption(entry.maxPlayersEnabled()) && !extraPlayers && ignoreMaintenance(event, "maxPlayers")){
|
||||
max = (entry.maxPlayersCount() == null) ? 0 : entry.maxPlayersCount();
|
||||
|
||||
logger.debug(PingEventHandler.class, "Max Players enabled. Applying '%d' as max player count...", max);
|
||||
|
||||
event.setMaxPlayers(max);
|
||||
}
|
||||
|
||||
GenericServer finalServer = event.createGenericServer(online, max, host);
|
||||
|
||||
if(ProfileManager.checkOption(entry.motd())){
|
||||
if(ProfileManager.checkOption(entry.motd()) && ignoreMaintenance(event, "motd")){
|
||||
logger.debug(PingEventHandler.class, "MOTD set. Applying '%s'...", String.join("\\n", entry.motd()));
|
||||
|
||||
event.setMotd(
|
||||
ComponentParser.list(entry.motd())
|
||||
.modifyText(text -> StringReplacer.replace(text, player, finalServer))
|
||||
@@ -97,11 +122,15 @@ public class PingEventHandler{
|
||||
|
||||
boolean hidePlayers = ProfileManager.checkOption(entry.hidePlayersEnabled());
|
||||
|
||||
if(hidePlayers){
|
||||
if(hidePlayers && ignoreMaintenance(event, "hidePlayers")){
|
||||
logger.debug(PingEventHandler.class, "Hide Players enabled. Hiding player count...");
|
||||
|
||||
event.hidePlayers();
|
||||
}
|
||||
|
||||
if(ProfileManager.checkOption(entry.playerCountText()) && !hidePlayers){
|
||||
if(ProfileManager.checkOption(entry.playerCountText()) && !hidePlayers && ignoreMaintenance(event, "playerCountText")){
|
||||
logger.debug(PingEventHandler.class, "Player Count Text set. Applying '%s'...", entry.playerCountText());
|
||||
|
||||
event.setPlayerCount(
|
||||
ComponentParser.text(entry.playerCountText())
|
||||
.modifyText(text -> StringReplacer.replace(text, player, finalServer))
|
||||
@@ -110,30 +139,34 @@ public class PingEventHandler{
|
||||
);
|
||||
}
|
||||
|
||||
if(ProfileManager.checkOption(entry.players()) && !hidePlayers){
|
||||
if(ProfileManager.checkOption(entry.players()) && !hidePlayers && ignoreMaintenance(event, "playerCountHover")){
|
||||
logger.debug(PingEventHandler.class, "Player Count Hover set. Applying '%s'...", String.join("\\n", entry.players()));
|
||||
|
||||
event.setPlayers(entry.players(), player, server);
|
||||
}
|
||||
|
||||
if(ProfileManager.checkOption(entry.favicon())){
|
||||
String favicon = StringReplacer.replace(entry.favicon(), player, server);
|
||||
if(ProfileManager.checkOption(entry.favicon()) && ignoreMaintenance(event, "favicon")){
|
||||
logger.debug(PingEventHandler.class, "Favicon set. Resolving '%s'...", entry.favicon());
|
||||
|
||||
F fav = plugin.getFaviconHandler().getFavicon(favicon, image -> {
|
||||
try{
|
||||
return event.createFavicon(image);
|
||||
}catch(Exception ex){
|
||||
plugin.getPluginLogger().warn("Encountered an Exception while creating Favicon!", ex);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
String faviconString = StringReplacer.replace(entry.favicon(), player, server);
|
||||
|
||||
if(fav == null){
|
||||
F favicon = plugin.getFaviconHandler().getFavicon(faviconString);
|
||||
|
||||
if(favicon == null){
|
||||
logger.debugWarn(PingEventHandler.class, "Favicon was invalid or not yet resolved! Using default favicon of Server/Proxy...");
|
||||
|
||||
event.setDefaultFavicon();
|
||||
}else{
|
||||
event.setFavicon(fav);
|
||||
logger.debug(PingEventHandler.class, "Applying favicon...");
|
||||
|
||||
event.setFavicon(favicon);
|
||||
}
|
||||
}
|
||||
|
||||
logger.debug(PingEventHandler.class, "Event handling completed. Updating Ping data...");
|
||||
event.updateEvent();
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
public static PAPIUtil getPAPIUtil(){
|
||||
@@ -149,4 +182,11 @@ public class PingEventHandler{
|
||||
|
||||
return (maintenanceUtil = new MaintenanceUtil());
|
||||
}
|
||||
|
||||
private static <F, P extends GenericPlayer> boolean ignoreMaintenance(GenericEventWrapper<F, P> event, String option){
|
||||
if(!event.isMaintenanceModeActive())
|
||||
return true;
|
||||
|
||||
return !event.getPlugin().getCore().getFileHandler().getBool(true, "disableDuringMaintenance", option);
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.core.file;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import org.spongepowered.configurate.ConfigurateException;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
@@ -32,16 +33,59 @@ import org.spongepowered.configurate.NodePath;
|
||||
import org.spongepowered.configurate.transformation.ConfigurationTransformation;
|
||||
import org.spongepowered.configurate.transformation.TransformAction;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
|
||||
public class ConfigMigrator{
|
||||
|
||||
public static final int LATEST = 1;
|
||||
public static final int LATEST = resolveConfigVersion();
|
||||
|
||||
private ConfigMigrator(){}
|
||||
|
||||
public static ConfigurationTransformation.Versioned create(){
|
||||
return ConfigurationTransformation.versionedBuilder()
|
||||
.versionKey("configVersion")
|
||||
.addVersion(LATEST, oneToTwo())
|
||||
.addVersion(LATEST, fourToFive())
|
||||
.addVersion(4, threeToFour())
|
||||
.addVersion(3, twoToThree())
|
||||
.addVersion(2, oneToTwo())
|
||||
.build();
|
||||
}
|
||||
|
||||
public static ConfigurationTransformation fourToFive(){
|
||||
return ConfigurationTransformation.builder()
|
||||
.addAction(NodePath.path(), (path, value) -> {
|
||||
value.node("disableDuringMaintenance", "motd").set(true);
|
||||
value.node("disableDuringMaintenance", "favicon").set(true);
|
||||
value.node("disableDuringMaintenance", "hidePlayers").set(true);
|
||||
value.node("disableDuringMaintenance", "playerCountText").set(true);
|
||||
value.node("disableDuringMaintenance", "playerCountHover").set(true);
|
||||
value.node("disableDuringMaintenance", "extraPlayers").set(true);
|
||||
value.node("disableDuringMaintenance", "maxPlayers").set(true);
|
||||
|
||||
return null;
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
public static ConfigurationTransformation threeToFour(){
|
||||
return ConfigurationTransformation.builder()
|
||||
.addAction(NodePath.path(), (path, value) -> {
|
||||
value.node("faviconCacheTime").set(1);
|
||||
|
||||
return null;
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
public static ConfigurationTransformation twoToThree(){
|
||||
return ConfigurationTransformation.builder()
|
||||
.addAction(NodePath.path(), (path, value) -> {
|
||||
value.node("debug").set(false);
|
||||
|
||||
return null;
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -67,9 +111,21 @@ public class ConfigMigrator{
|
||||
versioned.apply(node);
|
||||
final int endVersion = versioned.version(node);
|
||||
if(startVersion < endVersion)
|
||||
logger.info("Migrated config.yml from " + startVersion + " to " + endVersion);
|
||||
logger.info("Migrated config.yml from v" + startVersion + " to v" + endVersion);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
private static int resolveConfigVersion(){
|
||||
try(InputStream is = AdvancedServerList.class.getResourceAsStream("/version.properties")){
|
||||
Properties properties = new Properties();
|
||||
|
||||
properties.load(is);
|
||||
|
||||
return Integer.parseInt(properties.getProperty("config-version"));
|
||||
}catch(IOException | NumberFormatException ex){
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,10 +25,10 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.core.file;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileSerializer;
|
||||
import org.spongepowered.configurate.ConfigurateException;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
@@ -157,7 +157,7 @@ public class FileHandler{
|
||||
continue;
|
||||
|
||||
profiles.add(ServerListProfile.Builder.resolve(file.getName(), tmp, logger).build());
|
||||
logger.info("Loaded " + file.getName());
|
||||
logger.info("Loaded '%s'!", file.getName());
|
||||
}
|
||||
|
||||
if(profiles.isEmpty()){
|
||||
@@ -165,7 +165,7 @@ public class FileHandler{
|
||||
return false;
|
||||
}
|
||||
|
||||
profiles.sort(Comparator.comparing(ServerListProfile::getPriority).reversed());
|
||||
profiles.sort(Comparator.comparing(ServerListProfile::priority).reversed());
|
||||
return !profiles.isEmpty();
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ public class FileHandler{
|
||||
try{
|
||||
return loader.load();
|
||||
}catch(IOException ex){
|
||||
logger.warn("Cannot load " + path.toFile().getName() + " due to an IOException!", ex);
|
||||
logger.warn("Cannot load '%s' due to an IOException!", ex, path.toFile().getName());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -187,8 +187,17 @@ public class FileHandler{
|
||||
return node.node(path).getString(def);
|
||||
}
|
||||
|
||||
public boolean getBool(boolean def, Object... path){
|
||||
return node.node(path).getBoolean(def);
|
||||
}
|
||||
|
||||
public boolean getBoolean(Object... path){
|
||||
return node.node(path).getBoolean();
|
||||
return getBool(false, path);
|
||||
}
|
||||
|
||||
public long getLong(long def, long limit, Object... path){
|
||||
long value = node.node(path).getLong(def);
|
||||
return Math.max(value, limit);
|
||||
}
|
||||
|
||||
public boolean isOldConfig(){
|
||||
@@ -214,7 +223,7 @@ public class FileHandler{
|
||||
}
|
||||
|
||||
Files.copy(config, configBackup.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
logger.info("Saved backup as '" + configBackup.getName() + "'!");
|
||||
logger.info("Saved backup as '%s'!", configBackup.getName());
|
||||
|
||||
return true;
|
||||
}catch(IOException ex){
|
||||
|
||||
@@ -27,6 +27,10 @@ package ch.andre601.advancedserverlist.core.interfaces;
|
||||
|
||||
public interface PluginLogger{
|
||||
|
||||
void debug(Class<?> clazz, String msg, Object... args);
|
||||
|
||||
void debugWarn(Class<?> clazz, String msg, Object... args);
|
||||
|
||||
void info(String msg, Object... args);
|
||||
|
||||
void warn(String msg, Object... args);
|
||||
|
||||
+12
@@ -29,6 +29,7 @@ import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import ch.andre601.advancedserverlist.core.profiles.favicon.FaviconHandler;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public interface PluginCore<F>{
|
||||
@@ -39,6 +40,8 @@ public interface PluginCore<F>{
|
||||
|
||||
void loadMetrics();
|
||||
|
||||
void loadFaviconHandler(AdvancedServerList<F> core);
|
||||
|
||||
void clearFaviconCache();
|
||||
|
||||
AdvancedServerList<F> getCore();
|
||||
@@ -54,4 +57,13 @@ public interface PluginCore<F>{
|
||||
String getPlatformVersion();
|
||||
|
||||
String getLoader();
|
||||
|
||||
F createFavicon(BufferedImage image) throws Exception;
|
||||
|
||||
default boolean isDebugEnabled(){
|
||||
if(getCore() == null)
|
||||
return false;
|
||||
|
||||
return getCore().getFileHandler().getBoolean("debug");
|
||||
}
|
||||
}
|
||||
+1
-4
@@ -25,15 +25,14 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.core.interfaces.events;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.events.GenericServerListEvent;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.api.events.GenericServerListEvent;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
|
||||
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.List;
|
||||
|
||||
@@ -79,8 +78,6 @@ public interface GenericEventWrapper<F, P extends GenericPlayer>{
|
||||
|
||||
GenericServer createGenericServer(int playersOnline, int playersMax, String host);
|
||||
|
||||
F createFavicon(BufferedImage image) throws Exception;
|
||||
|
||||
default String resolveHost(InetSocketAddress address){
|
||||
return address == null ? null : address.getHostString();
|
||||
}
|
||||
|
||||
@@ -27,28 +27,4 @@ package ch.andre601.advancedserverlist.core.objects;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@SuppressWarnings("FieldMayBeFinal")
|
||||
public class CachedPlayer{
|
||||
|
||||
private String ip;
|
||||
private String name;
|
||||
private UUID uuid;
|
||||
|
||||
public CachedPlayer(String ip, String name, UUID uuid){
|
||||
this.ip = ip;
|
||||
this.name = name;
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public String getIp(){
|
||||
return ip;
|
||||
}
|
||||
|
||||
public String getName(){
|
||||
return name;
|
||||
}
|
||||
|
||||
public UUID getUuid(){
|
||||
return uuid;
|
||||
}
|
||||
}
|
||||
public record CachedPlayer(String ip, String name, UUID uuid){}
|
||||
+34
-59
@@ -29,7 +29,9 @@ import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.Expression;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.ProfileConditionParser;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
import ch.andre601.expressionparser.templates.ExpressionTemplate;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
@@ -37,38 +39,32 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public class ServerListProfile{
|
||||
public record ServerListProfile(int priority, String condition, ProfileEntry defaultProfile, List<ProfileEntry> profiles, String file){
|
||||
private static final Random random = new Random();
|
||||
|
||||
private final int priority;
|
||||
private final List<Expression> expressions;
|
||||
private final ProfileEntry defaultProfile;
|
||||
|
||||
private final List<ProfileEntry> profiles;
|
||||
|
||||
private final Random random = new Random();
|
||||
|
||||
public ServerListProfile(int priority, List<Expression> expressions, ProfileEntry defaultProfile, List<ProfileEntry> profiles){
|
||||
this.priority = priority;
|
||||
this.expressions = expressions;
|
||||
this.defaultProfile = defaultProfile;
|
||||
|
||||
this.profiles = profiles;
|
||||
}
|
||||
|
||||
public int getPriority(){
|
||||
return priority;
|
||||
}
|
||||
|
||||
public boolean evalConditions(GenericPlayer player, GenericServer server){
|
||||
if(expressions.isEmpty())
|
||||
public boolean evalConditions(ProfileConditionParser parser, PluginLogger logger, GenericPlayer player, GenericServer server){
|
||||
if(condition == null || condition.isEmpty())
|
||||
return true;
|
||||
|
||||
for(Expression expression : expressions){
|
||||
if(!expression.evaluate(player, server))
|
||||
return false;
|
||||
ParseWarnCollector collector = new ParseWarnCollector(condition);
|
||||
ExpressionTemplate template = parser.compile(condition, player, server, collector);
|
||||
|
||||
if(collector.hasWarnings()){
|
||||
logger.warn("Encountered %d Error(s) while parsing condition for file '%s':", collector.getWarnings().size(), file);
|
||||
|
||||
for(ParseWarnCollector.Context context : collector.getWarnings()){
|
||||
logger.warn(" - At position %s:", context.position() == -1 ? "Unknown" : context.position());
|
||||
logger.warn(" %s", condition);
|
||||
logger.warn(" ".repeat(context.position() + 5) + "^");
|
||||
logger.warn(" -> %s", context.message());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
if(template == null)
|
||||
return false;
|
||||
|
||||
return template.returnBooleanExpression().evaluate();
|
||||
}
|
||||
|
||||
public ProfileEntry getRandomProfile(){
|
||||
@@ -84,10 +80,6 @@ public class ServerListProfile{
|
||||
}
|
||||
}
|
||||
|
||||
public ProfileEntry getDefaultProfile(){
|
||||
return defaultProfile;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if the Profile...
|
||||
* ...doesn't have any valid MOTD set AND
|
||||
@@ -96,12 +88,12 @@ public class ServerListProfile{
|
||||
* ...doesn't have a favicon set.
|
||||
*/
|
||||
public boolean isInvalidProfile(){
|
||||
if(profiles.isEmpty())
|
||||
return defaultProfile.isInvalid();
|
||||
if(profiles().isEmpty())
|
||||
return defaultProfile().isInvalid();
|
||||
|
||||
boolean profilesValid = false;
|
||||
|
||||
for(ProfileEntry profile : profiles){
|
||||
for(ProfileEntry profile : profiles()){
|
||||
if(profile.isInvalid())
|
||||
continue;
|
||||
|
||||
@@ -117,10 +109,10 @@ public class ServerListProfile{
|
||||
private final String fileName;
|
||||
private final ConfigurationNode node;
|
||||
private final int priority;
|
||||
private final List<Expression> expressions = new ArrayList<>();
|
||||
|
||||
private final PluginLogger logger;
|
||||
|
||||
private String condition = null;
|
||||
private List<ProfileEntry> profiles = new ArrayList<>();
|
||||
private ProfileEntry defaultProfile = ProfileEntry.empty();
|
||||
|
||||
@@ -133,34 +125,17 @@ public class ServerListProfile{
|
||||
|
||||
public static Builder resolve(String fileName, ConfigurationNode node, PluginLogger logger){
|
||||
return new Builder(fileName, node, logger)
|
||||
.resolveExpressions()
|
||||
.resolveCondition()
|
||||
.resolveProfiles()
|
||||
.resolveDefaultProfile();
|
||||
}
|
||||
|
||||
private Builder resolveExpressions(){
|
||||
List<String> temp;
|
||||
try{
|
||||
temp = node.node("conditions").getList(String.class);
|
||||
}catch(SerializationException ex){
|
||||
logger.warn("Encountered a SerializationException while resolving conditions for %s", ex, fileName);
|
||||
return this;
|
||||
}
|
||||
|
||||
if(temp == null || temp.isEmpty())
|
||||
private Builder resolveCondition(){
|
||||
String condition = node.node("condition").getString();
|
||||
if(condition == null || condition.isEmpty())
|
||||
return this;
|
||||
|
||||
for(String str : temp){
|
||||
Expression expr = Expression.resolve(str);
|
||||
|
||||
if(expr.getResult() != Expression.ExpressionResult.VALID){
|
||||
logger.warn("Found invalid expression in condition '%s'! Reason: %s", str, expr.getResult().getMessage());
|
||||
continue;
|
||||
}
|
||||
|
||||
this.expressions.add(expr);
|
||||
}
|
||||
|
||||
this.condition = condition;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -184,7 +159,7 @@ public class ServerListProfile{
|
||||
}
|
||||
|
||||
public ServerListProfile build(){
|
||||
return new ServerListProfile(this.priority, this.expressions, this.defaultProfile, this.profiles);
|
||||
return new ServerListProfile(this.priority, this.condition, this.defaultProfile, this.profiles, this.fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
-226
@@ -1,226 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
|
||||
|
||||
public class Expression{
|
||||
|
||||
private final ExpressionResult result;
|
||||
|
||||
private final String left;
|
||||
private final Operator operator;
|
||||
private final String right;
|
||||
|
||||
private Expression(ExpressionResult result, String left, Operator operator, String right){
|
||||
this.result = result;
|
||||
this.left = left;
|
||||
this.operator = operator;
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
public static Expression createInvalid(ExpressionResult result){
|
||||
return new Expression(result, null, Operator.UNKNOWN, null);
|
||||
}
|
||||
|
||||
public static Expression resolve(String expression){
|
||||
Operator operator = Operator.UNKNOWN;
|
||||
|
||||
if(expression == null || expression.isEmpty()){
|
||||
return Expression.createInvalid(ExpressionResult.INVALID_NO_EXPRESSION);
|
||||
}
|
||||
|
||||
char[] chars = expression.toCharArray();
|
||||
|
||||
StringBuilder leftBuilder = new StringBuilder();
|
||||
StringBuilder rightBuilder = new StringBuilder();
|
||||
|
||||
boolean foundOperator = false;
|
||||
|
||||
for(int i = 0; i < chars.length; i++){
|
||||
char c = chars[i];
|
||||
char next = (i == (chars.length - 1)) ? '\0' : chars[i + 1];
|
||||
|
||||
Operator tmp = Operator.getOperand(c, next);
|
||||
if(tmp != Operator.UNKNOWN && !foundOperator){
|
||||
operator = tmp;
|
||||
foundOperator = true;
|
||||
|
||||
if(tmp.hasSecond())
|
||||
i++; // Skip next character if operator has 2
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if(foundOperator){
|
||||
rightBuilder.append(c);
|
||||
}else{
|
||||
leftBuilder.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
if(leftBuilder.isEmpty() || rightBuilder.isEmpty()){
|
||||
return Expression.createInvalid(ExpressionResult.INVALID_EMPTY_PARTS);
|
||||
}
|
||||
|
||||
return new Expression(ExpressionResult.VALID, leftBuilder.toString().trim(), operator, rightBuilder.toString().trim());
|
||||
}
|
||||
|
||||
public boolean evaluate(GenericPlayer player, GenericServer server){
|
||||
String newLeft = StringReplacer.replace(left, player, server);
|
||||
String newRight = StringReplacer.replace(right, player, server);
|
||||
|
||||
return operator.evaluate(newLeft, newRight);
|
||||
}
|
||||
|
||||
public ExpressionResult getResult(){
|
||||
return result;
|
||||
}
|
||||
|
||||
public enum Operator{
|
||||
LESS('<', '\0'){
|
||||
@Override
|
||||
public boolean evaluate(String left, String right){
|
||||
int leftInt = Operator.getInt(left);
|
||||
int rightInt = Operator.getInt(right);
|
||||
|
||||
return leftInt < rightInt;
|
||||
}
|
||||
},
|
||||
LESS_OR_EQUAL('<', '='){
|
||||
@Override
|
||||
public boolean evaluate(String left, String right){
|
||||
int leftInt = Operator.getInt(left);
|
||||
int rightInt = Operator.getInt(right);
|
||||
|
||||
return leftInt <= rightInt;
|
||||
}
|
||||
},
|
||||
EQUAL('=', '\0'){
|
||||
@Override
|
||||
public boolean evaluate(String left, String right){
|
||||
return left.equals(right);
|
||||
}
|
||||
},
|
||||
EQUALS_IGNORE_CASE('~', '='){
|
||||
@Override
|
||||
public boolean evaluate(String left, String right){
|
||||
return left.equalsIgnoreCase(right);
|
||||
}
|
||||
},
|
||||
NOT_EQUAL('!', '='){
|
||||
@Override
|
||||
public boolean evaluate(String left, String right){
|
||||
return !left.equals(right);
|
||||
}
|
||||
},
|
||||
NOT_EQUAL_IGNORE_CASE('!', '~'){
|
||||
@Override
|
||||
public boolean evaluate(String left, String right){
|
||||
return !left.equalsIgnoreCase(right);
|
||||
}
|
||||
},
|
||||
GREATER('>', '\0'){
|
||||
@Override
|
||||
public boolean evaluate(String left, String right){
|
||||
int leftInt = Operator.getInt(left);
|
||||
int rightInt = Operator.getInt(right);
|
||||
|
||||
return leftInt > rightInt;
|
||||
}
|
||||
},
|
||||
GREATER_OR_EQUAL('>', '='){
|
||||
@Override
|
||||
public boolean evaluate(String left, String right){
|
||||
int leftInt = Operator.getInt(left);
|
||||
int rightInt = Operator.getInt(right);
|
||||
|
||||
return leftInt >= rightInt;
|
||||
}
|
||||
},
|
||||
|
||||
UNKNOWN('\0', '\0'){
|
||||
@Override
|
||||
public boolean evaluate(String left, String right){
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
private static final Operator[] VALUES = values();
|
||||
|
||||
private final char first;
|
||||
private final char second;
|
||||
|
||||
Operator(char first, char second){
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
|
||||
public static Operator getOperand(char first, char second){
|
||||
for(Operator operator : VALUES){
|
||||
if(operator.first == first){
|
||||
if((!operator.hasSecond() && second != '=' && second != '~') || operator.second == second)
|
||||
return operator;
|
||||
}
|
||||
}
|
||||
|
||||
return Operator.UNKNOWN;
|
||||
}
|
||||
|
||||
public boolean hasSecond(){
|
||||
return second != '\0';
|
||||
}
|
||||
|
||||
public abstract boolean evaluate(String left, String right);
|
||||
|
||||
private static int getInt(String text){
|
||||
try{
|
||||
return Integer.parseInt(text);
|
||||
}catch(NumberFormatException ex){
|
||||
return text.length();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum ExpressionResult{
|
||||
VALID(null),
|
||||
|
||||
INVALID_NO_EXPRESSION("Received empty condition which isn't allowed!"),
|
||||
INVALID_EMPTY_PARTS ("Received condition with either left or right part being empty.");
|
||||
|
||||
private final String message;
|
||||
|
||||
ExpressionResult(String message){
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getMessage(){
|
||||
return message;
|
||||
}
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.reader.PlaceholderTokenReader;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.reader.PlaceholderValueReader;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens.CustomExpressionTokenizer;
|
||||
import ch.andre601.expressionparser.ExpressionParserEngine;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
import ch.andre601.expressionparser.operator.Operator;
|
||||
import ch.andre601.expressionparser.parsers.ExpressionTemplateParser;
|
||||
import ch.andre601.expressionparser.parsers.ValueReader;
|
||||
import ch.andre601.expressionparser.templates.ExpressionTemplate;
|
||||
import ch.andre601.expressionparser.tokens.Token;
|
||||
import ch.andre601.expressionparser.tokens.readers.TokenReader;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ProfileConditionParser implements ExpressionParserEngine{
|
||||
|
||||
private final CustomExpressionTokenizer tokenizer;
|
||||
private final ExpressionTemplateParser parser;
|
||||
|
||||
private ProfileConditionParser(List<TokenReader> tokenReaders, ImmutableMap<Token, Operator> operators, ImmutableList<ValueReader> valueReaders){
|
||||
this.tokenizer = new CustomExpressionTokenizer(tokenReaders);
|
||||
this.parser = new ExpressionTemplateParser(operators, valueReaders);
|
||||
}
|
||||
|
||||
public static ProfileConditionParser create(){
|
||||
return new ProfileConditionParserBuilder().addDefaults()
|
||||
.addTokenReader(new PlaceholderTokenReader(-20))
|
||||
.addValueReader(new PlaceholderValueReader())
|
||||
.build();
|
||||
}
|
||||
|
||||
public ExpressionTemplate compile(String text, GenericPlayer player, GenericServer server, ParseWarnCollector collector){
|
||||
return parser.parse(tokenizer.parse(text, player, server, collector), collector);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionTemplate compile(String s, ParseWarnCollector parseWarnCollector){
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class ProfileConditionParserBuilder extends ExpressionParserEngine.Builder<ProfileConditionParser>{
|
||||
@Override
|
||||
public ProfileConditionParser build(){
|
||||
return new ProfileConditionParser(this.getTokenReaders(), ImmutableMap.copyOf(this.getOperators()), ImmutableList.copyOf(this.getValueReaders()));
|
||||
}
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.reader;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
import ch.andre601.expressionparser.tokens.Token;
|
||||
import ch.andre601.expressionparser.tokens.readers.TokenReader;
|
||||
|
||||
import java.text.ParsePosition;
|
||||
|
||||
public abstract class CustomTokenReader extends TokenReader{
|
||||
|
||||
public CustomTokenReader(int priority){
|
||||
super(priority);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Token read(String text, ParsePosition position, ParseWarnCollector collector){
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract Token read(String text, ParsePosition position, GenericPlayer player, GenericServer server, ParseWarnCollector collector);
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.reader;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens.PlaceholderToken;
|
||||
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
import ch.andre601.expressionparser.tokens.Token;
|
||||
|
||||
import java.text.ParsePosition;
|
||||
|
||||
public class PlaceholderTokenReader extends CustomTokenReader{
|
||||
|
||||
public PlaceholderTokenReader(int priority){
|
||||
super(priority);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Token read(String text, ParsePosition position, GenericPlayer player, GenericServer server, ParseWarnCollector collector){
|
||||
if(position.getIndex() + 1 < text.length() && text.charAt(position.getIndex()) == '$' && text.charAt(position.getIndex() + 1) == '{'){
|
||||
position.setIndex(position.getIndex() + 2);
|
||||
return new PlaceholderToken(StringReplacer.parsePlaceholder(text, position, player, server, collector));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.reader;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens.PlaceholderToken;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
import ch.andre601.expressionparser.parsers.ExpressionTemplateParser;
|
||||
import ch.andre601.expressionparser.parsers.ValueReader;
|
||||
import ch.andre601.expressionparser.templates.ExpressionTemplate;
|
||||
import ch.andre601.expressionparser.tokens.Token;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PlaceholderValueReader extends ValueReader{
|
||||
@Override
|
||||
public ExpressionTemplate read(ExpressionTemplateParser parser, List<Token> tokens, ParseWarnCollector collector){
|
||||
if(tokens.get(0) instanceof PlaceholderToken){
|
||||
PlaceholderToken token = (PlaceholderToken)tokens.remove(0);
|
||||
return token.getValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.reader.CustomTokenReader;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
import ch.andre601.expressionparser.tokens.Token;
|
||||
import ch.andre601.expressionparser.tokens.readers.TokenReader;
|
||||
import com.google.common.collect.Ordering;
|
||||
|
||||
import java.text.ParsePosition;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class CustomExpressionTokenizer{
|
||||
|
||||
private static final Ordering<TokenReader> TOKEN_READER_ORDERING = Ordering.from(Comparator.comparingInt(TokenReader::getPriority)).reverse();
|
||||
|
||||
private final List<TokenReader> tokenReaders;
|
||||
|
||||
public CustomExpressionTokenizer(Iterable<TokenReader> tokenReaders){
|
||||
this.tokenReaders = TOKEN_READER_ORDERING.immutableSortedCopy(tokenReaders);
|
||||
}
|
||||
|
||||
public List<Token> parse(String text, GenericPlayer player, GenericServer server, ParseWarnCollector collector){
|
||||
ParsePosition position = new ParsePosition(0);
|
||||
|
||||
List<Token> tokens = new LinkedList<>();
|
||||
|
||||
next_token:
|
||||
while(true){
|
||||
while(position.getIndex() < text.length() && Character.isWhitespace(text.charAt(position.getIndex())))
|
||||
position.setIndex(position.getIndex() + 1);
|
||||
|
||||
if(position.getIndex() >= text.length())
|
||||
break;
|
||||
|
||||
for(TokenReader tokenReader : tokenReaders){
|
||||
Token token;
|
||||
if(tokenReader instanceof CustomTokenReader customTokenReader){
|
||||
if(null != (token = customTokenReader.read(text, position, player, server, collector))){
|
||||
tokens.add(token);
|
||||
continue next_token;
|
||||
}
|
||||
}else{
|
||||
if(null != (token = tokenReader.read(text, position, collector))){
|
||||
tokens.add(token);
|
||||
continue next_token;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
collector.appendWarningFormatted(position.getIndex(), "Illegal Token '%c'.", text.charAt(position.getIndex()));
|
||||
break;
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens;
|
||||
|
||||
import ch.andre601.expressionparser.expressions.ToBooleanExpression;
|
||||
import ch.andre601.expressionparser.expressions.ToDoubleExpression;
|
||||
import ch.andre601.expressionparser.expressions.ToStringExpression;
|
||||
import ch.andre601.expressionparser.templates.ExpressionTemplate;
|
||||
import ch.andre601.expressionparser.tokens.Token;
|
||||
|
||||
public class PlaceholderToken extends Token{
|
||||
|
||||
private final Placeholder value;
|
||||
|
||||
public PlaceholderToken(Placeholder value){
|
||||
super("PLACEHOLDER");
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Placeholder getValue(){
|
||||
return value;
|
||||
}
|
||||
|
||||
public static class Placeholder implements ExpressionTemplate{
|
||||
|
||||
private final ToBooleanExpression toBooleanExpression;
|
||||
private final ToDoubleExpression toDoubleExpression;
|
||||
private final ToStringExpression toStringExpression;
|
||||
|
||||
public Placeholder(String value){
|
||||
double doubleValue;
|
||||
try{
|
||||
doubleValue = Double.parseDouble(value);
|
||||
}catch(NumberFormatException ex){
|
||||
doubleValue = value.length();
|
||||
}
|
||||
|
||||
this.toBooleanExpression = ToBooleanExpression.literal(Boolean.parseBoolean(value));
|
||||
this.toDoubleExpression = ToDoubleExpression.literal(doubleValue);
|
||||
this.toStringExpression = ToStringExpression.literal(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ToBooleanExpression returnBooleanExpression(){
|
||||
return toBooleanExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ToDoubleExpression returnDoubleExpression(){
|
||||
return toDoubleExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ToStringExpression returnStringExpression(){
|
||||
return toStringExpression;
|
||||
}
|
||||
}
|
||||
}
|
||||
+117
-72
@@ -26,122 +26,167 @@
|
||||
package ch.andre601.advancedserverlist.core.profiles.favicon;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class FaviconHandler<F>{
|
||||
|
||||
private final Cache<String, CompletableFuture<F>> favicons = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(5, TimeUnit.MINUTES)
|
||||
.build();
|
||||
|
||||
private final AdvancedServerList<F> core;
|
||||
private final PluginLogger logger;
|
||||
private final ThreadPoolExecutor faviconThreadPool;
|
||||
private final Cache<String, CompletableFuture<F>> faviconCache;
|
||||
|
||||
private final Map<String, F> localFavicons = new HashMap<>();
|
||||
private final HttpClient client = HttpClient.newHttpClient();
|
||||
|
||||
public FaviconHandler(AdvancedServerList<F> core){
|
||||
this.core = core;
|
||||
this.logger = core.getPlugin().getPluginLogger();
|
||||
this.faviconThreadPool = createFaviconThreadPool();
|
||||
this.faviconCache = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(core.getFileHandler().getLong(1, 1, "faviconCacheTime"), TimeUnit.MINUTES)
|
||||
.build();
|
||||
|
||||
loadLocalFavicons();
|
||||
}
|
||||
|
||||
public F getFavicon(String input, Function<BufferedImage, F> function){
|
||||
public F getFavicon(String input){
|
||||
if(localFavicons.containsKey(input.toLowerCase(Locale.ROOT).split("\\.")[0])){
|
||||
return localFavicons.get(input.toLowerCase(Locale.ROOT).split("\\.")[0]);
|
||||
}
|
||||
|
||||
try{
|
||||
return favicons.get(input, () -> convert(input, function)).getNow(null);
|
||||
}catch(ExecutionException e){
|
||||
return faviconCache.get(input, () -> getFuture(input)).getNow(null);
|
||||
}catch(ExecutionException ex){
|
||||
logger.warn("Received ExecutionException while retrieving Favicon for '%s'.", ex, input);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void clearCache(){
|
||||
favicons.invalidateAll();
|
||||
public void cleanCache(){
|
||||
faviconCache.invalidateAll();
|
||||
loadLocalFavicons();
|
||||
}
|
||||
|
||||
private CompletableFuture<F> convert(String input, Function<BufferedImage, F> function){
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
BufferedImage img = resolveImage(core, input);
|
||||
if(img == null)
|
||||
return null;
|
||||
|
||||
return function.apply(img);
|
||||
}, faviconThreadPool);
|
||||
}
|
||||
|
||||
private BufferedImage resolveImage(AdvancedServerList<F> core, String input){
|
||||
InputStream stream;
|
||||
|
||||
private CompletableFuture<F> getFuture(String input){
|
||||
if(input.toLowerCase(Locale.ROOT).startsWith("https://")){
|
||||
stream = getFromUrl(core, input);
|
||||
logger.debug(FaviconHandler.class, "Resolving URL '%s'...", input);
|
||||
return CompletableFuture.supplyAsync(() -> fromURL(core, input), this.faviconThreadPool);
|
||||
}else
|
||||
if(input.toLowerCase(Locale.ROOT).endsWith(".png")){
|
||||
File folder = core.getPlugin().getFolderPath().resolve("favicons").toFile();
|
||||
if(!folder.exists()){
|
||||
core.getPlugin().getPluginLogger().warn("Cannot get Favicon %s from favicons folder. Folder doesn't exist!", input);
|
||||
return null;
|
||||
}
|
||||
|
||||
File file = new File(folder, input);
|
||||
|
||||
try{
|
||||
stream = new FileInputStream(file);
|
||||
}catch(IOException ex){
|
||||
core.getPlugin().getPluginLogger().warn("Cannot create Favicon from File %s.", input);
|
||||
core.getPlugin().getPluginLogger().warn("Cause: %s", ex.getMessage());
|
||||
return null;
|
||||
}
|
||||
logger.debug(FaviconHandler.class, "Resolving image file '%s'...", input);
|
||||
return CompletableFuture.completedFuture(localFavicons.get(input.toLowerCase(Locale.ROOT).split("\\.")[0]));
|
||||
}else{
|
||||
stream = getFromUrl(core, "https://mc-heads.net/avatar/" + input + "/64");
|
||||
logger.debug(FaviconHandler.class, "Resolving Name/UUID as https://mc-heads.net/avatar/%s/64...", input);
|
||||
return CompletableFuture.supplyAsync(() -> fromURL(core, "https://mc-heads.net/avatar/" + input + "/64"), this.faviconThreadPool);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadLocalFavicons(){
|
||||
this.localFavicons.clear();
|
||||
|
||||
logger.info("Loading local image files as Favicons...");
|
||||
|
||||
Path folder = core.getPlugin().getFolderPath().resolve("favicons");
|
||||
if(!Files.exists(folder)){
|
||||
try{
|
||||
Files.createDirectories(folder);
|
||||
logger.info("Created favicons folder.");
|
||||
}catch(IOException ex){
|
||||
logger.warn("Cannot create favicons folder. Encountered an IOException.", ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(stream == null){
|
||||
core.getPlugin().getPluginLogger().warn("Cannot create Favicon. InputStream was null.");
|
||||
return null;
|
||||
try(Stream<Path> pathStream = Files.list(folder)){
|
||||
pathStream.filter(Files::isRegularFile)
|
||||
.filter(file -> file.getFileName().toString().endsWith(".png"))
|
||||
.forEach(this::loadFile);
|
||||
}catch(IOException ex){
|
||||
logger.warn("Cannot load files from Favicons folder.", ex);
|
||||
}
|
||||
|
||||
try{
|
||||
BufferedImage original = ImageIO.read(stream);
|
||||
if(original == null){
|
||||
core.getPlugin().getPluginLogger().warn("Cannot create Favicon. Unable to create BufferedImage.");
|
||||
return null;
|
||||
}
|
||||
|
||||
private void loadFile(Path path){
|
||||
try(InputStream stream = Files.newInputStream(path)){
|
||||
F favicon = createFavicon(stream);
|
||||
if(favicon == null){
|
||||
logger.warn("Cannot create Favicon from file '%s'. Received Favicon was null.", path.getFileName().toString());
|
||||
return;
|
||||
}
|
||||
|
||||
BufferedImage favicon = new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D img = favicon.createGraphics();
|
||||
|
||||
// Resize original image to 64x64 and apply to favicon.
|
||||
img.drawImage(original, 0, 0, 64, 64, null);
|
||||
img.dispose();
|
||||
|
||||
return favicon;
|
||||
localFavicons.put(path.getFileName().toString().split("\\.")[0], favicon);
|
||||
logger.info("Loaded file '%s' as Favicon.", path.getFileName().toString());
|
||||
}catch(IOException ex){
|
||||
core.getPlugin().getPluginLogger().warn("Unable to create Favicon. Encountered IOException during creation.");
|
||||
core.getPlugin().getPluginLogger().warn("Cause: %s", ex.getMessage());
|
||||
logger.warn("Cannot create Favicon from file '%s'. Encountered IOException.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private F fromURL(AdvancedServerList<F> core, String url){
|
||||
try{
|
||||
logger.debug(FaviconHandler.class, "Creating Request for URL '%s'...", url);
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(new URI(url))
|
||||
.header("User-Agent", "AdvancedServerList-" + core.getPlugin().getLoader() + "/" + core.getVersion())
|
||||
.build();
|
||||
|
||||
try(InputStream stream = client.send(request, HttpResponse.BodyHandlers.ofInputStream()).body()){
|
||||
return createFavicon(stream);
|
||||
}catch(InterruptedException | IOException ex){
|
||||
logger.warn("Cannot create Favicon from URL '%s'. Encountered an Exception.", ex, url);
|
||||
return null;
|
||||
}
|
||||
}catch(URISyntaxException ex){
|
||||
logger.warn("Cannot create Favicon from URL '%s'. Encountered an IOException.", ex, url);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private InputStream getFromUrl(AdvancedServerList<F> core, String url){
|
||||
private F createFavicon(InputStream stream){
|
||||
try{
|
||||
URL faviconUrl = new URL(url);
|
||||
URLConnection connection = faviconUrl.openConnection();
|
||||
connection.setRequestProperty("User-Agent", "AdvancedServerList/" + core.getVersion());
|
||||
connection.connect();
|
||||
logger.debug(FaviconHandler.class, "Creating BufferedImage from InputStream...");
|
||||
BufferedImage original = ImageIO.read(stream);
|
||||
if(original == null){
|
||||
logger.warn("Cannot create Favicon. Received null BufferedImage.");
|
||||
return null;
|
||||
}
|
||||
|
||||
return connection.getInputStream();
|
||||
}catch(IOException ex){
|
||||
core.getPlugin().getPluginLogger().warn("Error while connecting to %s for Favicon creation.", url);
|
||||
core.getPlugin().getPluginLogger().warn("Cause: %s", ex.getMessage());
|
||||
// Don't waste resources resizing images already having right size.
|
||||
if(original.getWidth() == 64 && original.getHeight() == 64){
|
||||
logger.debug(FaviconHandler.class, "BufferedImage is 64x64 pixels. No resizing needed.");
|
||||
return core.getPlugin().createFavicon(original);
|
||||
}
|
||||
|
||||
logger.debug(FaviconHandler.class, "Resizing image to 64x64 pixels...");
|
||||
BufferedImage image = new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D graphics2D = image.createGraphics();
|
||||
|
||||
graphics2D.drawImage(original, 0, 0, 64, 64, null);
|
||||
graphics2D.dispose();
|
||||
|
||||
logger.debug(FaviconHandler.class, "Image resized! Returning Favicon...");
|
||||
return core.getPlugin().createFavicon(image);
|
||||
}catch(Exception ex){
|
||||
logger.warn("Unable to create Favicon. Received Exception.", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+14
-11
@@ -29,6 +29,8 @@ import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonIOException;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import io.leangen.geantyref.TypeToken;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
@@ -38,7 +40,9 @@ import java.lang.reflect.Type;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PlayerHandler{
|
||||
|
||||
@@ -68,19 +72,18 @@ public class PlayerHandler{
|
||||
}
|
||||
|
||||
if(core.getFileHandler().getBoolean("disableCache")){
|
||||
logger.info("'disable_cache' is set to true. Skipping playercache.json loading...");
|
||||
logger.info("'disableCache' is set to true. Skipping playercache.json loading...");
|
||||
return;
|
||||
}
|
||||
|
||||
try{
|
||||
BufferedReader reader = Files.newBufferedReader(cache);
|
||||
|
||||
|
||||
try(BufferedReader reader = Files.newBufferedReader(cache)){
|
||||
cachedPlayers = gson.fromJson(reader, listType);
|
||||
|
||||
reader.close();
|
||||
}catch(IOException ex){
|
||||
logger.warn("Encountered IOException while reading the playercache.json file!", ex);
|
||||
return;
|
||||
}catch(JsonIOException | JsonSyntaxException ex){
|
||||
logger.warn("Encountered Json exception while parsing playercache.json file!", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
// In case Gson messes up... I guess.
|
||||
@@ -127,7 +130,7 @@ public class PlayerHandler{
|
||||
return getDefaultPlayer();
|
||||
|
||||
for(CachedPlayer player : cachedPlayers){
|
||||
if(player.getIp().equals(key))
|
||||
if(player.ip().equals(key))
|
||||
return player;
|
||||
}
|
||||
|
||||
@@ -136,7 +139,7 @@ public class PlayerHandler{
|
||||
|
||||
public CachedPlayer getCachedPlayer(UUID uuid){
|
||||
for(CachedPlayer player : cachedPlayers){
|
||||
if(player.getUuid().equals(uuid))
|
||||
if(player.uuid().equals(uuid))
|
||||
return player;
|
||||
}
|
||||
|
||||
@@ -150,7 +153,7 @@ public class PlayerHandler{
|
||||
|
||||
private boolean contains(String ip){
|
||||
for(CachedPlayer player : cachedPlayers){
|
||||
if(player.getIp().equals(ip))
|
||||
if(player.ip().equals(ip))
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+12
-12
@@ -28,9 +28,9 @@ package ch.andre601.advancedserverlist.core.profiles.profile;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.api.objects.NullBool;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
@@ -45,7 +45,7 @@ public class ProfileManager{
|
||||
*/
|
||||
public static ProfileEntry merge(ServerListProfile profile){
|
||||
ProfileEntry entry = profile.getRandomProfile();
|
||||
ProfileEntry defEntry = profile.getDefaultProfile();
|
||||
ProfileEntry defEntry = profile.defaultProfile();
|
||||
|
||||
List<String> motd = resolveMOTD(entry, defEntry);
|
||||
List<String> players = resolvePlayers(entry, defEntry);
|
||||
@@ -67,7 +67,7 @@ public class ProfileManager{
|
||||
if(profile.isInvalidProfile())
|
||||
continue;
|
||||
|
||||
if(profile.evalConditions(player, server))
|
||||
if(profile.evalConditions(core.getParser(), core.getPlugin().getPluginLogger(), player, server))
|
||||
return profile;
|
||||
}
|
||||
|
||||
@@ -86,15 +86,15 @@ public class ProfileManager{
|
||||
Integer maxPlayers = resolveNullableInt(node, "playerCount", "maxPlayers", "amount");
|
||||
|
||||
return new ProfileEntry.Builder()
|
||||
.setMotd(motd)
|
||||
.setPlayers(players)
|
||||
.setPlayerCountText(playerCountText)
|
||||
.setFavicon(favicon)
|
||||
.setHidePlayersEnabled(hidePlayers)
|
||||
.setExtraPlayersEnabled(extraPlayersEnabled)
|
||||
.setMaxPlayersEnabled(maxPlayersEnabled)
|
||||
.setExtraPlayersCount(extraPlayers)
|
||||
.setMaxPlayersCount(maxPlayers)
|
||||
.motd(motd)
|
||||
.players(players)
|
||||
.playerCountText(playerCountText)
|
||||
.favicon(favicon)
|
||||
.hidePlayersEnabled(hidePlayers)
|
||||
.extraPlayersEnabled(extraPlayersEnabled)
|
||||
.maxPlayersEnabled(maxPlayersEnabled)
|
||||
.extraPlayersCount(extraPlayers)
|
||||
.maxPlayersCount(maxPlayers)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -25,11 +25,11 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.profile;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
import org.spongepowered.configurate.serialize.TypeSerializer;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
|
||||
+105
-86
@@ -29,6 +29,11 @@ import ch.andre601.advancedserverlist.api.AdvancedServerListAPI;
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens.PlaceholderToken;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
|
||||
import java.text.ParsePosition;
|
||||
|
||||
public class StringReplacer{
|
||||
|
||||
@@ -36,99 +41,113 @@ public class StringReplacer{
|
||||
if(input == null)
|
||||
return null;
|
||||
|
||||
char[] chars = input.toCharArray();
|
||||
ParsePosition position = new ParsePosition(0);
|
||||
StringBuilder builder = new StringBuilder(input.length());
|
||||
|
||||
StringBuilder identifier = new StringBuilder();
|
||||
StringBuilder placeholder = new StringBuilder();
|
||||
|
||||
AdvancedServerListAPI api = AdvancedServerListAPI.get();
|
||||
|
||||
for(int i = 0; i < chars.length; i++){
|
||||
char c = chars[i];
|
||||
char next = (i == (chars.length - 1)) ? '\0' : chars[i + 1];
|
||||
|
||||
if(c != '$' || i + 2 >= chars.length){
|
||||
builder.append(c);
|
||||
while(position.getIndex() < input.length()){
|
||||
if(position.getIndex() + 1 < input.length() && input.charAt(position.getIndex()) == '$' && input.charAt(position.getIndex() + 1) == '{'){
|
||||
position.setIndex(position.getIndex() + 2);
|
||||
builder.append(parsePlaceholder0(input, position, player, server, null));
|
||||
continue;
|
||||
}
|
||||
|
||||
if(next != '{'){
|
||||
if(next == '\0')
|
||||
continue;
|
||||
|
||||
builder.append(next);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
boolean identified = false;
|
||||
boolean invalid = true;
|
||||
|
||||
while(++i < chars.length){
|
||||
final char id = chars[i];
|
||||
|
||||
if(id == '}'){
|
||||
invalid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if(id == ' ' && !identified){
|
||||
identified = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(identified){
|
||||
placeholder.append(id);
|
||||
}else{
|
||||
identifier.append(id);
|
||||
}
|
||||
}
|
||||
|
||||
String identifierString = identifier.toString();
|
||||
String placeholderString = placeholder.toString();
|
||||
|
||||
identifier.setLength(0);
|
||||
placeholder.setLength(0);
|
||||
|
||||
if(invalid){
|
||||
builder.append("${").append(identifierString);
|
||||
|
||||
if(identified){
|
||||
builder.append(' ').append(placeholderString);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
PlaceholderProvider provider = api.retrievePlaceholderProvider(identifierString);
|
||||
if(provider == null){
|
||||
builder.append("${").append(identifierString);
|
||||
|
||||
if(identified){
|
||||
builder.append(' ').append(placeholderString);
|
||||
}
|
||||
|
||||
builder.append('}');
|
||||
continue;
|
||||
}
|
||||
|
||||
String replacement = provider.parsePlaceholder(placeholderString, player, server);
|
||||
if(replacement == null){
|
||||
builder.append("${").append(identifierString);
|
||||
|
||||
if(identified){
|
||||
builder.append(' ').append(placeholderString);
|
||||
}
|
||||
|
||||
builder.append('}');
|
||||
continue;
|
||||
}
|
||||
|
||||
builder.append(replacement);
|
||||
builder.append(input.charAt(position.getIndex()));
|
||||
position.setIndex(position.getIndex() + 1);
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static PlaceholderToken.Placeholder parsePlaceholder(String input, ParsePosition position, GenericPlayer player, GenericServer server, ParseWarnCollector collector){
|
||||
return new PlaceholderToken.Placeholder(parsePlaceholder0(input, position, player, server, collector));
|
||||
}
|
||||
|
||||
private static String parsePlaceholder0(String input, ParsePosition position, GenericPlayer player, GenericServer server, ParseWarnCollector collector){
|
||||
AdvancedServerListAPI api = AdvancedServerList.getApi();
|
||||
|
||||
int placeholderStart = position.getIndex() - 2;
|
||||
int index = position.getIndex();
|
||||
|
||||
StringBuilder identifier = new StringBuilder();
|
||||
StringBuilder values = new StringBuilder();
|
||||
|
||||
boolean identified = false;
|
||||
boolean invalid = true;
|
||||
|
||||
char[] chars = input.substring(index).toCharArray();
|
||||
for(final char c : chars){
|
||||
index++;
|
||||
|
||||
if(c == '}'){
|
||||
invalid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if(c == ' ' && !identified){
|
||||
identified = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(identified){
|
||||
values.append(c);
|
||||
}else{
|
||||
identifier.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
String identifierStr = identifier.toString();
|
||||
String valuesStr = values.toString();
|
||||
|
||||
StringBuilder raw = new StringBuilder();
|
||||
|
||||
// Condition parsing needs one extra increase of index... for some reason
|
||||
if(collector != null)
|
||||
index++;
|
||||
|
||||
position.setIndex(index);
|
||||
|
||||
if(invalid){
|
||||
raw.append("${").append(identifierStr);
|
||||
|
||||
if(identified)
|
||||
raw.append(' ').append(valuesStr);
|
||||
|
||||
if(collector != null)
|
||||
collector.appendWarningFormatted(placeholderStart, "Placeholder '%s' does not have a closing bracket (})", raw.toString());
|
||||
|
||||
return raw.toString();
|
||||
}
|
||||
|
||||
PlaceholderProvider provider = api.retrievePlaceholderProvider(identifierStr);
|
||||
if(provider == null){
|
||||
raw.append("${").append(identifierStr);
|
||||
|
||||
if(identified)
|
||||
raw.append(' ').append(valuesStr);
|
||||
|
||||
raw.append('}');
|
||||
|
||||
if(collector != null)
|
||||
collector.appendWarningFormatted(placeholderStart, "Placeholder '%s' does not have any available PlaceholderProvider", raw.toString());
|
||||
|
||||
return raw.toString();
|
||||
}
|
||||
|
||||
String replacement = provider.parsePlaceholder(valuesStr, player, server);
|
||||
if(replacement == null){
|
||||
raw.append("${").append(identifierStr);
|
||||
|
||||
if(identified)
|
||||
raw.append(' ').append(valuesStr);
|
||||
|
||||
raw.append('}');
|
||||
|
||||
if(collector != null)
|
||||
collector.appendWarningFormatted(placeholderStart, "Placeholder '%s' has an invalid value String '%s'", raw.toString(), valuesStr);
|
||||
|
||||
return raw.toString();
|
||||
}
|
||||
|
||||
return replacement;
|
||||
}
|
||||
}
|
||||
@@ -31,10 +31,65 @@ disableCache: false
|
||||
#
|
||||
checkUpdates: true
|
||||
|
||||
#
|
||||
# Should debug mode be enabled?
|
||||
#
|
||||
# When set to true will AdvancedServerList print additional messages to the console prefixed with "[DEBUG]".
|
||||
# It is recommended to only enable this when having problems or when being told to by the plugin dev, as it could
|
||||
# otherwise cause significant spam in your console.
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
#
|
||||
debug: false
|
||||
|
||||
#
|
||||
# Sets the time in minutes for favicons to be cached.
|
||||
# The number cannot be less than 1.
|
||||
#
|
||||
# Defaults to 1 if not set.
|
||||
#
|
||||
faviconCacheTime: 1
|
||||
|
||||
#
|
||||
# List of options that should be disabled while the Maintenance Mode of the plugin Maintenance is active.
|
||||
# Any option not listed here will NOT be disabled, meaning AdvancedServerList will continue to handle it.
|
||||
#
|
||||
# Each option defaults to true when not present, disabling said option while Maintenance is active.
|
||||
#
|
||||
disableDuringMaintenance:
|
||||
#
|
||||
# When true (Default), disables handling of MOTD while Maintenance is enabled.
|
||||
#
|
||||
motd: true
|
||||
#
|
||||
# When true (Default), disables handling of Favicon while Maintenance is enabled.
|
||||
#
|
||||
favicon: true
|
||||
#
|
||||
# When true (Default), disables hiding of player count while Maintenance is enabled.
|
||||
#
|
||||
hidePlayers: true
|
||||
#
|
||||
# When true (Default), disables handling of player count text while Maintenance is enabled.
|
||||
#
|
||||
playerCountText: true
|
||||
#
|
||||
# When true (Default), disables handling of player count hover while Maintenance is enabled.
|
||||
#
|
||||
playerCountHover: true
|
||||
#
|
||||
# When true (Default), disables use of extra players feature while Maintenance is enabled.
|
||||
#
|
||||
extraPlayers: true
|
||||
#
|
||||
# When true (Default), disables use of max players feature while Maintenance is enabled.
|
||||
#
|
||||
maxPlayers: true
|
||||
|
||||
#
|
||||
# DO NOT EDIT!
|
||||
#
|
||||
# This is used internally to determine if the config needs to be migrated.
|
||||
# Changing or even removing this option could result in your config being broken.
|
||||
#
|
||||
config-version: 2
|
||||
config-version: ${plugin.config.version}
|
||||
@@ -1,167 +1,169 @@
|
||||
#
|
||||
# Set the priority of this profile.
|
||||
# Higher number = Higher priority.
|
||||
# If there are multiple profiles (files) will they be sorted by priority, starting with highest.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#priority
|
||||
#
|
||||
priority: 0
|
||||
|
||||
#
|
||||
# Set conditions that needs to be met.
|
||||
# Only when all conditions return true will the profile be shown (Given no profile with higher priority is used).
|
||||
# Set condition(s) that should return true to display this profile.
|
||||
# This allows you to create profiles to only show for specific scenarios (i.e. player is banned).
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#conditions
|
||||
# Multiple conditions can be chaing with the keywords 'and', 'or', or their counterparts '&&' and '||'.
|
||||
#
|
||||
#conditions:
|
||||
# - '{playerVersion} < 759'
|
||||
# No condition or an empty condition will be treated as true by default.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#condition
|
||||
#
|
||||
condition: ''
|
||||
|
||||
#
|
||||
# Option that allows you to define multiple profiles to use.
|
||||
# Each entry supports the same options as the server list profile does. Whenever an option is not present, or set to
|
||||
# an empty value (If supported) would the option in the file be used (if present).
|
||||
# This allows you to f.e. randomize the MOTD while keeping other options the same, without copy-pasting the same options.
|
||||
# Set one or multiple profiles.
|
||||
#
|
||||
# A profile will be selected randomly.
|
||||
# A profile can contain the same options as used in the file itself, except for priority and condition.
|
||||
# If multiple entries are present, a random one will be selected. Any options set in the selected profile will override
|
||||
# any existing option in the file.
|
||||
#
|
||||
# Remove this option or set it to profiles: [] to use the global options of this file.
|
||||
# Example: The below profile configuration will randomly change the MOTD between two types, but keep the Hover text
|
||||
# the same.
|
||||
#
|
||||
# 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
|
||||
#
|
||||
#profiles:
|
||||
# - motd:
|
||||
# - '<aqua>Line 1'
|
||||
# - '<aqua>Line 2'
|
||||
# favicon: ''
|
||||
# playerCount:
|
||||
# hidePlayers: false
|
||||
# hover:
|
||||
# - '<green>Line 1'
|
||||
# - '<green>Line 2'
|
||||
# - '<green>Line 3'
|
||||
# text: ''
|
||||
# extraPlayers:
|
||||
# enabled: false
|
||||
# amount: 0
|
||||
profiles:
|
||||
- motd: ['<aqua>Line A', '<gold>Line B']
|
||||
- motd:
|
||||
- '<aqua>Line 1'
|
||||
- '<gold>Line 2'
|
||||
|
||||
#
|
||||
# Set the default (Global) MOTD used by this server list profile.
|
||||
# Supports HEX colors for 1.16+ servers including gradients using MiniMessage's <gradient:color:color> format.
|
||||
#
|
||||
# Remove this option or set it to motd: [] to not alter the MOTD.
|
||||
# Set the "Message of the day" to display.
|
||||
# This option supports RGB colors for 1.16+ Servers and clients, including gradients using MiniMessage's <gradient>
|
||||
# option.
|
||||
#
|
||||
# Only the first two lines will be considered and any additional one is ignored.
|
||||
#
|
||||
# When not present or empty (motd: []), no MOTD will be set.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#motd
|
||||
#
|
||||
motd:
|
||||
- '<grey>Line 1'
|
||||
- '<grey>Line 2'
|
||||
- '<grey>First Line'
|
||||
- '<grey>Second Line'
|
||||
|
||||
#
|
||||
# Allows you to set a global (Default) favicon for this server list profile.
|
||||
# You can use one of three possible options:
|
||||
# 1. A file name matching a PNG file located in the 'favicons' folder (Needs to end with .png)
|
||||
# 2. A URL pointing to a valid Image
|
||||
# 3. ${player name} to display the player's head as favicon. Uses https://mc-heads.net for this
|
||||
# Set the Favicon (image on the left of a server entry) to display.
|
||||
# This option supports three types of inputs:
|
||||
#
|
||||
# Remove this option or set to favicon: '' to not replace the Favicon.
|
||||
# 1. Name, including .png extension, pointing to an image located in the plugin's favicons folder.
|
||||
# 2. URL pointing to an image.*
|
||||
# 3. Player name, UUID or placeholders returning one of these.*
|
||||
# https://mc-heads.net will be used to retrieve an image of the provided name/UUID.
|
||||
#
|
||||
# * These images are loaded asynchronously, meaning they may not yet be "ready" when AdvancedServerList is done with
|
||||
# the event, requiring a refresh of the server list by the player to have it shown.
|
||||
#
|
||||
# Any images above or below 64x64 pixels will be automatically resized to these dimensions.
|
||||
#
|
||||
# If not present or empty (favicon: ''), defaults to not modifying the favicon.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#favicon
|
||||
#
|
||||
favicon: ''
|
||||
|
||||
#
|
||||
# Contains various options to manipulate the player count (Text displaying online and max players allowed).
|
||||
# Contains options for modifying the player count (Text displaying <online>/<max>).
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#playercount
|
||||
#
|
||||
playerCount:
|
||||
#
|
||||
# Whether AdvancedServerList should hide the player count or not.
|
||||
# When set to true will the player count display '???' instead of <online>/<max>
|
||||
# Set whether the Player count should be hidden.
|
||||
# When set to true, the player count will be displayed as '???' instead of the usual '<online>/<max>' and all other
|
||||
# playerCount options, except for extraPlayers and maxPlayers, will be ignored.
|
||||
#
|
||||
# Note that when this is enabled will all other options, except for 'extraPlayers', be ignored.
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
# If not present, defaults to false.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#hideplayers
|
||||
#
|
||||
hidePlayers: false
|
||||
#
|
||||
# Sets the text displayed when hovering over the player count.
|
||||
# Set the lines shown when the player hovers over the player count.
|
||||
# Unlike the MOTD option does this one only support basic color and formatting codes. Any RGB colors will be
|
||||
# downsampled to the nearest matching color.
|
||||
#
|
||||
# Remove this option or set it to hover: [] to not modify the player samples on the player count.
|
||||
# If not present or empty (hover: []), defaults to not modifying the hover.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#hover
|
||||
#
|
||||
hover:
|
||||
- '<grey>Line 1'
|
||||
- '<grey>Line 2'
|
||||
- '<grey>Line 3'
|
||||
- '<aqua>Line 1'
|
||||
- '<yellow>Line 2'
|
||||
- '<green>Line 3'
|
||||
#
|
||||
# Modifies the text that usually displays '<online>/<max>'
|
||||
#
|
||||
# Note that when used, the Ping icon will display as 'outdated server'/'outdated client'.
|
||||
# This is nothing that can be fixed or avoided and would require changes from Mojang.
|
||||
# Set the text that should be displayed instead of the default '<online>/<max>' text.
|
||||
#
|
||||
# Remove this option or set it to text: '' to not modify the player count text.
|
||||
# Using this option will show the server as "outdated" to the client (Have the ping icon crossed out).
|
||||
# This cannot be fixed and would require Mojang to change stuff.
|
||||
#
|
||||
# If not present or empty (text: ''), defaults to not modifying the text.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#text
|
||||
#
|
||||
text: ''
|
||||
#
|
||||
# Allows you to modify the max player count displayed.
|
||||
# Note that this will affect ${server playersMax} (Except for when used in conditions).
|
||||
# The extraPlayers feature allows to set a number that should be added to the current online players and then be
|
||||
# used as the "max" player count.
|
||||
#
|
||||
# Using this feature will modify the ${server playersMax} placeholder, except for usage in the condition option.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#extraplayers
|
||||
#
|
||||
extraPlayers:
|
||||
#
|
||||
# Enables/Disables the extraPlayers option.
|
||||
# When enabled will the total amount of players allowed to join be modified to the current
|
||||
# number of online players + 'amount'
|
||||
# Set whether the extraPlayers feature should be enabled or not.
|
||||
# When set to true, the max players count will be modified to be the number of online players with the 'amount'
|
||||
# value added to it.
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
# If not present, defaults to false.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#extraplayers-enabled
|
||||
#
|
||||
enabled: false
|
||||
#
|
||||
# Sets how much should be added/subtracted from the current number of online players
|
||||
# to then use for the max player count.
|
||||
# Set the number that should be added to the online player count to then use as the new max player count.
|
||||
#
|
||||
# Example:
|
||||
# When set to 1 while 10 players are online would the player count - if unmodified -
|
||||
# display '10/11'. When -1 is used will it display '10/9'
|
||||
# Example: Setting this to 1 will result in ${server playersMax} displaying 11 while 10 players are online,
|
||||
# 9 when 8 are online and so on.
|
||||
#
|
||||
# Defaults to 0 when not present.
|
||||
# If not present, defaults to 0.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#extraplayers-amount
|
||||
#
|
||||
amount: 0
|
||||
#
|
||||
# Allows you to set the max players that could join your server.
|
||||
# Note that this option influences the '${server playersMax}' placeholder.
|
||||
# The maxPlayers feature allows to set a number to use as the max player count to display.
|
||||
#
|
||||
# The settings of this option have no effect should 'extraPlayers' be enabled
|
||||
# Using this feature will modify the ${server playersMax} placeholder, except for usage in the condition option.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#maxplayers
|
||||
#
|
||||
maxPlayers:
|
||||
#
|
||||
# Enables/Disables the maxPlayers option.
|
||||
# When enabled will the total amount of players allowed to join be changed to what 'amount' is set to.
|
||||
# Set whether the maxPlayers feature should be enabled or not.
|
||||
# When set to true, the max player count will be set to the 'amount' value.
|
||||
#
|
||||
# If not present, defaults to false.
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#maxplayers-enabled
|
||||
#
|
||||
enabled: false
|
||||
#
|
||||
# Sets the number to display for the max number of players allowed to join your server.
|
||||
# Set the number that should be used as the new max players count.
|
||||
#
|
||||
# Example:
|
||||
# Setting this option to 0 (Default) while 1 player is online would display '1/0'
|
||||
#
|
||||
# Defaults to 0 if not set.
|
||||
# If not present, defaults to 0.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#maxplayers-amount
|
||||
#
|
||||
|
||||
@@ -23,4 +23,5 @@
|
||||
#
|
||||
#
|
||||
|
||||
version=${plugin.version}
|
||||
version=${plugin.version}
|
||||
config-version=${plugin.config.version}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.test;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
|
||||
public class DummyPluginLogger implements PluginLogger{
|
||||
@Override
|
||||
public void debug(Class<?> clazz, String msg, Object... args){
|
||||
info("[DEBUG] [" + clazz.getSimpleName() + "] " + msg, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debugWarn(Class<?> clazz, String msg, Object... args){
|
||||
warn("[DEBUG] [" + clazz.getSimpleName() + "] " + msg, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String msg, Object... args){
|
||||
System.out.printf((msg) + "%n", args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Object... args){
|
||||
System.out.printf((msg) + "%n", args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Throwable throwable){
|
||||
System.out.printf((msg) + "%n", throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Throwable throwable, Object... args){
|
||||
System.out.printf((msg) + "%n", args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.test;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.ProfileConditionParser;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
import ch.andre601.expressionparser.templates.ExpressionTemplate;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class ExpressionParserTests{
|
||||
|
||||
private final ProfileConditionParser parser = ProfileConditionParser.create();
|
||||
private final DummyPluginLogger logger = new DummyPluginLogger();
|
||||
private final Map<String, Boolean> testValuesMap = getTestMap();
|
||||
|
||||
@Test
|
||||
public void testBasicExpressionResults(){
|
||||
for(Map.Entry<String, Boolean> values : testValuesMap.entrySet()){
|
||||
logger.info("TEST[expression=\"%s\", expected=%b]", values.getKey(), values.getValue());
|
||||
|
||||
ParseWarnCollector collector = new ParseWarnCollector(values.getKey());
|
||||
ExpressionTemplate template = parser.compile(values.getKey(), null, null, collector);
|
||||
boolean result;
|
||||
if(template == null){
|
||||
result = false;
|
||||
}else{
|
||||
result = template.returnBooleanExpression().evaluate();
|
||||
}
|
||||
|
||||
logger.info("Result (output, isExpected): " + result + ", " + (result == values.getValue()));
|
||||
assertEquals(result, values.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Boolean> getTestMap(){
|
||||
return Map.of(
|
||||
"20 > 10", true,
|
||||
"10 > 20", false,
|
||||
"10 = 10", true,
|
||||
"10 = 20", false,
|
||||
"(10 - 5) > (1 + 1)", true,
|
||||
"(10 - 10) > (1 + 1)", false,
|
||||
"100 > 50 and 50 < 100", true,
|
||||
"100 < 50 and 50 > 100", false,
|
||||
"true or 100 > 10", true,
|
||||
"false or 100 < 10", false
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,9 @@
|
||||
package ch.andre601.advancedserverlist.test;
|
||||
|
||||
import com.unascribed.flexver.FlexVerComparator;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class FlexVerTests{
|
||||
|
||||
@@ -286,7 +288,9 @@ public class FlexVerTests{
|
||||
|
||||
private void compare(String version1, String comparator, String version2, int expected){
|
||||
String expression = version1 + " " + comparator + " " + version2 + "?";
|
||||
int result = FlexVerComparator.compare(version1, version2);
|
||||
|
||||
System.out.printf("│ %-24s %5b │\n", expression, FlexVerComparator.compare(version1, version2) == expected);
|
||||
assertEquals(result, expected);
|
||||
}
|
||||
}
|
||||
+13
-16
@@ -9,7 +9,6 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import posixpath
|
||||
import re
|
||||
|
||||
from mkdocs.config.defaults import MkDocsConfig
|
||||
@@ -25,21 +24,19 @@ def on_page_markdown(
|
||||
def replace(match: Match):
|
||||
type, args = match.groups()
|
||||
args = args.strip()
|
||||
if type == "abstract": return _admo(text = args, type = "abstract")
|
||||
elif type == "info": return _admo(text = args, type = "info")
|
||||
elif type == "tip": return _admo(text = args, type = "tip")
|
||||
elif type == "success": return _admo(text = args, type = "success")
|
||||
elif type == "question": return _admo(text = args, type = "question")
|
||||
elif type == "warning": return _admo(text = args, type = "warning")
|
||||
elif type == "failure": return _admo(text = args, type = "failure")
|
||||
elif type == "danger": return _admo(text = args, type = "danger")
|
||||
elif type == "bug": return _admo(text = args, type = "bug")
|
||||
elif type == "example": return _admo(text = args, type = "example")
|
||||
elif type == "quote": return _admo(text = args, type = "quote")
|
||||
else: return _admo(text = args)
|
||||
|
||||
# Otherwise, raise an error
|
||||
raise RuntimeError(f"Unknown shortcode: {type}")
|
||||
if type == "abstract": return _admo(text = args, type = "abstract")
|
||||
elif type == "info": return _admo(text = args, type = "info")
|
||||
elif type == "tip": return _admo(text = args, type = "tip")
|
||||
elif type == "success": return _admo(text = args, type = "success")
|
||||
elif type == "question": return _admo(text = args, type = "question")
|
||||
elif type == "warning": return _admo(text = args, type = "warning")
|
||||
elif type == "failure": return _admo(text = args, type = "failure")
|
||||
elif type == "danger": return _admo(text = args, type = "danger")
|
||||
elif type == "bug": return _admo(text = args, type = "bug")
|
||||
elif type == "example": return _admo(text = args, type = "example")
|
||||
elif type == "quote": return _admo(text = args, type = "quote")
|
||||
elif type == "deprecated": return _admo(text = args, type = "deprecated")
|
||||
else: return _admo(text = args)
|
||||
|
||||
# Find and replace all external asset URLs in current page
|
||||
return re.sub(
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
#
|
||||
# A simple hook that replaces any appearances of \| with just |.
|
||||
#
|
||||
# There is an inconsistency between GitHub flavourited Markdown and Python Markdown
|
||||
# where the former treats | as part of a table, even if it is inside inline code
|
||||
# causing unwanted table rendering.
|
||||
#
|
||||
# The only way to prevent this is to escape it by prefixing it with a back slash (\).
|
||||
# Unfortunately does this cause issues on Python-Markdown, as it renders inline code
|
||||
# content as-is without special treatments whatsoever, meaning that `\|` will be
|
||||
# rendered as <code>\|</code> in the end.
|
||||
#
|
||||
# Using this hook, `\|` is being turned into `|` before further processing, resulting
|
||||
# in <code>|</code> being rendered in the end, while preserving proper table rendering
|
||||
# on GitHub and co.
|
||||
#
|
||||
import re
|
||||
|
||||
from mkdocs.config.defaults import MkDocsConfig
|
||||
from mkdocs.structure.files import File, Files
|
||||
from mkdocs.structure.pages import Page
|
||||
|
||||
def on_page_markdown(
|
||||
markdown: str, *, page: Page, config: MkDocsConfig, files: Files
|
||||
):
|
||||
return re.sub(r"\\\|","|",markdown)
|
||||
@@ -8,28 +8,28 @@
|
||||
Object summaries
|
||||
-->
|
||||
{% if page.meta.constructors %}
|
||||
{{ info.summary('Constructor Summary', page.meta.constructors, details_type='constructor') }}
|
||||
{{ info.summary('Constructor Summary', page.meta.constructors, details_type='constructor', defaults=page.meta.defaults) }}
|
||||
{% endif %}
|
||||
{% if page.meta.classes %}
|
||||
{{ info.summary('Class Summary', page.meta.classes, details_type='class') }}
|
||||
{{ info.summary('Class Summary', page.meta.classes, details_type='class', defaults=page.meta.defaults) }}
|
||||
{% endif %}
|
||||
{% if page.meta.enums %}
|
||||
{{ info.summary('Enum Constant Summary', page.meta.enums, details_type='enum') }}
|
||||
{{ info.summary('Enum Constant Summary', page.meta.enums, details_type='enum', defaults=page.meta.defaults) }}
|
||||
{% endif %}
|
||||
{% if page.meta.methods or page.meta.inherits %}
|
||||
{{ info.summary('Method Summary', page.meta.methods, page.meta.inherits, details_type='method') }}
|
||||
{{ info.summary('Method Summary', page.meta.methods, page.meta.inherits, details_type='method', defaults=page.meta.defaults) }}
|
||||
{% endif %}
|
||||
<!--
|
||||
Detailed object info
|
||||
-->
|
||||
{% if page.meta.constructors %}
|
||||
{{ info.info('Constructor Detail', page.meta.constructors) }}
|
||||
{{ info.info('Constructor Detail', page.meta.constructors, 'constructor', defaults=page.meta.defaults) }}
|
||||
{% endif %}
|
||||
{% if page.meta.enums %}
|
||||
{{ info.info('Enum Constant Detail', page.meta.enums, true) }}
|
||||
{{ info.info('Enum Constant Detail', page.meta.enums, 'enum', defaults=page.meta.defaults) }}
|
||||
{% endif %}
|
||||
{% if page.meta.methods %}
|
||||
{{ info.info('Method Detail', page.meta.methods)}}
|
||||
{{ info.info('Method Detail', page.meta.methods, 'method', defaults=page.meta.defaults)}}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
@@ -1,4 +1,4 @@
|
||||
{% macro summary(title, summaries, inherits, details_type = 'unknown') -%}
|
||||
{% macro summary(title, summaries, inherits, details_type = 'unknown', defaults = []) -%}
|
||||
<h2 id="{{ title | lower() | replace(' ', '-') | e}}">
|
||||
{{ title }}
|
||||
</h2>
|
||||
@@ -28,6 +28,8 @@
|
||||
|
||||
{% if summary.type and summary.type.name %}
|
||||
{% set modifiers.name = modifiers.name ~ summary.type.name %}
|
||||
{% elif defaults and defaults.type and defaults.type.name %}
|
||||
{% set modifiers.name = modifiers.name ~ defaults.type.name %}
|
||||
{% else %}
|
||||
{% set modifiers.name = modifiers.name ~ "void" %}
|
||||
{% endif %}
|
||||
@@ -103,14 +105,14 @@
|
||||
</div>
|
||||
{%- endmacro %}
|
||||
|
||||
{% macro info(title, details, enum = false) -%}
|
||||
{% macro info(title, details, details_type = 'unknown', defaults = []) -%}
|
||||
<h2 id="{{ title | lower() | replace(' ', '-') | e}}">
|
||||
{{ title }}
|
||||
</h2>
|
||||
{% for detail in details %}
|
||||
<div class="api-detail">
|
||||
{% set final_name = namespace(name = "") %}
|
||||
{% if enum %}
|
||||
{% if details_type == "enum" %}
|
||||
{% set final_name.name = detail.name | upper() %}
|
||||
{% else %}
|
||||
{% set final_name.name = detail.name ~ "(" %}
|
||||
@@ -121,7 +123,7 @@
|
||||
{% if loop.revindex > 1 %}{% set final_name.name = final_name.name ~ ", " %}{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if not enum %}
|
||||
{% if details_type != "enum" %}
|
||||
{% set final_name.name = final_name.name ~ ")" %}
|
||||
{% endif %}
|
||||
|
||||
@@ -138,12 +140,20 @@
|
||||
<api__static></api__static> <api__final></api__final>
|
||||
{% endif %}
|
||||
|
||||
{% if detail.type %}
|
||||
{% if detail.type and details_type == "method" %}
|
||||
{% if detail.type.link %}
|
||||
<a href="{{ detail.type.link }}" class="api-type__{{- detail.type.type | default('primitive') -}}">{{ detail.type.name | default('void') | e }}</a>
|
||||
{% else %}
|
||||
<span class="api-type__{{- detail.type.type | default('primitive') -}}">{{ detail.type.name | default('void') | e }}</span>
|
||||
{% endif %}
|
||||
{% elif defaults and defaults.type and details_type == "method" %}
|
||||
{% if defaults.type.link %}
|
||||
<a href="{{ defaults.type.link }}" class="api-type__{{- defaults.type.type | default('primitive') -}}">{{ defaults.type.name | default('void') | e }}</a>
|
||||
{% else %}
|
||||
<span class="api-type__{{- defaults.type.type | default('primitive') -}}">{{ defaults.type.name | default('void') }}</span>
|
||||
{% endif %}
|
||||
{% elif details_type == "method" %}
|
||||
<span class="api-type__primitive">void</span>
|
||||
{% endif %}
|
||||
<code>{{ final_name.name | e }}</code><a href="#{{ final_name.name | lower() | replace(' ', '-') | e }}" class="headerlink" title="Permanent link">¶</a>
|
||||
</h3>
|
||||
|
||||
@@ -6,16 +6,6 @@
|
||||
<!-- Actions -->
|
||||
{% include "partials/actions.html" %}
|
||||
|
||||
{% if config.extra.github_repository %}
|
||||
<div class="admonition info">
|
||||
<p class="admonition-title">Moved</p>
|
||||
<p>
|
||||
The documenation has been moved and can now be found at <a href="https://asl.andre601.ch" target="_blank" rel="noreferral nofollow noopener"><strong>asl.andre601.ch</strong></a>.<br>
|
||||
This page in particular can be found at <a href="https://asl.andre601.ch/{{ page.url }}" target="_blank" rel="noreferral nofollow noopener"><strong>asl.andre601.ch/{{ page.url }}</strong></a>.
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!--
|
||||
Hack: check whether the content contains a h1 headline. If it doesn't, the
|
||||
page title (or respectively site name) is used as the main headline.
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
nav:
|
||||
- Home: index.md
|
||||
- getting-started
|
||||
- commands
|
||||
- profiles
|
||||
- examples
|
||||
- migration
|
||||
- api
|
||||
- PlaceholderAPI: placeholderapi
|
||||
@@ -0,0 +1,64 @@
|
||||
# BanPlugins Addon
|
||||
|
||||
The BanPlugins Addon was made to provide placeholders for different punishment plugins to use in AdvancedServerList.
|
||||
|
||||
## Placeholders
|
||||
|
||||
### AdvancedBan
|
||||
|
||||
Placeholders for the plugin [AdvancedBan](https://www.spigotmc.org/resources/8695/){ target="_blank" rel="nofollow" } are available to use.
|
||||
|
||||
| Placeholder | Description |
|
||||
|---------------------------------|-------------------------------------------------------------------------------------------|
|
||||
| `${advancedban isMuted}` | Whether the player is muted or not. |
|
||||
| `${advancedban muteReason}` | The reason for why the player was muted. Returns invalid placeholder if no mute was set. |
|
||||
| `${advancedban muteDuration}` | Relative time until the mute expires.[^1] Returns invalid placeholder if no mute was set. |
|
||||
| `${advancedban muteExpiration}` | Date on when the mute will expire.[^2] |
|
||||
| `${advancedban isBanned}` | Whether the player is banned or not. |
|
||||
| `${advancedban banReason}` | The reason for why the player was banned. Returns invalid placeholder if no ban was set. |
|
||||
| `${advancedban banDuration}` | Relative time until the ban expires.[^3] Returns invalid placeholder if no ban was set. |
|
||||
| `${advancedban banExpiration}` | Date on when the ban will expire.[^4] |
|
||||
|
||||
[^1]:
|
||||
An optional boolean can be added to set whether the duration should be from the start or not. `false` is the default.
|
||||
Example: `${advancedban muteDuration true}`
|
||||
[^2]:
|
||||
An optional Date and time Pattern can be set to change the displayed output. The default is `dd, MMM yyyy HH:mm:ss`.
|
||||
Example: `${advancedban muteExpiration yyyy-MM-dd HH:mm:ss}`
|
||||
[^3]:
|
||||
An optional boolean can be added to set whether the duration should be from the start or not. `false` is the default.
|
||||
Example: `${advancedban banDuration true}`
|
||||
[^4]:
|
||||
An optional Date and time Pattern can be set to change the displayed output. The default is `dd, MMM yyyy HH:mm:ss`.
|
||||
Example: `${advancedban banExpiration yyyy-MM-dd HH:mm:ss}`
|
||||
|
||||
### LibertyBans
|
||||
|
||||
Placeholders for the plugin [LibertyBans](https://modrinth.com/plugin/libertybans/){ target="_blank" rel="nofollow" } are available to use.
|
||||
|
||||
| Placeholder | Description |
|
||||
|---------------------------------|------------------------------------------------------------------------------------------|
|
||||
| `${libertybans isMuted}` | Whether the player is muted or not. |
|
||||
| `${libertybans muteReason}` | The reason for why the player was muted. Returns invalid placeholder if no mute was set. |
|
||||
| `${libertybans muteExpiration}` | Date on when the mute will expire.[^5] |
|
||||
| `${libertybans isBanned}` | Whether the player is banned or not. |
|
||||
| `${libertybans banReason}` | The reason for why the player was banned. Returns invalid placeholder if no ban was set. |
|
||||
| `${libertybans banExpiration}` | Date on when the ban will expire.[^6] |
|
||||
|
||||
[^5]:
|
||||
An optional Date and time Pattern can be set to change the displayed output. The default is `dd, MMM yyyy HH:mm:ss`.
|
||||
Example: `${libertybans muteExpiration yyyy-MM-dd HH:mm:ss}`
|
||||
[^6]:
|
||||
An optional Date and time Pattern can be set to change the displayed output. The default is `dd, MMM yyyy HH:mm:ss`.
|
||||
Example: `${libertybans banExpiration yyyy-MM-dd HH:mm:ss}`
|
||||
|
||||
## Example
|
||||
|
||||
```yaml title="banned.yml"
|
||||
priority: 1
|
||||
condition: '${advancedban isBanned}'
|
||||
|
||||
motd:
|
||||
- '<red>You were <bold>BANNED</bold>!'
|
||||
- '<red>Expires: <grey>${advancedban banExpiration}'
|
||||
```
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
icon: octicons/plus-circle-24
|
||||
---
|
||||
|
||||
# Addons
|
||||
|
||||
This section contains a curated list of add-ons for AdvancedServerList which can be used to enhance the plugin in different ways.
|
||||
Do you have a plugin that hooks into AdvancedServerList that is not listed here? Contact Andre601 on Discord and it will be added!
|
||||
|
||||
## First-party Addons
|
||||
|
||||
These Addons are made by Andre601 and available together with the plugin downloads.
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- [**BanPlugins**](banplugins.md)
|
||||
|
||||
----
|
||||
|
||||
Addon for different Punishment plugins such as AdvancedBan, that add new placeholders to use in AdvancedServerList.
|
||||
|
||||
</div>
|
||||
|
||||
## Third-party
|
||||
|
||||
Third-party addons made by other people not working on AdvancedServerList.
|
||||
|
||||
*Currently no entries*
|
||||
@@ -1,2 +0,0 @@
|
||||
nav:
|
||||
- ...
|
||||
+88
-1
@@ -7,6 +7,93 @@ icon: octicons/log-24
|
||||
This page lists the recent changes made towards the AdvancedServerListAPI.
|
||||
They are ordered newest to oldest.
|
||||
|
||||
## v3.3.0 { #v3.3.0 }
|
||||
|
||||
### :octicons-plus-circle-24:{ .changelog-added title="Added" } Added { #v3.3.0-added }
|
||||
|
||||
- Added `PostServerListSetEvent` to the different platform APIs.
|
||||
- Fired **after** AdvancedServerList is done with handling the PingEvent.
|
||||
- Allows to retrieve the [`ProfileEntry`][profileentry] used for the PingEvent.
|
||||
|
||||
## v3.2.1 { #v3.2.1 }
|
||||
|
||||
### :octicons-pencil-24:{ .changelog-changed title="Changed" } Changed { #v3.2.1-changed }
|
||||
|
||||
- Removed usage of `${api.version}` in the different pom.xml for version resolving.
|
||||
|
||||
## v3.2.0 { #v3.2.0 }
|
||||
|
||||
### :octicons-plus-circle-24:{ .changelog-added title="Added" } Added { #v3.2.0-added }
|
||||
|
||||
- New setter methods added to [`ProfileEntry.Builder`][profileentry.builder] class, replacing old ones (See deprecations below):
|
||||
- [`extraPlayersCount(Integer)`][extraplayerscount]
|
||||
- [`extraPlayersEnabled(NullBool)`][extraplayersenabled]
|
||||
- [`favicon(String)`][favicon]
|
||||
- [`hidePlayersEnabled(NullBool)`][hideplayersenabled]
|
||||
- [`maxPlayersCount(Integer)`][maxplayerscount]
|
||||
- [`maxPlayersEnabled(NullBool)`][maxplayersenabled]
|
||||
- [`motd(List<String>)`][motd]
|
||||
- [`playerCountText(String)`][playercounttext]
|
||||
- [`players(List<String>)`][players]
|
||||
|
||||
[extraplayerscount]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#extraplayerscount(integer)
|
||||
[extraplayersenabled]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#extraplayersenabled(nullbool)
|
||||
[favicon]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#favicon(string)
|
||||
[hideplayersenabled]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#hideplayersenabled(nullbool)
|
||||
[maxplayerscount]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#maxplayerscount(integer)
|
||||
[maxplayersenabled]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#maxplayersenabled(nullbool)
|
||||
[motd]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#motd(list<string>)
|
||||
[playercounttext]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#playercounttext(string)
|
||||
[players]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#players(list<string>)
|
||||
|
||||
### :octicons-pencil-24:{ .changelog-changed title="Changed" } Changed { #v3.2.0-changed }
|
||||
|
||||
- The API has been moved to Codeberg and is now available under a new repository URL to download. The group and artifact ID remained the same, but version no longer has a `v` prefix:
|
||||
|
||||
/// tab | ":simple-apachemaven: Maven (pom.xml)"
|
||||
```xml
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>codeberg</id>
|
||||
<url>https://codeberg.org/api/packages/Andre601/maven/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>ch.andre601.asl-api</groupId>
|
||||
<artifactId>api</artifactId>
|
||||
<version>{apiVersion}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
```
|
||||
///
|
||||
/// tab | ":simple-gradle: Gradle (build.gradle)"
|
||||
```groovy
|
||||
repositories {
|
||||
maven = { url ="https://codeberg.org/api/packages/Andre601/maven/" }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly "ch.andre601.asl-api:api:{apiVersion}"
|
||||
}
|
||||
```
|
||||
///
|
||||
|
||||
### :octicons-zap-24:{ .changelog-breaking title="Deprecated" } Deprecated { #v3.2.0-deprecated }
|
||||
|
||||
- Setters in [`ProfileEntry.Builder`][profileentry.builder] deprecated in favour of more consistent method naming.
|
||||
- `setExtraPlayersCount(Integer)`
|
||||
- `setExtraPlayersEnabled(NullBool)`
|
||||
- `setFavicon(String)`
|
||||
- `setHidePlayersEnabled(NullBool)`
|
||||
- `setMaxPlayersCount(Integer)`
|
||||
- `setMaxPlayersEnabled(NullBool)`
|
||||
- `setMotd(List<String>)`
|
||||
- `setPlayerCountText(String)`
|
||||
- `setPlayers(List<String>)`
|
||||
|
||||
## v3.1.0 { #v3.1.0 }
|
||||
|
||||
### :octicons-plus-circle-24:{ .changelog-added title="Added" } Added { #v3.1.0-added }
|
||||
@@ -111,6 +198,6 @@ Templates for changelog
|
||||
### :octicons-plus-circle-24:{ .changelog-added title="Added" } Added { #v-added }
|
||||
### :octicons-pencil-24:{ .changelog-changed title="Changed" } Changed { #v-changed }
|
||||
### :octicons-trash-24:{ .changelog-removed title="Removed" } Removed { #v-removed }
|
||||
### :octicons-zap-24:{ .changelog-deprecated title="Deprecated" } Deprecated { #v-deprecated }
|
||||
### :octicons-zap-24:{ .changelog-breaking title="Deprecated" } Deprecated { #v-deprecated }
|
||||
|
||||
-->
|
||||
+24
-13
@@ -4,8 +4,7 @@ icon: octicons/command-palette-24
|
||||
|
||||
# API
|
||||
|
||||
AdvancedServerList v2 introduced a new API that plugins can hook into to use.
|
||||
It provides a way for your plugin to provide its own placeholders that should be parsed by AdvancedServerList and also an event to modify the server list.
|
||||
AdvancedServerList offers an API that other plugins can use to add their own placeholder to the plugin, listen for specific events or even modify Server List Profiles on the fly.
|
||||
|
||||
## Add dependency
|
||||
|
||||
@@ -15,8 +14,8 @@ Add the following to your `pom.xml`, `build.gradle` or `build.gradle.kts` depend
|
||||
```xml title="pom.xml"
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>jitpack</id>
|
||||
<url>https://jitpack.io/</url>
|
||||
<id>codeberg</id>
|
||||
<url>https://codeberg.org/api/packages/Andre601/maven/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
@@ -54,7 +53,7 @@ Add the following to your `pom.xml`, `build.gradle` or `build.gradle.kts` depend
|
||||
/// tab | :simple-gradle: Gradle
|
||||
```groovy title="build.gradle"
|
||||
repositorories {
|
||||
maven { url = 'https://jitpack.io/' }
|
||||
maven { url = 'https://codeberg.org/api/packages/Andre601/maven/' }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -71,7 +70,7 @@ dependencies {
|
||||
/// tab | :simple-gradle: Gradle (KTS)
|
||||
```kotlin title="build.gradle.kts"
|
||||
repositories {
|
||||
maven("https://jitpack.io")
|
||||
maven("https://codeberg.org/api/packages/Andre601/maven/")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -362,18 +361,22 @@ Your plugin should now hook into AdvancedServerList and register its own custom
|
||||
|
||||
## Listening for events
|
||||
|
||||
<!-- admo:info This requires the platform specific dependencies -->
|
||||
<!-- admo:info These events require the platform-specific APIs -->
|
||||
|
||||
AdvancedServerList provides an Event that your plugin can listen for.
|
||||
The event is called `PreServerListSetEvent` and provides the following methods to use:
|
||||
AdvancedServerList provides Events that your plugin can listen for specific situations.
|
||||
|
||||
### PreServerListSetEvent
|
||||
|
||||
This event is called **before** AdvancedServerList starts handling the PingEvent of the Server/Proxy.
|
||||
It allows you to get and alter the [ProfileEntry][profileentry] used in the PingEvent, or even outright cancel the event itself.
|
||||
|
||||
The event offers the following methods:
|
||||
|
||||
- [`getEntry()`][getentry] - Gets the currently set [`ProfileEntry`][profileentry].
|
||||
- [`setEntry(ProfileEntry)`][setentry] - Sets a new [`ProfileEntry`][profileentry] to use.
|
||||
- [`isCancelled()`][iscancelled] - Gets the current cancelled state of the event.
|
||||
- [`setCancelled(boolean)`][setcancelled] - Sets the current cancelled state.
|
||||
|
||||
Setting the event's cancelled state to true will result in AdvancedServerList not altering the Server list.
|
||||
|
||||
Please check the server/proxy's documentation on how to listen for events with your plugin.
|
||||
|
||||
[getentry]: reference/api/ch.andre601.advancedserverlist.api/events/genericserverlistevent.md#getentry()
|
||||
@@ -381,6 +384,13 @@ Please check the server/proxy's documentation on how to listen for events with y
|
||||
[iscancelled]: reference/api/ch.andre601.advancedserverlist.api/events/genericserverlistevent.md#iscancelled()
|
||||
[setcancelled]: reference/api/ch.andre601.advancedserverlist.api/events/genericserverlistevent.md#setcancelled(boolean)
|
||||
|
||||
### PostServerListSetEvent
|
||||
|
||||
This event is called **after** AdvancedServerList has completed its handling of the Server's/Proxy's PingEvent.
|
||||
|
||||
It provides a method to retrieve the [ProfileEntry][profileentry] used during the PingEvent.
|
||||
Do note that this ProfileEntry is **not** a representation of what is actually displayed in the server list, but rather what has been used by AdvancedServerList. It may also be `null` should the event handling get cancelled for any reason.
|
||||
|
||||
[profileentry]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/index.md
|
||||
|
||||
### ProfileEntry
|
||||
@@ -388,8 +398,9 @@ Please check the server/proxy's documentation on how to listen for events with y
|
||||
The ProfileEntry record is the core class used within the `PreServerListSetEvent`. It sets what values (MOTD, Favicon, Players, etc.) should be displayed.
|
||||
Note that the record is - by nature - immutable and that the [`Builder`][builder] class should be used to create a new ProfileEntry instance to use.
|
||||
|
||||
A convenience method exists to create a `Builder` instance from an existing `ProfileEntry` in case you only want to alter certain options while everything else unchanged.
|
||||
A convenience method ([`builder()`][builder()]) exists to create a `Builder` instance from an existing `ProfileEntry` in case you only want to alter certain options while everything else should remain unchanged.
|
||||
|
||||
This allows you to customize the Server list using your plugin. Just keep in mind that other plugins may also do the same, overriding your changes.
|
||||
|
||||
[builder]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md
|
||||
[builder]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md
|
||||
[builder()]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/index.md#builder()
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
template: redirect.html
|
||||
|
||||
location: https://docs.andre601.ch/asl-api
|
||||
location: https://jd.andre601.ch/asl-api
|
||||
|
||||
title: Javadocs
|
||||
icon: octicons/link-external-24
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
nav:
|
||||
- index.md
|
||||
- api: api
|
||||
- platform-bukkit: platform-bukkit
|
||||
- platform-bungeecord: platform-bungeecord
|
||||
- platform-velocity: platform-velocity
|
||||
@@ -1,3 +0,0 @@
|
||||
nav:
|
||||
- index.md
|
||||
- ch.andre601.advancedserverlist.api: ch.andre601.advancedserverlist.api
|
||||
@@ -8,7 +8,7 @@ constructors:
|
||||
- name: 'identifier'
|
||||
description: 'The identifier to use for the placeholder. Cannot be empty.'
|
||||
type: String
|
||||
attributes:
|
||||
attribute:
|
||||
- notnull
|
||||
|
||||
methods:
|
||||
@@ -28,7 +28,7 @@ methods:
|
||||
type: GenericServer
|
||||
description: 'The <a href="./../objects/genericserver/"><code>GenericServer</code> instance</a> used.'
|
||||
returns: 'Possibly-parsed or possibly-null String to replace the placeholder with.'
|
||||
attributes:
|
||||
attribute:
|
||||
- nullable
|
||||
- abstract
|
||||
type:
|
||||
|
||||
+262
-107
@@ -1,59 +1,213 @@
|
||||
---
|
||||
template: api-doc.html
|
||||
|
||||
defaults:
|
||||
type:
|
||||
name: 'Builder'
|
||||
type: 'object'
|
||||
|
||||
constructors:
|
||||
- name: 'Builder'
|
||||
description: 'Empty Builder Constructor used to create a new instance of this class.'
|
||||
|
||||
methods:
|
||||
- name: 'setMotd'
|
||||
- name: 'extraPlayersCount'
|
||||
description: |
|
||||
Sets the number of players to add to the online players to use as the new max players value.<br>
|
||||
This option has no effect when <a href="../#extraplayersenabled()"><code>extraPlayersEnabled</code></a> is set to <a href="../../../objects/nullbool/#false"><code>NullBool.FALSE</code></a> or <a href="../../objects/nullbool/#not_set"><code>NullBool.NOT_SET</code></a>.<br>
|
||||
<br>
|
||||
Set this to <code>null</code> to not alter the max player count. Alternatively, set <a href="#setextraplayersenabled(nullbool)"><code>setExtraPlayersEnabled(NullBool)</code></a> to <a href="../../../objects/nullbool/#false"><code>NullBool.FALSE</code></a>.
|
||||
parameters:
|
||||
- name: 'extraPlayersCount'
|
||||
description: 'The number of extra players to add.'
|
||||
type: 'Integer'
|
||||
attribute:
|
||||
- 'nullable'
|
||||
returns: 'This Builder after the extra player count has been set. Useful for chaining.'
|
||||
- name: 'extraPlayersEnabled'
|
||||
description: |
|
||||
Sets whether the extra players feature should be enabled or not.<br>
|
||||
<br>
|
||||
Set to <a href="../../../objects/nullbool#not_set"><code>NullBool.NOT_SET</code></a> to not set this.
|
||||
parameters:
|
||||
- name: 'extraPlayersEnabled'
|
||||
description: 'Whether the extra players feature should be enabled or not.'
|
||||
type: 'NullBool'
|
||||
attribute:
|
||||
- 'notnull'
|
||||
returns: 'This Builder after the NullBool has been set. Useful for chaining.'
|
||||
throws:
|
||||
- name: 'IllegalArgumentException'
|
||||
description: Thrown by the <code>CheckUtil</code> in case <code>null</code> has been provided as parameter.
|
||||
- name: 'favicon'
|
||||
description: |
|
||||
Sets the value to use for the favicon.<br>
|
||||
The following values are supported:
|
||||
<ul>
|
||||
<li>URL to a valid PNG file.</li>
|
||||
<li>File name (with <code>.png</code> extension) matching a file saved in the favicons folder of AdvancedServerList.</li>
|
||||
<li><code>${player uuid}</code> to display the avatar of the player.
|
||||
</ul>
|
||||
Set to an empty String or <code>null</code> to not alter the Favicon.
|
||||
parameters:
|
||||
- name: 'favicon'
|
||||
description: 'The favicon to set.'
|
||||
type: 'String'
|
||||
attribute:
|
||||
- 'nullable'
|
||||
returns: 'This Builder after the Favicon has been set. Useful for chaining.'
|
||||
- name: 'hidePlayersEnabled'
|
||||
description: |
|
||||
Sets whether the player count should be hidden or not.<br>
|
||||
<br>
|
||||
Set to <a href="../../../objects/nullbool#not_set"><code>NullBool.NOT_SET</code></a> to not set this.
|
||||
parameters:
|
||||
- name: 'hidePlayersEnabled'
|
||||
description: 'Whether the player count should be hidden or not.'
|
||||
type: 'NullBool'
|
||||
attribute:
|
||||
- 'notnull'
|
||||
returns: 'This Builder after the NullBool has been set. Useful for chaining.'
|
||||
throws:
|
||||
- name: 'IllegalArgumentException'
|
||||
description: 'Thrown by the <code>CheckUtil</code> in case <code>null</code> has been provided as parameter.'
|
||||
- name: 'maxPlayersCount'
|
||||
description: |
|
||||
Sets the number of max players allowed to join this server.<br>
|
||||
This option has no effect when <a href="#maxplayersenabled(nullbool)">maxPlayersEnabled</a> is set to <a href="../../../objects/nullbool/#false"><code>NullBool.FALSE</code></a> or <a href="../../../objects/nullbool/#not_set"><code>NullBool.NOT_SET</code></a>.<br>
|
||||
<br>
|
||||
Set this to <code>null</code> to not alter the max player count. Alternatively <a href="#maxplayersenabled(nullbool)">disable max Players</a>.
|
||||
parameters:
|
||||
- name: 'maxPlayersCount'
|
||||
description: 'The number of max players to set.'
|
||||
type: 'Integer'
|
||||
attribute:
|
||||
- 'nullable'
|
||||
returns: 'This Builder after the max player count has been set. Useful for chaining.'
|
||||
- name: 'maxPlayersEnabled'
|
||||
description: |
|
||||
Sets whether the max players feature should be enabled.<br>
|
||||
<br>
|
||||
Set to <a href="../../../objects/nullbool/#not_set"><code>NullBool.NOT_SET</code></a> to not set this.<br>
|
||||
<br>
|
||||
An <code>IllegalArgumentException</code> may be thrown by the <code>CheckUtil</code> should maxPlayersEnabled be null.
|
||||
parameters:
|
||||
- name: 'maxPlayersEnabled'
|
||||
description: 'Whether the extra players feature should be enabled or not.'
|
||||
type: 'NullBool'
|
||||
attribute:
|
||||
- 'notnull'
|
||||
returns: 'This Builder after the NullBool has been set. Useful for chaining.'
|
||||
throws:
|
||||
- name: 'IllegalArgumentException'
|
||||
description: 'Thrown by the <code>CheckUtil</code> in case <code>null</code> has been provided as parameter.'
|
||||
- name: 'motd'
|
||||
description: |
|
||||
Sets a new MOTD to use.<br>
|
||||
<br>
|
||||
Set to an empty list to not change the MOTD.<br>
|
||||
Only the first two entries of the list will be considered and any additional ones discarded.
|
||||
returns: 'This Builder after the motd has been set. Useful for chaining.'
|
||||
Only the first two entries of the list will be considered and any additional ones discarded.<br>
|
||||
<br>
|
||||
An <code>IllegalArgumentException</code> may be thrown by the <code>CheckUtil</code> should the provided motd list be null.
|
||||
parameters:
|
||||
- name: 'motd'
|
||||
description: 'The MOTD to use.'
|
||||
type: 'List<String>'
|
||||
attributes:
|
||||
- notnull
|
||||
attribute:
|
||||
- 'notnull'
|
||||
returns: 'This Builder after the motd has been set. Useful for chaining.'
|
||||
throws:
|
||||
- name: 'IllegalArgumentException'
|
||||
description: 'Thrown by the <code>CheckUtil</code> in case <code>null</code> has been provided as parameter.'
|
||||
type:
|
||||
name: 'Builder'
|
||||
type: 'object'
|
||||
- name: 'setPlayers'
|
||||
description: |
|
||||
Sets the players (lines) to use for the hover.<br>
|
||||
<br>
|
||||
Set to an empty list to not change the hover text.
|
||||
returns: 'This Builder after the players have been set. Useful for chaining.'
|
||||
parameters:
|
||||
- name: 'players'
|
||||
description: 'The lines to set for the hover.'
|
||||
type: 'List<String>'
|
||||
attributes:
|
||||
- notnull
|
||||
throws:
|
||||
- name: 'IllegalArgumentException'
|
||||
description: 'Thrown by the <code>CheckUtil</code> in case <code>null</code> has been provided as parameter.'
|
||||
type:
|
||||
name: 'Builder'
|
||||
type: 'object'
|
||||
- name: 'setPlayerCountText'
|
||||
- name: 'playerCountText'
|
||||
description: |
|
||||
Sets the text to override the player count with.<br>
|
||||
<br>
|
||||
Set to an empty String or <code>null</code> to not alter the player count text.
|
||||
returns: 'This Builder after the player count text has been set. Useful for chaining.'
|
||||
parameters:
|
||||
- name: 'playerCountText'
|
||||
description: 'The text to show in the player count.'
|
||||
type: String
|
||||
attributes:
|
||||
type: 'String'
|
||||
attribute:
|
||||
- 'nullable'
|
||||
returns: 'This Builder after the player count text has been set. Useful for chaining.'
|
||||
- name: 'players'
|
||||
description: |
|
||||
Sets the players (lines) to use for the hover.<br>
|
||||
<br>
|
||||
Set to an empty list to not change the hover text.
|
||||
<br>
|
||||
An <code>IllegalArgumentException</code> may be thrown by the <code>CheckUtil</code> should the provided okayersmotd list be null.
|
||||
parameters:
|
||||
- name: 'players'
|
||||
description: 'The lines to set for the hover.'
|
||||
type: 'List<String>'
|
||||
attribute:
|
||||
- 'notnull'
|
||||
returns: 'This Builder after the players have been set. Useful for chaining.'
|
||||
throws:
|
||||
- name: 'IllegalArgumentException'
|
||||
description: 'Thrown by the <code>CheckUtil</code> in case <code>null</code> has been provided as parameter.'
|
||||
- name: 'build'
|
||||
description: 'Creates a new <a href="./.."><code>ProfileEntry</code> instance</a> with the values set in this Builder.'
|
||||
returns: 'New <a href="./.."><code>ProfileEntry</code> instance</a>.'
|
||||
type:
|
||||
name: 'ProfileEntry'
|
||||
type: 'object'
|
||||
link: './..'
|
||||
#
|
||||
# Deprecated stuff
|
||||
#
|
||||
- name: 'setExtraPlayerCount'
|
||||
description: |
|
||||
Sets the number of players to add to the online players to use as the new max players value.<br>
|
||||
This option has no effect when <a href="../#extraplayersenabled()"><code>extraPlayersEnabled</code></a> is set to <a href="../../objects/nullbool/#false"><code>NullBool.FALSE</code></a> or <a href="../../objects/nullbool/#not_set"><code>NullBool.NOT_SET</code></a>.<br>
|
||||
<br>
|
||||
Set this to <code>null</code> to not alter the max player count. Alternatively, set <a href="#setextraplayersenabled(nullbool)"><code>setExtraPlayersEnabled(NullBool)</code></a> to <a href="../../objects/nullbool/#false"><code>NullBool.FALSE</code></a>.
|
||||
returns: 'This Builder after the extra player count has been set. Useful for chaining.'
|
||||
parameters:
|
||||
- name: 'extraPlayersCount'
|
||||
description: 'The number of extra players to add.'
|
||||
type: Integer
|
||||
attribute:
|
||||
- nullable
|
||||
deprecated: 'Typo in the name. Use <a href="#setextraplayerscount(integer)">setExtraPlayersCount(Integer)</a> instead.'
|
||||
type:
|
||||
name: 'Builder'
|
||||
type: 'object'
|
||||
- name: 'setExtraPlayersCount'
|
||||
description: |
|
||||
Sets the number of players to add to the online players to use as the new max players value.<br>
|
||||
This option has no effect when <a href="../#extraplayersenabled()"><code>extraPlayersEnabled</code></a> is set to <a href="../../objects/nullbool/#false"><code>NullBool.FALSE</code></a> or <a href="../../objects/nullbool/#not_set"><code>NullBool.NOT_SET</code></a>.<br>
|
||||
<br>
|
||||
Set this to <code>null</code> to not alter the max player count. Alternatively, set <a href="#setextraplayersenabled(nullbool)"><code>setExtraPlayersEnabled(NullBool)</code></a> to <a href="../../objects/nullbool/#false"><code>NullBool.FALSE</code></a>.
|
||||
returns: 'This Builder after the extra player count has been set. Useful for chaining.'
|
||||
parameters:
|
||||
- name: 'extraPlayersCount'
|
||||
description: 'The number of extra players to add.'
|
||||
type: Integer
|
||||
attribute:
|
||||
- nullable
|
||||
deprecated: 'Method renamed to fit <a href="..">ProfileEntry</a> record more closely. Use <a href="#extraplayerscount(integer)">extraPlayersCount(Integer)</a> instead.'
|
||||
type:
|
||||
name: 'Builder'
|
||||
type: 'object'
|
||||
- name: 'setExtraPlayersEnabled'
|
||||
description: |
|
||||
Sets whether the extra players feature should be enabled or not.<br>
|
||||
<br>
|
||||
Set to <a href="../../objects/nullbool/#not_set"><code>NullBool.NOT_SET</code></a> to not set this.
|
||||
returns: 'This Builder after the NullBool has been set. Useful for chaining.'
|
||||
parameters:
|
||||
- name: 'extraPlayersEnabled'
|
||||
description: 'Whether the extra players feature should be enabled or not.'
|
||||
type: NullBool
|
||||
attribute:
|
||||
- notnull
|
||||
deprecated: 'Method renamed to fit <a href="..">ProfileEntry</a> record more closely. Use <a href="#extraplayersenabled(nullbool)">extraPlayersEnabled(NullBool)</a> instead.'
|
||||
throws:
|
||||
- name: 'IllegalArgumentException'
|
||||
description: 'Thrown by the <code>CheckUtil</code> in case <code>null</code> has been provided as parameter.'
|
||||
type:
|
||||
name: 'Builder'
|
||||
type: 'object'
|
||||
@@ -71,8 +225,9 @@ methods:
|
||||
- name: 'favicon'
|
||||
description: 'The favicon to set'
|
||||
type: String
|
||||
attributes:
|
||||
attribute:
|
||||
- nullable
|
||||
deprecated: 'Method renamed to fit <a href="..">ProfileEntry</a> record more closely. Use <a href="#favicon(string)">favicon(String)</a> instead.'
|
||||
type:
|
||||
name: 'Builder'
|
||||
type: 'object'
|
||||
@@ -86,83 +241,15 @@ methods:
|
||||
- name: 'hidePlayersEnabled'
|
||||
description: 'Whether the player count should be hidden or not.'
|
||||
type: NullBool
|
||||
attributes:
|
||||
attribute:
|
||||
- notnull
|
||||
deprecated: 'Method renamed to fit <a href="..">ProfileEntry</a> record more closely. Use <a href="#hideplayersenabled(nullbool)">hidePlayersEnabled(NullBool)</a> instead.'
|
||||
throws:
|
||||
- name: 'IllegalArgumentException'
|
||||
description: 'Thrown by the <code>CheckUtil</code> in case <code>null</code> has been provided as parameter.'
|
||||
type:
|
||||
name: 'Builder'
|
||||
type: 'object'
|
||||
- name: 'setExtraPlayersEnabled'
|
||||
description: |
|
||||
Sets whether the extra players feature should be enabled or not.<br>
|
||||
<br>
|
||||
Set to <a href="../../objects/nullbool/#not_set"><code>NullBool.NOT_SET</code></a> to not set this.
|
||||
returns: 'This Builder after the NullBool has been set. Useful for chaining.'
|
||||
parameters:
|
||||
- name: 'extraPlayersEnabled'
|
||||
description: 'Whether the extra players feature should be enabled or not.'
|
||||
type: NullBool
|
||||
attributes:
|
||||
- notnull
|
||||
throws:
|
||||
- name: 'IllegalArgumentException'
|
||||
description: 'Thrown by the <code>CheckUtil</code> in case <code>null</code> has been provided as parameter.'
|
||||
type:
|
||||
name: 'Builder'
|
||||
type: 'object'
|
||||
- name: 'setMaxPlayersEnabled'
|
||||
description: |
|
||||
Sets whether the max players feature should be enabled.<br>
|
||||
<br>
|
||||
Set to <a href="../../objects/nullbool/#not_set"><code>NullBool.NOT_SET</code></a> to not set this.
|
||||
returns: 'This Builder after the NullBool has been set. Useful for chaining.'
|
||||
parameters:
|
||||
- name: 'maxPlayersEnabled'
|
||||
description: 'Whether the extra players feature should be enabled or not.'
|
||||
type: NullBool
|
||||
attributes:
|
||||
- notnull
|
||||
throws:
|
||||
- name: 'IllegalArgumentException'
|
||||
description: 'Thrown by the <code>CheckUtil</code> in case <code>null</code> has been provided as parameter.'
|
||||
type:
|
||||
name: 'Builder'
|
||||
type: 'object'
|
||||
- name: 'setExtraPlayerCount'
|
||||
description: |
|
||||
Sets the number of players to add to the online players to use as the new max players value.<br>
|
||||
This option has no effect when <a href="../#extraplayersenabled()"><code>extraPlayersEnabled</code></a> is set to <a href="../../objects/nullbool/#false"><code>NullBool.FALSE</code></a> or <a href="../../objects/nullbool/#not_set"><code>NullBool.NOT_SET</code></a>.<br>
|
||||
<br>
|
||||
Set this to <code>null</code> to not alter the max player count. Alternatively, set <a href="#setextraplayersenabled(nullbool)"><code>setExtraPlayersEnabled(NullBool)</code></a> to <a href="../../objects/nullbool/#false"><code>NullBool.FALSE</code></a>.
|
||||
returns: 'This Builder after the extra player count has been set. Useful for chaining.'
|
||||
parameters:
|
||||
- name: 'extraPlayersCount'
|
||||
description: 'The number of extra players to add.'
|
||||
type: Integer
|
||||
attributes:
|
||||
- nullable
|
||||
deprecated: 'Typo in the name. Use <a href="#setextraplayerscount(integer)">setExtraPlayersCount(Integer)</a> instead.'
|
||||
type:
|
||||
name: 'Builder'
|
||||
type: 'object'
|
||||
- name: 'setExtraPlayersCount'
|
||||
description: |
|
||||
Sets the number of players to add to the online players to use as the new max players value.<br>
|
||||
This option has no effect when <a href="../#extraplayersenabled()"><code>extraPlayersEnabled</code></a> is set to <a href="../../objects/nullbool/#false"><code>NullBool.FALSE</code></a> or <a href="../../objects/nullbool/#not_set"><code>NullBool.NOT_SET</code></a>.<br>
|
||||
<br>
|
||||
Set this to <code>null</code> to not alter the max player count. Alternatively, set <a href="#setextraplayersenabled(nullbool)"><code>setExtraPlayersEnabled(NullBool)</code></a> to <a href="../../objects/nullbool/#false"><code>NullBool.FALSE</code></a>.
|
||||
returns: 'This Builder after the extra player count has been set. Useful for chaining.'
|
||||
parameters:
|
||||
- name: 'extraPlayersCount'
|
||||
description: 'The number of extra players to add.'
|
||||
type: Integer
|
||||
attributes:
|
||||
- nullable
|
||||
type:
|
||||
name: 'Builder'
|
||||
type: 'object'
|
||||
- name: 'setMaxPlayersCount'
|
||||
description: |
|
||||
Sets the number of max players allowed to join this server.<br>
|
||||
@@ -174,18 +261,86 @@ methods:
|
||||
- name: 'maxPlayersCount'
|
||||
description: 'The number of max players to set.'
|
||||
type: Integer
|
||||
attributes:
|
||||
attribute:
|
||||
- nullable
|
||||
deprecated: 'Method renamed to fit <a href="..">ProfileEntry</a> record more closely. Use <a href="#maxplayerscount(integer)">maxPlayersCount(Integer)</a> instead.'
|
||||
type:
|
||||
name: 'Builder'
|
||||
type: 'object'
|
||||
- name: 'build'
|
||||
description: 'Creates a new <a href="./.."><code>ProfileEntry</code> instance</a> with the values set in this Builder.'
|
||||
returns: 'New <a href="./.."><code>ProfileEntry</code> instance</a>.'
|
||||
- name: 'setMaxPlayersEnabled'
|
||||
description: |
|
||||
Sets whether the max players feature should be enabled.<br>
|
||||
<br>
|
||||
Set to <a href="../../objects/nullbool/#not_set"><code>NullBool.NOT_SET</code></a> to not set this.
|
||||
returns: 'This Builder after the NullBool has been set. Useful for chaining.'
|
||||
parameters:
|
||||
- name: 'maxPlayersEnabled'
|
||||
description: 'Whether the extra players feature should be enabled or not.'
|
||||
type: NullBool
|
||||
attribute:
|
||||
- notnull
|
||||
deprecated: 'Method renamed to fit <a href="..">ProfileEntry</a> record more closely. Use <a href="#maxplayersenabled(nullbool)">maxPlayersEnabled(NullBool)</a> instead.'
|
||||
throws:
|
||||
- name: 'IllegalArgumentException'
|
||||
description: 'Thrown by the <code>CheckUtil</code> in case <code>null</code> has been provided as parameter.'
|
||||
type:
|
||||
name: 'ProfileEntry'
|
||||
name: 'Builder'
|
||||
type: 'object'
|
||||
- name: 'setMotd'
|
||||
description: |
|
||||
Sets a new MOTD to use.<br>
|
||||
<br>
|
||||
Set to an empty list to not change the MOTD.<br>
|
||||
Only the first two entries of the list will be considered and any additional ones discarded.
|
||||
returns: 'This Builder after the motd has been set. Useful for chaining.'
|
||||
parameters:
|
||||
- name: 'motd'
|
||||
description: 'The MOTD to use.'
|
||||
type: 'List<String>'
|
||||
attribute:
|
||||
- notnull
|
||||
deprecated: 'Method renamed to fit <a href="..">ProfileEntry</a> record more closely. Use <a href="#motd(string)">motd(String)</a> instead.'
|
||||
throws:
|
||||
- name: 'IllegalArgumentException'
|
||||
description: 'Thrown by the <code>CheckUtil</code> in case <code>null</code> has been provided as parameter.'
|
||||
type:
|
||||
name: 'Builder'
|
||||
type: 'object'
|
||||
- name: 'setPlayerCountText'
|
||||
description: |
|
||||
Sets the text to override the player count with.<br>
|
||||
<br>
|
||||
Set to an empty String or <code>null</code> to not alter the player count text.
|
||||
returns: 'This Builder after the player count text has been set. Useful for chaining.'
|
||||
parameters:
|
||||
- name: 'playerCountText'
|
||||
description: 'The text to show in the player count.'
|
||||
type: String
|
||||
attribute:
|
||||
- nullable
|
||||
deprecated: 'Method renamed to fit <a href="..">ProfileEntry</a> record more closely. Use <a href="#playercounttext(string)">playerCountText(String)</a> instead.'
|
||||
type:
|
||||
name: 'Builder'
|
||||
type: 'object'
|
||||
- name: 'setPlayers'
|
||||
description: |
|
||||
Sets the players (lines) to use for the hover.<br>
|
||||
<br>
|
||||
Set to an empty list to not change the hover text.
|
||||
returns: 'This Builder after the players have been set. Useful for chaining.'
|
||||
parameters:
|
||||
- name: 'players'
|
||||
description: 'The lines to set for the hover.'
|
||||
type: 'List<String>'
|
||||
attribute:
|
||||
- notnull
|
||||
deprecated: 'Method renamed to fit <a href="..">ProfileEntry</a> record more closely. Use <a href="#players(list<string>)">players(List<String>)</a> instead.'
|
||||
throws:
|
||||
- name: 'IllegalArgumentException'
|
||||
description: 'Thrown by the <code>CheckUtil</code> in case <code>null</code> has been provided as parameter.'
|
||||
type:
|
||||
name: 'Builder'
|
||||
type: 'object'
|
||||
link: './..'
|
||||
---
|
||||
|
||||
# <api__class></api__class> Builder
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
nav:
|
||||
- index.md
|
||||
- ch.andre601.advancedserverlist.api.bukkit: ch.andre601.advancedserverlist.api.bukkit
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
---
|
||||
template: api-doc.html
|
||||
|
||||
constructors:
|
||||
- name: 'PostServerListSetEvent'
|
||||
description: 'Constructor for creating a new PostServerListSetEvent instance.'
|
||||
parameters:
|
||||
- name: 'entry'
|
||||
description: 'The <a href="../../../../api/ch.andre601.advancedserverlist.api/profiles/profileentry/"><code>ProfileEntry</code></a> used during the PingEvent.'
|
||||
type: ProfileEntry
|
||||
attribute:
|
||||
- nullable
|
||||
|
||||
methods:
|
||||
- name: 'getHandlerList'
|
||||
description: 'Static <a href="https://hub.spigotmc.org/javadocs/spigot/org/bukkit/event/HandlerList.html" target="_blank" rel="nofollow"><code>HandlerList</code></a> getter. Required by Paper.'
|
||||
returns: 'The static <a href="https://hub.spigotmc.org/javadocs/spigot/org/bukkit/event/HandlerList.html" target="_blank" rel="nofollow"><code>HandlerList instance</code></a> of this event.'
|
||||
attributes:
|
||||
- static
|
||||
type:
|
||||
name: 'HandlerList'
|
||||
type: 'object'
|
||||
- name: 'getEntry'
|
||||
description: |
|
||||
The <a href="../../../../api/ch.andre601.advancedserverlist.api/profiles/profileentry/"><code>ProfileEntry</code></a> that was used during the PingEvent handling.<br>
|
||||
<br>
|
||||
The returned value may be <code>null</code> should the PingEvent handling be cancelled at any point (i.e. due to an invalid protocol or because the <a href="../preserverlistsetevent/"><code>PreServerListSetEvent</code></a> has been cancelled).<br>
|
||||
The values within the ProfileEntry also do not represent what is actually used within the Server list itself, but only the values provided for the PingEvent handling.
|
||||
returns: 'Possibly-null ProfileEntry used for the PingEvent.'
|
||||
attributes:
|
||||
- nullable
|
||||
type:
|
||||
name: 'ProfileEntry'
|
||||
type: 'object'
|
||||
link: '../../../../api/ch.andre601.advancedserverlist.api/profiles/profileentry/'
|
||||
|
||||
inherits:
|
||||
'org.bukkit.event.Event':
|
||||
link: 'https://hub.spigotmc.org/javadocs/spigot/org/bukkit/event/Event.html'
|
||||
list:
|
||||
- 'getHandlers()'
|
||||
---
|
||||
|
||||
# <api__class></api__class> PostServerListSetEvent
|
||||
|
||||
Called **after** the plugin has updated the Server List.
|
||||
|
||||
The provided [`ProfileEntry`](#getentry()) may be null due to the PingEvent handling being cancelled (i.e. due to a invalid protocol or due to the [`PreServerListSetEvent`](preserverlistsetevent.md) being cancelled).
|
||||
The entry also only represents the values used during the PingEvent, not the actual content that is being displayed.
|
||||
@@ -1,3 +0,0 @@
|
||||
nav:
|
||||
- index.md
|
||||
- ch.andre601.advancedserverlist.api.bungeecord: ch.andre601.advancedserverlist.api.bungeecord
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
---
|
||||
template: api-doc.html
|
||||
|
||||
constructors:
|
||||
- name: 'PostServerListSetEvent'
|
||||
description: 'Constructor for creating a new PostServerListSetEvent instance.'
|
||||
parameters:
|
||||
- name: 'entry'
|
||||
description: 'The <a href="../../../../api/ch.andre601.advancedserverlist.api/profiles/profileentry/"><code>ProfileEntry</code></a> used during the PingEvent.'
|
||||
type: ProfileEntry
|
||||
attribute:
|
||||
- nullable
|
||||
|
||||
methods:
|
||||
- name: 'getEntry'
|
||||
description: |
|
||||
The <a href="../../../../api/ch.andre601.advancedserverlist.api/profiles/profileentry/"><code>ProfileEntry</code></a> that was used during the PingEvent handling.<br>
|
||||
<br>
|
||||
The returned value may be <code>null</code> should the PingEvent handling be cancelled at any point (i.e. due to an invalid protocol or because the <a href="../preserverlistsetevent/"><code>PreServerListSetEvent</code></a> has been cancelled).<br>
|
||||
The values within the ProfileEntry also do not represent what is actually used within the Server list itself, but only the values provided for the PingEvent handling.
|
||||
returns: 'Possibly-null ProfileEntry used for the PingEvent.'
|
||||
attributes:
|
||||
- nullable
|
||||
type:
|
||||
name: 'ProfileEntry'
|
||||
type: 'object'
|
||||
link: '../../../../api/ch.andre601.advancedserverlist.api/profiles/profileentry/'
|
||||
---
|
||||
|
||||
# <api__class></api__class> PostServerListSetEvent
|
||||
|
||||
Called **after** the plugin has updated the Server List.
|
||||
|
||||
The provided [`ProfileEntry`](#getentry()) may be null due to the PingEvent handling being cancelled (i.e. due to a invalid protocol or due to the [`PreServerListSetEvent`](preserverlistsetevent.md) being cancelled).
|
||||
The entry also only represents the values used during the PingEvent, not the actual content that is being displayed.
|
||||
@@ -1,3 +0,0 @@
|
||||
nav:
|
||||
- index.md
|
||||
- ch.andre601.advancedserverlist.api.velocity: ch.andre601.advancedserverlist.api.velocity
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
---
|
||||
template: api-doc.html
|
||||
|
||||
constructors:
|
||||
- name: 'PostServerListSetEvent'
|
||||
description: 'Constructor for creating a new PostServerListSetEvent instance.'
|
||||
parameters:
|
||||
- name: 'entry'
|
||||
description: 'The <a href="../../../../api/ch.andre601.advancedserverlist.api/profiles/profileentry/"><code>ProfileEntry</code></a> used during the PingEvent.'
|
||||
type: ProfileEntry
|
||||
attribute:
|
||||
- nullable
|
||||
|
||||
methods:
|
||||
- name: 'getEntry'
|
||||
description: |
|
||||
The <a href="../../../../api/ch.andre601.advancedserverlist.api/profiles/profileentry/"><code>ProfileEntry</code></a> that was used during the PingEvent handling.<br>
|
||||
<br>
|
||||
The returned value may be <code>null</code> should the PingEvent handling be cancelled at any point (i.e. due to an invalid protocol or because the <a href="../preserverlistsetevent/"><code>PreServerListSetEvent</code></a> has been cancelled).<br>
|
||||
The values within the ProfileEntry also do not represent what is actually used within the Server list itself, but only the values provided for the PingEvent handling.
|
||||
returns: 'Possibly-null ProfileEntry used for the PingEvent.'
|
||||
attributes:
|
||||
- nullable
|
||||
type:
|
||||
name: 'ProfileEntry'
|
||||
type: 'object'
|
||||
link: '../../../../api/ch.andre601.advancedserverlist.api/profiles/profileentry/'
|
||||
---
|
||||
|
||||
# <api__class></api__class> PostServerListSetEvent
|
||||
|
||||
Called **after** the plugin has updated the Server List.
|
||||
|
||||
The provided [`ProfileEntry`](#getentry()) may be null due to the PingEvent handling being cancelled (i.e. due to a invalid protocol or due to the [`PreServerListSetEvent`](preserverlistsetevent.md) being cancelled).
|
||||
The entry also only represents the values used during the PingEvent, not the actual content that is being displayed.
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
---
|
||||
template: redirect.html
|
||||
|
||||
location: https://github.com/Andre601/asl-api
|
||||
location: https://codeberg.org/Andre601/asl-api
|
||||
|
||||
title: Source Code
|
||||
icon: octicons/mark-github-16
|
||||
icon: simple/codeberg
|
||||
---
|
||||
|
||||
<!-- Comment to trigger proper build -->
|
||||
@@ -1 +0,0 @@
|
||||
hide: true
|
||||
@@ -1,5 +1,5 @@
|
||||
document$.subscribe(async () => {
|
||||
const url = 'https://codeberg-stats-proxy.vercel.app/repo'
|
||||
const url = 'https://codeberg-stats-proxy.vercel.app'
|
||||
const repo_stats = document.querySelector('[data-md-component="source"] .md-source__repository');
|
||||
|
||||
function loadCodebergInfo(data) {
|
||||
@@ -31,7 +31,7 @@ document$.subscribe(async () => {
|
||||
const versionToken = '{apiVersion}';
|
||||
const codeBlocks = document.querySelectorAll('.md-content pre code');
|
||||
for(const codeBlock of codeBlocks) {
|
||||
codeBlock.innerHTML = codeBlock.innerHTML.replace(new RegExp(versionToken, 'g'), version);
|
||||
codeBlock.innerHTML = codeBlock.innerHTML.replace(new RegExp(versionToken, 'g'), version.substring(1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,15 +40,15 @@ document$.subscribe(async () => {
|
||||
const versionToken = '{version}'
|
||||
const entries = document.querySelectorAll('.md-content code');
|
||||
for(const entry of entries) {
|
||||
entry.innerHTML = entry.innerHTML.replace(new RegExp(versionToken, 'g'), version);
|
||||
entry.innerHTML = entry.innerHTML.replace(new RegExp(versionToken, 'g'), version.substring(1));
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchApiInfo() {
|
||||
const tag = await fetch("https://api.github.com/repos/Andre601/asl-api/releases/latest").then(_ => _.json());
|
||||
const tag = await fetch(`${url}/api/latest-release`).then(_ => _.json());
|
||||
|
||||
const data = {
|
||||
"version": tag.tag_name
|
||||
"version": tag.name
|
||||
};
|
||||
|
||||
__md_set("__api_tag", data, sessionStorage);
|
||||
@@ -57,8 +57,8 @@ document$.subscribe(async () => {
|
||||
|
||||
async function fetchInfo() {
|
||||
const [release, repo] = await Promise.all([
|
||||
fetch(`${url}/latest-release`).then(_ => _.json()),
|
||||
fetch(`${url}/stats`).then(_ => _.json()),
|
||||
fetch(`${url}/repo/latest-release`).then(_ => _.json()),
|
||||
fetch(`${url}/repo/stats`).then(_ => _.json()),
|
||||
]);
|
||||
|
||||
const data = {
|
||||
|
||||
@@ -23,11 +23,13 @@
|
||||
--md-badge-bg--example: #7c4dff1a;
|
||||
--md-badge-fg--quote: #9e9e9e;
|
||||
--md-badge-bg--quote: #9e9e9e1a;
|
||||
--md-badge-fg--deprecated: #ff5252;
|
||||
--md-badge-bg--deprecated: #ff52521a;
|
||||
|
||||
--badge-icon--note: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M17.263 2.177a1.75 1.75 0 0 1 2.474 0l2.586 2.586a1.75 1.75 0 0 1 0 2.474L19.53 10.03l-.012.013L8.69 20.378a1.753 1.753 0 0 1-.699.409l-5.523 1.68a.748.748 0 0 1-.747-.188.748.748 0 0 1-.188-.747l1.673-5.5a1.75 1.75 0 0 1 .466-.756L14.476 4.963ZM4.708 16.361a.26.26 0 0 0-.067.108l-1.264 4.154 4.177-1.271a.253.253 0 0 0 .1-.059l10.273-9.806-2.94-2.939-10.279 9.813ZM19 8.44l2.263-2.262a.25.25 0 0 0 0-.354l-2.586-2.586a.25.25 0 0 0-.354 0L16.061 5.5Z"></path></svg>');
|
||||
--badge-icon--abstract: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M5.962 2.513a.75.75 0 0 1-.475.949l-.816.272a.25.25 0 0 0-.171.237V21.25c0 .138.112.25.25.25h14.5a.25.25 0 0 0 .25-.25V3.97a.25.25 0 0 0-.17-.236l-.817-.272a.75.75 0 0 1 .474-1.424l.816.273A1.751 1.751 0 0 1 21 3.97v17.28A1.75 1.75 0 0 1 19.25 23H4.75A1.75 1.75 0 0 1 3 21.25V3.97a1.75 1.75 0 0 1 1.197-1.66l.816-.272a.75.75 0 0 1 .949.475Z"></path><path d="M7 1.75C7 .784 7.784 0 8.75 0h6.5C16.216 0 17 .784 17 1.75v1.5A1.75 1.75 0 0 1 15.25 5h-6.5A1.75 1.75 0 0 1 7 3.25Zm1.75-.25a.25.25 0 0 0-.25.25v1.5c0 .138.112.25.25.25h6.5a.25.25 0 0 0 .25-.25v-1.5a.25.25 0 0 0-.25-.25Z"></path></svg>');
|
||||
--badge-icon--info: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M13 7.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0Zm-3 3.75a.75.75 0 0 1 .75-.75h1.5a.75.75 0 0 1 .75.75v4.25h.75a.75.75 0 0 1 0 1.5h-3a.75.75 0 0 1 0-1.5h.75V12h-.75a.75.75 0 0 1-.75-.75Z"></path><path d="M12 1c6.075 0 11 4.925 11 11s-4.925 11-11 11S1 18.075 1 12 5.925 1 12 1ZM2.5 12a9.5 9.5 0 0 0 9.5 9.5 9.5 9.5 0 0 0 9.5-9.5A9.5 9.5 0 0 0 12 2.5 9.5 9.5 0 0 0 2.5 12Z"></path></svg>');
|
||||
--badge-icon--tip: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M14.265 1.627c0 3.545 1.869 5.327 3.479 7.021 1.54 1.62 3.006 3.163 3.006 6.102 0 4.812-3.753 8.25-8.565 8.25-4.813 0-8.935-3.421-8.935-8.25 0-2.039.962-4.011 2.509-4.899.305-.175.672.007.803.334C7.563 12.684 8.797 12.64 9.437 12c.388-.387.47-1.116-.004-2.062-2.405-4.812 1.863-8.279 4.2-8.854.336-.082.615.198.632.543ZM12.185 21.5c4.059 0 7.065-2.84 7.065-6.75 0-2.337-1.093-3.489-2.678-5.158l-.021-.023c-1.44-1.517-3.139-3.351-3.649-6.557a6.148 6.148 0 0 0-1.911 1.76c-.787 1.144-1.147 2.633-.216 4.495.603 1.205.777 2.74-.277 3.794-.657.657-1.762 1.1-2.956.586-.752-.324-1.353-.955-1.838-1.79-.567.706-.954 1.74-.954 2.893 0 3.847 3.288 6.75 7.435 6.75Z"></path></svg>');
|
||||
--badge-icon--tip: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M12 2.5c-3.81 0-6.5 2.743-6.5 6.119 0 1.536.632 2.572 1.425 3.56.172.215.347.422.527.635l.096.112c.21.25.427.508.63.774.404.531.783 1.128.995 1.834a.75.75 0 0 1-1.436.432c-.138-.46-.397-.89-.753-1.357a18.111 18.111 0 0 0-.582-.714l-.092-.11c-.18-.212-.37-.436-.555-.667C4.87 12.016 4 10.651 4 8.618 4 4.363 7.415 1 12 1s8 3.362 8 7.619c0 2.032-.87 3.397-1.755 4.5-.185.23-.375.454-.555.667l-.092.109c-.21.248-.405.481-.582.714-.356.467-.615.898-.753 1.357a.751.751 0 0 1-1.437-.432c.213-.706.592-1.303.997-1.834.202-.266.419-.524.63-.774l.095-.112c.18-.213.355-.42.527-.634.793-.99 1.425-2.025 1.425-3.561C18.5 5.243 15.81 2.5 12 2.5ZM8.75 18h6.5a.75.75 0 0 1 0 1.5h-6.5a.75.75 0 0 1 0-1.5Zm.75 3.75a.75.75 0 0 1 .75-.75h3.5a.75.75 0 0 1 0 1.5h-3.5a.75.75 0 0 1-.75-.75Z"></path></svg>');
|
||||
--badge-icon--success: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M21.03 5.72a.75.75 0 0 1 0 1.06l-11.5 11.5a.747.747 0 0 1-1.072-.012l-5.5-5.75a.75.75 0 1 1 1.084-1.036l4.97 5.195L19.97 5.72a.75.75 0 0 1 1.06 0Z"></path></svg>');
|
||||
--badge-icon--question: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M10.97 8.265a1.45 1.45 0 0 0-.487.57.75.75 0 0 1-1.341-.67c.2-.402.513-.826.997-1.148C10.627 6.69 11.244 6.5 12 6.5c.658 0 1.369.195 1.934.619a2.45 2.45 0 0 1 1.004 2.006c0 1.033-.513 1.72-1.027 2.215-.19.183-.399.358-.579.508l-.147.123a4.329 4.329 0 0 0-.435.409v1.37a.75.75 0 1 1-1.5 0v-1.473c0-.237.067-.504.247-.736.22-.28.486-.517.718-.714l.183-.153.001-.001c.172-.143.324-.27.47-.412.368-.355.569-.676.569-1.136a.953.953 0 0 0-.404-.806C12.766 8.118 12.384 8 12 8c-.494 0-.814.121-1.03.265ZM13 17a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path><path d="M12 1c6.075 0 11 4.925 11 11s-4.925 11-11 11S1 18.075 1 12 5.925 1 12 1ZM2.5 12a9.5 9.5 0 0 0 9.5 9.5 9.5 9.5 0 0 0 9.5-9.5A9.5 9.5 0 0 0 12 2.5 9.5 9.5 0 0 0 2.5 12Z"></path></svg>');
|
||||
--badge-icon--warning: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M13 17.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0Zm-.25-8.25a.75.75 0 0 0-1.5 0v4.5a.75.75 0 0 0 1.5 0v-4.5Z"></path><path d="M9.836 3.244c.963-1.665 3.365-1.665 4.328 0l8.967 15.504c.963 1.667-.24 3.752-2.165 3.752H3.034c-1.926 0-3.128-2.085-2.165-3.752Zm3.03.751a1.002 1.002 0 0 0-1.732 0L2.168 19.499A1.002 1.002 0 0 0 3.034 21h17.932a1.002 1.002 0 0 0 .866-1.5L12.866 3.994Z"></path></svg>');
|
||||
@@ -36,6 +38,7 @@
|
||||
--badge-icon--bug: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M7.72.22a.75.75 0 0 1 1.06 0l1.204 1.203A4.98 4.98 0 0 1 12 1c.717 0 1.4.151 2.016.423L15.22.22a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-.971.972A4.991 4.991 0 0 1 17 6v1.104a2.755 2.755 0 0 1 1.917 1.974l1.998-.999a.75.75 0 0 1 .67 1.342L19 10.714V13.5l3.25.003a.75.75 0 0 1 0 1.5L19 15.001V16c0 .568-.068 1.134-.204 1.686l.04.018 2.75 1.375a.75.75 0 1 1-.671 1.342l-2.638-1.319A6.998 6.998 0 0 1 12 23a6.998 6.998 0 0 1-6.197-3.742l-2.758 1.181a.752.752 0 0 1-1.064-.776.752.752 0 0 1 .474-.602l2.795-1.199A6.976 6.976 0 0 1 5 16v-.996H1.75a.75.75 0 0 1 0-1.5H5v-2.79L2.415 9.42a.75.75 0 0 1 .67-1.342l1.998.999A2.756 2.756 0 0 1 7 7.104V6a4.99 4.99 0 0 1 1.69-3.748l-.97-.972a.75.75 0 0 1 0-1.06ZM6.5 9.75V16a5.5 5.5 0 1 0 11 0V9.75c0-.69-.56-1.25-1.25-1.25h-8.5c-.69 0-1.25.56-1.25 1.25ZM8.5 7h7V6a3.5 3.5 0 1 0-7 0Z"></path></svg>');
|
||||
--badge-icon--example: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M8 8.807V3.5h-.563a.75.75 0 0 1 0-1.5h9.125a.75.75 0 0 1 0 1.5H16v5.307l5.125 9.301c.964 1.75-.302 3.892-2.299 3.892H5.174c-1.998 0-3.263-2.142-2.3-3.892ZM4.189 18.832a1.123 1.123 0 0 0 .985 1.668h13.652a1.123 1.123 0 0 0 .985-1.668L17.7 15H6.3ZM14.5 3.5h-5V9a.75.75 0 0 1-.093.362L7.127 13.5h9.746l-2.28-4.138A.75.75 0 0 1 14.5 9Z"></path></svg>');
|
||||
--badge-icon--quote: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M3 6.25a.75.75 0 0 1 .75-.75h13.5a.75.75 0 0 1 0 1.5H3.75A.75.75 0 0 1 3 6.25Zm5 6.063a.75.75 0 0 1 .75-.75h11.5a.75.75 0 0 1 0 1.5H8.75a.75.75 0 0 1-.75-.75Zm0 5.937a.75.75 0 0 1 .75-.75h11.5a.75.75 0 0 1 0 1.5H8.75a.75.75 0 0 1-.75-.75ZM3.75 11a.75.75 0 0 1 .75.75v7a.75.75 0 0 1-1.5 0v-7a.75.75 0 0 1 .75-.75Z"></path></svg>');
|
||||
--badge-icon--deprecated: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M16 1.75V3h5.25a.75.75 0 0 1 0 1.5H2.75a.75.75 0 0 1 0-1.5H8V1.75C8 .784 8.784 0 9.75 0h4.5C15.216 0 16 .784 16 1.75Zm-6.5 0V3h5V1.75a.25.25 0 0 0-.25-.25h-4.5a.25.25 0 0 0-.25.25ZM4.997 6.178a.75.75 0 1 0-1.493.144L4.916 20.92a1.75 1.75 0 0 0 1.742 1.58h10.684a1.75 1.75 0 0 0 1.742-1.581l1.413-14.597a.75.75 0 0 0-1.494-.144l-1.412 14.596a.25.25 0 0 1-.249.226H6.658a.25.25 0 0 1-.249-.226L4.997 6.178Z"></path><path d="M9.206 7.501a.75.75 0 0 1 .793.705l.5 8.5A.75.75 0 1 1 9 16.794l-.5-8.5a.75.75 0 0 1 .705-.793Zm6.293.793A.75.75 0 1 0 14 8.206l-.5 8.5a.75.75 0 0 0 1.498.088l.5-8.5Z"></path></svg>');
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -257,4 +260,20 @@
|
||||
|
||||
-webkit-mask-image: var(--badge-icon--quote);
|
||||
mask-image: var(--badge-icon--quote);
|
||||
}
|
||||
|
||||
/* Deprecated */
|
||||
.mdx-admo--deprecated {
|
||||
border-color: var(--md-badge-fg--deprecated);
|
||||
}
|
||||
|
||||
.mdx-admo--deprecated .mdx-grid-child--icon {
|
||||
background-color: var(--md-badge-bg--deprecated);
|
||||
}
|
||||
|
||||
.mdx-admo--deprecated .mdx-grid-child--icon::before {
|
||||
background-color: var(--md-badge-fg--deprecated);
|
||||
|
||||
-webkit-mask-image: var(--badge-icon--deprecated);
|
||||
mask-image: var(--badge-icon--deprecated);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
:root {
|
||||
--admonition-icon--file: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M3 3a2 2 0 0 1 2-2h9.982a2 2 0 0 1 1.414.586l4.018 4.018A2 2 0 0 1 21 7.018V21a2 2 0 0 1-2 2H4.75a.75.75 0 0 1 0-1.5H19a.5.5 0 0 0 .5-.5V8.5h-4a2 2 0 0 1-2-2v-4H5a.5.5 0 0 0-.5.5v6.25a.75.75 0 0 1-1.5 0Zm12-.5v4a.5.5 0 0 0 .5.5h4a.5.5 0 0 0-.146-.336l-4.018-4.018A.5.5 0 0 0 15 2.5Z"></path><path d="M4.53 12.24a.75.75 0 0 1-.039 1.06l-2.639 2.45 2.64 2.45a.75.75 0 1 1-1.022 1.1l-3.23-3a.75.75 0 0 1 0-1.1l3.23-3a.75.75 0 0 1 1.06.04Zm3.979 1.06a.75.75 0 1 1 1.02-1.1l3.231 3a.75.75 0 0 1 0 1.1l-3.23 3a.75.75 0 1 1-1.021-1.1l2.639-2.45-2.64-2.45Z"></path></svg>');
|
||||
|
||||
--admonition-color-fg--file: #00c853;
|
||||
--admonition-color-bg--file: #00c8531a;
|
||||
}
|
||||
|
||||
.md-typeset .admonition.file,
|
||||
.md-typeset details.file {
|
||||
border-color: var(--admonition-color-fg--file);
|
||||
}
|
||||
|
||||
.md-typeset .file > .admonition-title,
|
||||
.md-typeset .file > summary {
|
||||
background-color: var(--admonition-color-bg--file);
|
||||
}
|
||||
|
||||
.md-typeset .file > .admonition-title::before,
|
||||
.md-typeset .file > summary::before {
|
||||
background-color: var(--admonition-color-fg--file);
|
||||
-webkit-mask-image: var(--admonition-icon--file);
|
||||
mask-image: var(--admonition-icon--file);
|
||||
}
|
||||
@@ -21,18 +21,24 @@ The following subcommands are available (Subcommands are case-insensitive):
|
||||
|
||||
### help
|
||||
|
||||
/// info |
|
||||
**Permission:** `advancedserverlist.command.help`
|
||||
|
||||
Shows a list of all available [subcommands](#subcommands) for AdvancedServerList.
|
||||
///
|
||||
|
||||
### reload
|
||||
|
||||
/// info |
|
||||
**Permission:** `advancedserverlist.command.reload`
|
||||
|
||||
Reloads the plugin's `config.yml` and all available YAML files in the `profiles` folder.
|
||||
///
|
||||
|
||||
### clearCache
|
||||
|
||||
/// info |
|
||||
**Permission:** `advancedserverlist.command.clearcache`
|
||||
|
||||
Clears the currently cached favicons and players.
|
||||
Clears the currently cached favicons and players.
|
||||
///
|
||||
+32
-16
@@ -6,18 +6,20 @@ icon: octicons/list-unordered-24
|
||||
|
||||
## About
|
||||
|
||||
<!-- admo:info The below examples may only work in v1.10.0 or newer! -->
|
||||
<!-- admo:info The below examples may only work in v3.7.0 or newer! -->
|
||||
|
||||
This page lists some examples you may want to use for your proxy or server.
|
||||
|
||||
Feel free to suggest additional examples on my [Discord Server](https://discord.gg/6dazXp6) in the `#advancedserverlist` channel.
|
||||
Feel free to suggest additional examples in the `advancedserverlist` category on the [M.O.S.S. Discord Server](https://discord.gg/MyPTjpsgGH){ target="_blank" rel="nofollow" }.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Versions](#versions)
|
||||
- [Different List for outdated Clients](#different-list-for-outdated-clients)
|
||||
- [Different MOTD for < 1.16](#different-motd-for-116)
|
||||
- [Spigot/PaperMC](#spigotpapermc)
|
||||
- [BungeeCord/Velocity](#bungeecordvelocity)
|
||||
- [Display MOTD for a set of subdomains](#display-motd-for-a-set-of-subdomains)
|
||||
- [PaperMC](#papermc)
|
||||
- [Different profile for banned Player](#different-profile-for-banned-player)
|
||||
- [Other](#other)
|
||||
- [Different profile for different host](#different-profile-for-different-host)
|
||||
@@ -38,8 +40,7 @@ This example here shows a separate MOTD and player count message for when the pl
|
||||
priority: 1
|
||||
|
||||
# Display this profile, if the version of the player is below 760 (1.19.1)
|
||||
conditions:
|
||||
- '${player protocol} < 760'
|
||||
condition: '${player protocol} < 760'
|
||||
|
||||
motd:
|
||||
- '<red>You are using an outdated client!'
|
||||
@@ -57,8 +58,7 @@ This profile would display a MOTD without HEX colours if the player's version is
|
||||
priority: 1
|
||||
|
||||
# Display this profile, if the version of the player is below 735 (1.16)
|
||||
conditions:
|
||||
- '${player protocol} < 735'
|
||||
condition: '${player protocol} < 735'
|
||||
|
||||
motd:
|
||||
- '<grey>Welcome to <aqua>YourServer.com</aqua>!'
|
||||
@@ -66,9 +66,28 @@ motd:
|
||||
```
|
||||
|
||||
----
|
||||
## Spigot/PaperMC
|
||||
## BungeeCord/Velocity
|
||||
|
||||
Examples that can be used with the Spigot or PaperMC version.
|
||||
Examples usable on the BungeeCord and Velocity version.
|
||||
|
||||
### Display MOTD for a set of subdomains
|
||||
|
||||
Displays the same MOTDs for the server when pinged on any sub-domain starting with `lobby` (i.e. `lobby-1.example.com`).
|
||||
|
||||
```yaml title="lobby-motd.yml"
|
||||
priority: 1
|
||||
|
||||
condition: '${server host} |- "lobby"'
|
||||
|
||||
motd:
|
||||
- '<green>Lobby Server'
|
||||
- '<grey>Example Server'
|
||||
```
|
||||
|
||||
----
|
||||
## PaperMC
|
||||
|
||||
Examples that can be used with the PaperMC version.
|
||||
|
||||
### Different profile for banned Player
|
||||
|
||||
@@ -79,8 +98,7 @@ Displays a separate profile for when the player has been banned from the server.
|
||||
```yaml title="banned.yml"
|
||||
priority: 1
|
||||
|
||||
conditions:
|
||||
- '${player isBanned} = true'
|
||||
condition: '${player isBanned}'
|
||||
|
||||
motd:
|
||||
- '<red>You have been <bold>BANNED</bold>!'
|
||||
@@ -103,8 +121,7 @@ Display a different profile when the playing pings a specific domain/IP.
|
||||
```yaml title="specific-host.yml"
|
||||
priority: 1
|
||||
|
||||
conditions:
|
||||
- '${server host} = other.example.com'
|
||||
condition: '${server host} = "host.example.com"'
|
||||
|
||||
motd:
|
||||
- '<grey>Please use <aqua>mc.example.com'
|
||||
@@ -118,12 +135,11 @@ Display a different profile, if the player pinging the server is "known" by Adva
|
||||
```yaml title="personalized.yml"
|
||||
priority: 1
|
||||
|
||||
conditions:
|
||||
- `${player name} != Anonymous` # "Anonymous" should be replaced with whatever you use in 'unknown_player'
|
||||
condition: '${player name} != "Anonymous"' # "Anonymous" would be the value from the "unknownPlayer > name" option.
|
||||
|
||||
motd:
|
||||
- '<grey>Hello there <aqua>${player name}</aqua>!'
|
||||
- '<grey>It's nice to see you again.'
|
||||
- '<grey>It''s nice to see you again.'
|
||||
|
||||
playerCount:
|
||||
hover:
|
||||
|
||||
+264
-116
@@ -5,59 +5,135 @@ icon: octicons/milestone-24
|
||||
# Getting Started
|
||||
|
||||
This page will explain how to set up AdvancedServerList and make it work for your server.
|
||||
It tries to be an easy to understand as possible. But if you still have problems, consider joining the [Discord Server](https://discord.gg/6dazXp6) for help.
|
||||
The guide is designed to be as easy to understand as possible. If you still have problems or questions, join the [M.O.S.S Discord Server](https://discord.gg/MyPTjpsgGH){ target="_blank" rel="nofollow" } for more help.
|
||||
|
||||
## 1. Download the plugin { #download-the-plugin }
|
||||
|
||||
The first step would be to download the plugin from a download page of your choice. As of writing this is AdvancedServerList updated and available on these sites:
|
||||
The first step would be to download the plugin from a download page of your choice.
|
||||
AdvancedServerList is available on the following places (Please note the current status!):
|
||||
|
||||
- [Modrinth]
|
||||
- [Codeberg]
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- [:simple-modrinth: **Modrinth**][modrinth]{ target="_blank" rel="nofollow" }
|
||||
|
||||
----
|
||||
|
||||
:octicons-check-24:{ style="color: var(--md-badge-fg--success);" } **Actively updated!**
|
||||
|
||||
- [:simple-codeberg: **Codeberg**][codeberg]{ target="_blank" rel="nofollow" }
|
||||
|
||||
----
|
||||
|
||||
:octicons-check-24:{ style="color: var(--md-badge-fg--success);" } **Actively updated!**
|
||||
|
||||
- [:fontawesome-solid-paper-plane: **HangarMC**][hangar]{ target="_blank" rel="nofollow" }
|
||||
|
||||
----
|
||||
|
||||
:octicons-check-24:{ style="color: var(--md-badge-fg--success);" } **Actively updated!**
|
||||
|
||||
|
||||
- [:simple-spigotmc: **SpigotMC**][spigot]{ target="_blank" rel="nofollow" }
|
||||
|
||||
----
|
||||
|
||||
:octicons-alert-24:{ style="color: var(--md-badge-fg--warning);" } **Discontinued!**
|
||||
|
||||
</div>
|
||||
|
||||
[modrinth]: https://modrinth.com/plugin/advancedserverlist
|
||||
[codeberg]: https://codeberg.org/Andre601/AdvancedServerList
|
||||
|
||||
The plugin is also available on these platforms, but not actively updated there anymore:
|
||||
|
||||
- [Spigot] (Latest version: `3.3.0-b1`)
|
||||
- [Hangar] (Latest version: `3.5.0`)
|
||||
|
||||
[spigot]: https://www.spigotmc.org/resources/102910/
|
||||
[hangar]: https://hangar.papermc.io/Andre_601/AdvancedServerList
|
||||
|
||||
The plugin is available for Spigot, Paper, BungeeCord, Waterfall and Velocity, and has been tested on these platforms. It may support additional forks, but this is not guaranteed.
|
||||
The plugin is available for Paper, BungeeCord, Waterfall and Velocity, and has been tested on these platforms. It may support additional forks, but this is not guaranteed.
|
||||
|
||||
The plugin also supports these additional plugins. Depending on the platform they are used in is the plugin required.
|
||||
The plugin also supports these additional plugins. They are all optional.
|
||||
|
||||
- [PlaceholderAPI] - Used on the Spigot and Paper server for additional Placeholder parsing.
|
||||
- - [ViaVersion] - Used on the Spigot and Paper server for additional protocol version handling.
|
||||
- [PAPIProxyBridge] - Used on BungeeCord, Waterfall and Velocity for PlaceholderAPI support.
|
||||
- [Maintenance] - Used to disable server list handling while maintenance is active.
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- [**PlaceholderAPI**][placeholderapi]{ target="_blank" rel="nofollow" }
|
||||
|
||||
----
|
||||
|
||||
AdvancedServerList supports the use of placeholder from PlaceholderAPI in all its text options, except for the `condition` option.
|
||||
|
||||
----
|
||||
|
||||
**Supported on:**
|
||||
:fontawesome-solid-paper-plane: Paper
|
||||
|
||||
- [**ViaVersion**][viaversion]{ target="_blank" rel="nofollow" }
|
||||
|
||||
----
|
||||
|
||||
When installed will AdvancedServerList use ViaVersion to resolve the protocol version of a player for its PlaceholderAPI placeholders.
|
||||
|
||||
----
|
||||
|
||||
**Supported on:**
|
||||
:fontawesome-solid-paper-plane: Paper
|
||||
|
||||
- [**PAPIProxyBridge**][papiproxybridge]{ target="_blank" rel="nofollow" }
|
||||
|
||||
----
|
||||
|
||||
Allows AdvancedServerList to parse placeholders from PlaceholderAPI while being used on a proxy.
|
||||
|
||||
----
|
||||
|
||||
**Supported on:**
|
||||
:simple-spigotmc: BungeeCord, :fontawesome-solid-paper-plane: Velocity
|
||||
|
||||
- [**Maintenance**][maintenance]{ target="_blank" rel="nofollow" }
|
||||
|
||||
----
|
||||
|
||||
AdvancedServerList will disable any modification of the server list entry should Maintenance mode be enabled, unless you change this in the config.yml file.
|
||||
|
||||
----
|
||||
|
||||
**Supported on:**
|
||||
:fontawesome-solid-paper-plane: Paper, :simple-spigotmc: BungeeCord, :fontawesome-solid-paper-plane: Velocity
|
||||
|
||||
- [**BanPlugins Addon**][addon]
|
||||
|
||||
----
|
||||
|
||||
Official Add-on for AdvancedServerList that adds placeholders for different Ban/Punishment plugins such as AdvancedBan and LibertyBans.
|
||||
|
||||
----
|
||||
|
||||
**Supported on:**
|
||||
:fontawesome-solid-paper-plane: Paper, :simple-spigotmc: BungeeCord, :fontawesome-solid-paper-plane: Velocity
|
||||
|
||||
</div>
|
||||
|
||||
[placeholderapi]: https://hangar.papermc.io/HelpChat/PlaceholderAPI
|
||||
[viaversion]: https://hangar.papermc.io/ViaVersion/ViaVersion
|
||||
[papiproxybridge]: https://hangar.papermc.io/William278/PAPIProxyBridge
|
||||
[maintenance]: https://hangar.papermc.io/kennytv/Maintenance
|
||||
[addon]: ../addons/banplugins.md
|
||||
|
||||
## 2. Installation { #installation }
|
||||
|
||||
Installing the plugin is as simple as moving the jar file into the plugins folder. Just make sure to download the right version of AdvancedServerList for the right platform.
|
||||
Installing the plugin is as simple as moving the jar file into the `plugins` folder. Just make sure to download the right version of AdvancedServerList for the right platform.
|
||||
Here is a quick table showing the jar file name with the platforms it is made for:
|
||||
|
||||
| Jar file name | Platforms |
|
||||
|-----------------------------------------------|-----------------------|
|
||||
| `AdvancedServerList-Paper-{version}.jar` | Spigot, Paper |
|
||||
| `AdvancedServerList-Paper-{version}.jar` | Paper |
|
||||
| `AdvancedServerList-BungeeCord-{version}.jar` | BungeeCord, Waterfall |
|
||||
| `AdvancedServerList-Velocity-{version}.jar` | Velocity |
|
||||
|
||||
After you added it to your plugins folder - alongside any other dependency you may want or need - (re)start your server or proxy to enable the plugin.
|
||||
After you added it to your plugins folder - alongside any other dependency you may want - (re)start your server or proxy to enable the plugin.
|
||||
If everything goes well should AdvancedServerList create a folder named `AdvancedServerList` (`advancedserverlist` on Velocity) with additional files and folders inside of it.
|
||||
|
||||
### Folder structure
|
||||
|
||||
When you install AdvancedServerList for the first time should it have created the following file structure inside the plugins folder of your Server or Proxy:
|
||||
```
|
||||
AdvancedServerList/
|
||||
AdvancedServerList/ # advancedserverlist/ on Velocity
|
||||
├── favicons/
|
||||
├── profiles/
|
||||
│ └── default.yml
|
||||
@@ -75,171 +151,175 @@ The profiles folder is home of the server list profile files which allow you to
|
||||
On first creation will the folder have a `default.yml` file. This file contains all the options available to use alongside comments to try and help you in using it properly.
|
||||
|
||||
/// details | default.yml content
|
||||
type: file
|
||||
|
||||
```yaml
|
||||
#
|
||||
# Set the priority of this profile.
|
||||
# Higher number = Higher priority.
|
||||
# If there are multiple profiles (files) will they be sorted by priority, starting with highest.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#priority
|
||||
#
|
||||
priority: 0
|
||||
|
||||
#
|
||||
# Set conditions that needs to be met.
|
||||
# Only when all conditions return true will the profile be shown (Given no profile with higher priority is used).
|
||||
# Set condition(s) that should return true to display this profile.
|
||||
# This allows you to create profiles to only show for specific scenarios (i.e. player is banned).
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#conditions
|
||||
# Multiple conditions can be chaing with the keywords 'and', 'or', or their counterparts '&&' and '||'.
|
||||
#
|
||||
#conditions:
|
||||
# - '{playerVersion} < 759'
|
||||
# No condition or an empty condition will be treated as true by default.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#condition
|
||||
#
|
||||
condition: ''
|
||||
|
||||
#
|
||||
# Option that allows you to define multiple profiles to use.
|
||||
# Each entry supports the same options as the server list profile does. Whenever an option is not present, or set to
|
||||
# an empty value (If supported) would the option in the file be used (if present).
|
||||
# This allows you to f.e. randomize the MOTD while keeping other options the same, without copy-pasting the same options.
|
||||
# Set one or multiple profiles.
|
||||
#
|
||||
# A profile will be selected randomly.
|
||||
# A profile can contain the same options as used in the file itself, except for priority and condition.
|
||||
# If multiple entries are present, a random one will be selected. Any options set in the selected profile will override
|
||||
# any existing option in the file.
|
||||
#
|
||||
# Remove this option or set it to profiles: [] to use the global options of this file.
|
||||
# Example: The below profile configuration will randomly change the MOTD between two types, but keep the Hover text
|
||||
# the same.
|
||||
#
|
||||
# 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
|
||||
#
|
||||
#profiles:
|
||||
# - motd:
|
||||
# - '<aqua>Line 1'
|
||||
# - '<aqua>Line 2'
|
||||
# favicon: ''
|
||||
# playerCount:
|
||||
# hidePlayers: false
|
||||
# hover:
|
||||
# - '<green>Line 1'
|
||||
# - '<green>Line 2'
|
||||
# - '<green>Line 3'
|
||||
# text: ''
|
||||
# extraPlayers:
|
||||
# enabled: false
|
||||
# amount: 0
|
||||
profiles:
|
||||
- motd: ['<aqua>Line A', '<gold>Line B']
|
||||
- motd:
|
||||
- '<aqua>Line 1'
|
||||
- '<gold>Line 2'
|
||||
|
||||
#
|
||||
# Set the default (Global) MOTD used by this server list profile.
|
||||
# Supports HEX colors for 1.16+ servers including gradients using MiniMessage's <gradient:color:color> format.
|
||||
#
|
||||
# Remove this option or set it to motd: [] to not alter the MOTD.
|
||||
# Set the "Message of the day" to display.
|
||||
# This option supports RGB colors for 1.16+ Servers and clients, including gradients using MiniMessage's <gradient>
|
||||
# option.
|
||||
#
|
||||
# Only the first two lines will be considered and any additional one is ignored.
|
||||
#
|
||||
# When not present or empty (motd: []), no MOTD will be set.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#motd
|
||||
#
|
||||
motd:
|
||||
- '<grey>Line 1'
|
||||
- '<grey>Line 2'
|
||||
- '<grey>First Line'
|
||||
- '<grey>Second Line'
|
||||
|
||||
#
|
||||
# Allows you to set a global (Default) favicon for this server list profile.
|
||||
# You can use one of three possible options:
|
||||
# 1. A file name matching a PNG file located in the 'favicons' folder (Needs to end with .png)
|
||||
# 2. A URL pointing to a valid Image
|
||||
# 3. ${player name} to display the player's head as favicon. Uses https://mc-heads.net for this
|
||||
# Set the Favicon (image on the left of a server entry) to display.
|
||||
# This option supports three types of inputs:
|
||||
#
|
||||
# Remove this option or set to favicon: '' to not replace the Favicon.
|
||||
# 1. Name, including .png extension, pointing to an image located in the plugin's favicons folder.
|
||||
# 2. URL pointing to an image.*
|
||||
# 3. Player name, UUID or placeholders returning one of these.*
|
||||
# https://mc-heads.net will be used to retrieve an image of the provided name/UUID.
|
||||
#
|
||||
# * These images are loaded asynchronously, meaning they may not yet be "ready" when AdvancedServerList is done with
|
||||
# the event, requiring a refresh of the server list by the player to have it shown.
|
||||
#
|
||||
# Any images above or below 64x64 pixels will be automatically resized to these dimensions.
|
||||
#
|
||||
# If not present or empty (favicon: ''), defaults to not modifying the favicon.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#favicon
|
||||
#
|
||||
favicon: ''
|
||||
|
||||
#
|
||||
# Contains various options to manipulate the player count (Text displaying online and max players allowed).
|
||||
# Contains options for modifying the player count (Text displaying <online>/<max>).
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#playercount
|
||||
#
|
||||
playerCount:
|
||||
#
|
||||
# Whether AdvancedServerList should hide the player count or not.
|
||||
# When set to true will the player count display '???' instead of <online>/<max>
|
||||
# Set whether the Player count should be hidden.
|
||||
# When set to true, the player count will be displayed as '???' instead of the usual '<online>/<max>' and all other
|
||||
# playerCount options, except for extraPlayers and maxPlayers, will be ignored.
|
||||
#
|
||||
# Note that when this is enabled will all other options, except for 'extraPlayers', be ignored.
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
# If not present, defaults to false.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#hideplayers
|
||||
#
|
||||
hidePlayers: false
|
||||
#
|
||||
# Sets the text displayed when hovering over the player count.
|
||||
# Set the lines shown when the player hovers over the player count.
|
||||
# Unlike the MOTD option does this one only support basic color and formatting codes. Any RGB colors will be
|
||||
# downsampled to the nearest matching color.
|
||||
#
|
||||
# Remove this option or set it to hover: [] to not modify the player samples on the player count.
|
||||
# If not present or empty (hover: []), defaults to not modifying the hover.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#hover
|
||||
#
|
||||
hover:
|
||||
- '<grey>Line 1'
|
||||
- '<grey>Line 2'
|
||||
- '<grey>Line 3'
|
||||
- '<aqua>Line 1'
|
||||
- '<yellow>Line 2'
|
||||
- '<green>Line 3'
|
||||
#
|
||||
# Modifies the text that usually displays '<online>/<max>'
|
||||
#
|
||||
# Note that when used, the Ping icon will display as 'outdated server'/'outdated client'.
|
||||
# This is nothing that can be fixed or avoided and would require changes from Mojang.
|
||||
# Set the text that should be displayed instead of the default '<online>/<max>' text.
|
||||
#
|
||||
# Remove this option or set it to text: '' to not modify the player count text.
|
||||
# Using this option will show the server as "outdated" to the client (Have the ping icon crossed out).
|
||||
# This cannot be fixed and would require Mojang to change stuff.
|
||||
#
|
||||
# If not present or empty (text: ''), defaults to not modifying the text.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#text
|
||||
#
|
||||
text: ''
|
||||
#
|
||||
# Allows you to modify the max player count displayed.
|
||||
# Note that this will affect ${server playersMax} (Except for when used in conditions).
|
||||
# The extraPlayers feature allows to set a number that should be added to the current online players and then be
|
||||
# used as the "max" player count.
|
||||
#
|
||||
# Using this feature will modify the ${server playersMax} placeholder, except for usage in the condition option.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#extraplayers
|
||||
#
|
||||
extraPlayers:
|
||||
#
|
||||
# Enables/Disables the extraPlayers option.
|
||||
# When enabled will the total amount of players allowed to join be modified to the current
|
||||
# number of online players + 'amount'
|
||||
# Set whether the extraPlayers feature should be enabled or not.
|
||||
# When set to true, the max players count will be modified to be the number of online players with the 'amount'
|
||||
# value added to it.
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
# If not present, defaults to false.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#extraplayers-enabled
|
||||
#
|
||||
enabled: false
|
||||
#
|
||||
# Sets how much should be added/subtracted from the current number of online players
|
||||
# to then use for the max player count.
|
||||
# Set the number that should be added to the online player count to then use as the new max player count.
|
||||
#
|
||||
# Example:
|
||||
# When set to 1 while 10 players are online would the player count - if unmodified -
|
||||
# display '10/11'. When -1 is used will it display '10/9'
|
||||
# Example: Setting this to 1 will result in ${server playersMax} displaying 11 while 10 players are online,
|
||||
# 9 when 8 are online and so on.
|
||||
#
|
||||
# Defaults to 0 when not present.
|
||||
# If not present, defaults to 0.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#extraplayers-amount
|
||||
#
|
||||
amount: 0
|
||||
#
|
||||
# Allows you to set the max players that could join your server.
|
||||
# Note that this option influences the '${server playersMax}' placeholder.
|
||||
# The maxPlayers feature allows to set a number to use as the max player count to display.
|
||||
#
|
||||
# The settings of this option have no effect should 'extraPlayers' be enabled
|
||||
# Using this feature will modify the ${server playersMax} placeholder, except for usage in the condition option.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#maxplayers
|
||||
#
|
||||
maxPlayers:
|
||||
#
|
||||
# Enables/Disables the maxPlayers option.
|
||||
# When enabled will the total amount of players allowed to join be changed to what 'amount' is set to.
|
||||
# Set whether the maxPlayers feature should be enabled or not.
|
||||
# When set to true, the max player count will be set to the 'amount' value.
|
||||
#
|
||||
# If not present, defaults to false.
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#maxplayers-enabled
|
||||
#
|
||||
enabled: false
|
||||
#
|
||||
# Sets the number to display for the max number of players allowed to join your server.
|
||||
# Set the number that should be used as the new max players count.
|
||||
#
|
||||
# Example:
|
||||
# Setting this option to 0 (Default) while 1 player is online would display '1/0'
|
||||
#
|
||||
# Defaults to 0 if not set.
|
||||
# If not present, defaults to 0.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#maxplayers-amount
|
||||
#
|
||||
@@ -254,13 +334,18 @@ These functions include, but aren't limited to:
|
||||
|
||||
- Setting the default name and UUID used for an unknown (Not cached) player.
|
||||
- Disabling/Enabling caching of players.
|
||||
- Disabling/Enabling checking for updates
|
||||
- Disabling/Enabling checking for updates.
|
||||
- Disabling/Enabling debug mode.
|
||||
- Setting how long favicons should be cached for.
|
||||
- Disabling/Enabling features of the plugin while the plugin Maintenance is active.
|
||||
- The config version used for migration. Don't touch this, or it may reset your config.
|
||||
|
||||
Similar to the default.yml is this file containing comments to try and explain the settings in questions.
|
||||
Do note that if the config gets migrated from an older version, that the comments will be discarded in the process, unfortunately.
|
||||
Note that the config can get migrated to newer versions, adding missing options in the process. However, comments will get lost during that process.
|
||||
|
||||
/// details | default config.yml content
|
||||
type: file
|
||||
|
||||
```yaml
|
||||
#
|
||||
# Used for when AdvancedServerList doesn't have a cached player to use for player placeholders.
|
||||
@@ -295,32 +380,91 @@ disableCache: false
|
||||
#
|
||||
checkUpdates: true
|
||||
|
||||
#
|
||||
# Should debug mode be enabled?
|
||||
#
|
||||
# When set to true will AdvancedServerList print additional messages to the console prefixed with "[DEBUG]".
|
||||
# It is recommended to only enable this when having problems or when being told to by the plugin dev, as it could
|
||||
# otherwise cause significant spam in your console.
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
#
|
||||
debug: false
|
||||
|
||||
#
|
||||
# Sets the time in minutes for favicons to be cached.
|
||||
# The number cannot be less than 1.
|
||||
#
|
||||
# Defaults to 1 if not set.
|
||||
#
|
||||
faviconCacheTime: 1
|
||||
|
||||
#
|
||||
# List of options that should be disabled while the Maintenance Mode of the plugin Maintenance is active.
|
||||
# Any option not listed here will NOT be disabled, meaning AdvancedServerList will continue to handle it.
|
||||
#
|
||||
# Each option defaults to true when not present, disabling said option while Maintenance is active.
|
||||
#
|
||||
disableDuringMaintenance:
|
||||
#
|
||||
# When true (Default), disables handling of MOTD while Maintenance is enabled.
|
||||
#
|
||||
motd: true
|
||||
#
|
||||
# When true (Default), disables handling of Favicon while Maintenance is enabled.
|
||||
#
|
||||
favicon: true
|
||||
#
|
||||
# When true (Default), disables hiding of player count while Maintenance is enabled.
|
||||
#
|
||||
hidePlayers: true
|
||||
#
|
||||
# When true (Default), disables handling of player count text while Maintenance is enabled.
|
||||
#
|
||||
playerCountText: true
|
||||
#
|
||||
# When true (Default), disables handling of player count hover while Maintenance is enabled.
|
||||
#
|
||||
playerCountHover: true
|
||||
#
|
||||
# When true (Default), disables use of extra players feature while Maintenance is enabled.
|
||||
#
|
||||
extraPlayers: true
|
||||
#
|
||||
# When true (Default), disables use of max players feature while Maintenance is enabled.
|
||||
#
|
||||
maxPlayers: true
|
||||
|
||||
#
|
||||
# DO NOT EDIT!
|
||||
#
|
||||
# This is used internally to determine if the config needs to be migrated.
|
||||
# Changing or even removing this option could result in your config being broken.
|
||||
#
|
||||
config-version: 2
|
||||
config-version: 5
|
||||
```
|
||||
///
|
||||
|
||||
#### Additionally created files and folders
|
||||
#### Additional created files and folders
|
||||
|
||||
There are certain files and folders that get created when certain events happen:
|
||||
|
||||
- A `playercache.json` file will be created on plugin shutdown containing a list of IPs, UUIDs and Player names for every player that joined the server while AdvancedServerList was running.
|
||||
This file allows to replace `${player name}` and `${player uuid}` with their name or UUID respectively, while they are not on the server, by using the IP they used to join with.
|
||||
This file is not created nor updated when `disableCache` is set to `true` in the config.yml
|
||||
- A `playercache.json` file will be created on plugin shutdown containing a collection of IPs, UUIDs and Player names for every player that joined the server while AdvancedServerList was running.
|
||||
This file is used to identify a player through their last used IP, to replace placeholders such as `${player name}` or `${player uuid}` with their respective values using the cached data.
|
||||
This file is not created, used, nor updated when `disableCache` is set to `true` in the config.yml
|
||||
- A `backups` folder containing old config.yml files.
|
||||
This folder is created when AdvancedServerList migrates your old config to a new version. This allows you to transfer settings over in case the migration didn't work properly.
|
||||
This folder is created when AdvancedServerList migrates your old config to a new version. This allows you to transfer settings over in case the migration didn't work properly.
|
||||
Each backup will have the name pattern `config-<date>.yml` with `<date>` being the date and time of when this file has been created.
|
||||
|
||||
## 3. Creating your first profile { #creating-your-first-profile }
|
||||
|
||||
Creating your first profile is relatively simple.
|
||||
|
||||
To start, open the `default.yml` file located inside the `profiles` folder using a file editor of your choice (VSCode or Notepad++ are recommended). It should contain all the available options for a server list profile.
|
||||
Next can you edit the options available to whatever you like. All text options (Except [conditions](../profiles/index.md#conditions)) support [MiniMessage formatting](../profiles/formatting.md).
|
||||
It's best to open the `default.yml` file located inside `profiles` with the file editor of your choice ([:simple-vscodium: VSCodeium](https://vscodium.com/) or [:simple-notepadplusplus: Notepad++](https://notepad-plus-plus.org/) are recommended).
|
||||
This file should contain all available options that you can set and alter.
|
||||
|
||||
Edit the options to whatever you like. All text-based options, except [`condition`](../profiles/index.md#condition), support [MiniMessage formatting](../profiles/formatting.md).
|
||||
Hexadecimal (RGB) colors are supported, however, only the [`motd` option](../profiles/index.md#motd) may display them and only for MC 1.16+ clients. Any other option will have the color down-sampled to the nearest supported color code.
|
||||
|
||||
If you're unsure how a specific option should look like, head over to the [Profiles page](../profiles/index.md) for more information about the general structure.
|
||||
All you need to know is, that a bare-bones server list profile requires a valid [priority](../profiles/index.md#priority) and at least one of the settings to be present.
|
||||
@@ -336,19 +480,23 @@ motd:
|
||||
|
||||
### Additional profiles
|
||||
|
||||
To add additional profiles, create a new YAML file inside the `profiles` folder. The name doesn't matter, but it is recommended to keep it lowercase, use alphanumeric characters (`a-z, 0-9`), hyphens (`-`), underscores (`_`) and avoid spaces.
|
||||
To add additional profiles, create a new YAML file inside the `profiles` folder. The name can be whatever you like, but it is recommended to keep it simple and only use alphanumeric characters (`a-z` and `0-9`), underlines and hyphens.
|
||||
|
||||
Inside the file, add a priority and at least one setting, similar to the above shown example.
|
||||
This would already be enough and AdvancedServerList would use it. If you however want to only show it when certain conditions are met, should you set the priority to a higher value and add conditions.
|
||||
This would already be enough to have a valid profile, but depending on the priority and file name may the file not be used, or used over other profiles.
|
||||
|
||||
Conditions can be multiple strings containing [operands](../profiles/index.md#operands) to evaluate them. As an example `${server playersOnline} >= 10` would return true if the current number of online players is larger or equal to 10.
|
||||
If you want to only show this file under specific situations can you use the [`condition`](../profiles/index.md#condition) option to apply conditions that need to be met to show the profile.
|
||||
The condition option would have a single String containing one or multiple [Expressions](../profiles/expressions.md). Only if the condition would return true, would the profile be displayed, granted that it has a higher priority than any other valid file with a true condition output.
|
||||
|
||||
Here is another example profile using conditions:
|
||||
/// info | Note
|
||||
Files without a condition or an empty condition will be treated as always having a true condition.
|
||||
///
|
||||
|
||||
Here is another example profile using conditions to show it when the player was banned on the server:
|
||||
```yaml title="other_profile.yml"
|
||||
priority: 1
|
||||
|
||||
conditions:
|
||||
- '${player isBanned} = true'
|
||||
condition: '${player isBanned}'
|
||||
|
||||
motd:
|
||||
- '<red>You got <bold>banned</bold> from this server.'
|
||||
@@ -361,7 +509,7 @@ The [Examples page](../examples/index.md) contains more examples of different se
|
||||
## 4. Loading profiles { #loading-profiles }
|
||||
|
||||
Once you've set up your server list profile(s) is it time to load it/them.
|
||||
To do this, simply run `/asl reload` as player (Requires permission `advancedserverlist.admin` or `advancedserverlist.command.reload`) or through the Server/Proxy console.
|
||||
To do this, simply run `/asl reload` as player (Requires permission `advancedserverlist.admin` or `advancedserverlist.command.reload`) or `asl reload` through the Server/Proxy console.
|
||||
|
||||
The plugin should then load any valid YAML file inside the `profiles` folder to then use.
|
||||
|
||||
|
||||
+56
-35
@@ -7,18 +7,21 @@ icon: octicons/home-24
|
||||
Welcome to the Wiki of AdvancedServerList!
|
||||
|
||||
On this site can you find the latest documentation for the plugin, including some useful examples.
|
||||
If you're new to the plugin is it recommended to check out the [Profiles page](profiles/index.md) for a quick start on how to use this plugin.
|
||||
If you're new to the plugin, check out [:octicons-milestone-24: **Getting Started**](getting-started/index.md) for a quick Start Guide.
|
||||
|
||||
## Downloads
|
||||
|
||||
[![modrinth-img]{ width="260" loading="lazy" }][modrinth-download]{ target="_blank" rel="noreferrer nofollow noopener" }
|
||||
[![hangar-img]{ width="260" loading="lazy" }][hangar-download]{ target="_blank" rel="noreferrer nofollow noopener" }
|
||||
[![hangar-img]{ width="260" loading="lazy" }][hangar-download]{ target="_blank" rel="noreferrer nofollow noopener" }
|
||||
[![codeberg-img]{ width="260" loading="lazy" }][codeberg-download]{ target="_blank" rel="noreferrer nofollow noopener" }
|
||||
|
||||
[modrinth-img]: https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact/available/modrinth_vector.svg "Available on Modrinth"
|
||||
[hangar-img]: https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact/available/hangar_vector.svg "Available on Hangar"
|
||||
[codeberg-img]: https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact/available/codeberg_vector.svg "Available on Codeberg"
|
||||
|
||||
[modrinth-download]: https://modrinth.com/plugin/advancedserverlist
|
||||
[hangar-download]: https://hangar.papermc.io/Andre_601/AdvancedServerList
|
||||
[codeberg-download]: https://codeberg.org/Andre601/AdvancedServerList
|
||||
|
||||
## Platforms
|
||||
|
||||
@@ -38,38 +41,56 @@ AdvancedServerList supports the following platforms:
|
||||
[paper]: https://papermc.io
|
||||
[velocity]: https://velocitypowered.com
|
||||
|
||||
## Dependencies
|
||||
|
||||
/// info
|
||||
All listed dependencies are optional.
|
||||
///
|
||||
|
||||
| Dependency | Platforms |
|
||||
|-------------------------------------------------------------------------|----------------------|
|
||||
| [PlaceholderAPI]{ target="_blank" rel="noreferrer nofollow noopener" } | Paper |
|
||||
| [ViaVersion]{ target="_blank" rel="noreferrer nofollow noopener" } | Paper |
|
||||
| [PAPIProxyBridge]{ target="_blank" rel="noreferrer nofollow noopener" } | BungeeCord, Velocity |
|
||||
| [Maintenance]{ target="_blank" rel="noreferrer nofollow noopener" } | All |
|
||||
|
||||
[placeholderapi]: https://hangar.papermc.io/HelpChat/PlaceholderAPI
|
||||
[viaversion]: https://hangar.papermc.io/ViaVersion/ViaVersion
|
||||
[papiproxybridge]: https://hangar.papermc.io/William278/PAPIProxyBridge
|
||||
[maintenance]: https://hangar.papermc.io/kennytv/Maintenance
|
||||
|
||||
## Pages
|
||||
|
||||
- [Getting started](getting-started/index.md)
|
||||
- [Commands](commands/index.md)
|
||||
- [Profiles](profiles/index.md)
|
||||
- [Formatting](profiles/formatting.md)
|
||||
- [Placeholders](profiles/placeholders.md)
|
||||
- [Examples](examples/index.md)
|
||||
- [Migration](migration/index.md)
|
||||
- [v1.5.3 to v1.6.0](migration/v1_5_3-to-v1_6_0.md)
|
||||
- [v1.9.0 to v1.10.0](migration/v1_9_0-to-v1_10_0.md)
|
||||
- [API](api/index.md)
|
||||
- [Changelog](api/changelog.md)
|
||||
- [Javadocs](api/javadocs.md) (External site)
|
||||
- [Source Code](api/source.md) (External site)
|
||||
- [Reference](api/reference/index.md)
|
||||
- [PlaceholderAPI](placeholderapi/index.md)
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- [:octicons-milestone-24: **Getting Started**](getting-started/index.md)
|
||||
|
||||
----
|
||||
|
||||
A simple guide on how to get started with AdvancedServerList.
|
||||
|
||||
- [:octicons-rel-file-path-24: **Commands**](commands/index.md)
|
||||
|
||||
----
|
||||
|
||||
A list of all available commands in AdvancedServerList.
|
||||
|
||||
- [:octicons-note-24: **Profiles**](profiles/index.md)
|
||||
|
||||
----
|
||||
|
||||
Pages containing information about the Server List Profile System and all its available options.
|
||||
|
||||
- [:octicons-list-unordered-24: **Examples**](examples/index.md)
|
||||
|
||||
----
|
||||
|
||||
Collection of various profile examples to use for different situations.
|
||||
|
||||
- [:octicons-file-directory-symlink-24: **Migration**](migration/index.md)
|
||||
|
||||
----
|
||||
|
||||
Pages explaining how to migrate from one version of the plugin to another.
|
||||
|
||||
- [:octicons-command-palette-24: **API**](api/index.md)
|
||||
|
||||
----
|
||||
|
||||
Pages all about the API of AdvancedServerList.
|
||||
|
||||
- [:octicons-plus-circle-24: **Addons**](addons/index.md)
|
||||
|
||||
----
|
||||
|
||||
Pages listing 1st-party and 3rd-party add-ons for AdvancedServerList.
|
||||
|
||||
- [:material-percent: **PlaceholderAPI**](placeholderapi/index.md)
|
||||
|
||||
----
|
||||
|
||||
Information about available placeholders to use in PlaceholderAPI and how to use placeholders from other plugins in AdvancedServerList using PlaceholderAPI.
|
||||
|
||||
</div>
|
||||
+33
-1
@@ -10,4 +10,36 @@ Note that these pages only cover server list profile files. The config.yml is au
|
||||
|
||||
## Pages
|
||||
|
||||
{nav}
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- [**v3.8.0 to v3.9.0**](v3_8_0-to-v3_9_0.md)
|
||||
|
||||
----
|
||||
|
||||
Migrate from version 3.8.0 to 3.9.0.
|
||||
|
||||
- [**v3.7.0 to v3.8.0**](v3_7_0-to-v3_8_0.md)
|
||||
|
||||
----
|
||||
|
||||
Migrating from version 3.7.0 to 3.8.0.
|
||||
|
||||
- [**< v3.7.0 to v3.7.0**](pre-v3_7_0-to-v3_7_0.md)
|
||||
|
||||
----
|
||||
|
||||
Migrate from any version prior to 3.7.0 to 3.7.0 or newer.
|
||||
|
||||
- [**v1.9.0 to v1.10.0**](v1_9_0-to-v1_10_0.md)
|
||||
|
||||
----
|
||||
|
||||
Migrate from version 1.9.0 to 1.10.0.
|
||||
|
||||
- [**v1.5.3 to v1.6.0**](v1_5_3-to-v1_6_0.md)
|
||||
|
||||
----
|
||||
|
||||
Migrate from version 1.5.3 to 1.6.0.
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,60 @@
|
||||
---
|
||||
icon: octicons/arrow-right-24
|
||||
---
|
||||
|
||||
# < v3.7.0 to v3.7.0
|
||||
|
||||
Version 3.7.0 of AdvancedServerList brought significant changes to its conditions system.
|
||||
Namely, the `conditions` option is now deprecated and planned for removal in a future release of the Plugin, and the new [`condition`](../profiles/index.md#condition) option should now be used instead.
|
||||
|
||||
## Migration
|
||||
|
||||
To migrate, all you have to do is take the entries of the old conditions option and convert them into a single String connected with `and` operators in between. See the [Example below](#example).
|
||||
|
||||
## Example
|
||||
|
||||
Here is a before and after example to help visualize the change:
|
||||
|
||||
/// tab | Before
|
||||
```yaml
|
||||
priority: 0
|
||||
|
||||
conditions:
|
||||
- '${player protocol} > 763'
|
||||
- '${player isWhitelisted} == true'
|
||||
|
||||
motd:
|
||||
- 'Welcome ${player name}!'
|
||||
```
|
||||
///
|
||||
|
||||
/// tab | After
|
||||
```yaml
|
||||
priority: 0
|
||||
|
||||
# The text can all be in one line. This is only for better readability.
|
||||
condition: |
|
||||
${player protocol} >= 763 and
|
||||
${player isWhitelisted}
|
||||
|
||||
motd:
|
||||
- 'Welcome ${player name}!'
|
||||
```
|
||||
///
|
||||
|
||||
/// tab | Diff View
|
||||
```diff
|
||||
priority: 0
|
||||
|
||||
-conditions:
|
||||
- - '${player protocol} >= 763'
|
||||
- - '${player isWhitelisted} == true'
|
||||
+# The text can all be in one line. This is only for better readability.
|
||||
+condition: |
|
||||
+ ${player protocol} >= 763 and
|
||||
+ ${player isWhitelisted}
|
||||
|
||||
motd:
|
||||
- 'Welcome ${player name}!'
|
||||
```
|
||||
///
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
icon: octicons/arrow-right-24
|
||||
---
|
||||
|
||||
# v3.7.0 to v3.8.0
|
||||
|
||||
v3.8.0 brought a small yet important change to the condition system, which is the change of the "contains" operand from `<-` to `<_` to avoid possible issues with numbers.
|
||||
|
||||
## Migration
|
||||
|
||||
To migrate, switch any appearances of `<-` with `<_`
|
||||
|
||||
## Example
|
||||
|
||||
Here is a before and after example to help visualize the change:
|
||||
|
||||
/// tab | Before
|
||||
```yaml
|
||||
priority: 0
|
||||
|
||||
condition: '${server host} <- "survival"'
|
||||
|
||||
motd:
|
||||
- 'Welcome ${player name}!'
|
||||
```
|
||||
///
|
||||
|
||||
/// tab | After
|
||||
```yaml
|
||||
priority: 0
|
||||
|
||||
condition: '${server host} <_ "survival"'
|
||||
|
||||
motd:
|
||||
- 'Welcome ${player name}!'
|
||||
```
|
||||
///
|
||||
|
||||
/// tab | Diff View
|
||||
```diff
|
||||
priority: 0
|
||||
|
||||
-condition: '${server host} <- "survival"'
|
||||
+condition: '${server host} <_ "survival"'
|
||||
|
||||
motd:
|
||||
- 'Welcome ${player name}!'
|
||||
```
|
||||
///
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
icon: octicons/arrow-right-24
|
||||
---
|
||||
|
||||
# v3.8.0 to v3.9.0
|
||||
|
||||
v3.9.0 brings a small change to the `~=` operand by changing it to `=~` for sake of consistent pattern design. Additionally, was `~` added as a single-character equivalent to `=`.
|
||||
|
||||
## Migration
|
||||
|
||||
To migrate, switch any appearances of `~=` with `=~` or `~`.
|
||||
|
||||
## Example
|
||||
|
||||
Here is a before and after example to help visualize the change:
|
||||
|
||||
/// tab | Before
|
||||
```yaml
|
||||
priority: 0
|
||||
|
||||
condition: '${player name} ~= "Someone"'
|
||||
|
||||
motd:
|
||||
- 'Welcome ${player name}!'
|
||||
```
|
||||
///
|
||||
|
||||
/// tab | After
|
||||
```yaml
|
||||
priority: 0
|
||||
|
||||
condition: '${player name} =~ "Someone"'
|
||||
|
||||
motd:
|
||||
- 'Welcome ${player name}!'
|
||||
```
|
||||
///
|
||||
|
||||
/// tab | Diff View
|
||||
```diff
|
||||
priority: 0
|
||||
|
||||
-condition: '${player name} ~= "Someone"'
|
||||
+condition: '${player name} =~ "Someone"'
|
||||
|
||||
motd:
|
||||
- 'Welcome ${player name}!'
|
||||
```
|
||||
///
|
||||
Loaded 100 of 135 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user