Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
816a58493a | ||
|
|
bc84cd2ec9 | ||
|
|
5f7fda250c | ||
|
|
03b58da260 | ||
|
|
238049b58c | ||
|
|
34a701cbe9 | ||
|
|
bdf42b3ef1 | ||
|
|
7b82fa17d0 | ||
|
|
05f1f285d0 | ||
|
|
12813a4a00 | ||
|
|
176b02ebe3 | ||
|
|
bd53bf7eb2 | ||
|
|
ae17d965e6 | ||
|
|
17b69fd38c | ||
|
|
ee9c6f77ec | ||
|
|
ddeb523154 | ||
|
|
04ec8e1927 | ||
|
|
f3f3cc7927 | ||
|
|
c7dd3f5344 | ||
|
|
19f534845f | ||
|
|
3c3110a3f8 | ||
|
|
2aa551090c | ||
|
|
57861e435c | ||
|
|
205e1e065d | ||
|
|
79ee776167 | ||
|
|
19869084e5 | ||
|
|
f1bd608fca | ||
|
|
2474e390f7 | ||
|
|
ef737d5566 | ||
|
|
9c64d3521e | ||
|
|
c7c8636720 | ||
|
|
cda72b3b3a | ||
|
|
04a1101045 | ||
|
|
44e3e51bbc | ||
|
|
40f2c44b5d | ||
|
|
16c26af04e | ||
|
|
85aa30f82c | ||
|
|
0ad119b6e0 | ||
|
|
a612e2216b | ||
|
|
2c0d3db9f4 | ||
|
|
8de820747a | ||
|
|
6469893b15 | ||
|
|
a46feb5e03 | ||
|
|
2e39683687 | ||
|
|
78464ac222 | ||
|
|
92b12fd612 | ||
|
|
5e90191aa4 | ||
|
|
1b4ee54b73 | ||
|
|
409c007759 | ||
|
|
49cd7410cf | ||
|
|
978b21360e | ||
|
|
0d1fbc15ce | ||
|
|
1cf3ba543d | ||
|
|
358830cbfb | ||
|
|
ea193d7bd3 | ||
|
|
8e59336833 | ||
|
|
5083f0a3d2 | ||
|
|
d20fdd3086 | ||
|
|
e005d80192 | ||
|
|
afd791b808 | ||
|
|
0acdcba09b | ||
|
|
872078ff05 | ||
|
|
4bfb1ec29b | ||
|
|
97f073685e | ||
|
|
08ab52d7f0 | ||
|
|
e7b7c78b11 | ||
|
|
7df02868ad | ||
|
|
063b5f90e9 | ||
|
|
dd700f99e2 | ||
|
|
7b9f418b23 | ||
|
|
fa163e0593 | ||
|
|
8ba86bec71 | ||
|
|
971f404f20 | ||
|
|
f378b1e10a | ||
|
|
13a281ebf7 | ||
|
|
e7f210739f | ||
|
|
addca59c39 | ||
|
|
f93880a0f5 | ||
|
|
489e8b60aa | ||
|
|
bf418d8a9a | ||
|
|
1e1f11cde9 | ||
|
|
34179eb850 | ||
|
|
cfcd488d44 | ||
|
|
a49b838b83 | ||
|
|
fdeec1e97c | ||
|
|
39ba75410e | ||
|
|
c20d6be447 | ||
|
|
d2f7f256d3 | ||
|
|
fb6abf7161 | ||
|
|
445bdac8a7 | ||
|
|
7bdabf93b8 | ||
|
|
8d9c0549b7 | ||
|
|
4d94a4879b | ||
|
|
924a72c537 | ||
|
|
75abdccd06 | ||
|
|
bb4b92e37e | ||
|
|
880616135f | ||
|
|
be72744651 | ||
|
|
c43090bdd8 | ||
|
|
50143c2374 | ||
|
|
951f1853fc | ||
|
|
a69962dd86 | ||
|
|
29e0bf8476 | ||
|
|
ee41a234e8 | ||
|
|
c8cf01319a | ||
|
|
3f4da7884f | ||
|
|
965df44783 | ||
|
|
b9b8f8b36d | ||
|
|
d293cdfb39 | ||
|
|
e3dc3ea548 | ||
|
|
3037d3a742 | ||
|
|
2230800deb | ||
|
|
1f0b8f783f | ||
|
|
da8d4e93ab | ||
|
|
aa38567232 | ||
|
|
b6757b9622 | ||
|
|
ca288fdf75 | ||
|
|
8b74c29bbe | ||
|
|
5aae4a17ef | ||
|
|
778212d48a | ||
|
|
8d126436ea | ||
|
|
ec40db1b26 | ||
|
|
263c197845 | ||
|
|
7bdc14aa30 | ||
|
|
7ba5209222 | ||
|
|
71e62e0bae | ||
|
|
4a8029ec31 | ||
|
|
382038b9a4 | ||
|
|
7f59851a3b | ||
|
|
0ebcc449f8 | ||
|
|
323614d8c5 | ||
|
|
264dedca34 | ||
|
|
ce26decb7d | ||
|
|
37085e82f0 | ||
|
|
041430e842 | ||
|
|
6762cbc245 | ||
|
|
917d3640f0 | ||
|
|
0cece71f37 | ||
|
|
d9c9f30cea | ||
|
|
dcb119df96 | ||
|
|
78ae7fbcb2 | ||
|
|
1545aad32d | ||
|
|
035d485561 | ||
|
|
f34a1ad2e4 | ||
|
|
5ceef81927 | ||
|
|
6315f74312 | ||
|
|
086a45593b | ||
|
|
1095166155 | ||
|
|
bf89a7cb12 | ||
|
|
729b671c5a | ||
|
|
380791cd45 | ||
|
|
ca80083414 | ||
|
|
ee7fa16514 | ||
|
|
c86a3d4101 | ||
|
|
6fd6a8fe38 | ||
|
|
b05b38e0e8 | ||
|
|
d55298d61b | ||
|
|
37ccf7176c | ||
|
|
868c93ac09 | ||
|
|
f927e836f5 | ||
|
|
2172628985 | ||
|
|
628b1763da | ||
|
|
bbe5fea132 | ||
|
|
8b555a8f53 | ||
|
|
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 |
No files matched your search
@@ -0,0 +1,11 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: API Support
|
||||
about: For API support, please create an issue in the `asl-api` repository.
|
||||
url: https://codeberg.org/Andre601/asl-api
|
||||
- name: Discord Server
|
||||
about: Please ask questions in the `#asl-support` channel on the M.O.S.S. Discord Server.
|
||||
url: https://discord.gg/MyPTjpsgGH
|
||||
- name: Wiki
|
||||
about: Check the Wiki for explanations about the features and examples.
|
||||
url: https://asl.andre601.ch
|
||||
@@ -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">
|
||||
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 156 KiB After Width: | Height: | Size: 156 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
@@ -0,0 +1,37 @@
|
||||
name: Pull Request
|
||||
description: Create a new Pull request
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |-
|
||||
Thank you for creating a Pull request!
|
||||
|
||||
Please be sure to fill out this template with all requested information to ensure it being valid and not being closed unmerged.
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Type
|
||||
description: What kind of Pull request is this?
|
||||
options:
|
||||
- Enhancement
|
||||
- Bugfix
|
||||
- Documentation
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Breaking Change?
|
||||
description: |-
|
||||
Is this a breaking change?
|
||||
A breaking change means that it becomes incompatible with previous server/proxy versions or plugin versions.
|
||||
options:
|
||||
- Yes
|
||||
- No
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Description
|
||||
description: Provide a detailed description of what this Pull request is doing. Link any issues this Pull request may fix/close.
|
||||
validations:
|
||||
required: true
|
||||
@@ -1,2 +0,0 @@
|
||||
patreon: andre_601
|
||||
ko_fi: andre_601
|
||||
@@ -1,41 +0,0 @@
|
||||
name: API support
|
||||
description: Ask for help with the API.
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |-
|
||||
## Before opening
|
||||
Please make sure you've checked the following things first:
|
||||
|
||||
- You're using the latest release of AdvancedServerList [[Download from Modrinth](https://modrinth.com/plugin/advancedserverlist)] and the right API version.
|
||||
- You're using a supported Proxy/Server version. As of right now is only 1.19+ supported.
|
||||
- The Feature you suggest hasn't been suggested before.
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Platforms
|
||||
description: On what platform(s) are you using the API?
|
||||
multiple: true
|
||||
options:
|
||||
- Proxy (BungeeCord, Waterfall, ...)
|
||||
- Proxy (Velocity)
|
||||
- Server (Spigot, Paper, ...)
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Description
|
||||
description: |-
|
||||
Give a detailed description of what exactly you try to do, what steps you did and what you need help with.
|
||||
placeholder: I tried to...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Code
|
||||
description: |-
|
||||
Provide code-snippets to help us better understand what you tried.
|
||||
The code is automatically parsed as Java Code.
|
||||
render: java
|
||||
validations:
|
||||
required: true
|
||||
@@ -1,8 +0,0 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Discord Server
|
||||
about: Ask questions about the plugin in the `#advancedserverlist` channel.
|
||||
url: https://discord.gg/6dazXp6
|
||||
- name: Wiki
|
||||
about: Check the Wiki for explanations about the features and examples.
|
||||
url: https://docs.andre601.ch/AdvancedServerList
|
||||
@@ -1,14 +0,0 @@
|
||||
"Target: All":
|
||||
- all: ["bukkit/**", "bungeecord/**", "core/**", "velocity/**"]
|
||||
|
||||
"Target: Bukkit":
|
||||
- all: ["bukkit/**", "!bungeecord/**", "!core/**", "!velocity/**"]
|
||||
|
||||
"Target: BungeeCord":
|
||||
- all: ["!bukkit/**", "bungeecord/**", "!core/**", "!velocity/**"]
|
||||
|
||||
"Target: Core":
|
||||
- all: ["!bukkit/**", "!bungeecord/**", "core/**", "!velocity/**"]
|
||||
|
||||
"Target: Velocity":
|
||||
- all: ["!bukkit/**", "!bungeecord/**", "!core/**", "velocity/**"]
|
||||
@@ -1,49 +0,0 @@
|
||||
name: 'Deploy Site (Push)'
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
GITHUB_REPO_INSTANCE: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python 3.7
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.x
|
||||
- name: Create/Get Cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
key: ${{ github.ref }}
|
||||
path: .cache
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip setuptools
|
||||
python -m pip install -r requirements.txt
|
||||
- name: Build docs
|
||||
run: mkdocs build
|
||||
- name: Configure GitHub Pages
|
||||
uses: actions/configure-pages@v4
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: 'site/'
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
@@ -0,0 +1,64 @@
|
||||
when:
|
||||
- event: pull_request
|
||||
path:
|
||||
include: [".woodpecker/pr_preview.yml", "docs/**", "mkdocs.yml", "requirements.txt"]
|
||||
|
||||
variables:
|
||||
setup_git: &setup_git
|
||||
- apk add git
|
||||
- git config --global user.email "andre_601-bot@noreply.codeberg.org"
|
||||
- git config --global user.name "PR Docs Preview Builder"
|
||||
|
||||
steps:
|
||||
- name: "Clone Preview Repository"
|
||||
image: alpine:3.18.4
|
||||
commands:
|
||||
- chmod -R a+w .
|
||||
- <<: *setup_git
|
||||
- git clone https://codeberg.org/Andre601/preview.git site
|
||||
- chmod -R a+w site
|
||||
- cd site
|
||||
- git switch ${CI_REPO_NAME,,}/${CI_COMMIT_PULL_REQUEST} 2>/dev/null || git switch -c ${CI_REPO_NAME,,}/${CI_COMMIT_PULL_REQUEST}
|
||||
- name: "Build Docs"
|
||||
image: woodpeckerci/plugin-mkdocs:latest
|
||||
settings:
|
||||
pip_install_file: requirements.txt
|
||||
- name: "Commit and Push"
|
||||
image: alpine:3.18.4
|
||||
secrets:
|
||||
- bot_token
|
||||
commands:
|
||||
- <<: *setup_git
|
||||
- mv preview-domains site/.domains
|
||||
- cd site
|
||||
- git remote add upstream https://$BOT_TOKEN@codeberg.org/Andre601/preview.git
|
||||
- git add --all
|
||||
- git commit -m "Update Preview for ${CI_REPO_NAME}/${CI_COMMIT_PULL_REQUEST} ($( env TZ=Europe/Zurich date +"%d.%m.%Y %Z" )) [SKIP CI]"
|
||||
- git push --set-upstream upstream ${CI_REPO_NAME,,}/${CI_COMMIT_PULL_REQUEST} -f
|
||||
- name: "Comment on Success"
|
||||
image: mcs94/gitea-comment
|
||||
when:
|
||||
- status: ["success"]
|
||||
settings:
|
||||
gitea_address: https://codeberg.org
|
||||
gitea_token:
|
||||
from_secret: BOT_TOKEN
|
||||
comment: |-
|
||||
Pull request Preview Ready!
|
||||
|
||||
| Name | Value |
|
||||
|--------|--------------------------------------------------------------------------|
|
||||
| Commit | ${CI_COMMIT_SHA} |
|
||||
| Link | https://preview.andre601.ch/@${CI_REPO_NAME,,}~${CI_COMMIT_PULL_REQUEST} |
|
||||
- name: "Comment on Failure"
|
||||
image: mcs94/gitea-comment
|
||||
when:
|
||||
- status: ["failure"]
|
||||
settings:
|
||||
gitea_address: https://codeberg.org
|
||||
gitea_token:
|
||||
from_secret: BOT_TOKEN
|
||||
comment: |-
|
||||
Pull request Preview **failed**!
|
||||
|
||||
Please check the CI logs for details: ${CI_PIPELINE_URL}
|
||||
@@ -1,29 +1,24 @@
|
||||
when:
|
||||
- event: tag
|
||||
branch: master
|
||||
branch: ${CI_REPO_DEFAULT_BRANCH}
|
||||
|
||||
steps:
|
||||
createFiles:
|
||||
- name: "Build Jar and Upload"
|
||||
image: maven:3.9.6-eclipse-temurin-17
|
||||
secrets:
|
||||
- source: cb_token
|
||||
target: codeberg_api_token
|
||||
- source: modrinth_api_token
|
||||
target: modrinth_api_token
|
||||
- source: hangar_api_token
|
||||
target: hangar_api_token
|
||||
- source: discord_webhook_url
|
||||
target: discord_webhook_url
|
||||
- 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
|
||||
# Move VersionUploader jar file
|
||||
- cd version-uploader/target/
|
||||
- cd version-uploader/target
|
||||
- mv VersionUploader.jar ../../
|
||||
- cd ../../
|
||||
# Execute Jar file
|
||||
- java -jar VersionUploader.jar --all
|
||||
uploadToCodeberg:
|
||||
- name: "Upload Jars to Codeber"
|
||||
image: woodpeckerci/plugin-gitea-release
|
||||
settings:
|
||||
base_url: https://codeberg.org
|
||||
@@ -33,4 +28,19 @@ steps:
|
||||
- "velocity/target/AdvancedServerList-*.jar"
|
||||
- "addons/banplugins/target/AdvancedServerList-*.jar"
|
||||
api_key:
|
||||
from_secret: CB_TOKEN
|
||||
from_secret: cb_token
|
||||
- name: "Create Post on Mastodon"
|
||||
image: woodpeckerci/plugin-mastodon-post
|
||||
when:
|
||||
- status: ["success"]
|
||||
settings:
|
||||
server_url: https://blobfox.coffee
|
||||
access_token:
|
||||
from_secret: mastodon_token
|
||||
status: |-
|
||||
#AdvancedServerList was updated to ${CI_COMMIT_TAG} and can be downloaded from #Modrinth, #Hangar and #Codeberg!
|
||||
|
||||
Modrinth - https://modrinth.com/plugin/advancedserverlist
|
||||
Hangar - https://hangar.papermc.io/Andre_601/AdvancedServerList
|
||||
Codeberg - https://codeberg.org/Andre601/AdvancedServerList
|
||||
visibility: public
|
||||
@@ -1,36 +1,36 @@
|
||||
when:
|
||||
- branch: master
|
||||
event: push
|
||||
- event: push
|
||||
branch: ${CI_REPO_DEFAULT_BRANCH}
|
||||
path:
|
||||
include: ['requirements.txt', 'mkdocs.yml', 'docs/**']
|
||||
include: [".woodpecker/publish_docs.yml", "docs/**", "mkdocs.yml", "requirements.txt"]
|
||||
|
||||
variables:
|
||||
setup_git: &setup_git
|
||||
- apk add git
|
||||
- git config --global user.email "github@andre601.ch"
|
||||
- git config --global user.email "andre_601-bot@noreply.codeberg.org"
|
||||
- git config --global user.name "ASL Docs Builder"
|
||||
|
||||
steps:
|
||||
cloneTargetRepo:
|
||||
- name: "Clone target Repository"
|
||||
image: alpine:3.18.4
|
||||
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.git site
|
||||
- chmod -R a+w site
|
||||
buildDocs:
|
||||
- name: "Build Docs"
|
||||
image: woodpeckerci/plugin-mkdocs:latest
|
||||
settings:
|
||||
pip_install_file: requirements.txt
|
||||
commitAndPush:
|
||||
- name: "Commit and Push"
|
||||
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
|
||||
@@ -8,11 +8,9 @@ AdvancedServerList is a plugin that allows 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
|
||||
|
||||
@@ -90,8 +88,8 @@ You can disable this in the global bStats config file located in `/plugins/bstat
|
||||
|
||||
## Support
|
||||
|
||||
<a href="https://discord.gg/6dazXp6" target="_blank">
|
||||
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact-minimal/social/discord-singular_vector.svg" height="64" alt="discord" title="Join my Discord Server">
|
||||
<a href="https://discord.gg/MyPTjpsgGH" target="_blank">
|
||||
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact-minimal/social/discord-singular_vector.svg" height="64" alt="discord" title="Join the M.O.S.S. Discord Server">
|
||||
</a>
|
||||
<a href="https://app.revolt.chat/invite/74TpERXA" target="_blank">
|
||||
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact-minimal/social/revolt-singular_vector.svg" height="64" alt="revolt" title="Join my Revolt Server">
|
||||
|
||||
@@ -54,6 +54,10 @@
|
||||
<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>
|
||||
@@ -78,6 +82,12 @@
|
||||
<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>
|
||||
@@ -86,6 +96,12 @@
|
||||
<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>
|
||||
@@ -106,7 +122,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.12.1</version>
|
||||
<version>3.13.0</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
@@ -27,13 +27,15 @@ 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());
|
||||
ADVANCED_BAN("AdvancedBan", new AdvancedBanPlaceholders()),
|
||||
LIBERTY_BANS("LibertyBans", new LibertyBansPlaceholders());
|
||||
|
||||
private final String plugin;
|
||||
private final PlaceholderProvider placeholderProvider;
|
||||
|
||||
@@ -27,13 +27,15 @@ 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());
|
||||
ADVANCED_BAN("AdvancedBan", new AdvancedBanPlaceholders()),
|
||||
LIBERTY_BANS("LibertyBans", new LibertyBansPlaceholders());
|
||||
|
||||
private final String plugin;
|
||||
private final PlaceholderProvider placeholderProvider;
|
||||
|
||||
@@ -30,8 +30,6 @@ import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.banplugins.providers.AdvancedBanProvider;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class AdvancedBanPlaceholders extends PlaceholderProvider{
|
||||
|
||||
private final AdvancedBanProvider provider = new AdvancedBanProvider();
|
||||
@@ -42,7 +40,7 @@ public class AdvancedBanPlaceholders extends PlaceholderProvider{
|
||||
|
||||
@Override
|
||||
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
|
||||
String[] args = placeholder.split("\\s");
|
||||
String[] args = placeholder.split("\\s", 2);
|
||||
|
||||
return switch(args[0]) {
|
||||
// Mute-related placeholders
|
||||
@@ -52,9 +50,6 @@ public class AdvancedBanPlaceholders extends PlaceholderProvider{
|
||||
if(args.length == 1)
|
||||
yield provider.muteDuration(player);
|
||||
|
||||
if(args.length > 2)
|
||||
yield null;
|
||||
|
||||
boolean fromStart = Boolean.getBoolean(args[1]);
|
||||
yield provider.muteDuration(player, fromStart);
|
||||
}
|
||||
@@ -62,9 +57,7 @@ public class AdvancedBanPlaceholders extends PlaceholderProvider{
|
||||
if(args.length == 1)
|
||||
yield provider.muteExpirationDate(player);
|
||||
|
||||
String pattern = String.join(" ", Arrays.copyOfRange(args, 1, args.length));
|
||||
|
||||
yield provider.banExpirationDate(player, pattern);
|
||||
yield provider.banExpirationDate(player, args[1]);
|
||||
}
|
||||
|
||||
// Ban-related placeholders
|
||||
@@ -74,9 +67,6 @@ public class AdvancedBanPlaceholders extends PlaceholderProvider{
|
||||
if(args.length == 1)
|
||||
yield provider.banDuration(player);
|
||||
|
||||
if(args.length > 2)
|
||||
yield null;
|
||||
|
||||
boolean fromStart = Boolean.getBoolean(args[1]);
|
||||
yield provider.banDuration(player, fromStart);
|
||||
}
|
||||
@@ -84,9 +74,7 @@ public class AdvancedBanPlaceholders extends PlaceholderProvider{
|
||||
if(args.length == 1)
|
||||
yield provider.banExpirationDate(player);
|
||||
|
||||
String pattern = String.join(" ", Arrays.copyOfRange(args, 1, args.length));
|
||||
|
||||
yield provider.banExpirationDate(player, pattern);
|
||||
yield provider.banExpirationDate(player, args[1]);
|
||||
}
|
||||
|
||||
// Unknown/Invalid placeholder.
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -105,8 +105,7 @@ public class AdvancedBanProvider implements PunishmentProvider{
|
||||
if(end < 0L)
|
||||
return "never";
|
||||
|
||||
Date date = new Date(end);
|
||||
return new SimpleDateFormat(pattern).format(date);
|
||||
return this.returnDate(pattern, end);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -119,8 +118,7 @@ public class AdvancedBanProvider implements PunishmentProvider{
|
||||
if(end < 0L)
|
||||
return "never";
|
||||
|
||||
Date date = new Date(end);
|
||||
return new SimpleDateFormat(pattern).format(date);
|
||||
return this.returnDate(pattern, end);
|
||||
}
|
||||
|
||||
public String muteDuration(GenericPlayer player, boolean fromStart){
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,9 @@ 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);
|
||||
@@ -53,4 +56,13 @@ public interface PunishmentProvider{
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -6,5 +6,6 @@ description: 'AdvancedBan Add-on for AdvancedServerList to add placeholders to u
|
||||
softDepends:
|
||||
- AdvancedServerList
|
||||
- AdvancedBan
|
||||
- LibertyBans
|
||||
|
||||
main: 'ch.andre601.advancedserverlist.banplugins.bungeecord.BungeeCordBanPluginsAddon'
|
||||
@@ -12,5 +12,8 @@ dependencies:
|
||||
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"
|
||||
}
|
||||
@@ -49,6 +49,10 @@
|
||||
<id>sonatype</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>sonatype-snapshots</id>
|
||||
<url>https://s01.oss.sonatype.org/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
@@ -64,6 +68,8 @@
|
||||
<version>${api.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- BungeeCord API -->
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
@@ -78,34 +84,56 @@
|
||||
<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.16.0</version>
|
||||
<scope>compile</scope>
|
||||
<version>${dependency.adventure-api}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-text-minimessage</artifactId>
|
||||
<version>4.16.0</version>
|
||||
<scope>compile</scope>
|
||||
<version>${dependency.adventure-text-minimessage}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-platform-bungeecord</artifactId>
|
||||
<version>4.3.2</version>
|
||||
<scope>compile</scope>
|
||||
<version>${dependency.adventure-platform-bungeecord}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Metrics -->
|
||||
<dependency>
|
||||
<groupId>org.bstats</groupId>
|
||||
<artifactId>bstats-bungeecord</artifactId>
|
||||
<version>3.0.2</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Configurate -->
|
||||
<dependency>
|
||||
<groupId>org.spongepowered</groupId>
|
||||
<artifactId>configurate-yaml</artifactId>
|
||||
<version>4.1.2</version>
|
||||
<version>${dependency.configurate-yaml}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Plugins -->
|
||||
<dependency>
|
||||
<groupId>com.github.LeonMangler</groupId>
|
||||
<artifactId>PremiumVanishAPI</artifactId>
|
||||
<version>2.9.0-4</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Other -->
|
||||
<dependency>
|
||||
<groupId>com.alessiodp.libby</groupId>
|
||||
<artifactId>libby-bungee</artifactId>
|
||||
<version>2.0.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
@@ -122,33 +150,30 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.12.1</version>
|
||||
<version>3.13.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.5.2</version>
|
||||
<version>3.5.3</version>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>org.spongepowered.configurate</pattern>
|
||||
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.configurate</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>net.kyori</pattern>
|
||||
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.kyori</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.bstats</pattern>
|
||||
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.bstats</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>net.byteflux.libby</pattern>
|
||||
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.libby</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>
|
||||
|
||||
@@ -29,29 +29,57 @@ 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 com.alessiodp.libby.BungeeLibraryManager;
|
||||
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 boolean successfulLoad = false;
|
||||
|
||||
private AdvancedServerList<Favicon> core;
|
||||
private FaviconHandler<Favicon> faviconHandler = null;
|
||||
private BungeeAudiences audiences = null;
|
||||
private final PluginLogger logger = new BungeeLogger(this);
|
||||
|
||||
@Override
|
||||
public void onLoad(){
|
||||
logger.info("Loading libraries. This may take a while...");
|
||||
successfulLoad = loadLibs();
|
||||
if(successfulLoad){
|
||||
logger.info("Library loading completed successfully!");
|
||||
}else{
|
||||
logger.warn("Library loading completed with errors!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable(){
|
||||
this.core = AdvancedServerList.init(this, BungeePlayerPlaceholders.init(), BungeeServerPlaceholders.init());
|
||||
if(!successfulLoad){
|
||||
logger.warn("There were issues during the plugins Loading-phase! Please see the console for possible reasons.");
|
||||
logger.warn("The plugin won't be enabled to avoid problems.");
|
||||
return;
|
||||
}
|
||||
|
||||
this.audiences = BungeeAudiences.create(this);
|
||||
this.core = AdvancedServerList.init(this, BungeePlayerPlaceholders.init(), BungeeServerPlaceholders.init(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -129,8 +157,40 @@ public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
|
||||
return "bungeecord";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPluginEnabled(String plugin){
|
||||
return getProxy().getPluginManager().getPlugin(plugin) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Favicon createFavicon(BufferedImage image) throws IllegalArgumentException{
|
||||
return Favicon.create(image);
|
||||
}
|
||||
|
||||
public BungeeAudiences getAudiences(){
|
||||
return audiences;
|
||||
}
|
||||
|
||||
public int getOnlinePlayers(ServerInfo server){
|
||||
List<ProxiedPlayer> players = new ArrayList<>(server == null ? getProxy().getPlayers() : server.getPlayers());
|
||||
|
||||
// Exclude players when PremiumVanish is enabled and player is hidden.
|
||||
if(getProxy().getPluginManager().getPlugin("PremiumVanish") != null){
|
||||
players.removeIf(BungeeVanishAPI::isInvisible);
|
||||
}
|
||||
|
||||
return players.size();
|
||||
}
|
||||
|
||||
private boolean loadLibs(){
|
||||
try{
|
||||
BungeeLibraryManager libraryManager = new BungeeLibraryManager(this);
|
||||
libraryManager.configureFromJSON("dependencies.json");
|
||||
|
||||
return true;
|
||||
}catch(Exception ex){
|
||||
logger.warn("Encountered an Exception while trying to load dependencies.", ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -29,8 +29,8 @@ 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.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;
|
||||
@@ -142,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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -64,7 +68,7 @@ public class BungeeServerPlaceholders extends PlaceholderProvider{
|
||||
if(info == null)
|
||||
continue;
|
||||
|
||||
players += info.getPlayers().size();
|
||||
players += plugin.getOnlinePlayers(info);
|
||||
}
|
||||
|
||||
yield String.valueOf(players);
|
||||
@@ -6,5 +6,6 @@ description: '${plugin.description}'
|
||||
softDepends:
|
||||
- PAPIProxyBridge
|
||||
- Maintenance
|
||||
- ServerListPlus
|
||||
|
||||
main: 'ch.andre601.advancedserverlist.bungeecord.BungeeCordCore'
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"repositories": [
|
||||
"https://repo.papermc.io/repository/maven-public"
|
||||
],
|
||||
"libraries": [
|
||||
{
|
||||
"groupId": "net{}kyori",
|
||||
"artifactId": "adventure-api",
|
||||
"version": "${dependency.adventure-api}",
|
||||
"resolveTransitiveDependencies": true
|
||||
},
|
||||
{
|
||||
"groupId": "net{}kyori",
|
||||
"artifactId": "adventure-text-minimessage",
|
||||
"version": "${dependency.adventure-text-minimessage}",
|
||||
"resolveTransitiveDependencies": true
|
||||
},
|
||||
{
|
||||
"groupId": "net{}kyori",
|
||||
"artifactId": "adventure-platform-bungeecord",
|
||||
"version": "${dependency.adventure-platform-bungeecord}",
|
||||
"resolveTransitiveDependencies": true
|
||||
},
|
||||
{
|
||||
"groupId": "org{}spongepowered",
|
||||
"artifactId": "configurate-yaml",
|
||||
"version": "${dependency.configurate-yaml}",
|
||||
"resolveTransitiveDependencies": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -41,7 +41,7 @@
|
||||
<properties>
|
||||
<maven.compiler.source>16</maven.compiler.source>
|
||||
<maven.compiler.target>16</maven.compiler.target>
|
||||
<plugin.config.version>4</plugin.config.version>
|
||||
<plugin.config.version>5</plugin.config.version>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
@@ -57,6 +57,14 @@
|
||||
<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>
|
||||
<repository>
|
||||
<id>codemc</id>
|
||||
<url>https://repo.codemc.io/repository/maven-releases/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
@@ -68,14 +76,14 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.andre601</groupId>
|
||||
<artifactId>ExpressionParser</artifactId>
|
||||
<version>v1.2.0</version>
|
||||
<artifactId>expressionparser</artifactId>
|
||||
<version>1.4.2</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spongepowered</groupId>
|
||||
<artifactId>configurate-yaml</artifactId>
|
||||
<version>4.1.2</version>
|
||||
<version>${dependency.configurate-yaml}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -83,21 +91,23 @@
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-api</artifactId>
|
||||
<version>4.16.0</version>
|
||||
<version>${dependency.adventure-api}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-text-minimessage</artifactId>
|
||||
<version>4.16.0</version>
|
||||
<version>${dependency.adventure-text-minimessage}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-text-serializer-legacy</artifactId>
|
||||
<version>4.16.0</version>
|
||||
<version>${dependency.adventure-text-serializer-legacy}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Misc -->
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
@@ -113,7 +123,7 @@
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>33.0.0-jre</version>
|
||||
<version>33.2.0-jre</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -130,6 +140,12 @@
|
||||
<version>4.2.0-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.minecrell</groupId>
|
||||
<artifactId>ServerListPlus</artifactId>
|
||||
<version>3.5.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Test dependencies -->
|
||||
<dependency>
|
||||
@@ -152,12 +168,12 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.12.1</version>
|
||||
<version>3.13.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.5.2</version>
|
||||
<version>3.5.3</version>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<filters>
|
||||
@@ -165,6 +181,7 @@
|
||||
<artifact>*:*</artifact>
|
||||
<excludes>
|
||||
<exclude>META-INF/*.SF</exclude>
|
||||
<exclude>META-INF/*.DSA</exclude>
|
||||
<exclude>META-INF/*.RSA</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
|
||||
@@ -46,7 +46,7 @@ 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;
|
||||
@@ -59,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();
|
||||
}
|
||||
@@ -88,7 +88,7 @@ public class AdvancedServerList<F>{
|
||||
return version;
|
||||
}
|
||||
|
||||
public AdvancedServerListAPI getApi(){
|
||||
public static AdvancedServerListAPI getApi(){
|
||||
return api;
|
||||
}
|
||||
|
||||
@@ -96,6 +96,10 @@ public class AdvancedServerList<F>{
|
||||
return parser;
|
||||
}
|
||||
|
||||
public UpdateChecker getUpdateChecker(){
|
||||
return updateChecker;
|
||||
}
|
||||
|
||||
public void disable(){
|
||||
getPlugin().getPluginLogger().info("Saving playercache.json file...");
|
||||
getPlayerHandler().save();
|
||||
|
||||
@@ -27,6 +27,7 @@ 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;
|
||||
@@ -62,6 +63,8 @@ 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;
|
||||
@@ -74,6 +77,31 @@ public class UpdateChecker{
|
||||
startUpdateChecker();
|
||||
}
|
||||
|
||||
public void performeCachedUpdateCheck(CmdSender sender){
|
||||
ModrinthVersion version = cache.get(() -> {
|
||||
try{
|
||||
return performUpdateCheck().join();
|
||||
}catch(Exception ex){
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
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();
|
||||
try{
|
||||
@@ -144,22 +172,22 @@ public class UpdateChecker{
|
||||
}
|
||||
|
||||
private void printUpdateBanner(ModrinthVersion version){
|
||||
logger.info("==================================================================");
|
||||
logger.info("You are running an outdated version of AdvancedServerList!");
|
||||
logger.info("");
|
||||
logger.info("Your version: %s", core.getVersion());
|
||||
logger.info("Modrinth: %s", version.versionNumber());
|
||||
logger.info("");
|
||||
logger.warn("==================================================================");
|
||||
logger.warn("You are running an outdated version of AdvancedServerList!");
|
||||
logger.warn("");
|
||||
logger.warn("Your version: %s", core.getVersion());
|
||||
logger.warn("Modrinth: %s", version.versionNumber());
|
||||
logger.warn("");
|
||||
|
||||
if(!version.isRelease()){
|
||||
logger.info("WARNING!");
|
||||
logger.info("This is a %s version and may contain breaking changes and/or bugs!", version.versionType());
|
||||
logger.info("");
|
||||
logger.warn("WARNING!");
|
||||
logger.warn("This is a %s version and may contain breaking changes and/or bugs!", version.versionType());
|
||||
logger.warn("");
|
||||
}
|
||||
|
||||
logger.info("Download the latest version from here:");
|
||||
logger.info("https://modrinth.com/plugin/advancedserverlist/version/%s", version.id());
|
||||
logger.info("==================================================================");
|
||||
logger.warn("Download the latest version from here:");
|
||||
logger.warn("https://modrinth.com/plugin/advancedserverlist/version/%s", version.id());
|
||||
logger.warn("==================================================================");
|
||||
}
|
||||
|
||||
public record ModrinthVersion(String id, String versionNumber, String 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,18 +28,22 @@ package ch.andre601.advancedserverlist.core.commands;
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.PluginCommand;
|
||||
import ch.andre601.advancedserverlist.core.migration.serverlistplus.SLPConfigMigrator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class CommandHandler{
|
||||
|
||||
private final List<PluginCommand> subCommands = new ArrayList<>();
|
||||
private final List<PluginCommand> subCommands;
|
||||
|
||||
public CommandHandler(AdvancedServerList<?> core){
|
||||
subCommands.add(new Help());
|
||||
subCommands.add(new Reload(core));
|
||||
subCommands.add(new ClearCache(core));
|
||||
subCommands = List.of(
|
||||
new Help(),
|
||||
new Reload(core),
|
||||
new ClearCache(core),
|
||||
new Migrate(core)
|
||||
);
|
||||
}
|
||||
|
||||
public void handle(CmdSender sender, String[] args){
|
||||
@@ -58,7 +62,7 @@ public class CommandHandler{
|
||||
return;
|
||||
}
|
||||
|
||||
subCommand.handle(sender);
|
||||
subCommand.handle(sender, Arrays.copyOfRange(args, 1, args.length));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -73,7 +77,7 @@ public class CommandHandler{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(CmdSender sender){
|
||||
public void handle(CmdSender sender, String[] args){
|
||||
sender.sendPrefixedMsg("- Commands");
|
||||
sender.sendMsg();
|
||||
sender.sendMsg("<aqua>/asl <white>help <grey>- Shows this help");
|
||||
@@ -81,6 +85,8 @@ public class CommandHandler{
|
||||
sender.sendMsg("<aqua>/asl <white>reload <grey>- Reloads the config.yml and profiles");
|
||||
sender.sendMsg();
|
||||
sender.sendMsg("<aqua>/asl <white>clearCache <grey>- Clears the Player and Favicon cache");
|
||||
sender.sendMsg();
|
||||
sender.sendMsg("<aqua>/asl <white>migrate <grey><</grey>plugin<grey>> - Migrates configuration of another plugin");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +101,7 @@ public class CommandHandler{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(CmdSender sender){
|
||||
public void handle(CmdSender sender, String[] args){
|
||||
sender.sendPrefixedMsg("Reloading plugin...");
|
||||
|
||||
if(core.getFileHandler().reloadConfig()){
|
||||
@@ -125,7 +131,7 @@ public class CommandHandler{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(CmdSender sender){
|
||||
public void handle(CmdSender sender, String[] args){
|
||||
sender.sendPrefixedMsg("Clearing caches...");
|
||||
|
||||
core.clearFaviconCache();
|
||||
@@ -137,4 +143,45 @@ public class CommandHandler{
|
||||
sender.sendPrefixedMsg("<green>Cache clearing complete!");
|
||||
}
|
||||
}
|
||||
|
||||
private static class Migrate extends PluginCommand{
|
||||
|
||||
private final AdvancedServerList<?> core;
|
||||
|
||||
public Migrate(AdvancedServerList<?> core){
|
||||
super("migrate");
|
||||
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(CmdSender sender, String[] args){
|
||||
if(args.length == 0){
|
||||
sender.sendErrorMsg("<red>Insufficient arguments! Please provide a plugin to migrate from.");
|
||||
sender.sendErrorMsg("<red>Available options:");
|
||||
sender.sendErrorMsg(" - ServerListPlus");
|
||||
return;
|
||||
}
|
||||
|
||||
if(args[0].equalsIgnoreCase("serverlistplus")){
|
||||
if(!core.getPlugin().isPluginEnabled("ServerListPlus")){
|
||||
sender.sendErrorMsg("<red>Plugin ServerListPlus is not enabled.");
|
||||
sender.sendErrorMsg("<red>It needs to be active for the migration to work!");
|
||||
return;
|
||||
}
|
||||
|
||||
sender.sendPrefixedMsg("Migrating ServerListPlus configuration file...");
|
||||
|
||||
int migrated = SLPConfigMigrator.migrate(core, sender);
|
||||
if(migrated == 0){
|
||||
sender.sendErrorMsg("<red>Unable to migrate any ServerListPlus configuration. Check console for details!");
|
||||
}else{
|
||||
sender.sendPrefixedMsg("<green>Migration complete!");
|
||||
}
|
||||
}else{
|
||||
sender.sendErrorMsg("<red>Unknown plugin <grey>%s</grey>. Available Options:", args[0]);
|
||||
sender.sendErrorMsg(" - ServerListPlus");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,11 +44,11 @@ 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){
|
||||
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.isMaintenanceModeActive()){
|
||||
event.getPlugin().getPluginLogger().debug(PingEventHandler.class, "Not handling event. Either protocol was invalid of Maintenance is enabled.");
|
||||
return;
|
||||
if(event.isInvalidProtocol()){
|
||||
event.getPlugin().getPluginLogger().debug(PingEventHandler.class, "Not handling event. Protocol was invalid.");
|
||||
return null;
|
||||
}
|
||||
|
||||
PluginCore<F> plugin = event.getPlugin();
|
||||
@@ -70,7 +70,7 @@ public class PingEventHandler{
|
||||
|
||||
if(profile == null){
|
||||
logger.debugWarn(PingEventHandler.class, "Server List Profile couldn't be resolved properly. Cancelling event handling...");
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
logger.debug(PingEventHandler.class, "Received valid Server List Profile. Calling PreServerListSetEvent...");
|
||||
@@ -78,7 +78,7 @@ public class PingEventHandler{
|
||||
GenericServerListEvent e = event.callEvent(ProfileManager.merge(profile));
|
||||
if(e == null || e.isCancelled()){
|
||||
logger.debug(PingEventHandler.class, "PreServerListSetEvent was cancelled. Stopping ping handling...");
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
logger.debug(PingEventHandler.class, "PreServerListSetEvent completed. Proceeding with ping handling...");
|
||||
@@ -86,12 +86,12 @@ public class PingEventHandler{
|
||||
ProfileEntry entry = e.getEntry();
|
||||
if(entry.isInvalid()){
|
||||
logger.debugWarn(PingEventHandler.class, "No valid ProfileEntry retrieved. Cancelling ping handling...");
|
||||
return;
|
||||
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);
|
||||
@@ -99,7 +99,7 @@ public class PingEventHandler{
|
||||
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);
|
||||
@@ -109,7 +109,7 @@ public class PingEventHandler{
|
||||
|
||||
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(
|
||||
@@ -122,13 +122,13 @@ 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(
|
||||
@@ -139,13 +139,13 @@ 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())){
|
||||
if(ProfileManager.checkOption(entry.favicon()) && ignoreMaintenance(event, "favicon")){
|
||||
logger.debug(PingEventHandler.class, "Favicon set. Resolving '%s'...", entry.favicon());
|
||||
|
||||
String faviconString = StringReplacer.replace(entry.favicon(), player, server);
|
||||
@@ -165,6 +165,8 @@ public class PingEventHandler{
|
||||
|
||||
logger.debug(PingEventHandler.class, "Event handling completed. Updating Ping data...");
|
||||
event.updateEvent();
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
public static PAPIUtil getPAPIUtil(){
|
||||
@@ -180,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);
|
||||
}
|
||||
}
|
||||
@@ -46,12 +46,29 @@ public class ConfigMigrator{
|
||||
public static ConfigurationTransformation.Versioned create(){
|
||||
return ConfigurationTransformation.versionedBuilder()
|
||||
.versionKey("configVersion")
|
||||
.addVersion(LATEST, threeToFour())
|
||||
.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) -> {
|
||||
|
||||
@@ -187,8 +187,12 @@ 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){
|
||||
|
||||
@@ -43,5 +43,5 @@ public abstract class PluginCommand{
|
||||
return "advancedserverlist.command." + getArgument().toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
public abstract void handle(CmdSender sender);
|
||||
public abstract void handle(CmdSender sender, String[] args);
|
||||
}
|
||||
@@ -58,6 +58,8 @@ public interface PluginCore<F>{
|
||||
|
||||
String getLoader();
|
||||
|
||||
boolean isPluginEnabled(String plugin);
|
||||
|
||||
F createFavicon(BufferedImage image) throws Exception;
|
||||
|
||||
default boolean isDebugEnabled(){
|
||||
|
||||
@@ -0,0 +1,456 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.migration.serverlistplus;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.NullBool;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
|
||||
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileSerializer;
|
||||
import net.minecrell.serverlistplus.core.ServerListPlusCore;
|
||||
import net.minecrell.serverlistplus.core.config.PersonalizedStatusConf;
|
||||
import net.minecrell.serverlistplus.core.config.ServerStatusConf;
|
||||
import net.minecrell.serverlistplus.core.util.BooleanOrList;
|
||||
import net.minecrell.serverlistplus.core.util.IntegerRange;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
import org.spongepowered.configurate.yaml.NodeStyle;
|
||||
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class SLPConfigMigrator{
|
||||
|
||||
private static final Pattern RGB_COLOR_PATTERN = Pattern.compile("&(?<color>#[a-fA-F0-9]{6})");
|
||||
private static final Pattern COLOR_CODE_PATTERN = Pattern.compile("&(?<color>[abcdefklmnorABCDEFKLMNOR0123456789])");
|
||||
private static final Pattern RGB_GRADIENT_PATTERN = Pattern.compile(
|
||||
"%gradient" +
|
||||
"(?<start>#[a-fA-F0-9]{6})" + // Starting color
|
||||
"(?<end>#[a-fA-F0-9]{6})" + // Ending color
|
||||
"%" +
|
||||
"(?<text>.+?)" + // Text
|
||||
"%gradient%");
|
||||
|
||||
private static final Map<String, String> STATIC_REPLACEMENTS = Map.of(
|
||||
"%player%", "${player name}",
|
||||
"%uuid%", "${player uuid}",
|
||||
"%_uuid_%", "${player uuid}",
|
||||
"%online%", "${server playersOnline}",
|
||||
"%max%", "${server playersMax}");
|
||||
|
||||
public static int migrate(AdvancedServerList<?> core, CmdSender sender){
|
||||
ServerListPlusCore slpCore = ServerListPlusCore.getInstance();
|
||||
PluginLogger logger = core.getPlugin().getPluginLogger();
|
||||
if(slpCore == null){
|
||||
logger.warn("[Migrator - ServerListPlus] Cannot migrate ServerListPlus config. ServerListPlus is not active!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ServerStatusConf conf = slpCore.getConf(ServerStatusConf.class);
|
||||
if(conf == null){
|
||||
logger.warn("[Migrator - ServerListPlus] Cannot migrate ServerListPlus configuration. Received configuration was null.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
PersonalizedStatusConf.StatusConf defConf = conf.Default;
|
||||
PersonalizedStatusConf.StatusConf personalizedConf = conf.Personalized;
|
||||
PersonalizedStatusConf.StatusConf banned = conf.Banned;
|
||||
|
||||
sender.sendPrefixedMsg("Migrating <white>Default</white>...");
|
||||
int defConfParsed = parseConf(core, sender, defConf, Type.DEFAULT);
|
||||
|
||||
sender.sendPrefixedMsg("Migrating <white>Personalized</white>...");
|
||||
int personalizedParsed = parseConf(core, sender, personalizedConf, Type.PERSONALIZED);
|
||||
|
||||
sender.sendPrefixedMsg("Migrating <white>Banned</white>...");
|
||||
int bannedParsed = parseConf(core, sender, banned, Type.BANNED);
|
||||
|
||||
return defConfParsed + personalizedParsed + bannedParsed;
|
||||
}
|
||||
|
||||
private static int parseConf(AdvancedServerList<?> core, CmdSender sender, PersonalizedStatusConf.StatusConf conf, Type type){
|
||||
PluginLogger logger = core.getPlugin().getPluginLogger();
|
||||
if(conf == null){
|
||||
logger.info("[Migrator - ServerListPlus] No StatusConf found for type %s. Skipping...", type.getName());
|
||||
sender.sendPrefixedMsg(" -> Not found! Skipping...");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ProfileEntry.Builder builder = ProfileEntry.empty().builder();
|
||||
List<ProfileEntry.Builder> profiles = new ArrayList<>();
|
||||
|
||||
List<List<String>> motds = resolveMotds(conf.Description);
|
||||
List<String> favicons = resolveFavicons(conf.Favicon);
|
||||
List<List<String>> hovers = resolveHover(conf.Players);
|
||||
NullBool hidePlayers = conf.Players != null ? NullBool.resolve(conf.Players.Hidden) : NullBool.NOT_SET;
|
||||
List<Integer> maxPlayers = resolveMaxPlayers(conf.Players);
|
||||
List<String> playerCount = resolvePlayerCounts(conf.Players);
|
||||
|
||||
int size = getMaxListSize(motds, favicons, hovers, maxPlayers, playerCount);
|
||||
for(int i = 0; i < size; i++){
|
||||
profiles.add(ProfileEntry.empty().builder());
|
||||
}
|
||||
|
||||
apply(motds, builder, profiles, ProfileEntry.Builder::motd);
|
||||
apply(favicons, builder, profiles, ProfileEntry.Builder::favicon);
|
||||
apply(hovers, builder, profiles, ProfileEntry.Builder::players);
|
||||
apply(maxPlayers, builder, profiles, (build, count) -> build.maxPlayersEnabled(NullBool.TRUE).maxPlayersCount(count));
|
||||
apply(playerCount, builder, profiles, ProfileEntry.Builder::playerCountText);
|
||||
|
||||
builder.hidePlayersEnabled(hidePlayers);
|
||||
|
||||
ProfileEntry entry = builder.build();
|
||||
List<ProfileEntry> profileEntries = profiles.stream()
|
||||
.map(ProfileEntry.Builder::build)
|
||||
.toList();
|
||||
|
||||
if(entry.isInvalid() && profileEntries.isEmpty()){
|
||||
logger.warn("[Migrator - ServerListPlus] Unable to parse ServerListPlus configuration of type %s. Generated ProfileEntry was invalid.", type.getName());
|
||||
sender.sendErrorMsg(" -> <red>Received invalid Configuration.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Path profile = core.getPlugin().getFolderPath().resolve("profiles").resolve(type.getFile());
|
||||
if(Files.exists(profile)){
|
||||
logger.warn("[Migrator - ServerListPlus] Cannot create new file %s. One with the same name is already present", type.getFile());
|
||||
sender.sendErrorMsg(" -> <red>File</red> %s <red>already present.", type.getFile());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
try{
|
||||
Files.createFile(profile);
|
||||
}catch(IOException ex){
|
||||
logger.warn("[Migrator - ServerListPlus] Encountered an IOException while trying to create file %s.", ex, type.getFile());
|
||||
sender.sendErrorMsg(" -> <red>File creation error.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
YamlConfigurationLoader loader = YamlConfigurationLoader.builder()
|
||||
.path(profile)
|
||||
.indent(2)
|
||||
.nodeStyle(NodeStyle.BLOCK)
|
||||
.defaultOptions(opt -> opt.serializers(build -> build.register(ProfileEntry.class, ProfileSerializer.INSTANCE)))
|
||||
.build();
|
||||
|
||||
ConfigurationNode node;
|
||||
try{
|
||||
node = loader.load();
|
||||
}catch(IOException ex){
|
||||
logger.warn("[Migrator - ServerListPlus] Encountered an IOException while trying to load file %s.", ex, type.getFile());
|
||||
sender.sendErrorMsg(" -> <red>File loading error.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(node == null){
|
||||
logger.warn("[Migrator - ServerListPlus] Cannot migrate Configuration of type %s. ConfigurationNode was null.", type.getName());
|
||||
sender.sendErrorMsg(" -> <red>File loading error.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
try{
|
||||
node.node("priority")
|
||||
.set(type != Type.DEFAULT ? 1 : 0);
|
||||
|
||||
if(type == Type.PERSONALIZED){
|
||||
node.node("condition")
|
||||
.set("${player name} != \"" +
|
||||
core.getFileHandler().getString("Anonymous", "unknownPlayer", "name") +
|
||||
"\"");
|
||||
}else
|
||||
if(type == Type.BANNED){
|
||||
node.node("condition")
|
||||
.set("${player isBanned}");
|
||||
}
|
||||
|
||||
if(!profiles.isEmpty()){
|
||||
node.node("profiles").setList(ProfileEntry.class, profileEntries);
|
||||
}
|
||||
|
||||
node.set(entry);
|
||||
}catch(SerializationException ex){
|
||||
logger.warn("Encountered a SerializationException while setting values.", ex);
|
||||
sender.sendErrorMsg(" -> <red>Error while updating file</red> %s<red>.", type.getFile());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
try{
|
||||
loader.save(node);
|
||||
sender.sendPrefixedMsg(" -> <green>Completed!");
|
||||
|
||||
return 1;
|
||||
}catch(IOException ex){
|
||||
logger.warn("[Migrator - ServerListPlus] Encountered an IOException while trying to save new file %s.", ex, type.getFile());
|
||||
sender.sendErrorMsg(" -> <red>File saving error.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static int getMaxListSize(List<?>... lists){
|
||||
int size = 0;
|
||||
for(List<?> list : lists){
|
||||
if(list.size() > size)
|
||||
size = list.size();
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
private static List<List<String>> resolveMotds(List<String> descriptions){
|
||||
if(descriptions == null || descriptions.isEmpty())
|
||||
return Collections.emptyList();
|
||||
|
||||
List<List<String>> motds = new ArrayList<>();
|
||||
for(String line : descriptions){
|
||||
motds.add(getList(line));
|
||||
}
|
||||
|
||||
return motds;
|
||||
}
|
||||
|
||||
private static List<String> resolveFavicons(PersonalizedStatusConf.StatusConf.FaviconConf faviconConf){
|
||||
if(faviconConf == null || faviconConf.Disabled != null && faviconConf.Disabled)
|
||||
return Collections.emptyList();
|
||||
|
||||
List<String> list = new ArrayList<>();
|
||||
|
||||
if(faviconConf.Heads != null){
|
||||
for(String head : faviconConf.Heads){
|
||||
list.add(
|
||||
"https://mc-heads.net/avatar/" +
|
||||
replacePlaceholders(head) +
|
||||
"/64/nohelm"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if(faviconConf.Helms != null){
|
||||
for(String helm : faviconConf.Helms){
|
||||
list.add(replacePlaceholders(helm));
|
||||
}
|
||||
}
|
||||
|
||||
if(faviconConf.Files != null){
|
||||
for(String file : faviconConf.Files){
|
||||
if(!file.toLowerCase(Locale.ROOT).endsWith(".png"))
|
||||
continue;
|
||||
|
||||
list.add(replacePlaceholders(file));
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private static List<List<String>> resolveHover(PersonalizedStatusConf.StatusConf.PlayersConf playersConf){
|
||||
if(playersConf == null)
|
||||
return Collections.emptyList();
|
||||
|
||||
BooleanOrList<String> booleanOrList = playersConf.Hover;
|
||||
if(booleanOrList == null)
|
||||
return Collections.emptyList();
|
||||
|
||||
if(booleanOrList.getList() != null){
|
||||
List<List<String>> hovers = new ArrayList<>();
|
||||
for(String line : booleanOrList.getList()){
|
||||
if(line == null)
|
||||
continue;
|
||||
|
||||
hovers.add(getList(line));
|
||||
}
|
||||
|
||||
return hovers;
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private static List<Integer> resolveMaxPlayers(PersonalizedStatusConf.StatusConf.PlayersConf playersConf){
|
||||
if(playersConf == null)
|
||||
return Collections.emptyList();
|
||||
|
||||
List<IntegerRange> maxPlayers = playersConf.Max;
|
||||
if(maxPlayers == null)
|
||||
return Collections.emptyList();
|
||||
|
||||
List<Integer> values = new ArrayList<>();
|
||||
for(IntegerRange range : maxPlayers){
|
||||
if(range == null)
|
||||
continue;
|
||||
|
||||
values.add(range.to());
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
private static List<String> resolvePlayerCounts(PersonalizedStatusConf.StatusConf.PlayersConf playersConf){
|
||||
if(playersConf == null)
|
||||
return Collections.emptyList();
|
||||
|
||||
if(playersConf.Slots == null)
|
||||
return Collections.emptyList();
|
||||
|
||||
return playersConf.Slots.stream()
|
||||
.map(SLPConfigMigrator::replacePlaceholders)
|
||||
.toList();
|
||||
}
|
||||
|
||||
private static <T> void apply(List<T> list, ProfileEntry.Builder builder, List<ProfileEntry.Builder> profiles,
|
||||
BiConsumer<ProfileEntry.Builder, T> builderConsumer){
|
||||
if(list.size() == 1){
|
||||
builderConsumer.accept(builder, list.get(0));
|
||||
}else
|
||||
if(list.size() > 1){
|
||||
for(int i = 0; i < list.size(); i++){
|
||||
builderConsumer.accept(profiles.get(i), list.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> getList(String line){
|
||||
return Arrays.asList(replacePlaceholders(line).split("\n"));
|
||||
}
|
||||
|
||||
private static String replacePlaceholders(String input){
|
||||
StringBuilder parsed = new StringBuilder(input);
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
Matcher rgbColorMatcher = RGB_COLOR_PATTERN.matcher(parsed.toString());
|
||||
if(rgbColorMatcher.find()){
|
||||
do{
|
||||
rgbColorMatcher.appendReplacement(builder, "<" + rgbColorMatcher.group("color") + ">");
|
||||
}while(rgbColorMatcher.find());
|
||||
|
||||
rgbColorMatcher.appendTail(builder);
|
||||
parsed = builder;
|
||||
}
|
||||
|
||||
Matcher colorCodeMatcher = COLOR_CODE_PATTERN.matcher(parsed.toString());
|
||||
if(colorCodeMatcher.find()){
|
||||
builder.setLength(0);
|
||||
do{
|
||||
String color = colorCodeMatcher.group("color").toLowerCase(Locale.ROOT);
|
||||
switch(color){
|
||||
case "a" -> colorCodeMatcher.appendReplacement(builder, "<green>");
|
||||
case "b" -> colorCodeMatcher.appendReplacement(builder, "<aqua>");
|
||||
case "c" -> colorCodeMatcher.appendReplacement(builder, "<red>");
|
||||
case "d" -> colorCodeMatcher.appendReplacement(builder, "<light_purple>");
|
||||
case "e" -> colorCodeMatcher.appendReplacement(builder, "<yellow>");
|
||||
case "f" -> colorCodeMatcher.appendReplacement(builder, "<white>");
|
||||
case "k" -> colorCodeMatcher.appendReplacement(builder, "<obfuscated>");
|
||||
case "l" -> colorCodeMatcher.appendReplacement(builder, "<bold>");
|
||||
case "m" -> colorCodeMatcher.appendReplacement(builder, "<strikethrough>");
|
||||
case "n" -> colorCodeMatcher.appendReplacement(builder, "<underlined>");
|
||||
case "o" -> colorCodeMatcher.appendReplacement(builder, "<italic>");
|
||||
case "r" -> colorCodeMatcher.appendReplacement(builder, "<reset>");
|
||||
case "0" -> colorCodeMatcher.appendReplacement(builder, "<black>");
|
||||
case "1" -> colorCodeMatcher.appendReplacement(builder, "<dark_blue>");
|
||||
case "2" -> colorCodeMatcher.appendReplacement(builder, "<dark_green>");
|
||||
case "3" -> colorCodeMatcher.appendReplacement(builder, "<dark_aqua>");
|
||||
case "4" -> colorCodeMatcher.appendReplacement(builder, "<dark_red>");
|
||||
case "5" -> colorCodeMatcher.appendReplacement(builder, "<dark_purple>");
|
||||
case "6" -> colorCodeMatcher.appendReplacement(builder, "<gold>");
|
||||
case "7" -> colorCodeMatcher.appendReplacement(builder, "<grey>");
|
||||
case "8" -> colorCodeMatcher.appendReplacement(builder, "<dark_grey>");
|
||||
case "9" -> colorCodeMatcher.appendReplacement(builder, "<blue>");
|
||||
// This one shouldn't be reachable given the pattern, but you never know...
|
||||
default -> colorCodeMatcher.appendReplacement(builder, "&" + color);
|
||||
}
|
||||
}while(colorCodeMatcher.find());
|
||||
|
||||
colorCodeMatcher.appendTail(builder);
|
||||
parsed = builder;
|
||||
}
|
||||
|
||||
Matcher rgbGradientMatcher = RGB_GRADIENT_PATTERN.matcher(parsed.toString());
|
||||
if(rgbGradientMatcher.find()){
|
||||
builder.setLength(0);
|
||||
do{
|
||||
String start = rgbGradientMatcher.group("start");
|
||||
String end = rgbGradientMatcher.group("end");
|
||||
String text = rgbGradientMatcher.group("text");
|
||||
|
||||
rgbGradientMatcher.appendReplacement(builder, "<gradient:" + start + ":" + end + ">" + text + "</gradient>");
|
||||
}while(rgbGradientMatcher.find());
|
||||
|
||||
rgbGradientMatcher.appendTail(builder);
|
||||
parsed = builder;
|
||||
}
|
||||
|
||||
return replaceStaticPlaceholders(parsed);
|
||||
}
|
||||
|
||||
private static String replaceStaticPlaceholders(StringBuilder input){
|
||||
if(input.isEmpty())
|
||||
return "";
|
||||
|
||||
for(Map.Entry<String, String> entry : STATIC_REPLACEMENTS.entrySet()){
|
||||
int index = 0;
|
||||
while((index = input.indexOf(entry.getKey(), index)) != -1){
|
||||
input.replace(index, index + entry.getKey().length(), entry.getValue());
|
||||
index += entry.getValue().length();
|
||||
}
|
||||
}
|
||||
|
||||
return input.toString();
|
||||
}
|
||||
|
||||
private enum Type{
|
||||
DEFAULT("Default", "slp_default.yml"),
|
||||
PERSONALIZED("Personalized", "slp_personalized.yml"),
|
||||
BANNED("Banned", "slp_banned.yml");
|
||||
|
||||
private final String name, file;
|
||||
|
||||
Type(String name, String file){
|
||||
this.name = name;
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public String getName(){
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getFile(){
|
||||
return file;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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){}
|
||||
@@ -31,7 +31,6 @@ import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.ProfileConditionParser;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
import ch.andre601.expressionparser.templates.ExpressionTemplate;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
@@ -39,7 +38,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public record ServerListProfile(int priority, String condition, ProfileEntry defaultProfile, List<ProfileEntry> profiles){
|
||||
public record ServerListProfile(int priority, String condition, ProfileEntry defaultProfile, List<ProfileEntry> profiles, String file){
|
||||
private static final Random random = new Random();
|
||||
|
||||
public boolean evalConditions(ProfileConditionParser parser, PluginLogger logger, GenericPlayer player, GenericServer server){
|
||||
@@ -47,24 +46,22 @@ public record ServerListProfile(int priority, String condition, ProfileEntry def
|
||||
return true;
|
||||
|
||||
ParseWarnCollector collector = new ParseWarnCollector(condition);
|
||||
ExpressionTemplate template = parser.compile(condition, player, server, collector);
|
||||
|
||||
boolean result = parser.evaluate(condition, player, server, collector);
|
||||
|
||||
if(collector.hasWarnings()){
|
||||
logger.warn("Encountered %d Error(s) while parsing condition '%s':", collector.getWarnings().size(), condition);
|
||||
logger.warn("Encountered %d Error(s) while parsing condition for file '%s':", collector.getWarnings().size(), file);
|
||||
|
||||
for(ParseWarnCollector.Context context : collector.getWarnings()){
|
||||
if(context.position() <= -1){
|
||||
logger.warn(" - %s", context.message());
|
||||
}else{
|
||||
logger.warn(" - At Position %d: %s", context.position(), context.message());
|
||||
}
|
||||
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());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(template == null)
|
||||
return false;
|
||||
|
||||
return template.returnBooleanExpression().evaluate();
|
||||
return result;
|
||||
}
|
||||
|
||||
public ProfileEntry getRandomProfile(){
|
||||
@@ -123,6 +120,13 @@ public record ServerListProfile(int priority, String condition, ProfileEntry def
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public Builder(String filename, int priority, PluginLogger logger){
|
||||
this.fileName = filename;
|
||||
this.node = null;
|
||||
this.priority = priority;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public static Builder resolve(String fileName, ConfigurationNode node, PluginLogger logger){
|
||||
return new Builder(fileName, node, logger)
|
||||
.resolveCondition()
|
||||
@@ -131,6 +135,9 @@ public record ServerListProfile(int priority, String condition, ProfileEntry def
|
||||
}
|
||||
|
||||
private Builder resolveCondition(){
|
||||
if(node == null)
|
||||
throw new IllegalStateException("ConfigurationNode was null!");
|
||||
|
||||
String condition = node.node("condition").getString();
|
||||
if(condition == null || condition.isEmpty())
|
||||
return this;
|
||||
@@ -140,6 +147,9 @@ public record ServerListProfile(int priority, String condition, ProfileEntry def
|
||||
}
|
||||
|
||||
private Builder resolveProfiles(){
|
||||
if(node == null)
|
||||
throw new IllegalStateException("ConfigurationNode was null!");
|
||||
|
||||
try{
|
||||
this.profiles = node.node("profiles").getList(ProfileEntry.class);
|
||||
}catch(SerializationException ex){
|
||||
@@ -150,6 +160,9 @@ public record ServerListProfile(int priority, String condition, ProfileEntry def
|
||||
}
|
||||
|
||||
private Builder resolveDefaultProfile(){
|
||||
if(node == null)
|
||||
throw new IllegalStateException("ConfigurationNode was null!");
|
||||
|
||||
try{
|
||||
this.defaultProfile = node.get(ProfileEntry.class);
|
||||
}catch(SerializationException ex){
|
||||
@@ -159,7 +172,7 @@ public record ServerListProfile(int priority, String condition, ProfileEntry def
|
||||
}
|
||||
|
||||
public ServerListProfile build(){
|
||||
return new ServerListProfile(this.priority, this.condition, this.defaultProfile, this.profiles);
|
||||
return new ServerListProfile(this.priority, this.condition, this.defaultProfile, this.profiles, this.fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,14 +54,18 @@ public class ProfileConditionParser implements ExpressionParserEngine{
|
||||
}
|
||||
|
||||
public static ProfileConditionParser create(){
|
||||
return new ProfileConditionParserBuilder().createDefault()
|
||||
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);
|
||||
public boolean evaluate(String text, GenericPlayer player, GenericServer server, ParseWarnCollector collector){
|
||||
ExpressionTemplate result = parser.parse(tokenizer.parse(text, player, server, collector), collector);
|
||||
if(result == null)
|
||||
return false;
|
||||
|
||||
return result.returnBooleanExpression().evaluate();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions.placeholders;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.AdvancedServerListAPI;
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens.PlaceholderToken;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
|
||||
import java.text.ParsePosition;
|
||||
|
||||
public class PlaceholderParser{
|
||||
|
||||
public static PlaceholderToken.Placeholder parse(String text, ParsePosition position, GenericPlayer player, GenericServer server, ParseWarnCollector collector){
|
||||
AdvancedServerListAPI api = AdvancedServerListAPI.get();
|
||||
|
||||
// We want to point to the start of a placeholder in the ParseWarnCollector.
|
||||
// Since the PlaceholderTokenReader updates the index by 2 are we reverting this here.
|
||||
int placeholderStart = position.getIndex() - 2;
|
||||
int index = position.getIndex();
|
||||
|
||||
StringBuilder identifier = new StringBuilder();
|
||||
StringBuilder values = new StringBuilder();
|
||||
|
||||
boolean identified = false;
|
||||
boolean invalid = true;
|
||||
|
||||
char[] chars = text.substring(index).toCharArray();
|
||||
for(final char c : chars){
|
||||
index++;
|
||||
|
||||
if(c == '}'){
|
||||
invalid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if(c == ' ' && !identified){
|
||||
identified = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(identified){
|
||||
values.append(c);
|
||||
}else{
|
||||
identifier.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
String identifierStr = identifier.toString();
|
||||
String valuesStr = values.toString();
|
||||
|
||||
StringBuilder raw = new StringBuilder();
|
||||
|
||||
// Skipping whatever character we currently were on (i.e. })
|
||||
position.setIndex(index + 1);
|
||||
|
||||
if(invalid){
|
||||
raw.append("${").append(identifierStr);
|
||||
|
||||
if(identified)
|
||||
raw.append(' ').append(valuesStr);
|
||||
|
||||
collector.appendWarningFormatted(placeholderStart, "Placeholder '%s' does not have a closing bracket (}).", raw.toString());
|
||||
return new PlaceholderToken.Placeholder(raw.toString());
|
||||
}
|
||||
|
||||
PlaceholderProvider provider = api.retrievePlaceholderProvider(identifierStr);
|
||||
if(provider == null){
|
||||
raw.append("${").append(identifierStr);
|
||||
|
||||
if(identified)
|
||||
raw.append(' ').append(valuesStr);
|
||||
|
||||
raw.append('}');
|
||||
|
||||
collector.appendWarningFormatted(placeholderStart, "Placeholder '%s' does not have any available PlaceholderProvider", raw.toString());
|
||||
return new PlaceholderToken.Placeholder(raw.toString());
|
||||
}
|
||||
|
||||
String replacement = provider.parsePlaceholder(valuesStr, player, server);
|
||||
if(replacement == null){
|
||||
raw.append("${").append(identifierStr);
|
||||
|
||||
if(identified)
|
||||
raw.append(' ').append(valuesStr);
|
||||
|
||||
raw.append('}');
|
||||
|
||||
collector.appendWarningFormatted(placeholderStart, "Placeholder '%s' has an invalid value String '%s'.", raw.toString(), valuesStr);
|
||||
return new PlaceholderToken.Placeholder(raw.toString());
|
||||
}
|
||||
|
||||
return new PlaceholderToken.Placeholder(replacement);
|
||||
}
|
||||
}
|
||||
@@ -27,8 +27,8 @@ package ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.rea
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.PlaceholderParser;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens.PlaceholderToken;
|
||||
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
import ch.andre601.expressionparser.tokens.Token;
|
||||
|
||||
@@ -44,7 +44,7 @@ public class PlaceholderTokenReader extends CustomTokenReader{
|
||||
public Token read(String text, ParsePosition position, GenericPlayer player, GenericServer server, ParseWarnCollector collector){
|
||||
if(position.getIndex() + 1 < text.length() && text.charAt(position.getIndex()) == '$' && text.charAt(position.getIndex() + 1) == '{'){
|
||||
position.setIndex(position.getIndex() + 2);
|
||||
return new PlaceholderToken(PlaceholderParser.parse(text, position, player, server, collector));
|
||||
return new PlaceholderToken(StringReplacer.parsePlaceholder(text, position, player, server, collector));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -70,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.
|
||||
@@ -129,7 +130,7 @@ public class PlayerHandler{
|
||||
return getDefaultPlayer();
|
||||
|
||||
for(CachedPlayer player : cachedPlayers){
|
||||
if(player.getIp().equals(key))
|
||||
if(player.ip().equals(key))
|
||||
return player;
|
||||
}
|
||||
|
||||
@@ -138,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;
|
||||
}
|
||||
|
||||
@@ -152,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -3,53 +3,111 @@
|
||||
#
|
||||
unknownPlayer:
|
||||
#
|
||||
# The name to use. Defaults to Anonymous.
|
||||
# The name to use.
|
||||
#
|
||||
# Default: Anonymous
|
||||
#
|
||||
name: "Anonymous"
|
||||
#
|
||||
# The UUID to use. Defaults to 606e2ff0-ed77-4842-9d6c-e1d3321c7838 (UUID of MHF_Question).
|
||||
# The UUID to use.
|
||||
#
|
||||
# Default: 606e2ff0-ed77-4842-9d6c-e1d3321c7838 (UUID of MHF_Question).
|
||||
#
|
||||
uuid: "606e2ff0-ed77-4842-9d6c-e1d3321c7838"
|
||||
|
||||
#
|
||||
# Should the Caching of players be disabled?
|
||||
#
|
||||
# When set to true will AdvancedServerList not load any players from the cache.data file (if present) nor save any to it.
|
||||
# Placeholders that rely on the player being cached (such as ${player name}) will not work while this option is enabled.
|
||||
# When set to true will no player joining the server be cached and saved to the playercache.json file.
|
||||
# This will also cause placeholders using a cached player such as ${player name} to no longer work.
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
# Default: false
|
||||
#
|
||||
disableCache: false
|
||||
|
||||
#
|
||||
# Should AdvancedServerList check for new versions?
|
||||
#
|
||||
# When set to true will AdvancedServerList check for a new version on modrinth.com every 12 hours and inform you in the
|
||||
# console about whether it found any new update or not.
|
||||
# When set to true will AdvancedServerList look for a new update on startup and repeat that check
|
||||
# every 12 hours after that.
|
||||
# It uses Modrinth to check for updates.
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
# Default: true
|
||||
#
|
||||
checkUpdates: true
|
||||
|
||||
#
|
||||
# Should debug mode be enabled?
|
||||
#
|
||||
# When set to true will AdvancedServerList print additional messages to the console prefixed with "[DEBUG]".
|
||||
# It is recommended to only enable this when having problems or when being told to by the plugin dev, as it could
|
||||
# otherwise cause significant spam in your console.
|
||||
# Additional messages prefixed with [DEBUG] will be printed in the console when this option is set
|
||||
# to true.
|
||||
# Enabling this option is only recommended for when you have problems, or have been told to enable
|
||||
# it by the plugin developer, as it can otherwise spam your console.
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
# Default: false
|
||||
#
|
||||
debug: false
|
||||
|
||||
#
|
||||
# Sets the time in minutes for favicons to be cached.
|
||||
# The number cannot be less than 1.
|
||||
# Sets how long Favicons should be cached. Value is in minutes with the lowest possible value being 1.
|
||||
#
|
||||
# Defaults to 1 if not set.
|
||||
# This option only affects dynamic favicons created from a placeholder or URL. Local favicons will
|
||||
# not be affected.
|
||||
#
|
||||
# Default: 1
|
||||
#
|
||||
faviconCacheTime: 1
|
||||
|
||||
#
|
||||
# Options to disable while the Maintenance Plugin is present and Maintenance Mode is active.
|
||||
#
|
||||
# Should an option be removed from this section will AdvancedServerList continue to set it, as if
|
||||
# the Maintenance plugin isn't active.
|
||||
#
|
||||
disableDuringMaintenance:
|
||||
#
|
||||
# Whether MOTD changing should be disabled while Maintenance mode is active.
|
||||
#
|
||||
# Default: true
|
||||
#
|
||||
motd: true
|
||||
#
|
||||
# Whether favicon changing should be disabled while Maintenance mode is active.
|
||||
#
|
||||
# Default: true
|
||||
#
|
||||
favicon: true
|
||||
#
|
||||
# Whether player hiding should be disabled while Maintenance mode is active.
|
||||
#
|
||||
# Default: true
|
||||
#
|
||||
hidePlayers: true
|
||||
#
|
||||
# Whether player count text changing should be disabled while Maintenance mode is active.
|
||||
#
|
||||
# Default: true
|
||||
#
|
||||
playerCountText: true
|
||||
#
|
||||
# Whether player count hover changing should be disabled while Maintenance mode is active.
|
||||
#
|
||||
# Default: true
|
||||
#
|
||||
playerCountHover: true
|
||||
#
|
||||
# Whether the extra players feature should be disabled while Maintenance mode is active.
|
||||
#
|
||||
# Default: true
|
||||
#
|
||||
extraPlayers: true
|
||||
#
|
||||
# Whether the max players feature should be disabled while Maintenance mode is active.
|
||||
#
|
||||
# Default: true
|
||||
#
|
||||
maxPlayers: true
|
||||
|
||||
#
|
||||
# DO NOT EDIT!
|
||||
#
|
||||
|
||||
@@ -1,176 +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 need to me met to show this profile.
|
||||
# You can use keywords 'and' or 'or' (Or alternatively '&&' or `||`) to make more complex condition sets.
|
||||
# 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).
|
||||
#
|
||||
# Multiple conditions can be chaing with the keywords 'and', 'or', or their counterparts '&&' and '||'.
|
||||
#
|
||||
# No condition or an empty condition will be treated as true by default.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#condition
|
||||
#
|
||||
# condition: '${player protocol} < 759'
|
||||
#
|
||||
condition: ''
|
||||
|
||||
#
|
||||
# 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 one or multiple profiles.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#conditions
|
||||
# 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.
|
||||
#
|
||||
#conditions:
|
||||
# - '{playerVersion} < 759'
|
||||
|
||||
# Example: The below profile configuration will randomly change the MOTD between two types, but keep the Hover text
|
||||
# the same.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# A profile will be selected randomly.
|
||||
#
|
||||
# Remove this option or set it to profiles: [] to use the global options of this file.
|
||||
# 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
|
||||
#
|
||||
|
||||
@@ -27,7 +27,6 @@ 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;
|
||||
@@ -46,15 +45,9 @@ public class ExpressionParserTests{
|
||||
logger.info("TEST[expression=\"%s\", expected=%b]", values.getKey(), values.getValue());
|
||||
|
||||
ParseWarnCollector collector = new ParseWarnCollector(values.getKey());
|
||||
ExpressionTemplate template = parser.compile(values.getKey(), null, null, collector);
|
||||
boolean result;
|
||||
if(template == null){
|
||||
result = false;
|
||||
}else{
|
||||
result = template.returnBooleanExpression().evaluate();
|
||||
}
|
||||
boolean result = parser.evaluate(values.getKey(), null, null, collector);
|
||||
|
||||
logger.info("Result (output, isExpected): " + result + ", " + (result == values.getValue()));
|
||||
logger.info("Result (Output, Expected?): %b, %b", result, (result == values.getValue()));
|
||||
assertEquals(result, values.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,10 +0,0 @@
|
||||
nav:
|
||||
- Home: index.md
|
||||
- getting-started
|
||||
- commands
|
||||
- profiles
|
||||
- examples
|
||||
- migration
|
||||
- api
|
||||
- addons
|
||||
- PlaceholderAPI: placeholderapi
|
||||
@@ -32,6 +32,26 @@ Placeholders for the plugin [AdvancedBan](https://www.spigotmc.org/resources/869
|
||||
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"
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
nav:
|
||||
- ...
|
||||
@@ -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 }
|
||||
|
||||
-->
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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,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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,10 +45,10 @@ document$.subscribe(async () => {
|
||||
}
|
||||
|
||||
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 = {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -18,21 +18,41 @@ The following subcommands are available (Subcommands are case-insensitive):
|
||||
- [`help`](#help)
|
||||
- [`reload`](#reload)
|
||||
- [`clearCache`](#clearcache)
|
||||
- [`migrate <plugin>`](#migrate)
|
||||
|
||||
### 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.
|
||||
///
|
||||
|
||||
### migrate <plugin> { #migrate }
|
||||
|
||||
/// info |
|
||||
**Permission:** `advancedserverlist.command.migrate`
|
||||
|
||||
**Arguments:
|
||||
|
||||
- `<plugin>` - The plugin to migrate from.
|
||||
|
||||
Migrates files from one plugin over to AdvancedServerList.
|
||||
Check the [Migration Page](../migration/index.md) for a list of supported plugins.
|
||||
///
|
||||
@@ -10,7 +10,7 @@ icon: octicons/list-unordered-24
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ 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 }
|
||||
|
||||
@@ -14,26 +14,26 @@ AdvancedServerList is available on the following places (Please note the current
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- [:simple-modrinth: **Modrinth**][modrinth]
|
||||
- [:simple-modrinth: **Modrinth**][modrinth]{ target="_blank" rel="nofollow" }
|
||||
|
||||
----
|
||||
|
||||
:octicons-check-24:{ style="color: var(--md-badge-fg--success);" } **Actively updated!**
|
||||
|
||||
- [:simple-codeberg: **Codeberg**][codeberg]
|
||||
- [: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]
|
||||
- [: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]
|
||||
- [:simple-spigotmc: **SpigotMC**][spigot]{ target="_blank" rel="nofollow" }
|
||||
|
||||
----
|
||||
|
||||
@@ -52,51 +52,72 @@ The plugin also supports these additional plugins. They are all optional.
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- [**PlaceholderAPI**][placeholderapi]
|
||||
|
||||
----
|
||||
|
||||
Supported on:
|
||||
|
||||
- :fontawesome-solid-paper-plane: Paper
|
||||
|
||||
- [**ViaVersion**][viaversion]
|
||||
- [**PlaceholderAPI**][placeholderapi]{ target="_blank" rel="nofollow" }
|
||||
|
||||
----
|
||||
|
||||
Supported on:
|
||||
|
||||
- :fontawesome-solid-paper-plane: Paper
|
||||
|
||||
- [**PAPIProxyBridge**][papiproxybridge]
|
||||
AdvancedServerList supports the use of placeholder from PlaceholderAPI in all its text options, except for the `condition` option.
|
||||
|
||||
----
|
||||
|
||||
Supported on:
|
||||
|
||||
- :simple-spigotmc: BungeeCord
|
||||
- :fontawesome-solid-paper-plane: Velocity
|
||||
**Supported on:**
|
||||
:fontawesome-solid-paper-plane: Paper
|
||||
|
||||
- [**Maintenance**][maintenance]
|
||||
- [**ViaVersion**][viaversion]{ target="_blank" rel="nofollow" }
|
||||
|
||||
----
|
||||
|
||||
Supported on:
|
||||
When installed will AdvancedServerList use ViaVersion to resolve the protocol version of a player for its PlaceholderAPI placeholders.
|
||||
|
||||
- :fontawesome-solid-paper-plane: Paper
|
||||
- :simple-spigotmc: BungeeCord
|
||||
- :fontawesome-solid-paper-plane: Velocity
|
||||
----
|
||||
|
||||
**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 |
|
||||
@@ -112,7 +133,7 @@ If everything goes well should AdvancedServerList create a folder named `Advance
|
||||
|
||||
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
|
||||
@@ -130,170 +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 need to me met to show this profile.
|
||||
# You can use keywords 'and' or 'or' (Or alternatively '&&' or `||`) to make more complex condition sets.
|
||||
# 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).
|
||||
#
|
||||
# Multiple conditions can be chaing with the keywords 'and', 'or', or their counterparts '&&' and '||'.
|
||||
#
|
||||
# No condition or an empty condition will be treated as true by default.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#condition
|
||||
#
|
||||
# condition: '${player protocol} < 759'
|
||||
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
|
||||
#
|
||||
@@ -310,83 +336,157 @@ These functions include, but aren't limited to:
|
||||
- Disabling/Enabling caching of players.
|
||||
- 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.
|
||||
#
|
||||
unknownPlayer:
|
||||
#
|
||||
# The name to use. Defaults to Anonymous.
|
||||
# The name to use.
|
||||
#
|
||||
# Default: Anonymous
|
||||
#
|
||||
name: "Anonymous"
|
||||
#
|
||||
# The UUID to use. Defaults to 606e2ff0-ed77-4842-9d6c-e1d3321c7838 (UUID of MHF_Question).
|
||||
# The UUID to use.
|
||||
#
|
||||
# Default: 606e2ff0-ed77-4842-9d6c-e1d3321c7838 (UUID of MHF_Question).
|
||||
#
|
||||
uuid: "606e2ff0-ed77-4842-9d6c-e1d3321c7838"
|
||||
|
||||
#
|
||||
# Should the Caching of players be disabled?
|
||||
#
|
||||
# When set to true will AdvancedServerList not load any players from the cache.data file (if present) nor save any to it.
|
||||
# Placeholders that rely on the player being cached (such as ${player name}) will not work while this option is enabled.
|
||||
# When set to true will no player joining the server be cached and saved to the playercache.json file.
|
||||
# This will also cause placeholders using a cached player such as ${player name} to no longer work.
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
# Default: false
|
||||
#
|
||||
disableCache: false
|
||||
|
||||
#
|
||||
# Should AdvancedServerList check for new versions?
|
||||
#
|
||||
# When set to true will AdvancedServerList check for a new version on modrinth.com every 12 hours and inform you in the
|
||||
# console about whether it found any new update or not.
|
||||
# When set to true will AdvancedServerList look for a new update on startup and repeat that check
|
||||
# every 12 hours after that.
|
||||
# It uses Modrinth to check for updates.
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
# Default: true
|
||||
#
|
||||
checkUpdates: true
|
||||
|
||||
#
|
||||
# Should debug mode be enabled?
|
||||
#
|
||||
# When set to true will AdvancedServerList print additional messages to the console prefixed with "[DEBUG]".
|
||||
# It is recommended to only enable this when having problems or when being told to by the plugin dev, as it could
|
||||
# otherwise cause significant spam in your console.
|
||||
# Additional messages prefixed with [DEBUG] will be printed in the console when this option is set
|
||||
# to true.
|
||||
# Enabling this option is only recommended for when you have problems, or have been told to enable
|
||||
# it by the plugin developer, as it can otherwise spam your console.
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
# Default: false
|
||||
#
|
||||
debug: false
|
||||
|
||||
#
|
||||
# Sets how long Favicons should be cached. Value is in minutes with the lowest possible value being 1.
|
||||
#
|
||||
# This option only affects dynamic favicons created from a placeholder or URL. Local favicons will
|
||||
# not be affected.
|
||||
#
|
||||
# Default: 1
|
||||
#
|
||||
faviconCacheTime: 1
|
||||
|
||||
#
|
||||
# Options to disable while the Maintenance Plugin is present and Maintenance Mode is active.
|
||||
#
|
||||
# Should an option be removed from this section will AdvancedServerList continue to set it, as if
|
||||
# the Maintenance plugin isn't active.
|
||||
#
|
||||
disableDuringMaintenance:
|
||||
#
|
||||
# Whether MOTD changing should be disabled while Maintenance mode is active.
|
||||
#
|
||||
# Default: true
|
||||
#
|
||||
motd: true
|
||||
#
|
||||
# Whether favicon changing should be disabled while Maintenance mode is active.
|
||||
#
|
||||
# Default: true
|
||||
#
|
||||
favicon: true
|
||||
#
|
||||
# Whether player hiding should be disabled while Maintenance mode is active.
|
||||
#
|
||||
# Default: true
|
||||
#
|
||||
hidePlayers: true
|
||||
#
|
||||
# Whether player count text changing should be disabled while Maintenance mode is active.
|
||||
#
|
||||
# Default: true
|
||||
#
|
||||
playerCountText: true
|
||||
#
|
||||
# Whether player count hover changing should be disabled while Maintenance mode is active.
|
||||
#
|
||||
# Default: true
|
||||
#
|
||||
playerCountHover: true
|
||||
#
|
||||
# Whether the extra players feature should be disabled while Maintenance mode is active.
|
||||
#
|
||||
# Default: true
|
||||
#
|
||||
extraPlayers: true
|
||||
#
|
||||
# Whether the max players feature should be disabled while Maintenance mode is active.
|
||||
#
|
||||
# Default: true
|
||||
#
|
||||
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 [condition](../profiles/index.md#condition)) 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.
|
||||
@@ -402,16 +502,16 @@ 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 to have a valid profile, but depending on the priority and file name may the file not be used, or used over other profiles.
|
||||
|
||||
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 muliple [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.
|
||||
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.
|
||||
|
||||
/// info | Note
|
||||
Profiles which do not have any conditions, or have an empty condition, will always considered to have a true condition, meaning that a profile with higher priority and no condition will be selected over a profile with lower priority and a condition, even if said condition returns true.
|
||||
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:
|
||||
@@ -431,7 +531,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.
|
||||
|
||||
|
||||
@@ -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>
|
||||
@@ -1,7 +0,0 @@
|
||||
nav:
|
||||
- index.md
|
||||
- v3_8_0-to-v3_9_0.md
|
||||
- v3_7_0-to-v3_8_0.md
|
||||
- pre-v3_7_0-to-v3_7_0.md
|
||||
- v1_9_0-to-v1_10_0.md
|
||||
- v1_5_3-to-v1_6_0.md
|
||||
@@ -4,14 +4,34 @@ icon: octicons/file-directory-symlink-24
|
||||
|
||||
# Migration
|
||||
|
||||
This page lists all migration guides for specific AdvancedServerList versions.
|
||||
## Other Plugins
|
||||
|
||||
Note that these pages only cover server list profile files. The config.yml is automatically being migrated (Feature since v3.1.0).
|
||||
|
||||
## Pages
|
||||
The below pages show guides on how to migrate from another plugin to AdvancedServerList.
|
||||
These pages may include important information about the migration process and what you may have to do before, during or after the process.
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- [**ServerListPlus**](serverlistplus.md)
|
||||
|
||||
----
|
||||
|
||||
Migrate from the Plugin [ServerListPlus](https://github.com/Minecrell/ServerListPlus).
|
||||
|
||||
</div>
|
||||
|
||||
## AdvancedServerList
|
||||
|
||||
The below pages show guides on how to migrate from one version to another of AdvancedServerList.
|
||||
These guides are only for the Server List Profile files, as the config.yml gets automatically migrated (Feature since v3.1.0).
|
||||
|
||||
<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)
|
||||
|
||||
----
|
||||
|
||||
@@ -49,8 +49,12 @@ 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,30 @@
|
||||
---
|
||||
icon: octicons/arrow-right-24
|
||||
---
|
||||
|
||||
# ServerListPlus
|
||||
|
||||
Version `v4.8.0-b1` added support for migrating your existing `ServerListPlus.yml` configuration to AdvancedServerList.
|
||||
|
||||
## Important notes
|
||||
|
||||
- Migration requires that ServerListPlus is present and running, as AdvancedServerList will use its internal code to process the file.
|
||||
- The files `slp_default.yml`, `slp_personalized.yml` and `slp_banned.yml` will be created, depending on if the corresponding type (`Default`, `Personalized` and `Banned`) are present.
|
||||
Should a file with the same name be found will it be skipped.
|
||||
- The plugin will convert placeholders and color/formatting codes in the following way:
|
||||
|
||||
| Placeholder/Color/Format | Conversion |
|
||||
|--------------------------------------------|-----------------------------------------------------------------------------------|
|
||||
| `%player%` | `${player name}` |
|
||||
| `%uuid%` and `%_uuid_%` | `${player uuid}` |
|
||||
| `%online%` | `${server playersOnline}` |
|
||||
| `%max%` | `${server playersMax}` |
|
||||
| `&<color/format>` | Corresponding color/formatting code in MiniMessage (i.e. `&1 -> <dark_blue>`)[^1] |
|
||||
| `&#<hexcode>` | `<#<hexcode>>` |
|
||||
| `%gradient#<start>#<end>%<text>%gradient%` | `<gradient:#<start>:#<end>><text></gradient>` |
|
||||
|
||||
## How to Migrate
|
||||
|
||||
Execute the command [`/asl migrate serverlistplus`](../commands/index.md#migrate) to start the migration process. Make sure that ServerListPlus is present and enabled.
|
||||
|
||||
[^1]: The color/formatting code conversion is lazy and not context sensitive, meaning that a case like `&1Hello &l%player%&1!` will be converted to `<dark_blue>Hellow <bold>${player name}<dark_blue>` when it should be `<dark_blue>Hello <bold>${player name}</bold>!`. So keep that in mind.
|
||||
@@ -18,7 +18,7 @@ Here is a before and after example to help visualize the change:
|
||||
```yaml
|
||||
priority: 0
|
||||
|
||||
conditions: '${server host} <- "survival"'
|
||||
condition: '${server host} <- "survival"'
|
||||
|
||||
motd:
|
||||
- 'Welcome ${player name}!'
|
||||
|
||||