mirror of
https://codeberg.org/Andre601/AdvancedServerList.git
synced 2026-11-05 17:02:34 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba311f42c4 | ||
|
|
1b5379d54b | ||
|
|
03a1908ca6 | ||
|
|
f9574d2f83 | ||
|
|
7e45439dfe | ||
|
|
2a8b4ed640 | ||
|
|
86c053e445 | ||
|
|
7eba04bb9a | ||
|
|
b4ac677f67 | ||
|
|
989d44cc5e | ||
|
|
9821875e7a | ||
|
|
07e3b6702b | ||
|
|
31889fbd9c | ||
|
|
87a089a0fa | ||
|
|
88b91e8859 | ||
|
|
f8097e3c72 | ||
|
|
e237c990d8 | ||
|
|
21c0ba975c | ||
|
|
642ce922c3 | ||
|
|
6e5466aacf | ||
|
|
e6635cd844 | ||
|
|
229ab60c57 | ||
|
|
483daee999 | ||
|
|
31ffcd7f7b | ||
|
|
e5139cc00d | ||
|
|
9b1b95b27a | ||
|
|
88d3ceeaf3 | ||
|
|
f74f2f337c | ||
|
|
87b35f240e | ||
|
|
fc861ea304 | ||
|
|
927971ca12 | ||
|
|
0ecb8383e3 | ||
|
|
9c3b2220d5 | ||
|
|
46e15441fd | ||
|
|
2d2a1ca805 | ||
|
|
c577264e1d | ||
|
|
27c3972ab0 | ||
|
|
e4c90730ba | ||
|
|
0694e08399 | ||
|
|
2fefa966dd | ||
|
|
a57cf3df17 | ||
|
|
1ae7260cf3 | ||
|
|
8459eee57d | ||
|
|
f5cebf42ab | ||
|
|
731bdeba7d | ||
|
|
d14cda243a | ||
|
|
0a98aad138 | ||
|
|
1249a08264 | ||
|
|
c0414a5962 | ||
|
|
9cc4d4bb36 | ||
|
|
338358a2ab | ||
|
|
805ba83bb6 | ||
|
|
0f646a8f8d | ||
|
|
2519f09f6f | ||
|
|
60bca9e3d7 | ||
|
|
da8f72fc50 | ||
|
|
c42d4b8967 | ||
|
|
0110854ae4 | ||
|
|
d6d5952cbc | ||
|
|
f9d961cae7 | ||
|
|
a387feea23 | ||
|
|
359c58163b | ||
|
|
0892f5cd1d | ||
|
|
452a7e6dcf | ||
|
|
162dd10a73 | ||
|
|
35120c5364 | ||
|
|
6c828171d2 | ||
|
|
dcc51f8458 | ||
|
|
1287ca62fe | ||
|
|
1ff439fa95 | ||
|
|
ed0f832b2f | ||
|
|
b8e6b2acc6 | ||
|
|
fba32c91c5 | ||
|
|
6505ded12b | ||
|
|
53088affcb | ||
|
|
9c030764fa | ||
|
|
d5d58f1eea | ||
|
|
7181092821 | ||
|
|
fc5ee4f242 | ||
|
|
6e74c4fb14 | ||
|
|
f6a27342e6 | ||
|
|
38b50df2c9 | ||
|
|
db93816e55 | ||
|
|
244c2440fc | ||
|
|
8e2c644669 | ||
|
|
a68809ab31 | ||
|
|
4b4fd80abe | ||
|
|
48ea128267 | ||
|
|
68e5795618 | ||
|
|
1aa20e4196 | ||
|
|
6db25c8f9c | ||
|
|
0ef3db752d | ||
|
|
1a26f5ad34 | ||
|
|
17a5574be7 | ||
|
|
c7bfb8a736 | ||
|
|
7a756c3b98 | ||
|
|
1539e1c3c0 | ||
|
|
a86872c021 | ||
|
|
7d12499f39 | ||
|
|
455434b5f3 | ||
|
|
b66251ab20 | ||
|
|
4a1dfa5cb4 | ||
|
|
1efd65e16c | ||
|
|
908da9cd32 | ||
|
|
e8a30c6ef7 | ||
|
|
df164c104f | ||
|
|
acdf6f6e9a | ||
|
|
f52a63a8f1 | ||
|
|
6a92cb3a16 | ||
|
|
1175451753 | ||
|
|
5c4130411b | ||
|
|
05727eeec5 | ||
|
|
10af949abc | ||
|
|
9851347e74 | ||
|
|
c3e01c8b9c | ||
|
|
a646d9e998 | ||
|
|
3c50a30d4a | ||
|
|
4328ad6b44 | ||
|
|
34b0555508 | ||
|
|
c92cd0058b | ||
|
|
2cfe8b8a27 | ||
|
|
6530fed704 | ||
|
|
7efb203e7b | ||
|
|
1a34376100 | ||
|
|
ec1aa5b393 | ||
|
|
9683d3c001 | ||
|
|
db60545fcc | ||
|
|
392495ef63 | ||
|
|
903764b234 | ||
|
|
72329ed1e4 | ||
|
|
c516b56053 | ||
|
|
5e4295fbfb | ||
|
|
b140c0aa32 | ||
|
|
8f7b293541 | ||
|
|
6f878164c5 | ||
|
|
a16801ff56 | ||
|
|
65a89cf762 | ||
|
|
27d4ada179 | ||
|
|
574edfb246 | ||
|
|
7b7aad9d4e | ||
|
|
c5c9ed8109 | ||
|
|
58fea4090d | ||
|
|
cd0aad6ec1 | ||
|
|
fa45844434 | ||
|
|
c4e2a144b5 | ||
|
|
7fe93c7021 | ||
|
|
1d413a5c2a | ||
|
|
51db52dbdd | ||
|
|
4ade528188 | ||
|
|
64ba48a7c7 | ||
|
|
ac4edb2b97 | ||
|
|
3ea000c98b | ||
|
|
746bef13e1 | ||
|
|
355ab73546 | ||
|
|
67170c70e0 | ||
|
|
f99c2df4e8 | ||
|
|
212ec04fb8 | ||
|
|
89c6089101 | ||
|
|
87bce39d9a | ||
|
|
18900547a0 | ||
|
|
5df2e05a14 | ||
|
|
d4e4173cc3 | ||
|
|
562ad481c5 | ||
|
|
a0ee2a4322 | ||
|
|
2c92efdb43 | ||
|
|
555dc9d6a5 | ||
|
|
27742c5e1b | ||
|
|
280aeb8d2e | ||
|
|
92a868f0fa | ||
|
|
189ac5e09b | ||
|
|
833cb81d65 | ||
|
|
ab09422da5 | ||
|
|
64cad6dc26 | ||
|
|
ce78b493f4 | ||
|
|
c43048ea3f | ||
|
|
6d4d1600ab | ||
|
|
f114e99b9b | ||
|
|
3d587bc86d | ||
|
|
bd8c6be7c6 | ||
|
|
b5d5d508e2 | ||
|
|
3001b65fe8 | ||
|
|
c82771db59 | ||
|
|
9880836c25 | ||
|
|
f12ae28722 | ||
|
|
42b0f0e94f | ||
|
|
0a4b872051 | ||
|
|
b1322105ed | ||
|
|
831ca57fbb | ||
|
|
6502639cd3 | ||
|
|
5059b80db2 | ||
|
|
ecdaf72963 | ||
|
|
28e2ca69ed | ||
|
|
9cad78b6e4 | ||
|
|
af8654666b | ||
|
|
6cd474b35d | ||
|
|
3802ab556c | ||
|
|
3a520eeaf0 | ||
|
|
204f43c112 | ||
|
|
fc8ed8e49e | ||
|
|
56082c308b | ||
|
|
205e563095 | ||
|
|
5b01940c60 | ||
|
|
cbb087e3d1 | ||
|
|
524b926244 | ||
|
|
4059bbfe93 | ||
|
|
9b0b69a4f4 | ||
|
|
10a82eb951 | ||
|
|
690f7dfaf0 | ||
|
|
6a22d20b3a | ||
|
|
b1072bb1fa | ||
|
|
d20da91bab | ||
|
|
17e9692028 | ||
|
|
45dc8a5fe6 | ||
|
|
a237ac1ce4 | ||
|
|
27e66a16b9 |
No files matched your search
@@ -24,11 +24,11 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python 3.7
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.x
|
||||
- name: Create/Get Cache
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
key: ${{ github.ref }}
|
||||
path: .cache
|
||||
@@ -39,11 +39,11 @@ jobs:
|
||||
- name: Build docs
|
||||
run: mkdocs build
|
||||
- name: Configure GitHub Pages
|
||||
uses: actions/configure-pages@v3
|
||||
uses: actions/configure-pages@v4
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v2
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: 'site/'
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v2
|
||||
uses: actions/deploy-pages@v4
|
||||
@@ -4,16 +4,16 @@ when:
|
||||
|
||||
steps:
|
||||
createFiles:
|
||||
image: maven:3.9.4-eclipse-temurin-17
|
||||
image: maven:3.9.6-eclipse-temurin-17
|
||||
secrets:
|
||||
- source: cb_token
|
||||
target: codeberg_api_token
|
||||
- source: gh_token
|
||||
target: github_api_token
|
||||
- source: modrinth_api_token
|
||||
target: modrinth_api_token
|
||||
- source: hangar_api_token
|
||||
target: hangar_api_token
|
||||
- source: discord_webhook_url
|
||||
target: discord_webhook_url
|
||||
commands:
|
||||
# Create the jar files.
|
||||
- mvn clean install
|
||||
@@ -28,8 +28,9 @@ steps:
|
||||
settings:
|
||||
base_url: https://codeberg.org
|
||||
files:
|
||||
- "bukkit/target/AdvancedServerList-*.jar"
|
||||
- "bungeecord/target/AdvancedServerList-*.jar"
|
||||
- "paper/target/AdvancedServerList-*.jar"
|
||||
- "velocity/target/AdvancedServerList-*.jar"
|
||||
- "addons/banplugins/target/AdvancedServerList-*.jar"
|
||||
api_key:
|
||||
from_secret: CB_TOKEN
|
||||
@@ -4,25 +4,33 @@ when:
|
||||
path:
|
||||
include: ['requirements.txt', 'mkdocs.yml', 'docs/**']
|
||||
|
||||
variables:
|
||||
setup_git: &setup_git
|
||||
- apk add git
|
||||
- git config --global user.email "github@andre601.ch"
|
||||
- git config --global user.name "ASL Docs Builder"
|
||||
|
||||
steps:
|
||||
cloneTargetRepo:
|
||||
image: alpine:3.18.4
|
||||
commands:
|
||||
- chmod -R a+w .
|
||||
- <<: *setup_git
|
||||
- git clone -b pages https://codeberg.org/Andre601/AdvancedServerList.git site
|
||||
- chmod -R a+w site
|
||||
buildDocs:
|
||||
image: python
|
||||
image: woodpeckerci/plugin-mkdocs:latest
|
||||
settings:
|
||||
pip_install_file: requirements.txt
|
||||
commitAndPush:
|
||||
image: alpine:3.18.4
|
||||
secrets:
|
||||
- cb_token
|
||||
commands:
|
||||
- chmod -R a+w .
|
||||
- git config --global --add safe.directory /woodpecker/src/codeberg.org/Andre601/blog-source/website
|
||||
- git config --global user.email "github@andre601.ch"
|
||||
- git config --global user.name "CI Website Builder"
|
||||
- git fetch --unshallow
|
||||
- git clone -b pages https://codeberg.org/Andre601/AdvancedServerList.git site
|
||||
- chmod -R a+w site
|
||||
- python -m pip install --upgrade pip
|
||||
- python -m pip install -r requirements.txt
|
||||
- mkdocs build
|
||||
- <<: *setup_git
|
||||
- mv domains site/.domains
|
||||
- cd site
|
||||
- git remote set-url origin https://$CB_TOKEN@codeberg.org/Andre601/AdvancedServerList.git
|
||||
- git add --all
|
||||
- git commit -m "Update AdvancedServerList Docs ($( env TZ=Europe/Zurich date +"%d.%m.%Y" )) [CI SKIP]"
|
||||
- git commit -m "Update AdvancedServerList Docs ($( env TZ=Europe/Zurich date +"%d.%m.%Y %Z" )) [SKIP CI]"
|
||||
- git push
|
||||
@@ -1,6 +1,6 @@
|
||||
# AdvancedServerList
|
||||
|
||||
AdvancedServerList is a plugin that allowys you to customize your server's MOTD, favicon, Player count text and player count hover displayed in a player's multiplayer server list based on conditions and priorities.
|
||||
AdvancedServerList is a plugin that allows you to customize your server's MOTD, favicon, Player count text and player count hover displayed in a player's multiplayer server list based on conditions and priorities.
|
||||
|
||||
## Downloads
|
||||
|
||||
@@ -8,15 +8,14 @@ AdvancedServerList is a plugin that allowys you to customize your server's MOTD,
|
||||
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact/available/modrinth_vector.svg" height="46" alt="modrinth" title="Available on Modrinth">
|
||||
</a>
|
||||
<br>
|
||||
<!--
|
||||
<a href="https://hangar.papermc.io/Andre_601/AdvancedServerList" target="_blank">
|
||||
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact/available/hangar_vector.svg" height="46" alt="hangar" title="Available on Hangar">
|
||||
</a>
|
||||
-->
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
<a href="https://www.spigotmc.org" target="_blank">
|
||||
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact-minimal/supported/spigot_vector.svg" height="64" alt="platform-spigot" title="Tested on Spigot">
|
||||
</a>
|
||||
<a href="https://papermc.io" target="_blank">
|
||||
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact-minimal/supported/paper_vector.svg" height="64" alt="platform-paper" title="Tested on Paper">
|
||||
</a>
|
||||
@@ -31,29 +30,33 @@ AdvancedServerList is a plugin that allowys you to customize your server's MOTD,
|
||||
</a>
|
||||
|
||||
## What is a Server List Profile?
|
||||
|
||||
A Server List Profile refers to a YAML file located in the plugin's `profiles` directory.
|
||||
It allows you to configure specific aspects of the server display in the MC-Client's multiplayer server list, such as the MOTD, player count text, player count hover or Favicon.
|
||||
|
||||
> [*Read More*][profiles]
|
||||
|
||||
### Conditions
|
||||
Thanks to conditions can you determine when a profile should be displayed in the player’s server list, to allow displaying specific text (i.e. a warning when they are using an outdated version).
|
||||
|
||||
When multiple profiles exist that have valid conditions will the one with the highest priority (Higher number = higher priority) be selected. Having no conditions makes the profile automatically return true.
|
||||
Thanks to conditions can you determine when a profile should be displayed in the player's server list, to allow displaying specific text (i.e. a warning when they are using an outdated version).
|
||||
|
||||
When multiple profiles exist that have valid conditions will the one with the highest priority (Higher number = higher priority) be selected. Having no conditions makes it automatically true.
|
||||
|
||||
> [*Read More*][conditions]
|
||||
|
||||
### Placeholders
|
||||
|
||||
Placeholders can be used within conditions to further customize them. They can also be used in any other text option to display their respective values.
|
||||
The format is `${<target> <identifier>}` which was adopted from BungeeTabListPlus. Depending on what platform you use the plugin on are only specific placeholders available.
|
||||
|
||||
When using the SpigotMC/PaperMC version, or while PAPIProxyBridge is installed on your proxy, can you also use placeholders from [PlaceholderAPI][placeholderapi] using its `%<identifier>_<values>%` placeholder format. PlaceholderAPI needs to be installed for that.
|
||||
When using the SpigotMC/PaperMC version, or while [PAPIProxyBridge][papiproxybridge] is installed on your proxy, can you also use placeholders from [PlaceholderAPI][placeholderapi] using its `%<identifier>_<values>%` placeholder format. PlaceholderAPI needs to be installed on the server (not proxy) for that.
|
||||
|
||||
If you're a plugin dev can you even add your own custom placeholders through AdvancedServerList's own API.
|
||||
|
||||
> [*Read More*][placeholders]
|
||||
|
||||
### Formatting
|
||||
|
||||
The plugin uses the MiniMessage format for a consistent, easy way of formatting your text.
|
||||
Only certain options are usable for each option. As an example does motd support HEX colours and gradients, while the other options only support default colour codes.
|
||||
|
||||
@@ -61,13 +64,14 @@ Only certain options are usable for each option. As an example does motd support
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Dependency | Platforms | Required? |
|
||||
|-------------------|----------------------|-----------|
|
||||
| [ProtocolLib] | Spigot | Yes |
|
||||
| [PlaceholderAPI] | Spigot, Paper | No |
|
||||
| [ViaVersion] | Spigot, Paper | No |
|
||||
| [PAPIProxyBridge] | BungeeCord, Velocity | No |
|
||||
| [Maintenance] | All | No |
|
||||
All listed dependencies are optional.
|
||||
|
||||
| Dependency | Platforms |
|
||||
|-------------------|----------------------|
|
||||
| [PlaceholderAPI] | Paper |
|
||||
| [ViaVersion] | Paper |
|
||||
| [PAPIProxyBridge] | BungeeCord, Velocity |
|
||||
| [Maintenance] | All |
|
||||
|
||||
## Statistics
|
||||
|
||||
@@ -98,13 +102,12 @@ You can disable this in the global bStats config file located in `/plugins/bstat
|
||||
|
||||
<!-- Links -->
|
||||
[profiles]: https://asl.andre601.ch/profiles/
|
||||
[conditions]: https://asl.andre601.ch/profiles/#conditions
|
||||
[conditions]: https://asl.andre601.ch/profiles/#condition
|
||||
[placeholders]: https://asl.andre601.ch/profiles/placeholders/
|
||||
[minimessage]: https://asl.andre601.ch/profiles/formatting/
|
||||
|
||||
[modrinth]: https://modrinth.com/plugin/advancedserverlist
|
||||
|
||||
[protocollib]: https://hangar.papermc.io/dmulloy2/ProtocolLib
|
||||
[placeholderapi]: https://hangar.papermc.io/HelpChat/PlaceholderAPI
|
||||
[viaversion]: https://hangar.papermc.io/ViaVersion/ViaVersion
|
||||
[papiproxybridge]: https://hangar.papermc.io/William278/PAPIProxyBridge
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ MIT License
|
||||
~
|
||||
~ Copyright (c) 2022-2024 Andre_601
|
||||
~
|
||||
~ Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
~ of this software and associated documentation files (the "Software"), to deal
|
||||
~ in the Software without restriction, including without limitation the rights
|
||||
~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
~ copies of the Software, and to permit persons to whom the Software is
|
||||
~ furnished to do so, subject to the following conditions:
|
||||
~
|
||||
~ The above copyright notice and this permission notice shall be included in all
|
||||
~ copies or substantial portions of the Software.
|
||||
~
|
||||
~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
~ SOFTWARE.
|
||||
~
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>parent</artifactId>
|
||||
<groupId>ch.andre601.advancedserverlist</groupId>
|
||||
<version>parent</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>banplugins</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>${plugin.version}</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>16</maven.compiler.source>
|
||||
<maven.compiler.target>16</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>sonatype</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>papermc</id>
|
||||
<url>https://papermc.io/repo/repository/maven-public/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<!-- Proxy/Server -->
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>1.20-R0.2</version>
|
||||
<type>jar</type>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>1.20-R0.2</version>
|
||||
<type>javadoc</type>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.papermc.paper</groupId>
|
||||
<artifactId>paper-api</artifactId>
|
||||
<version>1.20-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Plugin APIs -->
|
||||
<dependency>
|
||||
<groupId>com.github.DevLeoko</groupId>
|
||||
<artifactId>AdvancedBan</artifactId>
|
||||
<version>v2.3.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.andre601.asl-api</groupId>
|
||||
<artifactId>api</artifactId>
|
||||
<version>${api.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>AdvancedServerList-BanPlugins-Addon-${plugin.version}</finalName>
|
||||
<resources>
|
||||
<resource>
|
||||
<filtering>true</filtering>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.12.1</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.banplugins.bungeecord;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.banplugins.placeholders.AdvancedBanPlaceholders;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public enum BungeeCordBanPlugins{
|
||||
|
||||
ADVANCED_BAN("AdvancedBan", new AdvancedBanPlaceholders());
|
||||
|
||||
private final String plugin;
|
||||
private final PlaceholderProvider placeholderProvider;
|
||||
|
||||
BungeeCordBanPlugins(String plugin, PlaceholderProvider placeholderProvider){
|
||||
this.plugin = plugin;
|
||||
this.placeholderProvider = placeholderProvider;
|
||||
}
|
||||
|
||||
public static Map<String, PlaceholderProvider> getBanPlugins(){
|
||||
Map<String, PlaceholderProvider> content = new HashMap<>();
|
||||
|
||||
for(BungeeCordBanPlugins bungeeCordBanPlugins : BungeeCordBanPlugins.values()){
|
||||
content.put(bungeeCordBanPlugins.plugin, bungeeCordBanPlugins.placeholderProvider);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.banplugins.bungeecord;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.AdvancedServerListAPI;
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class BungeeCordBanPluginsAddon extends Plugin{
|
||||
|
||||
@Override
|
||||
public void onEnable(){
|
||||
if(getProxy().getPluginManager().getPlugin("AdvancedServerList") == null){
|
||||
getLogger().warning("AdvancedServerList is not enabled. This plugin requires it to function!");
|
||||
return;
|
||||
}
|
||||
|
||||
int loadedPlaceholders = loadPlaceholderProviders();
|
||||
if(loadedPlaceholders == 0){
|
||||
getLogger().warning("No compatible Ban plugin was found to register placeholders for.");
|
||||
}else{
|
||||
getLogger().info("Loaded " + loadedPlaceholders + " Placeholder Set(s) for AdvancedServerList!");
|
||||
}
|
||||
}
|
||||
|
||||
private int loadPlaceholderProviders(){
|
||||
int loaded = 0;
|
||||
Map<String, PlaceholderProvider> banPlugins = BungeeCordBanPlugins.getBanPlugins();
|
||||
AdvancedServerListAPI api = AdvancedServerListAPI.get();
|
||||
|
||||
for(Map.Entry<String, PlaceholderProvider> entry : banPlugins.entrySet()){
|
||||
if(getProxy().getPluginManager().getPlugin(entry.getKey()) != null){
|
||||
getLogger().info("Registering Placeholders for " + entry.getKey() + "...");
|
||||
api.addPlaceholderProvider(entry.getValue());
|
||||
getLogger().info("Placeholder successfully registered!");
|
||||
|
||||
loaded++;
|
||||
}
|
||||
}
|
||||
|
||||
return loaded;
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.banplugins.paper;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.banplugins.placeholders.AdvancedBanPlaceholders;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public enum PaperBanPlugins{
|
||||
|
||||
ADVANCED_BAN("AdvancedBan", new AdvancedBanPlaceholders());
|
||||
|
||||
private final String plugin;
|
||||
private final PlaceholderProvider placeholderProvider;
|
||||
|
||||
PaperBanPlugins(String plugin, PlaceholderProvider placeholderProvider){
|
||||
this.plugin = plugin;
|
||||
this.placeholderProvider = placeholderProvider;
|
||||
}
|
||||
|
||||
public static Map<String, PlaceholderProvider> getBanPlugins(){
|
||||
Map<String, PlaceholderProvider> content = new HashMap<>();
|
||||
|
||||
for(PaperBanPlugins paperBanPlugins : PaperBanPlugins.values()){
|
||||
content.put(paperBanPlugins.plugin, paperBanPlugins.placeholderProvider);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.banplugins.paper;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.AdvancedServerListAPI;
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class PaperBanPluginsAddon extends JavaPlugin{
|
||||
|
||||
@Override
|
||||
public void onEnable(){
|
||||
if(!getServer().getPluginManager().isPluginEnabled("AdvancedServerList")){
|
||||
getLogger().warning("AdvancedServerList is not enabled. This plugin requires it to function!");
|
||||
getServer().getPluginManager().disablePlugin(this);
|
||||
return;
|
||||
}
|
||||
|
||||
int loadedPlaceholders = loadPlaceholderProviders();
|
||||
if(loadedPlaceholders == 0){
|
||||
getLogger().warning("No compatible Ban plugin was found to register placeholders for. Disabling plugin...");
|
||||
|
||||
getServer().getPluginManager().disablePlugin(this);
|
||||
}else{
|
||||
getLogger().info("Loaded " + loadedPlaceholders + " Placeholder Set(s) for AdvancedServerList!");
|
||||
}
|
||||
}
|
||||
|
||||
private int loadPlaceholderProviders(){
|
||||
int loaded = 0;
|
||||
Map<String, PlaceholderProvider> banPlugins = PaperBanPlugins.getBanPlugins();
|
||||
AdvancedServerListAPI api = AdvancedServerListAPI.get();
|
||||
|
||||
for(Map.Entry<String, PlaceholderProvider> entry : banPlugins.entrySet()){
|
||||
if(getServer().getPluginManager().isPluginEnabled(entry.getKey())){
|
||||
getLogger().info("Registering Placeholders for " + entry.getKey() + "...");
|
||||
api.addPlaceholderProvider(entry.getValue());
|
||||
getLogger().info("Placeholder successfully registered!");
|
||||
|
||||
loaded++;
|
||||
}
|
||||
}
|
||||
|
||||
return loaded;
|
||||
}
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.banplugins.placeholders;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.banplugins.providers.AdvancedBanProvider;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class AdvancedBanPlaceholders extends PlaceholderProvider{
|
||||
|
||||
private final AdvancedBanProvider provider = new AdvancedBanProvider();
|
||||
|
||||
public AdvancedBanPlaceholders(){
|
||||
super("advancedban");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
|
||||
String[] args = placeholder.split("\\s");
|
||||
|
||||
return switch(args[0]) {
|
||||
// Mute-related placeholders
|
||||
case "isMuted" -> String.valueOf(provider.muted(player));
|
||||
case "muteReason" -> provider.muteReason(player);
|
||||
case "muteDuration" -> {
|
||||
if(args.length == 1)
|
||||
yield provider.muteDuration(player);
|
||||
|
||||
if(args.length > 2)
|
||||
yield null;
|
||||
|
||||
boolean fromStart = Boolean.getBoolean(args[1]);
|
||||
yield provider.muteDuration(player, fromStart);
|
||||
}
|
||||
case "muteExpiration" -> {
|
||||
if(args.length == 1)
|
||||
yield provider.muteExpirationDate(player);
|
||||
|
||||
String pattern = String.join(" ", Arrays.copyOfRange(args, 1, args.length));
|
||||
|
||||
yield provider.banExpirationDate(player, pattern);
|
||||
}
|
||||
|
||||
// Ban-related placeholders
|
||||
case "isBanned" -> String.valueOf(provider.banned(player));
|
||||
case "banReason" -> provider.banReason(player);
|
||||
case "banDuration" -> {
|
||||
if(args.length == 1)
|
||||
yield provider.banDuration(player);
|
||||
|
||||
if(args.length > 2)
|
||||
yield null;
|
||||
|
||||
boolean fromStart = Boolean.getBoolean(args[1]);
|
||||
yield provider.banDuration(player, fromStart);
|
||||
}
|
||||
case "banExpiration" -> {
|
||||
if(args.length == 1)
|
||||
yield provider.banExpirationDate(player);
|
||||
|
||||
String pattern = String.join(" ", Arrays.copyOfRange(args, 1, args.length));
|
||||
|
||||
yield provider.banExpirationDate(player, pattern);
|
||||
}
|
||||
|
||||
// Unknown/Invalid placeholder.
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
}
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.banplugins.providers;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.primitives.UnsignedLongs;
|
||||
import me.leoko.advancedban.manager.PunishmentManager;
|
||||
import me.leoko.advancedban.utils.Punishment;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
public class AdvancedBanProvider implements PunishmentProvider{
|
||||
|
||||
private static PunishmentManager getAPI(){
|
||||
return PunishmentManager.get();
|
||||
}
|
||||
|
||||
private static String noDashesUUID(UUID uuid){
|
||||
return hexString(uuid.getMostSignificantBits()) + hexString(uuid.getLeastSignificantBits());
|
||||
}
|
||||
|
||||
private static Punishment mute(GenericPlayer player){
|
||||
return getAPI().getMute(noDashesUUID(player.getUUID()));
|
||||
}
|
||||
|
||||
private static Punishment ban(GenericPlayer player){
|
||||
return getAPI().getBan(noDashesUUID(player.getUUID()));
|
||||
}
|
||||
|
||||
private static String hexString(long unsigned){
|
||||
return Strings.padStart(UnsignedLongs.toString(unsigned, 16), 16, '0');
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean muted(GenericPlayer player){
|
||||
return getAPI().isMuted(noDashesUUID(player.getUUID()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean banned(GenericPlayer player){
|
||||
return getAPI().isBanned(noDashesUUID(player.getUUID()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String muteReason(GenericPlayer player){
|
||||
Punishment mute = mute(player);
|
||||
if(mute == null)
|
||||
return null;
|
||||
|
||||
return mute.getReason();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String banReason(GenericPlayer player){
|
||||
Punishment ban = ban(player);
|
||||
if(ban == null)
|
||||
return null;
|
||||
|
||||
return ban.getReason();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String muteDuration(GenericPlayer player){
|
||||
return muteDuration(player, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String banDuration(GenericPlayer player){
|
||||
return banDuration(player, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String muteExpirationDate(GenericPlayer player, String pattern){
|
||||
Punishment mute = mute(player);
|
||||
if(mute == null)
|
||||
return null;
|
||||
|
||||
long end = mute.getEnd();
|
||||
if(end < 0L)
|
||||
return "never";
|
||||
|
||||
Date date = new Date(end);
|
||||
return new SimpleDateFormat(pattern).format(date);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String banExpirationDate(GenericPlayer player, String pattern){
|
||||
Punishment ban = ban(player);
|
||||
if(ban == null)
|
||||
return null;
|
||||
|
||||
long end = ban.getEnd();
|
||||
if(end < 0L)
|
||||
return "never";
|
||||
|
||||
Date date = new Date(end);
|
||||
return new SimpleDateFormat(pattern).format(date);
|
||||
}
|
||||
|
||||
public String muteDuration(GenericPlayer player, boolean fromStart){
|
||||
Punishment mute = mute(player);
|
||||
if(mute == null)
|
||||
return null;
|
||||
|
||||
return mute.getDuration(fromStart);
|
||||
}
|
||||
|
||||
public String banDuration(GenericPlayer player, boolean fromStart){
|
||||
Punishment ban = ban(player);
|
||||
if(ban == null)
|
||||
return null;
|
||||
|
||||
return ban.getDuration(fromStart);
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.banplugins.providers;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
|
||||
public interface PunishmentProvider{
|
||||
|
||||
boolean muted(GenericPlayer player);
|
||||
|
||||
boolean banned(GenericPlayer player);
|
||||
|
||||
String muteReason(GenericPlayer player);
|
||||
|
||||
String banReason(GenericPlayer player);
|
||||
|
||||
String muteDuration(GenericPlayer player);
|
||||
|
||||
String banDuration(GenericPlayer player);
|
||||
|
||||
default String muteExpirationDate(GenericPlayer player){
|
||||
return muteExpirationDate(player, "dd, MMM yyyy HH:mm:ss");
|
||||
}
|
||||
|
||||
String muteExpirationDate(GenericPlayer player, String pattern);
|
||||
|
||||
default String banExpirationDate(GenericPlayer player){
|
||||
return banExpirationDate(player, "dd, MMM yyyy HH:mm:ss");
|
||||
}
|
||||
|
||||
String banExpirationDate(GenericPlayer player, String pattern);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
name: 'ASLBanPluginsAddon'
|
||||
author: 'Andre_601'
|
||||
version: '${plugin.version}'
|
||||
description: 'AdvancedBan Add-on for AdvancedServerList to add placeholders to use.'
|
||||
|
||||
softDepends:
|
||||
- AdvancedServerList
|
||||
- AdvancedBan
|
||||
|
||||
main: 'ch.andre601.advancedserverlist.banplugins.bungeecord.BungeeCordBanPluginsAddon'
|
||||
@@ -0,0 +1,16 @@
|
||||
name: 'ASLBanPluginsAddon'
|
||||
author: 'Andre_601'
|
||||
version: '${plugin.version}'
|
||||
|
||||
main: 'ch.andre601.advancedserverlist.banplugins.paper.AdvancedBanPlaceholders'
|
||||
|
||||
api-version: '1.19'
|
||||
|
||||
dependencies:
|
||||
server:
|
||||
AdvancedServerList:
|
||||
required: false
|
||||
load: BEFORE
|
||||
AdvancedBans:
|
||||
required: false
|
||||
load: BEFORE
|
||||
-75
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.bukkit.commands;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
|
||||
import ch.andre601.advancedserverlist.paper.commands.PaperCmdSender;
|
||||
import ch.andre601.advancedserverlist.spigot.commands.SpigotCmdSender;
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
public class CmdAdvancedServerList extends Command implements CommandExecutor{
|
||||
|
||||
private final PluginCore<?> plugin;
|
||||
private final BukkitAudiences audiences;
|
||||
|
||||
public CmdAdvancedServerList(PluginCore<?> plugin){
|
||||
this(plugin, null);
|
||||
}
|
||||
|
||||
public CmdAdvancedServerList(PluginCore<?> plugin, BukkitAudiences audiences){
|
||||
super(
|
||||
"advancedserverlist",
|
||||
"Main command of the plugin",
|
||||
"/asl [reload|help|clearCache]",
|
||||
Collections.singletonList("asl")
|
||||
);
|
||||
|
||||
this.plugin = plugin;
|
||||
this.audiences = audiences;
|
||||
}
|
||||
|
||||
public boolean execute(@NotNull CommandSender sender, @NotNull String s, @NotNull String[] args){
|
||||
plugin.getCore().getCommandHandler().handle(getSender(sender), args);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command cmd, @NotNull String label, @NotNull String[] args){
|
||||
plugin.getCore().getCommandHandler().handle(getSender(sender), args);
|
||||
return true;
|
||||
}
|
||||
|
||||
private CmdSender getSender(CommandSender sender){
|
||||
return audiences == null ? new PaperCmdSender(sender) : new SpigotCmdSender(sender, audiences);
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.bukkit.listeners;
|
||||
|
||||
import ch.andre601.advancedserverlist.bukkit.BukkitCore;
|
||||
import ch.andre601.advancedserverlist.bukkit.objects.placeholders.PAPIPlaceholders;
|
||||
import ch.andre601.advancedserverlist.spigot.SpigotCore;
|
||||
import ch.andre601.advancedserverlist.spigot.listeners.ProtocolLibEvents;
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.server.ServerLoadEvent;
|
||||
|
||||
public class LoadEvent implements Listener{
|
||||
|
||||
private final BukkitCore<?> plugin;
|
||||
|
||||
private LoadEvent(BukkitCore<?> plugin){
|
||||
this.plugin = plugin;
|
||||
plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
||||
}
|
||||
|
||||
public static void init(BukkitCore<?> plugin){
|
||||
new LoadEvent(plugin);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onServerLoad(ServerLoadEvent event){
|
||||
JoinEvent.init(plugin);
|
||||
WorldEvents.init(plugin);
|
||||
|
||||
// Populate WorldCache with all loaded worlds
|
||||
Bukkit.getWorlds().forEach(world -> plugin.getWorldCache().addWorld(world.getName(), world));
|
||||
|
||||
if(!(plugin instanceof SpigotCore spigotCore))
|
||||
return;
|
||||
|
||||
if(!Bukkit.getPluginManager().isPluginEnabled("ProtocolLib")){
|
||||
plugin.getCore().getPlugin().getPluginLogger().warn("ProtocolLib not found! AdvancedServerList requires it to work on Spigot!");
|
||||
|
||||
Bukkit.getPluginManager().disablePlugin(plugin);
|
||||
return;
|
||||
}
|
||||
|
||||
ProtocolLibEvents.init(spigotCore, ProtocolLibrary.getProtocolManager());
|
||||
|
||||
if(Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI"))
|
||||
spigotCore.setPapiPlaceholders(PAPIPlaceholders.init(spigotCore));
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.paper;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
|
||||
import io.papermc.paper.plugin.loader.PluginClasspathBuilder;
|
||||
import io.papermc.paper.plugin.loader.PluginLoader;
|
||||
import io.papermc.paper.plugin.loader.library.impl.MavenLibraryResolver;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.logger.slf4j.ComponentLogger;
|
||||
import org.eclipse.aether.artifact.DefaultArtifact;
|
||||
import org.eclipse.aether.graph.Dependency;
|
||||
import org.eclipse.aether.repository.RemoteRepository;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ASLLoader implements PluginLoader{
|
||||
@Override
|
||||
public void classloader(@NotNull PluginClasspathBuilder pluginClasspathBuilder){
|
||||
ComponentLogger logger = pluginClasspathBuilder.getContext().getLogger();
|
||||
|
||||
logger.info(Component.text("Loading Libraries for plugin..."));
|
||||
|
||||
MavenLibraryResolver resolver = new MavenLibraryResolver();
|
||||
|
||||
resolver.addRepository(new RemoteRepository.Builder(
|
||||
"paper-maven",
|
||||
"default",
|
||||
"https://repo.papermc.io/repository/maven-public/"
|
||||
).build());
|
||||
|
||||
logger.info(Component.text("Loading com.squareup.okhttp3:okhttp:4.10.0 from repo.papermc.io..."));
|
||||
|
||||
resolver.addDependency(new Dependency(new DefaultArtifact("com.squareup.okhttp3:okhttp:4.10.0"), null));
|
||||
pluginClasspathBuilder.addLibrary(resolver);
|
||||
|
||||
logger.info(Component.text("Loading libraries complete!"));
|
||||
}
|
||||
}
|
||||
@@ -1,178 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.spigot;
|
||||
|
||||
import ch.andre601.advancedserverlist.bukkit.BukkitCore;
|
||||
import ch.andre601.advancedserverlist.bukkit.commands.CmdAdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.bukkit.logging.BukkitLogger;
|
||||
import ch.andre601.advancedserverlist.bukkit.objects.placeholders.BukkitPlayerPlaceholders;
|
||||
import ch.andre601.advancedserverlist.bukkit.objects.placeholders.BukkitServerPlaceholders;
|
||||
import ch.andre601.advancedserverlist.bukkit.objects.placeholders.PAPIPlaceholders;
|
||||
import ch.andre601.advancedserverlist.bukkit.objects.WorldCache;
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import ch.andre601.advancedserverlist.core.profiles.favicon.FaviconHandler;
|
||||
import ch.andre601.advancedserverlist.bukkit.listeners.LoadEvent;
|
||||
import com.comphenix.protocol.wrappers.WrappedServerPing;
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||
import org.bstats.bukkit.Metrics;
|
||||
import org.bstats.charts.SimplePie;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class SpigotCore extends BukkitCore<WrappedServerPing.CompressedImage>{
|
||||
|
||||
private final PluginLogger logger = new BukkitLogger(getLogger());
|
||||
|
||||
private AdvancedServerList<WrappedServerPing.CompressedImage> core;
|
||||
private FaviconHandler<WrappedServerPing.CompressedImage> faviconHandler = null;
|
||||
private PAPIPlaceholders<WrappedServerPing.CompressedImage> papiPlaceholders = null;
|
||||
private WorldCache worldCache = null;
|
||||
|
||||
@Override
|
||||
public void onEnable(){
|
||||
try{
|
||||
Class.forName("io.papermc.paper.configuration.ConfigurationLoaders");
|
||||
|
||||
printPaperInfo();
|
||||
}catch(ClassNotFoundException ex){
|
||||
try{
|
||||
// Above class only exists since 1.19+, so this is a fallback for older versions.
|
||||
Class.forName("com.destroystokyo.paper.PaperConfig");
|
||||
|
||||
printPaperInfo();
|
||||
}catch(ClassNotFoundException ignored){}
|
||||
}
|
||||
|
||||
this.core = AdvancedServerList.init(this, BukkitPlayerPlaceholders.init(), BukkitServerPlaceholders.init());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable(){
|
||||
if(papiPlaceholders != null){
|
||||
papiPlaceholders.unregister();
|
||||
papiPlaceholders = null;
|
||||
}
|
||||
|
||||
if(worldCache != null)
|
||||
worldCache = null;
|
||||
|
||||
getCore().disable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadCommands(){
|
||||
PluginCommand cmd = getServer().getPluginCommand("advancedserverlist");
|
||||
if(cmd == null){
|
||||
getPluginLogger().warn("Unable to register command /advancedserverlist");
|
||||
return;
|
||||
}
|
||||
cmd.setExecutor(new CmdAdvancedServerList(this, BukkitAudiences.create(this)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadEvents(){
|
||||
LoadEvent.init(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadMetrics(){
|
||||
new Metrics(this, 15584).addCustomChart(new SimplePie("profiles",
|
||||
() -> String.valueOf(core.getFileHandler().getProfiles().size())
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearFaviconCache(){
|
||||
if(faviconHandler == null)
|
||||
return;
|
||||
|
||||
faviconHandler.clearCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AdvancedServerList<WrappedServerPing.CompressedImage> getCore(){
|
||||
return core;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getFolderPath(){
|
||||
return getDataFolder().toPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginLogger getPluginLogger(){
|
||||
return logger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FaviconHandler<WrappedServerPing.CompressedImage> getFaviconHandler(){
|
||||
if(faviconHandler == null)
|
||||
faviconHandler = new FaviconHandler<>(core);
|
||||
|
||||
return faviconHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlatformName(){
|
||||
return getServer().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlatformVersion(){
|
||||
return getServer().getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLoader(){
|
||||
return "spigot";
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorldCache getWorldCache(){
|
||||
if(worldCache != null)
|
||||
return worldCache;
|
||||
|
||||
return (worldCache = new WorldCache());
|
||||
}
|
||||
|
||||
public void setPapiPlaceholders(PAPIPlaceholders<WrappedServerPing.CompressedImage> papiPlaceholders){
|
||||
this.papiPlaceholders = papiPlaceholders;
|
||||
}
|
||||
|
||||
private void printPaperInfo(){
|
||||
getPluginLogger().warn("======================================================================================");
|
||||
getPluginLogger().warn("You are using the Spigot version of AdvancedServerList on a Paper server.");
|
||||
getPluginLogger().warn("It is recommended to use the dedicated Paper version, to benefit from the");
|
||||
getPluginLogger().warn("following improvements:");
|
||||
getPluginLogger().warn(" - No downloading of external Libraries already provided by Paper (i.e. Adventure).");
|
||||
getPluginLogger().warn(" - No dependency on ProtocolLib thanks to provided Events.");
|
||||
getPluginLogger().warn("");
|
||||
getPluginLogger().warn("AdvancedServerList may work as normal, but consider using the PaperMC version instead!");
|
||||
getPluginLogger().warn("======================================================================================");
|
||||
}
|
||||
}
|
||||
-203
@@ -1,203 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.spigot.listeners;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.events.GenericServerListEvent;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.bukkit.BukkitCore;
|
||||
import ch.andre601.advancedserverlist.bukkit.listeners.PreServerListSetEventImpl;
|
||||
import ch.andre601.advancedserverlist.bukkit.objects.impl.BukkitServerImpl;
|
||||
import ch.andre601.advancedserverlist.core.events.PingEventHandler;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.events.GenericEventWrapper;
|
||||
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
|
||||
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
|
||||
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
|
||||
import ch.andre601.advancedserverlist.spigot.SpigotCore;
|
||||
import ch.andre601.advancedserverlist.bukkit.objects.impl.BukkitPlayerImpl;
|
||||
import com.comphenix.protocol.events.PacketEvent;
|
||||
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
||||
import com.comphenix.protocol.wrappers.WrappedGameProfile;
|
||||
import com.comphenix.protocol.wrappers.WrappedServerPing;
|
||||
import me.clip.placeholderapi.PlaceholderAPI;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.*;
|
||||
|
||||
public class ProtocolLibEventWrapper implements GenericEventWrapper<WrappedServerPing.CompressedImage, BukkitPlayerImpl>{
|
||||
|
||||
private final SpigotCore plugin;
|
||||
private final PacketEvent event;
|
||||
private final WrappedServerPing ping;
|
||||
|
||||
public ProtocolLibEventWrapper(SpigotCore plugin, PacketEvent event){
|
||||
this.plugin = plugin;
|
||||
this.event = event;
|
||||
this.ping = event.getPacket().getServerPings().read(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GenericServerListEvent callEvent(ProfileEntry entry){
|
||||
PreServerListSetEventImpl event = new PreServerListSetEventImpl(entry);
|
||||
plugin.getServer().getPluginManager().callEvent(event);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxPlayers(int maxPlayers){
|
||||
ping.setPlayersMaximum(maxPlayers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMotd(Component component){
|
||||
ping.setMotD(WrappedChatComponent.fromJson(GsonComponentSerializer.gson().serialize(component)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hidePlayers(){
|
||||
ping.setPlayersVisible(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerCount(String name){
|
||||
ping.setVersionName(name);
|
||||
ping.setVersionProtocol(-1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayers(List<String> lines, BukkitPlayerImpl player, GenericServer server){
|
||||
List<WrappedGameProfile> players = new ArrayList<>(lines.size());
|
||||
|
||||
for(String line : lines){
|
||||
String parsed = ComponentParser.text(line)
|
||||
.modifyText(text -> StringReplacer.replace(text, player, server))
|
||||
.modifyText(text -> {
|
||||
if(plugin.getServer().getPluginManager().isPluginEnabled("PlaceholderAPI"))
|
||||
return PlaceholderAPI.setPlaceholders(player.getPlayer(), text);
|
||||
|
||||
return text;
|
||||
})
|
||||
.toString();
|
||||
|
||||
players.add(new WrappedGameProfile(UUID.randomUUID(), parsed));
|
||||
}
|
||||
|
||||
ping.setPlayers(players);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFavicon(WrappedServerPing.CompressedImage favicon){
|
||||
ping.setFavicon(favicon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultFavicon(){
|
||||
ping.setFavicon(ping.getFavicon());
|
||||
}
|
||||
|
||||
// Not used in ProtocolLib
|
||||
@Override
|
||||
public void updateEvent(){
|
||||
event.getPacket().getServerPings().write(0, ping);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInvalidProtocol(){
|
||||
return event.getPlayer().getAddress() == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMaintenanceModeActive(){
|
||||
if(!Bukkit.getPluginManager().isPluginEnabled("Maintenance"))
|
||||
return false;
|
||||
|
||||
return PingEventHandler.getMaintenanceUtil().isMaintenanceEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtocolVersion(){
|
||||
return ping.getVersionProtocol();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOnlinePlayers(){
|
||||
return ping.getPlayersOnline();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxPlayers(){
|
||||
return ping.getPlayersMaximum();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPlayerIP(){
|
||||
return event.getPlayer().getAddress() == null ? "UNKNOWN" : event.getPlayer().getAddress().getHostString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parsePAPIPlaceholders(String text, BukkitPlayerImpl player){
|
||||
if(plugin.getServer().getPluginManager().isPluginEnabled("PlaceholderAPI"))
|
||||
return PlaceholderAPI.setPlaceholders(player.getPlayer(), text);
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVirtualHost(){
|
||||
String host = this.resolveHost(event.getPlayer().getAddress());
|
||||
if(host == null)
|
||||
return null;
|
||||
|
||||
return ProtocolLibEvents.getHostAddresses().get(host);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BukkitCore<WrappedServerPing.CompressedImage> getPlugin(){
|
||||
return plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BukkitPlayerImpl createPlayer(CachedPlayer player, int protocol){
|
||||
OfflinePlayer pl = Bukkit.getOfflinePlayer(player.getUuid());
|
||||
|
||||
return new BukkitPlayerImpl(pl.hasPlayedBefore() ? pl : null, player, protocol);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GenericServer createGenericServer(int playersOnline, int playersMax, String host){
|
||||
return new BukkitServerImpl(plugin.getWorldCache().worlds(), playersOnline, playersMax, host);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WrappedServerPing.CompressedImage createFavicon(BufferedImage image) throws Exception{
|
||||
return WrappedServerPing.CompressedImage.fromPng(image);
|
||||
}
|
||||
}
|
||||
-84
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.spigot.listeners;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.events.PingEventHandler;
|
||||
import ch.andre601.advancedserverlist.spigot.SpigotCore;
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.ProtocolManager;
|
||||
import com.comphenix.protocol.events.ListenerPriority;
|
||||
import com.comphenix.protocol.events.PacketAdapter;
|
||||
import com.comphenix.protocol.events.PacketEvent;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public class ProtocolLibEvents implements Listener{
|
||||
|
||||
private final ProtocolManager protocolManager;
|
||||
|
||||
private static final Map<String, String> hostAddresses = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||
|
||||
private ProtocolLibEvents(SpigotCore plugin, ProtocolManager protocolManager){
|
||||
this.protocolManager = protocolManager;
|
||||
|
||||
loadPacketListener(plugin);
|
||||
Bukkit.getPluginManager().registerEvents(this, plugin);
|
||||
}
|
||||
|
||||
public static void init(SpigotCore plugin, ProtocolManager protocolManager){
|
||||
new ProtocolLibEvents(plugin, protocolManager);
|
||||
}
|
||||
|
||||
public static Map<String, String> getHostAddresses(){
|
||||
return hostAddresses;
|
||||
}
|
||||
|
||||
private void loadPacketListener(SpigotCore spigotPlugin){
|
||||
protocolManager.addPacketListener(new PacketAdapter(spigotPlugin, ListenerPriority.LOW, PacketType.Handshake.Client.SET_PROTOCOL){
|
||||
@Override
|
||||
public void onPacketReceiving(PacketEvent event){
|
||||
InetSocketAddress address = event.getPlayer().getAddress();
|
||||
if(address == null)
|
||||
return;
|
||||
|
||||
String host = event.getPacket().getStrings().read(0);
|
||||
|
||||
hostAddresses.put(address.getHostString(), host);
|
||||
}
|
||||
});
|
||||
|
||||
protocolManager.addPacketListener(new PacketAdapter(spigotPlugin, ListenerPriority.LOW, PacketType.Status.Server.SERVER_INFO){
|
||||
@Override
|
||||
public void onPacketSending(PacketEvent event){
|
||||
PingEventHandler.handleEvent(new ProtocolLibEventWrapper(spigotPlugin, event));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
+7
-17
@@ -67,33 +67,33 @@
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>1.20-R0.1</version>
|
||||
<version>1.20-R0.2</version>
|
||||
<type>jar</type>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>1.20-R0.1</version>
|
||||
<version>1.20-R0.2</version>
|
||||
<type>javadoc</type>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-api</artifactId>
|
||||
<version>4.14.0</version>
|
||||
<version>4.16.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-text-minimessage</artifactId>
|
||||
<version>4.14.0</version>
|
||||
<version>4.16.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-platform-bungeecord</artifactId>
|
||||
<version>4.3.1</version>
|
||||
<version>4.3.2</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -108,12 +108,6 @@
|
||||
<version>4.1.2</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>4.11.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
@@ -128,12 +122,12 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.11.0</version>
|
||||
<version>3.12.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<version>3.5.2</version>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<relocations>
|
||||
@@ -149,10 +143,6 @@
|
||||
<pattern>org.bstats</pattern>
|
||||
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.bstats</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>okhttp3</pattern>
|
||||
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.okhttp3</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
<filters>
|
||||
<filter>
|
||||
|
||||
+13
-2
@@ -40,13 +40,14 @@ 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;
|
||||
|
||||
public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
|
||||
|
||||
private AdvancedServerList<Favicon> core;
|
||||
private FaviconHandler<Favicon> faviconHandler = null;
|
||||
private final PluginLogger logger = new BungeeLogger(getLogger());
|
||||
private final PluginLogger logger = new BungeeLogger(this);
|
||||
|
||||
@Override
|
||||
public void onEnable(){
|
||||
@@ -77,12 +78,17 @@ public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadFaviconHandler(AdvancedServerList<Favicon> core){
|
||||
faviconHandler = new FaviconHandler<>(core);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearFaviconCache(){
|
||||
if(faviconHandler == null)
|
||||
return;
|
||||
|
||||
faviconHandler.clearCache();
|
||||
faviconHandler.cleanCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -122,4 +128,9 @@ public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
|
||||
public String getLoader(){
|
||||
return "bungeecord";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Favicon createFavicon(BufferedImage image) throws IllegalArgumentException{
|
||||
return Favicon.create(image);
|
||||
}
|
||||
}
|
||||
+1
-7
@@ -25,11 +25,11 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.bungeecord.listeners;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.events.GenericServerListEvent;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
|
||||
import ch.andre601.advancedserverlist.bungeecord.objects.BungeePlayerImpl;
|
||||
import ch.andre601.advancedserverlist.api.events.GenericServerListEvent;
|
||||
import ch.andre601.advancedserverlist.bungeecord.objects.BungeeProxyImpl;
|
||||
import ch.andre601.advancedserverlist.core.events.PingEventHandler;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
|
||||
@@ -46,7 +46,6 @@ import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.ProxyPingEvent;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -205,9 +204,4 @@ public class BungeeEventWrapper implements GenericEventWrapper<Favicon, BungeePl
|
||||
|
||||
return new BungeeProxyImpl(servers, playersOnline, playersMax, host);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Favicon createFavicon(BufferedImage image) throws IllegalArgumentException{
|
||||
return Favicon.create(image);
|
||||
}
|
||||
}
|
||||
+17
-2
@@ -25,6 +25,7 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.bungeecord.logging;
|
||||
|
||||
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
|
||||
import java.util.logging.Level;
|
||||
@@ -32,10 +33,24 @@ import java.util.logging.Logger;
|
||||
|
||||
public class BungeeLogger implements PluginLogger{
|
||||
|
||||
private final BungeeCordCore plugin;
|
||||
private final Logger logger;
|
||||
|
||||
public BungeeLogger(Logger logger){
|
||||
this.logger = logger;
|
||||
public BungeeLogger(BungeeCordCore plugin){
|
||||
this.plugin = plugin;
|
||||
this.logger = plugin.getLogger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Class<?> clazz, String msg, Object... args){
|
||||
if(plugin.isDebugEnabled())
|
||||
info("[DEBUG] [" + clazz.getSimpleName() + "] " + msg, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debugWarn(Class<?> clazz, String msg, Object... args){
|
||||
if(plugin.isDebugEnabled())
|
||||
warn("[DEBUG] [" + clazz.getSimpleName() + "] " + msg, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+9
-3
@@ -53,10 +53,14 @@ public class BungeeServerPlaceholders extends PlaceholderProvider{
|
||||
return switch(args[0]){
|
||||
case "playersOnline" -> {
|
||||
if(args.length >= 2){
|
||||
int players = 0;
|
||||
String[] servers = args[1].split(",");
|
||||
|
||||
for(int i = 1; i < args.length; i++){
|
||||
ServerInfo info = proxy.getServers().get(args[i]);
|
||||
int players = 0;
|
||||
for(String serverName : servers){
|
||||
if(serverName.isEmpty())
|
||||
continue;
|
||||
|
||||
ServerInfo info = proxy.getServers().get(serverName.strip());
|
||||
if(info == null)
|
||||
continue;
|
||||
|
||||
@@ -81,6 +85,8 @@ public class BungeeServerPlaceholders extends PlaceholderProvider{
|
||||
|
||||
if(args.length == 2){
|
||||
ServerInfo info = proxy.getServers().get(args[1]);
|
||||
if(info == null)
|
||||
yield null;
|
||||
|
||||
yield String.valueOf(((InetSocketAddress)info.getSocketAddress()).getHostString());
|
||||
}
|
||||
|
||||
+25
-16
@@ -41,6 +41,7 @@
|
||||
<properties>
|
||||
<maven.compiler.source>16</maven.compiler.source>
|
||||
<maven.compiler.target>16</maven.compiler.target>
|
||||
<plugin.config.version>4</plugin.config.version>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
@@ -65,28 +66,36 @@
|
||||
<version>${api.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.andre601</groupId>
|
||||
<artifactId>ExpressionParser</artifactId>
|
||||
<version>v1.2.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spongepowered</groupId>
|
||||
<artifactId>configurate-yaml</artifactId>
|
||||
<version>4.1.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- MiniMessage -->
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-api</artifactId>
|
||||
<version>4.14.0</version>
|
||||
<version>4.16.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-text-minimessage</artifactId>
|
||||
<version>4.14.0</version>
|
||||
<version>4.16.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-text-serializer-legacy</artifactId>
|
||||
<version>4.14.0</version>
|
||||
<version>4.16.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -95,12 +104,6 @@
|
||||
<version>2.10.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<version>4.11.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.unascribed</groupId>
|
||||
<artifactId>flexver-java</artifactId>
|
||||
@@ -110,13 +113,15 @@
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>32.1.3-jre</version>
|
||||
<version>33.0.0-jre</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Plugins -->
|
||||
<dependency>
|
||||
<groupId>net.william278</groupId>
|
||||
<artifactId>papiproxybridge</artifactId>
|
||||
<version>1.4.2</version>
|
||||
<version>1.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -128,9 +133,9 @@
|
||||
|
||||
<!-- Test dependencies -->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.13.2</version>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>5.10.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
@@ -147,12 +152,12 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.11.0</version>
|
||||
<version>3.12.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<version>3.5.2</version>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<filters>
|
||||
@@ -169,6 +174,10 @@
|
||||
<pattern>com.unascribed</pattern>
|
||||
<shadedPattern>ch.andre601.advancedserverlist.core.depends.flexver</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>ch.andre601.expressionparser</pattern>
|
||||
<shadedPattern>ch.andre601.advancedserverlist.core.depends.expressionparser</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
<executions>
|
||||
|
||||
@@ -31,11 +31,11 @@ import ch.andre601.advancedserverlist.core.check.UpdateChecker;
|
||||
import ch.andre601.advancedserverlist.core.commands.CommandHandler;
|
||||
import ch.andre601.advancedserverlist.core.file.FileHandler;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.ProfileConditionParser;
|
||||
import ch.andre601.advancedserverlist.core.profiles.players.PlayerHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
@@ -47,6 +47,7 @@ public class AdvancedServerList<F>{
|
||||
private final CommandHandler commandHandler;
|
||||
private final PlayerHandler playerHandler;
|
||||
private final AdvancedServerListAPI api = AdvancedServerListAPI.get();
|
||||
private final ProfileConditionParser parser = ProfileConditionParser.create();
|
||||
|
||||
private UpdateChecker updateChecker;
|
||||
|
||||
@@ -91,6 +92,10 @@ public class AdvancedServerList<F>{
|
||||
return api;
|
||||
}
|
||||
|
||||
public ProfileConditionParser getParser(){
|
||||
return parser;
|
||||
}
|
||||
|
||||
public void disable(){
|
||||
getPlugin().getPluginLogger().info("Saving playercache.json file...");
|
||||
getPlayerHandler().save();
|
||||
@@ -136,15 +141,13 @@ public class AdvancedServerList<F>{
|
||||
}
|
||||
|
||||
if(getFileHandler().loadProfiles()){
|
||||
getPlugin().getPluginLogger().info("Successfully loaded " + getFileHandler().getProfiles().size() + " profiles!");
|
||||
getPlugin().getPluginLogger().info("Successfully loaded %d profile(s)!", getFileHandler().getProfiles().size());
|
||||
}else{
|
||||
getPlugin().getPluginLogger().warn("Unable to load profiles! Check previous lines for errors.");
|
||||
return;
|
||||
}
|
||||
|
||||
Path folder = getPlugin().getFolderPath().resolve("favicons");
|
||||
if(!folder.toFile().exists() && folder.toFile().mkdirs())
|
||||
getPlugin().getPluginLogger().info("Successfully created favicons folder.");
|
||||
getPlugin().loadFaviconHandler(this);
|
||||
|
||||
getPlugin().getPluginLogger().info("Loading Commands...");
|
||||
plugin.loadCommands();
|
||||
|
||||
@@ -30,18 +30,17 @@ import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import com.google.gson.FieldNamingPolicy;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.unascribed.flexver.FlexVerComparator;
|
||||
import io.leangen.geantyref.TypeToken;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
@@ -49,12 +48,10 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class UpdateChecker{
|
||||
|
||||
private final String url = "https://api.modrinth.com/v2/project/advancedserverlist/version?loaders=[\"%s\"]";
|
||||
private final OkHttpClient client = new OkHttpClient();
|
||||
|
||||
private final AdvancedServerList<?> core;
|
||||
private final PluginLogger logger;
|
||||
private final String loader;
|
||||
@SuppressWarnings("FieldCanBeLocal")
|
||||
// 'https://api.modrinth.com/v2/project/advancedserverlist/version?loaders=["%s"]' URL encoded.
|
||||
private final String url = "https://api.modrinth.com/v2/project/advancedserverlist/version?loaders=%%5B%%22%s%%22%%5D";
|
||||
private final HttpClient client = HttpClient.newHttpClient();
|
||||
|
||||
private final Type listType = new TypeToken<ArrayList<ModrinthVersion>>(){}.getType();
|
||||
private final Gson gson = new GsonBuilder()
|
||||
@@ -65,6 +62,10 @@ public class UpdateChecker{
|
||||
|
||||
private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(new UpdateCheckThread());
|
||||
|
||||
private final AdvancedServerList<?> core;
|
||||
private final PluginLogger logger;
|
||||
private final String loader;
|
||||
|
||||
public UpdateChecker(AdvancedServerList<?> core){
|
||||
this.core = core;
|
||||
this.logger = core.getPlugin().getPluginLogger();
|
||||
@@ -73,42 +74,13 @@ public class UpdateChecker{
|
||||
startUpdateChecker();
|
||||
}
|
||||
|
||||
public void startUpdateChecker(){
|
||||
executor.scheduleAtFixedRate(() -> {
|
||||
logger.info("Checking for a new update...");
|
||||
checkUpdate().whenComplete((version, throwable) -> {
|
||||
if(version == null || throwable != null){
|
||||
logger.warn("Failed to look for any updates. See previous messages for reasons.");
|
||||
return;
|
||||
}
|
||||
|
||||
int result = version.compare(core.getVersion());
|
||||
switch(result){
|
||||
case -1 -> printUpdateBanner(version.getVersionNumber(), version.getId(), version.isRelease());
|
||||
case 0 -> logger.info("No new update found. You're running the latest version!");
|
||||
case 1 -> logger.info(
|
||||
"Your version (%s) is higher than the latest release (%s). Are you running a dev build?",
|
||||
core.getVersion(), version.getVersionNumber()
|
||||
);
|
||||
}
|
||||
});
|
||||
}, 0L, 12L, TimeUnit.HOURS);
|
||||
}
|
||||
|
||||
public void disable(){
|
||||
executor.shutdown();
|
||||
client.dispatcher().executorService().shutdown();
|
||||
try{
|
||||
if(!executor.awaitTermination(1, TimeUnit.SECONDS)){
|
||||
executor.shutdownNow();
|
||||
if(!executor.awaitTermination(1, TimeUnit.SECONDS))
|
||||
logger.warn("Scheduler didn't terminate in time!");
|
||||
}
|
||||
|
||||
if(!client.dispatcher().executorService().awaitTermination(1, TimeUnit.SECONDS)){
|
||||
client.dispatcher().executorService().shutdownNow();
|
||||
if(!client.dispatcher().executorService().awaitTermination(1, TimeUnit.SECONDS))
|
||||
logger.warn("OkHttp's Scheduler didn't terminate in time!");
|
||||
logger.warn("Scheduler did not terminate in time!");
|
||||
}
|
||||
}catch(InterruptedException ex){
|
||||
executor.shutdownNow();
|
||||
@@ -116,108 +88,93 @@ public class UpdateChecker{
|
||||
}
|
||||
}
|
||||
|
||||
private CompletableFuture<ModrinthVersion> checkUpdate(){
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
PluginLogger logger = core.getPlugin().getPluginLogger();
|
||||
if(core.getVersion().equals("UNKNOWN")){
|
||||
logger.warn("Cannot perform Update check! Plugin version couldn't be parsed.");
|
||||
return null;
|
||||
}
|
||||
private void startUpdateChecker(){
|
||||
executor.scheduleAtFixedRate(() -> {
|
||||
logger.info("Looking for an update...");
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.url(String.format(url, loader))
|
||||
.header("User-Agent", "AdvancedServerList-" + loader + "/" + core.getVersion())
|
||||
.build();
|
||||
|
||||
try(Response response = client.newCall(request).execute()){
|
||||
if(!response.isSuccessful()){
|
||||
logger.warn("Encountered a non-successful response from Modrinth! Code: %d", response.code());
|
||||
return null;
|
||||
}
|
||||
|
||||
ResponseBody body = response.body();
|
||||
if(body == null){
|
||||
logger.warn("Received an empty Response body from Modrinth!");
|
||||
return null;
|
||||
performUpdateCheck().whenComplete((version, throwable) -> {
|
||||
if(version == null || throwable != null){
|
||||
logger.warn("Failed to look for any updates. Check previous messages for causes.");
|
||||
return;
|
||||
}
|
||||
|
||||
String responseString = body.string();
|
||||
if(responseString.isEmpty()){
|
||||
logger.warn("Received an empty Response body from Modrinth!");
|
||||
return null;
|
||||
logger.debug(UpdateChecker.class, "Comparing versions...");
|
||||
|
||||
int result = version.compare(core.getVersion());
|
||||
switch(result){
|
||||
case -1 -> printUpdateBanner(version);
|
||||
case 0 -> logger.info("You are running the latest version!");
|
||||
case 1 -> logger.info(
|
||||
"Your version (%s) seems to be newer than the latest release (%s). Are you running a dev build?",
|
||||
core.getVersion(), version.versionNumber()
|
||||
);
|
||||
}
|
||||
|
||||
List<ModrinthVersion> list = gson.fromJson(responseString, listType);
|
||||
if(list == null || list.isEmpty()){
|
||||
logger.warn("Couldn't convert JSON Array into a valid list.");
|
||||
return null;
|
||||
}
|
||||
|
||||
ModrinthVersion version = list.get(0);
|
||||
|
||||
if(version.getVersionNumber() == null || version.getVersionNumber().isEmpty()){
|
||||
logger.warn("Cannot check latest version. Received version number was null/empty.");
|
||||
return null;
|
||||
}
|
||||
|
||||
return version;
|
||||
}catch(JsonSyntaxException ex){
|
||||
logger.warn("Encountered invalid JSON from Response body!", ex);
|
||||
return null;
|
||||
}catch(IOException ex){
|
||||
logger.warn("Encountered Exception while checking for an update!", ex);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
});
|
||||
}, 0L, 12L, TimeUnit.HOURS);
|
||||
}
|
||||
|
||||
private void printUpdateBanner(String version, String versionId, boolean isRelease){
|
||||
private CompletableFuture<ModrinthVersion> performUpdateCheck(){
|
||||
String finalUrl = String.format(url, loader);
|
||||
|
||||
logger.debug(UpdateChecker.class, "Checking '%s' for updates...", finalUrl);
|
||||
|
||||
if(core.getVersion().equals("UNKNOWN")){
|
||||
logger.warn("Cannot perform update check. Plugin version is 'UNKNOWN'!");
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
HttpRequest request;
|
||||
try{
|
||||
request = HttpRequest.newBuilder()
|
||||
.uri(new URI(finalUrl))
|
||||
.header("User-Agent", "AdvancedServerList-" + loader + "/" + core.getVersion())
|
||||
.build();
|
||||
}catch(URISyntaxException ex){
|
||||
logger.warn("Cannot perform update check. URL '%s' is not a valid URI.", ex, finalUrl);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
|
||||
return client.sendAsync(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8))
|
||||
.thenApply(response -> new ArrayList<ModrinthVersion>(gson.fromJson(response.body(), listType)))
|
||||
.thenApply(list -> list.get(0))
|
||||
.exceptionally((throwable) -> {
|
||||
logger.warn("Encountered exception while performing update check!", throwable);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private void printUpdateBanner(ModrinthVersion version){
|
||||
logger.info("==================================================================");
|
||||
logger.info("You are running an outdated version of AdvancedServerList!");
|
||||
logger.info("");
|
||||
logger.info("Your version: %s", core.getVersion());
|
||||
logger.info("Modrinth version: %s", version);
|
||||
logger.info("Modrinth: %s", version.versionNumber());
|
||||
logger.info("");
|
||||
|
||||
if(!isRelease){
|
||||
logger.info("WARNING: This release is an Alpha/Beta! It may contain");
|
||||
logger.info(" breaking changes!");
|
||||
if(!version.isRelease()){
|
||||
logger.info("WARNING!");
|
||||
logger.info("This is a %s version and may contain breaking changes and/or bugs!", version.versionType());
|
||||
logger.info("");
|
||||
}
|
||||
|
||||
logger.info("You can download the latest release from here:");
|
||||
logger.info("https://modrinth.com/plugin/advancedserverlist/version/%s", versionId);
|
||||
logger.info("Download the latest version from here:");
|
||||
logger.info("https://modrinth.com/plugin/advancedserverlist/version/%s", version.id());
|
||||
logger.info("==================================================================");
|
||||
}
|
||||
|
||||
public static class ModrinthVersion{
|
||||
@SuppressWarnings("FieldMayBeFinal")
|
||||
private String id;
|
||||
@SuppressWarnings("FieldMayBeFinal")
|
||||
private String versionNumber;
|
||||
@SuppressWarnings("FieldMayBeFinal")
|
||||
private String versionType;
|
||||
|
||||
public ModrinthVersion(String id, String versionNumber, String versionType){
|
||||
this.id = id;
|
||||
this.versionNumber = versionNumber;
|
||||
this.versionType = versionType;
|
||||
}
|
||||
|
||||
public String getId(){
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getVersionNumber(){
|
||||
return versionNumber;
|
||||
}
|
||||
public record ModrinthVersion(String id, String versionNumber, String versionType){
|
||||
|
||||
public boolean isRelease(){
|
||||
return versionType.equals("release");
|
||||
return versionType().equals("release");
|
||||
}
|
||||
|
||||
public int compare(String version){
|
||||
return FlexVerComparator.compare(version, versionNumber);
|
||||
return FlexVerComparator.compare(version, versionNumber());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
return String.format("ModrinthVersion{id=%s,versionNumber=%s,versionType=%s}", id, versionNumber, versionType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,10 @@ package ch.andre601.advancedserverlist.core.compat.papi;
|
||||
|
||||
import net.william278.papiproxybridge.api.PlaceholderAPI;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
|
||||
+47
-16
@@ -30,9 +30,10 @@ import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.core.compat.maintenance.MaintenanceUtil;
|
||||
import ch.andre601.advancedserverlist.core.compat.papi.PAPIUtil;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.events.GenericEventWrapper;
|
||||
import ch.andre601.advancedserverlist.core.compat.papi.PAPIUtil;
|
||||
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
|
||||
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
|
||||
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileManager;
|
||||
@@ -44,11 +45,17 @@ public class PingEventHandler{
|
||||
private static MaintenanceUtil maintenanceUtil = null;
|
||||
|
||||
public static <F, P extends GenericPlayer> void handleEvent(GenericEventWrapper<F, P> event){
|
||||
if(event.isInvalidProtocol() || event.isMaintenanceModeActive())
|
||||
event.getPlugin().getPluginLogger().debug(PingEventHandler.class, "Received ping event. Handling it...");
|
||||
if(event.isInvalidProtocol() || event.isMaintenanceModeActive()){
|
||||
event.getPlugin().getPluginLogger().debug(PingEventHandler.class, "Not handling event. Either protocol was invalid of Maintenance is enabled.");
|
||||
return;
|
||||
}
|
||||
|
||||
PluginCore<F> plugin = event.getPlugin();
|
||||
String host = event.getVirtualHost();
|
||||
PluginLogger logger = plugin.getPluginLogger();
|
||||
|
||||
logger.debug(PingEventHandler.class, "Protocol valid. Continue handling...");
|
||||
|
||||
int online = event.getOnlinePlayers();
|
||||
int max = event.getMaxPlayers();
|
||||
@@ -61,32 +68,50 @@ public class PingEventHandler{
|
||||
|
||||
ServerListProfile profile = ProfileManager.resolveProfile(plugin.getCore(), player, server);
|
||||
|
||||
if(profile == null)
|
||||
if(profile == null){
|
||||
logger.debugWarn(PingEventHandler.class, "Server List Profile couldn't be resolved properly. Cancelling event handling...");
|
||||
return;
|
||||
}
|
||||
|
||||
logger.debug(PingEventHandler.class, "Received valid Server List Profile. Calling PreServerListSetEvent...");
|
||||
|
||||
GenericServerListEvent e = event.callEvent(ProfileManager.merge(profile));
|
||||
if(e == null || e.isCancelled())
|
||||
if(e == null || e.isCancelled()){
|
||||
logger.debug(PingEventHandler.class, "PreServerListSetEvent was cancelled. Stopping ping handling...");
|
||||
return;
|
||||
}
|
||||
|
||||
logger.debug(PingEventHandler.class, "PreServerListSetEvent completed. Proceeding with ping handling...");
|
||||
|
||||
ProfileEntry entry = e.getEntry();
|
||||
if(entry.isInvalid())
|
||||
if(entry.isInvalid()){
|
||||
logger.debugWarn(PingEventHandler.class, "No valid ProfileEntry retrieved. Cancelling ping handling...");
|
||||
return;
|
||||
}
|
||||
|
||||
boolean extraPlayers = ProfileManager.checkOption(entry.extraPlayersEnabled());
|
||||
|
||||
if(extraPlayers){
|
||||
max = online + (entry.extraPlayersCount() == null ? 0 : entry.extraPlayersCount());
|
||||
|
||||
logger.debug(PingEventHandler.class, "Extra Players enabled. Applying '%d' as max player count...", max);
|
||||
|
||||
event.setMaxPlayers(max);
|
||||
}
|
||||
|
||||
if(ProfileManager.checkOption(entry.maxPlayersEnabled()) && !extraPlayers){
|
||||
max = (entry.maxPlayersCount() == null) ? 0 : entry.maxPlayersCount();
|
||||
|
||||
logger.debug(PingEventHandler.class, "Max Players enabled. Applying '%d' as max player count...", max);
|
||||
|
||||
event.setMaxPlayers(max);
|
||||
}
|
||||
|
||||
GenericServer finalServer = event.createGenericServer(online, max, host);
|
||||
|
||||
if(ProfileManager.checkOption(entry.motd())){
|
||||
logger.debug(PingEventHandler.class, "MOTD set. Applying '%s'...", String.join("\\n", entry.motd()));
|
||||
|
||||
event.setMotd(
|
||||
ComponentParser.list(entry.motd())
|
||||
.modifyText(text -> StringReplacer.replace(text, player, finalServer))
|
||||
@@ -98,10 +123,14 @@ public class PingEventHandler{
|
||||
boolean hidePlayers = ProfileManager.checkOption(entry.hidePlayersEnabled());
|
||||
|
||||
if(hidePlayers){
|
||||
logger.debug(PingEventHandler.class, "Hide Players enabled. Hiding player count...");
|
||||
|
||||
event.hidePlayers();
|
||||
}
|
||||
|
||||
if(ProfileManager.checkOption(entry.playerCountText()) && !hidePlayers){
|
||||
logger.debug(PingEventHandler.class, "Player Count Text set. Applying '%s'...", entry.playerCountText());
|
||||
|
||||
event.setPlayerCount(
|
||||
ComponentParser.text(entry.playerCountText())
|
||||
.modifyText(text -> StringReplacer.replace(text, player, finalServer))
|
||||
@@ -111,28 +140,30 @@ public class PingEventHandler{
|
||||
}
|
||||
|
||||
if(ProfileManager.checkOption(entry.players()) && !hidePlayers){
|
||||
logger.debug(PingEventHandler.class, "Player Count Hover set. Applying '%s'...", String.join("\\n", entry.players()));
|
||||
|
||||
event.setPlayers(entry.players(), player, server);
|
||||
}
|
||||
|
||||
if(ProfileManager.checkOption(entry.favicon())){
|
||||
String favicon = StringReplacer.replace(entry.favicon(), player, server);
|
||||
logger.debug(PingEventHandler.class, "Favicon set. Resolving '%s'...", entry.favicon());
|
||||
|
||||
F fav = plugin.getFaviconHandler().getFavicon(favicon, image -> {
|
||||
try{
|
||||
return event.createFavicon(image);
|
||||
}catch(Exception ex){
|
||||
plugin.getPluginLogger().warn("Encountered an Exception while creating Favicon!", ex);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
String faviconString = StringReplacer.replace(entry.favicon(), player, server);
|
||||
|
||||
if(fav == null){
|
||||
F favicon = plugin.getFaviconHandler().getFavicon(faviconString);
|
||||
|
||||
if(favicon == null){
|
||||
logger.debugWarn(PingEventHandler.class, "Favicon was invalid or not yet resolved! Using default favicon of Server/Proxy...");
|
||||
|
||||
event.setDefaultFavicon();
|
||||
}else{
|
||||
event.setFavicon(fav);
|
||||
logger.debug(PingEventHandler.class, "Applying favicon...");
|
||||
|
||||
event.setFavicon(favicon);
|
||||
}
|
||||
}
|
||||
|
||||
logger.debug(PingEventHandler.class, "Event handling completed. Updating Ping data...");
|
||||
event.updateEvent();
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.core.file;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import org.spongepowered.configurate.ConfigurateException;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
@@ -32,16 +33,42 @@ import org.spongepowered.configurate.NodePath;
|
||||
import org.spongepowered.configurate.transformation.ConfigurationTransformation;
|
||||
import org.spongepowered.configurate.transformation.TransformAction;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
|
||||
public class ConfigMigrator{
|
||||
|
||||
public static final int LATEST = 1;
|
||||
public static final int LATEST = resolveConfigVersion();
|
||||
|
||||
private ConfigMigrator(){}
|
||||
|
||||
public static ConfigurationTransformation.Versioned create(){
|
||||
return ConfigurationTransformation.versionedBuilder()
|
||||
.versionKey("configVersion")
|
||||
.addVersion(LATEST, oneToTwo())
|
||||
.addVersion(LATEST, threeToFour())
|
||||
.addVersion(3, twoToThree())
|
||||
.addVersion(2, oneToTwo())
|
||||
.build();
|
||||
}
|
||||
|
||||
public static ConfigurationTransformation threeToFour(){
|
||||
return ConfigurationTransformation.builder()
|
||||
.addAction(NodePath.path(), (path, value) -> {
|
||||
value.node("faviconCacheTime").set(1);
|
||||
|
||||
return null;
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
public static ConfigurationTransformation twoToThree(){
|
||||
return ConfigurationTransformation.builder()
|
||||
.addAction(NodePath.path(), (path, value) -> {
|
||||
value.node("debug").set(false);
|
||||
|
||||
return null;
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -67,9 +94,21 @@ public class ConfigMigrator{
|
||||
versioned.apply(node);
|
||||
final int endVersion = versioned.version(node);
|
||||
if(startVersion < endVersion)
|
||||
logger.info("Migrated config.yml from " + startVersion + " to " + endVersion);
|
||||
logger.info("Migrated config.yml from v" + startVersion + " to v" + endVersion);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
private static int resolveConfigVersion(){
|
||||
try(InputStream is = AdvancedServerList.class.getResourceAsStream("/version.properties")){
|
||||
Properties properties = new Properties();
|
||||
|
||||
properties.load(is);
|
||||
|
||||
return Integer.parseInt(properties.getProperty("config-version"));
|
||||
}catch(IOException | NumberFormatException ex){
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,10 +25,10 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.core.file;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileSerializer;
|
||||
import org.spongepowered.configurate.ConfigurateException;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
@@ -157,7 +157,7 @@ public class FileHandler{
|
||||
continue;
|
||||
|
||||
profiles.add(ServerListProfile.Builder.resolve(file.getName(), tmp, logger).build());
|
||||
logger.info("Loaded " + file.getName());
|
||||
logger.info("Loaded '%s'!", file.getName());
|
||||
}
|
||||
|
||||
if(profiles.isEmpty()){
|
||||
@@ -165,7 +165,7 @@ public class FileHandler{
|
||||
return false;
|
||||
}
|
||||
|
||||
profiles.sort(Comparator.comparing(ServerListProfile::getPriority).reversed());
|
||||
profiles.sort(Comparator.comparing(ServerListProfile::priority).reversed());
|
||||
return !profiles.isEmpty();
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ public class FileHandler{
|
||||
try{
|
||||
return loader.load();
|
||||
}catch(IOException ex){
|
||||
logger.warn("Cannot load " + path.toFile().getName() + " due to an IOException!", ex);
|
||||
logger.warn("Cannot load '%s' due to an IOException!", ex, path.toFile().getName());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -191,6 +191,11 @@ public class FileHandler{
|
||||
return node.node(path).getBoolean();
|
||||
}
|
||||
|
||||
public long getLong(long def, long limit, Object... path){
|
||||
long value = node.node(path).getLong(def);
|
||||
return Math.max(value, limit);
|
||||
}
|
||||
|
||||
public boolean isOldConfig(){
|
||||
return node.node("configVersion").virtual() || node.node("configVersion").getInt(0) < ConfigMigrator.LATEST;
|
||||
}
|
||||
@@ -214,7 +219,7 @@ public class FileHandler{
|
||||
}
|
||||
|
||||
Files.copy(config, configBackup.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
logger.info("Saved backup as '" + configBackup.getName() + "'!");
|
||||
logger.info("Saved backup as '%s'!", configBackup.getName());
|
||||
|
||||
return true;
|
||||
}catch(IOException ex){
|
||||
|
||||
@@ -27,6 +27,10 @@ package ch.andre601.advancedserverlist.core.interfaces;
|
||||
|
||||
public interface PluginLogger{
|
||||
|
||||
void debug(Class<?> clazz, String msg, Object... args);
|
||||
|
||||
void debugWarn(Class<?> clazz, String msg, Object... args);
|
||||
|
||||
void info(String msg, Object... args);
|
||||
|
||||
void warn(String msg, Object... args);
|
||||
|
||||
+12
@@ -29,6 +29,7 @@ import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import ch.andre601.advancedserverlist.core.profiles.favicon.FaviconHandler;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public interface PluginCore<F>{
|
||||
@@ -39,6 +40,8 @@ public interface PluginCore<F>{
|
||||
|
||||
void loadMetrics();
|
||||
|
||||
void loadFaviconHandler(AdvancedServerList<F> core);
|
||||
|
||||
void clearFaviconCache();
|
||||
|
||||
AdvancedServerList<F> getCore();
|
||||
@@ -54,4 +57,13 @@ public interface PluginCore<F>{
|
||||
String getPlatformVersion();
|
||||
|
||||
String getLoader();
|
||||
|
||||
F createFavicon(BufferedImage image) throws Exception;
|
||||
|
||||
default boolean isDebugEnabled(){
|
||||
if(getCore() == null)
|
||||
return false;
|
||||
|
||||
return getCore().getFileHandler().getBoolean("debug");
|
||||
}
|
||||
}
|
||||
+1
-4
@@ -25,15 +25,14 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.core.interfaces.events;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.events.GenericServerListEvent;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.api.events.GenericServerListEvent;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
|
||||
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.List;
|
||||
|
||||
@@ -79,8 +78,6 @@ public interface GenericEventWrapper<F, P extends GenericPlayer>{
|
||||
|
||||
GenericServer createGenericServer(int playersOnline, int playersMax, String host);
|
||||
|
||||
F createFavicon(BufferedImage image) throws Exception;
|
||||
|
||||
default String resolveHost(InetSocketAddress address){
|
||||
return address == null ? null : address.getHostString();
|
||||
}
|
||||
|
||||
+34
-59
@@ -29,7 +29,9 @@ import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.Expression;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.ProfileConditionParser;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
import ch.andre601.expressionparser.templates.ExpressionTemplate;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
@@ -37,38 +39,32 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public class ServerListProfile{
|
||||
public record ServerListProfile(int priority, String condition, ProfileEntry defaultProfile, List<ProfileEntry> profiles){
|
||||
private static final Random random = new Random();
|
||||
|
||||
private final int priority;
|
||||
private final List<Expression> expressions;
|
||||
private final ProfileEntry defaultProfile;
|
||||
|
||||
private final List<ProfileEntry> profiles;
|
||||
|
||||
private final Random random = new Random();
|
||||
|
||||
public ServerListProfile(int priority, List<Expression> expressions, ProfileEntry defaultProfile, List<ProfileEntry> profiles){
|
||||
this.priority = priority;
|
||||
this.expressions = expressions;
|
||||
this.defaultProfile = defaultProfile;
|
||||
|
||||
this.profiles = profiles;
|
||||
}
|
||||
|
||||
public int getPriority(){
|
||||
return priority;
|
||||
}
|
||||
|
||||
public boolean evalConditions(GenericPlayer player, GenericServer server){
|
||||
if(expressions.isEmpty())
|
||||
public boolean evalConditions(ProfileConditionParser parser, PluginLogger logger, GenericPlayer player, GenericServer server){
|
||||
if(condition == null || condition.isEmpty())
|
||||
return true;
|
||||
|
||||
for(Expression expression : expressions){
|
||||
if(!expression.evaluate(player, server))
|
||||
return false;
|
||||
ParseWarnCollector collector = new ParseWarnCollector(condition);
|
||||
ExpressionTemplate template = parser.compile(condition, player, server, collector);
|
||||
|
||||
if(collector.hasWarnings()){
|
||||
logger.warn("Encountered %d Error(s) while parsing condition '%s':", collector.getWarnings().size(), condition);
|
||||
|
||||
for(ParseWarnCollector.Context context : collector.getWarnings()){
|
||||
if(context.position() <= -1){
|
||||
logger.warn(" - %s", context.message());
|
||||
}else{
|
||||
logger.warn(" - At Position %d: %s", context.position(), context.message());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
if(template == null)
|
||||
return false;
|
||||
|
||||
return template.returnBooleanExpression().evaluate();
|
||||
}
|
||||
|
||||
public ProfileEntry getRandomProfile(){
|
||||
@@ -84,10 +80,6 @@ public class ServerListProfile{
|
||||
}
|
||||
}
|
||||
|
||||
public ProfileEntry getDefaultProfile(){
|
||||
return defaultProfile;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if the Profile...
|
||||
* ...doesn't have any valid MOTD set AND
|
||||
@@ -96,12 +88,12 @@ public class ServerListProfile{
|
||||
* ...doesn't have a favicon set.
|
||||
*/
|
||||
public boolean isInvalidProfile(){
|
||||
if(profiles.isEmpty())
|
||||
return defaultProfile.isInvalid();
|
||||
if(profiles().isEmpty())
|
||||
return defaultProfile().isInvalid();
|
||||
|
||||
boolean profilesValid = false;
|
||||
|
||||
for(ProfileEntry profile : profiles){
|
||||
for(ProfileEntry profile : profiles()){
|
||||
if(profile.isInvalid())
|
||||
continue;
|
||||
|
||||
@@ -117,10 +109,10 @@ public class ServerListProfile{
|
||||
private final String fileName;
|
||||
private final ConfigurationNode node;
|
||||
private final int priority;
|
||||
private final List<Expression> expressions = new ArrayList<>();
|
||||
|
||||
private final PluginLogger logger;
|
||||
|
||||
private String condition = null;
|
||||
private List<ProfileEntry> profiles = new ArrayList<>();
|
||||
private ProfileEntry defaultProfile = ProfileEntry.empty();
|
||||
|
||||
@@ -133,34 +125,17 @@ public class ServerListProfile{
|
||||
|
||||
public static Builder resolve(String fileName, ConfigurationNode node, PluginLogger logger){
|
||||
return new Builder(fileName, node, logger)
|
||||
.resolveExpressions()
|
||||
.resolveCondition()
|
||||
.resolveProfiles()
|
||||
.resolveDefaultProfile();
|
||||
}
|
||||
|
||||
private Builder resolveExpressions(){
|
||||
List<String> temp;
|
||||
try{
|
||||
temp = node.node("conditions").getList(String.class);
|
||||
}catch(SerializationException ex){
|
||||
logger.warn("Encountered a SerializationException while resolving conditions for %s", ex, fileName);
|
||||
return this;
|
||||
}
|
||||
|
||||
if(temp == null || temp.isEmpty())
|
||||
private Builder resolveCondition(){
|
||||
String condition = node.node("condition").getString();
|
||||
if(condition == null || condition.isEmpty())
|
||||
return this;
|
||||
|
||||
for(String str : temp){
|
||||
Expression expr = Expression.resolve(str);
|
||||
|
||||
if(expr.getResult() != Expression.ExpressionResult.VALID){
|
||||
logger.warn("Found invalid expression in condition '%s'! Reason: %s", str, expr.getResult().getMessage());
|
||||
continue;
|
||||
}
|
||||
|
||||
this.expressions.add(expr);
|
||||
}
|
||||
|
||||
this.condition = condition;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -184,7 +159,7 @@ public class ServerListProfile{
|
||||
}
|
||||
|
||||
public ServerListProfile build(){
|
||||
return new ServerListProfile(this.priority, this.expressions, this.defaultProfile, this.profiles);
|
||||
return new ServerListProfile(this.priority, this.condition, this.defaultProfile, this.profiles);
|
||||
}
|
||||
}
|
||||
}
|
||||
-226
@@ -1,226 +0,0 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
|
||||
|
||||
public class Expression{
|
||||
|
||||
private final ExpressionResult result;
|
||||
|
||||
private final String left;
|
||||
private final Operator operator;
|
||||
private final String right;
|
||||
|
||||
private Expression(ExpressionResult result, String left, Operator operator, String right){
|
||||
this.result = result;
|
||||
this.left = left;
|
||||
this.operator = operator;
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
public static Expression createInvalid(ExpressionResult result){
|
||||
return new Expression(result, null, Operator.UNKNOWN, null);
|
||||
}
|
||||
|
||||
public static Expression resolve(String expression){
|
||||
Operator operator = Operator.UNKNOWN;
|
||||
|
||||
if(expression == null || expression.isEmpty()){
|
||||
return Expression.createInvalid(ExpressionResult.INVALID_NO_EXPRESSION);
|
||||
}
|
||||
|
||||
char[] chars = expression.toCharArray();
|
||||
|
||||
StringBuilder leftBuilder = new StringBuilder();
|
||||
StringBuilder rightBuilder = new StringBuilder();
|
||||
|
||||
boolean foundOperator = false;
|
||||
|
||||
for(int i = 0; i < chars.length; i++){
|
||||
char c = chars[i];
|
||||
char next = (i == (chars.length - 1)) ? '\0' : chars[i + 1];
|
||||
|
||||
Operator tmp = Operator.getOperand(c, next);
|
||||
if(tmp != Operator.UNKNOWN && !foundOperator){
|
||||
operator = tmp;
|
||||
foundOperator = true;
|
||||
|
||||
if(tmp.hasSecond())
|
||||
i++; // Skip next character if operator has 2
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if(foundOperator){
|
||||
rightBuilder.append(c);
|
||||
}else{
|
||||
leftBuilder.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
if(leftBuilder.isEmpty() || rightBuilder.isEmpty()){
|
||||
return Expression.createInvalid(ExpressionResult.INVALID_EMPTY_PARTS);
|
||||
}
|
||||
|
||||
return new Expression(ExpressionResult.VALID, leftBuilder.toString().trim(), operator, rightBuilder.toString().trim());
|
||||
}
|
||||
|
||||
public boolean evaluate(GenericPlayer player, GenericServer server){
|
||||
String newLeft = StringReplacer.replace(left, player, server);
|
||||
String newRight = StringReplacer.replace(right, player, server);
|
||||
|
||||
return operator.evaluate(newLeft, newRight);
|
||||
}
|
||||
|
||||
public ExpressionResult getResult(){
|
||||
return result;
|
||||
}
|
||||
|
||||
public enum Operator{
|
||||
LESS('<', '\0'){
|
||||
@Override
|
||||
public boolean evaluate(String left, String right){
|
||||
int leftInt = Operator.getInt(left);
|
||||
int rightInt = Operator.getInt(right);
|
||||
|
||||
return leftInt < rightInt;
|
||||
}
|
||||
},
|
||||
LESS_OR_EQUAL('<', '='){
|
||||
@Override
|
||||
public boolean evaluate(String left, String right){
|
||||
int leftInt = Operator.getInt(left);
|
||||
int rightInt = Operator.getInt(right);
|
||||
|
||||
return leftInt <= rightInt;
|
||||
}
|
||||
},
|
||||
EQUAL('=', '\0'){
|
||||
@Override
|
||||
public boolean evaluate(String left, String right){
|
||||
return left.equals(right);
|
||||
}
|
||||
},
|
||||
EQUALS_IGNORE_CASE('~', '='){
|
||||
@Override
|
||||
public boolean evaluate(String left, String right){
|
||||
return left.equalsIgnoreCase(right);
|
||||
}
|
||||
},
|
||||
NOT_EQUAL('!', '='){
|
||||
@Override
|
||||
public boolean evaluate(String left, String right){
|
||||
return !left.equals(right);
|
||||
}
|
||||
},
|
||||
NOT_EQUAL_IGNORE_CASE('!', '~'){
|
||||
@Override
|
||||
public boolean evaluate(String left, String right){
|
||||
return !left.equalsIgnoreCase(right);
|
||||
}
|
||||
},
|
||||
GREATER('>', '\0'){
|
||||
@Override
|
||||
public boolean evaluate(String left, String right){
|
||||
int leftInt = Operator.getInt(left);
|
||||
int rightInt = Operator.getInt(right);
|
||||
|
||||
return leftInt > rightInt;
|
||||
}
|
||||
},
|
||||
GREATER_OR_EQUAL('>', '='){
|
||||
@Override
|
||||
public boolean evaluate(String left, String right){
|
||||
int leftInt = Operator.getInt(left);
|
||||
int rightInt = Operator.getInt(right);
|
||||
|
||||
return leftInt >= rightInt;
|
||||
}
|
||||
},
|
||||
|
||||
UNKNOWN('\0', '\0'){
|
||||
@Override
|
||||
public boolean evaluate(String left, String right){
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
private static final Operator[] VALUES = values();
|
||||
|
||||
private final char first;
|
||||
private final char second;
|
||||
|
||||
Operator(char first, char second){
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
|
||||
public static Operator getOperand(char first, char second){
|
||||
for(Operator operator : VALUES){
|
||||
if(operator.first == first){
|
||||
if((!operator.hasSecond() && second != '=' && second != '~') || operator.second == second)
|
||||
return operator;
|
||||
}
|
||||
}
|
||||
|
||||
return Operator.UNKNOWN;
|
||||
}
|
||||
|
||||
public boolean hasSecond(){
|
||||
return second != '\0';
|
||||
}
|
||||
|
||||
public abstract boolean evaluate(String left, String right);
|
||||
|
||||
private static int getInt(String text){
|
||||
try{
|
||||
return Integer.parseInt(text);
|
||||
}catch(NumberFormatException ex){
|
||||
return text.length();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum ExpressionResult{
|
||||
VALID(null),
|
||||
|
||||
INVALID_NO_EXPRESSION("Received empty condition which isn't allowed!"),
|
||||
INVALID_EMPTY_PARTS ("Received condition with either left or right part being empty.");
|
||||
|
||||
private final String message;
|
||||
|
||||
ExpressionResult(String message){
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getMessage(){
|
||||
return message;
|
||||
}
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.reader.PlaceholderTokenReader;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.reader.PlaceholderValueReader;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens.CustomExpressionTokenizer;
|
||||
import ch.andre601.expressionparser.ExpressionParserEngine;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
import ch.andre601.expressionparser.operator.Operator;
|
||||
import ch.andre601.expressionparser.parsers.ExpressionTemplateParser;
|
||||
import ch.andre601.expressionparser.parsers.ValueReader;
|
||||
import ch.andre601.expressionparser.templates.ExpressionTemplate;
|
||||
import ch.andre601.expressionparser.tokens.Token;
|
||||
import ch.andre601.expressionparser.tokens.readers.TokenReader;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ProfileConditionParser implements ExpressionParserEngine{
|
||||
|
||||
private final CustomExpressionTokenizer tokenizer;
|
||||
private final ExpressionTemplateParser parser;
|
||||
|
||||
private ProfileConditionParser(List<TokenReader> tokenReaders, ImmutableMap<Token, Operator> operators, ImmutableList<ValueReader> valueReaders){
|
||||
this.tokenizer = new CustomExpressionTokenizer(tokenReaders);
|
||||
this.parser = new ExpressionTemplateParser(operators, valueReaders);
|
||||
}
|
||||
|
||||
public static ProfileConditionParser create(){
|
||||
return new ProfileConditionParserBuilder().createDefault()
|
||||
.addTokenReader(new PlaceholderTokenReader(-20))
|
||||
.addValueReader(new PlaceholderValueReader())
|
||||
.build();
|
||||
}
|
||||
|
||||
public ExpressionTemplate compile(String text, GenericPlayer player, GenericServer server, ParseWarnCollector collector){
|
||||
return parser.parse(tokenizer.parse(text, player, server, collector), collector);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExpressionTemplate compile(String s, ParseWarnCollector parseWarnCollector){
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class ProfileConditionParserBuilder extends ExpressionParserEngine.Builder<ProfileConditionParser>{
|
||||
@Override
|
||||
public ProfileConditionParser build(){
|
||||
return new ProfileConditionParser(this.getTokenReaders(), ImmutableMap.copyOf(this.getOperators()), ImmutableList.copyOf(this.getValueReaders()));
|
||||
}
|
||||
}
|
||||
}
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions.placeholders;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.AdvancedServerListAPI;
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens.PlaceholderToken;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
|
||||
import java.text.ParsePosition;
|
||||
|
||||
public class PlaceholderParser{
|
||||
|
||||
public static PlaceholderToken.Placeholder parse(String text, ParsePosition position, GenericPlayer player, GenericServer server, ParseWarnCollector collector){
|
||||
AdvancedServerListAPI api = AdvancedServerListAPI.get();
|
||||
|
||||
// We want to point to the start of a placeholder in the ParseWarnCollector.
|
||||
// Since the PlaceholderTokenReader updates the index by 2 are we reverting this here.
|
||||
int placeholderStart = position.getIndex() - 2;
|
||||
int index = position.getIndex();
|
||||
|
||||
StringBuilder identifier = new StringBuilder();
|
||||
StringBuilder values = new StringBuilder();
|
||||
|
||||
boolean identified = false;
|
||||
boolean invalid = true;
|
||||
|
||||
char[] chars = text.substring(index).toCharArray();
|
||||
for(final char c : chars){
|
||||
index++;
|
||||
|
||||
if(c == '}'){
|
||||
invalid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if(c == ' ' && !identified){
|
||||
identified = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(identified){
|
||||
values.append(c);
|
||||
}else{
|
||||
identifier.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
String identifierStr = identifier.toString();
|
||||
String valuesStr = values.toString();
|
||||
|
||||
StringBuilder raw = new StringBuilder();
|
||||
|
||||
// Skipping whatever character we currently were on (i.e. })
|
||||
position.setIndex(index + 1);
|
||||
|
||||
if(invalid){
|
||||
raw.append("${").append(identifierStr);
|
||||
|
||||
if(identified)
|
||||
raw.append(' ').append(valuesStr);
|
||||
|
||||
collector.appendWarningFormatted(placeholderStart, "Placeholder '%s' does not have a closing bracket (}).", raw.toString());
|
||||
return new PlaceholderToken.Placeholder(raw.toString());
|
||||
}
|
||||
|
||||
PlaceholderProvider provider = api.retrievePlaceholderProvider(identifierStr);
|
||||
if(provider == null){
|
||||
raw.append("${").append(identifierStr);
|
||||
|
||||
if(identified)
|
||||
raw.append(' ').append(valuesStr);
|
||||
|
||||
raw.append('}');
|
||||
|
||||
collector.appendWarningFormatted(placeholderStart, "Placeholder '%s' does not have any available PlaceholderProvider", raw.toString());
|
||||
return new PlaceholderToken.Placeholder(raw.toString());
|
||||
}
|
||||
|
||||
String replacement = provider.parsePlaceholder(valuesStr, player, server);
|
||||
if(replacement == null){
|
||||
raw.append("${").append(identifierStr);
|
||||
|
||||
if(identified)
|
||||
raw.append(' ').append(valuesStr);
|
||||
|
||||
raw.append('}');
|
||||
|
||||
collector.appendWarningFormatted(placeholderStart, "Placeholder '%s' has an invalid value String '%s'.", raw.toString(), valuesStr);
|
||||
return new PlaceholderToken.Placeholder(raw.toString());
|
||||
}
|
||||
|
||||
return new PlaceholderToken.Placeholder(replacement);
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.reader;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
import ch.andre601.expressionparser.tokens.Token;
|
||||
import ch.andre601.expressionparser.tokens.readers.TokenReader;
|
||||
|
||||
import java.text.ParsePosition;
|
||||
|
||||
public abstract class CustomTokenReader extends TokenReader{
|
||||
|
||||
public CustomTokenReader(int priority){
|
||||
super(priority);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Token read(String text, ParsePosition position, ParseWarnCollector collector){
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract Token read(String text, ParsePosition position, GenericPlayer player, GenericServer server, ParseWarnCollector collector);
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.reader;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.PlaceholderParser;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens.PlaceholderToken;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
import ch.andre601.expressionparser.tokens.Token;
|
||||
|
||||
import java.text.ParsePosition;
|
||||
|
||||
public class PlaceholderTokenReader extends CustomTokenReader{
|
||||
|
||||
public PlaceholderTokenReader(int priority){
|
||||
super(priority);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Token read(String text, ParsePosition position, GenericPlayer player, GenericServer server, ParseWarnCollector collector){
|
||||
if(position.getIndex() + 1 < text.length() && text.charAt(position.getIndex()) == '$' && text.charAt(position.getIndex() + 1) == '{'){
|
||||
position.setIndex(position.getIndex() + 2);
|
||||
return new PlaceholderToken(PlaceholderParser.parse(text, position, player, server, collector));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.reader;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens.PlaceholderToken;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
import ch.andre601.expressionparser.parsers.ExpressionTemplateParser;
|
||||
import ch.andre601.expressionparser.parsers.ValueReader;
|
||||
import ch.andre601.expressionparser.templates.ExpressionTemplate;
|
||||
import ch.andre601.expressionparser.tokens.Token;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PlaceholderValueReader extends ValueReader{
|
||||
@Override
|
||||
public ExpressionTemplate read(ExpressionTemplateParser parser, List<Token> tokens, ParseWarnCollector collector){
|
||||
if(tokens.get(0) instanceof PlaceholderToken){
|
||||
PlaceholderToken token = (PlaceholderToken)tokens.remove(0);
|
||||
return token.getValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.reader.CustomTokenReader;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
import ch.andre601.expressionparser.tokens.Token;
|
||||
import ch.andre601.expressionparser.tokens.readers.TokenReader;
|
||||
import com.google.common.collect.Ordering;
|
||||
|
||||
import java.text.ParsePosition;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class CustomExpressionTokenizer{
|
||||
|
||||
private static final Ordering<TokenReader> TOKEN_READER_ORDERING = Ordering.from(Comparator.comparingInt(TokenReader::getPriority)).reverse();
|
||||
|
||||
private final List<TokenReader> tokenReaders;
|
||||
|
||||
public CustomExpressionTokenizer(Iterable<TokenReader> tokenReaders){
|
||||
this.tokenReaders = TOKEN_READER_ORDERING.immutableSortedCopy(tokenReaders);
|
||||
}
|
||||
|
||||
public List<Token> parse(String text, GenericPlayer player, GenericServer server, ParseWarnCollector collector){
|
||||
ParsePosition position = new ParsePosition(0);
|
||||
|
||||
List<Token> tokens = new LinkedList<>();
|
||||
|
||||
next_token:
|
||||
while(true){
|
||||
while(position.getIndex() < text.length() && Character.isWhitespace(text.charAt(position.getIndex())))
|
||||
position.setIndex(position.getIndex() + 1);
|
||||
|
||||
if(position.getIndex() >= text.length())
|
||||
break;
|
||||
|
||||
for(TokenReader tokenReader : tokenReaders){
|
||||
Token token;
|
||||
if(tokenReader instanceof CustomTokenReader customTokenReader){
|
||||
if(null != (token = customTokenReader.read(text, position, player, server, collector))){
|
||||
tokens.add(token);
|
||||
continue next_token;
|
||||
}
|
||||
}else{
|
||||
if(null != (token = tokenReader.read(text, position, collector))){
|
||||
tokens.add(token);
|
||||
continue next_token;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
collector.appendWarningFormatted(position.getIndex(), "Illegal Token '%c'.", text.charAt(position.getIndex()));
|
||||
break;
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.conditions.placeholders.tokens;
|
||||
|
||||
import ch.andre601.expressionparser.expressions.ToBooleanExpression;
|
||||
import ch.andre601.expressionparser.expressions.ToDoubleExpression;
|
||||
import ch.andre601.expressionparser.expressions.ToStringExpression;
|
||||
import ch.andre601.expressionparser.templates.ExpressionTemplate;
|
||||
import ch.andre601.expressionparser.tokens.Token;
|
||||
|
||||
public class PlaceholderToken extends Token{
|
||||
|
||||
private final Placeholder value;
|
||||
|
||||
public PlaceholderToken(Placeholder value){
|
||||
super("PLACEHOLDER");
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Placeholder getValue(){
|
||||
return value;
|
||||
}
|
||||
|
||||
public static class Placeholder implements ExpressionTemplate{
|
||||
|
||||
private final ToBooleanExpression toBooleanExpression;
|
||||
private final ToDoubleExpression toDoubleExpression;
|
||||
private final ToStringExpression toStringExpression;
|
||||
|
||||
public Placeholder(String value){
|
||||
double doubleValue;
|
||||
try{
|
||||
doubleValue = Double.parseDouble(value);
|
||||
}catch(NumberFormatException ex){
|
||||
doubleValue = value.length();
|
||||
}
|
||||
|
||||
this.toBooleanExpression = ToBooleanExpression.literal(Boolean.parseBoolean(value));
|
||||
this.toDoubleExpression = ToDoubleExpression.literal(doubleValue);
|
||||
this.toStringExpression = ToStringExpression.literal(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ToBooleanExpression returnBooleanExpression(){
|
||||
return toBooleanExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ToDoubleExpression returnDoubleExpression(){
|
||||
return toDoubleExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ToStringExpression returnStringExpression(){
|
||||
return toStringExpression;
|
||||
}
|
||||
}
|
||||
}
|
||||
+117
-72
@@ -26,122 +26,167 @@
|
||||
package ch.andre601.advancedserverlist.core.profiles.favicon;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class FaviconHandler<F>{
|
||||
|
||||
private final Cache<String, CompletableFuture<F>> favicons = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(5, TimeUnit.MINUTES)
|
||||
.build();
|
||||
|
||||
private final AdvancedServerList<F> core;
|
||||
private final PluginLogger logger;
|
||||
private final ThreadPoolExecutor faviconThreadPool;
|
||||
private final Cache<String, CompletableFuture<F>> faviconCache;
|
||||
|
||||
private final Map<String, F> localFavicons = new HashMap<>();
|
||||
private final HttpClient client = HttpClient.newHttpClient();
|
||||
|
||||
public FaviconHandler(AdvancedServerList<F> core){
|
||||
this.core = core;
|
||||
this.logger = core.getPlugin().getPluginLogger();
|
||||
this.faviconThreadPool = createFaviconThreadPool();
|
||||
this.faviconCache = CacheBuilder.newBuilder()
|
||||
.expireAfterWrite(core.getFileHandler().getLong(1, 1, "faviconCacheTime"), TimeUnit.MINUTES)
|
||||
.build();
|
||||
|
||||
loadLocalFavicons();
|
||||
}
|
||||
|
||||
public F getFavicon(String input, Function<BufferedImage, F> function){
|
||||
public F getFavicon(String input){
|
||||
if(localFavicons.containsKey(input.toLowerCase(Locale.ROOT).split("\\.")[0])){
|
||||
return localFavicons.get(input.toLowerCase(Locale.ROOT).split("\\.")[0]);
|
||||
}
|
||||
|
||||
try{
|
||||
return favicons.get(input, () -> convert(input, function)).getNow(null);
|
||||
}catch(ExecutionException e){
|
||||
return faviconCache.get(input, () -> getFuture(input)).getNow(null);
|
||||
}catch(ExecutionException ex){
|
||||
logger.warn("Received ExecutionException while retrieving Favicon for '%s'.", ex, input);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void clearCache(){
|
||||
favicons.invalidateAll();
|
||||
public void cleanCache(){
|
||||
faviconCache.invalidateAll();
|
||||
loadLocalFavicons();
|
||||
}
|
||||
|
||||
private CompletableFuture<F> convert(String input, Function<BufferedImage, F> function){
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
BufferedImage img = resolveImage(core, input);
|
||||
if(img == null)
|
||||
return null;
|
||||
|
||||
return function.apply(img);
|
||||
}, faviconThreadPool);
|
||||
}
|
||||
|
||||
private BufferedImage resolveImage(AdvancedServerList<F> core, String input){
|
||||
InputStream stream;
|
||||
|
||||
private CompletableFuture<F> getFuture(String input){
|
||||
if(input.toLowerCase(Locale.ROOT).startsWith("https://")){
|
||||
stream = getFromUrl(core, input);
|
||||
logger.debug(FaviconHandler.class, "Resolving URL '%s'...", input);
|
||||
return CompletableFuture.supplyAsync(() -> fromURL(core, input), this.faviconThreadPool);
|
||||
}else
|
||||
if(input.toLowerCase(Locale.ROOT).endsWith(".png")){
|
||||
File folder = core.getPlugin().getFolderPath().resolve("favicons").toFile();
|
||||
if(!folder.exists()){
|
||||
core.getPlugin().getPluginLogger().warn("Cannot get Favicon %s from favicons folder. Folder doesn't exist!", input);
|
||||
return null;
|
||||
}
|
||||
|
||||
File file = new File(folder, input);
|
||||
|
||||
try{
|
||||
stream = new FileInputStream(file);
|
||||
}catch(IOException ex){
|
||||
core.getPlugin().getPluginLogger().warn("Cannot create Favicon from File %s.", input);
|
||||
core.getPlugin().getPluginLogger().warn("Cause: %s", ex.getMessage());
|
||||
return null;
|
||||
}
|
||||
logger.debug(FaviconHandler.class, "Resolving image file '%s'...", input);
|
||||
return CompletableFuture.completedFuture(localFavicons.get(input.toLowerCase(Locale.ROOT).split("\\.")[0]));
|
||||
}else{
|
||||
stream = getFromUrl(core, "https://mc-heads.net/avatar/" + input + "/64");
|
||||
logger.debug(FaviconHandler.class, "Resolving Name/UUID as https://mc-heads.net/avatar/%s/64...", input);
|
||||
return CompletableFuture.supplyAsync(() -> fromURL(core, "https://mc-heads.net/avatar/" + input + "/64"), this.faviconThreadPool);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadLocalFavicons(){
|
||||
this.localFavicons.clear();
|
||||
|
||||
logger.info("Loading local image files as Favicons...");
|
||||
|
||||
Path folder = core.getPlugin().getFolderPath().resolve("favicons");
|
||||
if(!Files.exists(folder)){
|
||||
try{
|
||||
Files.createDirectories(folder);
|
||||
logger.info("Created favicons folder.");
|
||||
}catch(IOException ex){
|
||||
logger.warn("Cannot create favicons folder. Encountered an IOException.", ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(stream == null){
|
||||
core.getPlugin().getPluginLogger().warn("Cannot create Favicon. InputStream was null.");
|
||||
return null;
|
||||
try(Stream<Path> pathStream = Files.list(folder)){
|
||||
pathStream.filter(Files::isRegularFile)
|
||||
.filter(file -> file.getFileName().toString().endsWith(".png"))
|
||||
.forEach(this::loadFile);
|
||||
}catch(IOException ex){
|
||||
logger.warn("Cannot load files from Favicons folder.", ex);
|
||||
}
|
||||
|
||||
try{
|
||||
BufferedImage original = ImageIO.read(stream);
|
||||
if(original == null){
|
||||
core.getPlugin().getPluginLogger().warn("Cannot create Favicon. Unable to create BufferedImage.");
|
||||
return null;
|
||||
}
|
||||
|
||||
private void loadFile(Path path){
|
||||
try(InputStream stream = Files.newInputStream(path)){
|
||||
F favicon = createFavicon(stream);
|
||||
if(favicon == null){
|
||||
logger.warn("Cannot create Favicon from file '%s'. Received Favicon was null.", path.getFileName().toString());
|
||||
return;
|
||||
}
|
||||
|
||||
BufferedImage favicon = new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D img = favicon.createGraphics();
|
||||
|
||||
// Resize original image to 64x64 and apply to favicon.
|
||||
img.drawImage(original, 0, 0, 64, 64, null);
|
||||
img.dispose();
|
||||
|
||||
return favicon;
|
||||
localFavicons.put(path.getFileName().toString().split("\\.")[0], favicon);
|
||||
logger.info("Loaded file '%s' as Favicon.", path.getFileName().toString());
|
||||
}catch(IOException ex){
|
||||
core.getPlugin().getPluginLogger().warn("Unable to create Favicon. Encountered IOException during creation.");
|
||||
core.getPlugin().getPluginLogger().warn("Cause: %s", ex.getMessage());
|
||||
logger.warn("Cannot create Favicon from file '%s'. Encountered IOException.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private F fromURL(AdvancedServerList<F> core, String url){
|
||||
try{
|
||||
logger.debug(FaviconHandler.class, "Creating Request for URL '%s'...", url);
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(new URI(url))
|
||||
.header("User-Agent", "AdvancedServerList-" + core.getPlugin().getLoader() + "/" + core.getVersion())
|
||||
.build();
|
||||
|
||||
try(InputStream stream = client.send(request, HttpResponse.BodyHandlers.ofInputStream()).body()){
|
||||
return createFavicon(stream);
|
||||
}catch(InterruptedException | IOException ex){
|
||||
logger.warn("Cannot create Favicon from URL '%s'. Encountered an Exception.", ex, url);
|
||||
return null;
|
||||
}
|
||||
}catch(URISyntaxException ex){
|
||||
logger.warn("Cannot create Favicon from URL '%s'. Encountered an IOException.", ex, url);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private InputStream getFromUrl(AdvancedServerList<F> core, String url){
|
||||
private F createFavicon(InputStream stream){
|
||||
try{
|
||||
URL faviconUrl = new URL(url);
|
||||
URLConnection connection = faviconUrl.openConnection();
|
||||
connection.setRequestProperty("User-Agent", "AdvancedServerList/" + core.getVersion());
|
||||
connection.connect();
|
||||
logger.debug(FaviconHandler.class, "Creating BufferedImage from InputStream...");
|
||||
BufferedImage original = ImageIO.read(stream);
|
||||
if(original == null){
|
||||
logger.warn("Cannot create Favicon. Received null BufferedImage.");
|
||||
return null;
|
||||
}
|
||||
|
||||
return connection.getInputStream();
|
||||
}catch(IOException ex){
|
||||
core.getPlugin().getPluginLogger().warn("Error while connecting to %s for Favicon creation.", url);
|
||||
core.getPlugin().getPluginLogger().warn("Cause: %s", ex.getMessage());
|
||||
// Don't waste resources resizing images already having right size.
|
||||
if(original.getWidth() == 64 && original.getHeight() == 64){
|
||||
logger.debug(FaviconHandler.class, "BufferedImage is 64x64 pixels. No resizing needed.");
|
||||
return core.getPlugin().createFavicon(original);
|
||||
}
|
||||
|
||||
logger.debug(FaviconHandler.class, "Resizing image to 64x64 pixels...");
|
||||
BufferedImage image = new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D graphics2D = image.createGraphics();
|
||||
|
||||
graphics2D.drawImage(original, 0, 0, 64, 64, null);
|
||||
graphics2D.dispose();
|
||||
|
||||
logger.debug(FaviconHandler.class, "Image resized! Returning Favicon...");
|
||||
return core.getPlugin().createFavicon(image);
|
||||
}catch(Exception ex){
|
||||
logger.warn("Unable to create Favicon. Received Exception.", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -38,7 +38,9 @@ import java.lang.reflect.Type;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PlayerHandler{
|
||||
|
||||
|
||||
+3
-3
@@ -28,9 +28,9 @@ package ch.andre601.advancedserverlist.core.profiles.profile;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.api.objects.NullBool;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.core.AdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
|
||||
@@ -45,7 +45,7 @@ public class ProfileManager{
|
||||
*/
|
||||
public static ProfileEntry merge(ServerListProfile profile){
|
||||
ProfileEntry entry = profile.getRandomProfile();
|
||||
ProfileEntry defEntry = profile.getDefaultProfile();
|
||||
ProfileEntry defEntry = profile.defaultProfile();
|
||||
|
||||
List<String> motd = resolveMOTD(entry, defEntry);
|
||||
List<String> players = resolvePlayers(entry, defEntry);
|
||||
@@ -67,7 +67,7 @@ public class ProfileManager{
|
||||
if(profile.isInvalidProfile())
|
||||
continue;
|
||||
|
||||
if(profile.evalConditions(player, server))
|
||||
if(profile.evalConditions(core.getParser(), core.getPlugin().getPluginLogger(), player, server))
|
||||
return profile;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -25,11 +25,11 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.core.profiles.profile;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.spongepowered.configurate.ConfigurationNode;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
import org.spongepowered.configurate.serialize.TypeSerializer;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
|
||||
@@ -31,10 +31,29 @@ disableCache: false
|
||||
#
|
||||
checkUpdates: true
|
||||
|
||||
#
|
||||
# Should debug mode be enabled?
|
||||
#
|
||||
# When set to true will AdvancedServerList print additional messages to the console prefixed with "[DEBUG]".
|
||||
# It is recommended to only enable this when having problems or when being told to by the plugin dev, as it could
|
||||
# otherwise cause significant spam in your console.
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
#
|
||||
debug: false
|
||||
|
||||
#
|
||||
# Sets the time in minutes for favicons to be cached.
|
||||
# The number cannot be less than 1.
|
||||
#
|
||||
# Defaults to 1 if not set.
|
||||
#
|
||||
faviconCacheTime: 1
|
||||
|
||||
#
|
||||
# DO NOT EDIT!
|
||||
#
|
||||
# This is used internally to determine if the config needs to be migrated.
|
||||
# Changing or even removing this option could result in your config being broken.
|
||||
#
|
||||
config-version: 2
|
||||
config-version: ${plugin.config.version}
|
||||
@@ -6,6 +6,15 @@
|
||||
#
|
||||
priority: 0
|
||||
|
||||
#
|
||||
# Set conditions that need to me met to show this profile.
|
||||
# You can use keywords 'and' or 'or' (Or alternatively '&&' or `||`) to make more complex condition sets.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#condition
|
||||
#
|
||||
# condition: '${player protocol} < 759'
|
||||
#
|
||||
|
||||
#
|
||||
# Set conditions that needs to be met.
|
||||
# Only when all conditions return true will the profile be shown (Given no profile with higher priority is used).
|
||||
|
||||
@@ -23,4 +23,5 @@
|
||||
#
|
||||
#
|
||||
|
||||
version=${plugin.version}
|
||||
version=${plugin.version}
|
||||
config-version=${plugin.config.version}
|
||||
+26
-18
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -23,30 +23,38 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.spigot.commands;
|
||||
package ch.andre601.advancedserverlist.test;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
|
||||
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
|
||||
public class SpigotCmdSender implements CmdSender{
|
||||
|
||||
private final CommandSender sender;
|
||||
private final BukkitAudiences bukkitAudiences;
|
||||
|
||||
public SpigotCmdSender(CommandSender sender, BukkitAudiences bukkitAudiences){
|
||||
this.sender = sender;
|
||||
this.bukkitAudiences = bukkitAudiences;
|
||||
public class DummyPluginLogger implements PluginLogger{
|
||||
@Override
|
||||
public void debug(Class<?> clazz, String msg, Object... args){
|
||||
info("[DEBUG] [" + clazz.getSimpleName() + "] " + msg, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String permission){
|
||||
return sender.hasPermission(permission) || sender.hasPermission("advancedserverlist.admin");
|
||||
public void debugWarn(Class<?> clazz, String msg, Object... args){
|
||||
warn("[DEBUG] [" + clazz.getSimpleName() + "] " + msg, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMsg(String msg, Object... args){
|
||||
bukkitAudiences.sender(sender).sendMessage(ComponentParser.text(String.format(msg, args)).toComponent());
|
||||
public void info(String msg, Object... args){
|
||||
System.out.printf((msg) + "%n", args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Object... args){
|
||||
System.out.printf((msg) + "%n", args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Throwable throwable){
|
||||
System.out.printf((msg) + "%n", throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String msg, Throwable throwable, Object... args){
|
||||
System.out.printf((msg) + "%n", args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2024 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.test;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.profiles.conditions.ProfileConditionParser;
|
||||
import ch.andre601.expressionparser.ParseWarnCollector;
|
||||
import ch.andre601.expressionparser.templates.ExpressionTemplate;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class ExpressionParserTests{
|
||||
|
||||
private final ProfileConditionParser parser = ProfileConditionParser.create();
|
||||
private final DummyPluginLogger logger = new DummyPluginLogger();
|
||||
private final Map<String, Boolean> testValuesMap = getTestMap();
|
||||
|
||||
@Test
|
||||
public void testBasicExpressionResults(){
|
||||
for(Map.Entry<String, Boolean> values : testValuesMap.entrySet()){
|
||||
logger.info("TEST[expression=\"%s\", expected=%b]", values.getKey(), values.getValue());
|
||||
|
||||
ParseWarnCollector collector = new ParseWarnCollector(values.getKey());
|
||||
ExpressionTemplate template = parser.compile(values.getKey(), null, null, collector);
|
||||
boolean result;
|
||||
if(template == null){
|
||||
result = false;
|
||||
}else{
|
||||
result = template.returnBooleanExpression().evaluate();
|
||||
}
|
||||
|
||||
logger.info("Result (output, isExpected): " + result + ", " + (result == values.getValue()));
|
||||
assertEquals(result, values.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Boolean> getTestMap(){
|
||||
return Map.of(
|
||||
"20 > 10", true,
|
||||
"10 > 20", false,
|
||||
"10 = 10", true,
|
||||
"10 = 20", false,
|
||||
"(10 - 5) > (1 + 1)", true,
|
||||
"(10 - 10) > (1 + 1)", false,
|
||||
"100 > 50 and 50 < 100", true,
|
||||
"100 < 50 and 50 > 100", false,
|
||||
"true or 100 > 10", true,
|
||||
"false or 100 < 10", false
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,9 @@
|
||||
package ch.andre601.advancedserverlist.test;
|
||||
|
||||
import com.unascribed.flexver.FlexVerComparator;
|
||||
import org.junit.Test;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class FlexVerTests{
|
||||
|
||||
@@ -286,7 +288,9 @@ public class FlexVerTests{
|
||||
|
||||
private void compare(String version1, String comparator, String version2, int expected){
|
||||
String expression = version1 + " " + comparator + " " + version2 + "?";
|
||||
int result = FlexVerComparator.compare(version1, version2);
|
||||
|
||||
System.out.printf("│ %-24s %5b │\n", expression, FlexVerComparator.compare(version1, version2) == expected);
|
||||
assertEquals(result, expected);
|
||||
}
|
||||
}
|
||||
+17
-21
@@ -9,7 +9,6 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import posixpath
|
||||
import re
|
||||
|
||||
from mkdocs.config.defaults import MkDocsConfig
|
||||
@@ -25,21 +24,19 @@ def on_page_markdown(
|
||||
def replace(match: Match):
|
||||
type, args = match.groups()
|
||||
args = args.strip()
|
||||
if type == "abstract": return _admo(text = args, type = "abstract")
|
||||
elif type == "info": return _admo(text = args, type = "info")
|
||||
elif type == "tip": return _admo(text = args, type = "tip")
|
||||
elif type == "success": return _admo(text = args, type = "success")
|
||||
elif type == "question": return _admo(text = args, type = "question")
|
||||
elif type == "warning": return _admo(text = args, type = "warning")
|
||||
elif type == "failure": return _admo(text = args, type = "failure")
|
||||
elif type == "danger": return _admo(text = args, type = "danger")
|
||||
elif type == "bug": return _admo(text = args, type = "bug")
|
||||
elif type == "example": return _admo(text = args, type = "example")
|
||||
elif type == "quote": return _admo(text = args, type = "quote")
|
||||
else: return _admo(text = args)
|
||||
|
||||
# Otherwise, raise an error
|
||||
raise RuntimeError(f"Unknown shortcode: {type}")
|
||||
if type == "abstract": return _admo(text = args, type = "abstract")
|
||||
elif type == "info": return _admo(text = args, type = "info")
|
||||
elif type == "tip": return _admo(text = args, type = "tip")
|
||||
elif type == "success": return _admo(text = args, type = "success")
|
||||
elif type == "question": return _admo(text = args, type = "question")
|
||||
elif type == "warning": return _admo(text = args, type = "warning")
|
||||
elif type == "failure": return _admo(text = args, type = "failure")
|
||||
elif type == "danger": return _admo(text = args, type = "danger")
|
||||
elif type == "bug": return _admo(text = args, type = "bug")
|
||||
elif type == "example": return _admo(text = args, type = "example")
|
||||
elif type == "quote": return _admo(text = args, type = "quote")
|
||||
elif type == "deprecated": return _admo(text = args, type = "deprecated")
|
||||
else: return _admo(text = args)
|
||||
|
||||
# Find and replace all external asset URLs in current page
|
||||
return re.sub(
|
||||
@@ -48,11 +45,10 @@ def on_page_markdown(
|
||||
)
|
||||
|
||||
def _admo(text: str = "", type: str = ""):
|
||||
classes = f"mdx-badge mdx-badge--{type}" if type else "mdx-badge"
|
||||
iconClasses = f"mdx-badge__icon mdx-badge--{type}" if type else "mdx-badge__icon"
|
||||
classes = f"mdx-grid-wrapper mdx-admo--{type}" if type else "mdx-grid-wrapper"
|
||||
return "".join([
|
||||
f"<div class=\"{classes}\">",
|
||||
f"<span class=\"{iconClasses}\"></span>",
|
||||
*([f"<span class=\"mdx-badge__text\">{text}</span>"] if text else []),
|
||||
f"</div>",
|
||||
f"<div class=\"mdx-grid-child mdx-grid-child--icon\"></div>",
|
||||
f"<div class=\"mdx-grid-child\">{text}</div>"
|
||||
"</div>",
|
||||
])
|
||||
@@ -0,0 +1,26 @@
|
||||
#
|
||||
# A simple hook that replaces any appearances of \| with just |.
|
||||
#
|
||||
# There is an inconsistency between GitHub flavourited Markdown and Python Markdown
|
||||
# where the former treats | as part of a table, even if it is inside inline code
|
||||
# causing unwanted table rendering.
|
||||
#
|
||||
# The only way to prevent this is to escape it by prefixing it with a back slash (\).
|
||||
# Unfortunately does this cause issues on Python-Markdown, as it renders inline code
|
||||
# content as-is without special treatments whatsoever, meaning that `\|` will be
|
||||
# rendered as <code>\|</code> in the end.
|
||||
#
|
||||
# Using this hook, `\|` is being turned into `|` before further processing, resulting
|
||||
# in <code>|</code> being rendered in the end, while preserving proper table rendering
|
||||
# on GitHub and co.
|
||||
#
|
||||
import re
|
||||
|
||||
from mkdocs.config.defaults import MkDocsConfig
|
||||
from mkdocs.structure.files import File, Files
|
||||
from mkdocs.structure.pages import Page
|
||||
|
||||
def on_page_markdown(
|
||||
markdown: str, *, page: Page, config: MkDocsConfig, files: Files
|
||||
):
|
||||
return re.sub(r"\\\|","|",markdown)
|
||||
+3
-1
@@ -1,8 +1,10 @@
|
||||
nav:
|
||||
- Home: index.md
|
||||
- getting-started
|
||||
- commands
|
||||
- profiles
|
||||
- examples
|
||||
- migration
|
||||
- api
|
||||
- PlaceholderAPI: placeholderapi
|
||||
- addons
|
||||
- PlaceholderAPI: placeholderapi
|
||||
@@ -0,0 +1,44 @@
|
||||
# BanPlugins Addon
|
||||
|
||||
The BanPlugins Addon was made to provide placeholders for different punishment plugins to use in AdvancedServerList.
|
||||
|
||||
## Placeholders
|
||||
|
||||
### AdvancedBan
|
||||
|
||||
Placeholders for the plugin [AdvancedBan](https://www.spigotmc.org/resources/8695/){ target="_blank" rel="nofollow" } are available to use.
|
||||
|
||||
| Placeholder | Description |
|
||||
|---------------------------------|-------------------------------------------------------------------------------------------|
|
||||
| `${advancedban isMuted}` | Whether the player is muted or not. |
|
||||
| `${advancedban muteReason}` | The reason for why the player was muted. Returns invalid placeholder if no mute was set. |
|
||||
| `${advancedban muteDuration}` | Relative time until the mute expires.[^1] Returns invalid placeholder if no mute was set. |
|
||||
| `${advancedban muteExpiration}` | Date on when the mute will expire.[^2] |
|
||||
| `${advancedban isBanned}` | Whether the player is banned or not. |
|
||||
| `${advancedban banReason}` | The reason for why the player was banned. Returns invalid placeholder if no ban was set. |
|
||||
| `${advancedban banDuration}` | Relative time until the ban expires.[^3] Returns invalid placeholder if no ban was set. |
|
||||
| `${advancedban banExpiration}` | Date on when the ban will expire.[^4] |
|
||||
|
||||
[^1]:
|
||||
An optional boolean can be added to set whether the duration should be from the start or not. `false` is the default.
|
||||
Example: `${advancedban muteDuration true}`
|
||||
[^2]:
|
||||
An optional Date and time Pattern can be set to change the displayed output. The default is `dd, MMM yyyy HH:mm:ss`.
|
||||
Example: `${advancedban muteExpiration yyyy-MM-dd HH:mm:ss}`
|
||||
[^3]:
|
||||
An optional boolean can be added to set whether the duration should be from the start or not. `false` is the default.
|
||||
Example: `${advancedban banDuration true}`
|
||||
[^4]:
|
||||
An optional Date and time Pattern can be set to change the displayed output. The default is `dd, MMM yyyy HH:mm:ss`.
|
||||
Example: `${advancedban banExpiration yyyy-MM-dd HH:mm:ss}`
|
||||
|
||||
## Example
|
||||
|
||||
```yaml title="banned.yml"
|
||||
priority: 1
|
||||
condition: '${advancedban isBanned}'
|
||||
|
||||
motd:
|
||||
- '<red>You were <bold>BANNED</bold>!'
|
||||
- '<red>Expires: <grey>${advancedban banExpiration}'
|
||||
```
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
icon: octicons/plus-circle-24
|
||||
---
|
||||
|
||||
# Addons
|
||||
|
||||
This section contains a curated list of add-ons for AdvancedServerList which can be used to enhance the plugin in different ways.
|
||||
Do you have a plugin that hooks into AdvancedServerList that is not listed here? Contact Andre601 on Discord and it will be added!
|
||||
|
||||
## First-party Addons
|
||||
|
||||
These Addons are made by Andre601 and available together with the plugin downloads.
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- [**BanPlugins**](banplugins.md)
|
||||
|
||||
----
|
||||
|
||||
Addon for different Punishment plugins such as AdvancedBan, that add new placeholders to use in AdvancedServerList.
|
||||
|
||||
</div>
|
||||
|
||||
## Third-party
|
||||
|
||||
Third-party addons made by other people not working on AdvancedServerList.
|
||||
|
||||
*Currently no entries*
|
||||
+273
-243
@@ -11,76 +11,79 @@ It provides a way for your plugin to provide its own placeholders that should be
|
||||
|
||||
Add the following to your `pom.xml`, `build.gradle` or `build.gradle.kts` depending on what you use:
|
||||
|
||||
=== ":simple-apachemaven: Maven"
|
||||
/// tab | :simple-apachemaven: Maven
|
||||
```xml title="pom.xml"
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>jitpack</id>
|
||||
<url>https://jitpack.io/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>ch.andre601.asl-api</groupId>
|
||||
<artifactId>api</artifactId>
|
||||
<version>{apiVersion}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Optional platform dependencies -->
|
||||
<dependency>
|
||||
<groupId>ch.andre601.asl-api</groupId>
|
||||
<artifactId>platform-bukkit</artifactId>
|
||||
<version>{apiVersion}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.andre601.asl-api</groupId>
|
||||
<artifactId>platform-bungeecord</artifactId>
|
||||
<version>{apiVersion}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.andre601.asl-api</groupId>
|
||||
<artifactId>platform-velocity</artifactId>
|
||||
<version>{apiVersion}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
```
|
||||
///
|
||||
|
||||
/// tab | :simple-gradle: Gradle
|
||||
```groovy title="build.gradle"
|
||||
repositorories {
|
||||
maven { url = 'https://jitpack.io/' }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly 'ch.andre601.asl-api:api:{apiVersion}'
|
||||
|
||||
```xml title="pom.xml"
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>jitpack</id>
|
||||
<url>https://jitpack.io/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
// Optional platform dependencies
|
||||
compileOnly 'ch.andre601.asl-api:platform-bukkit:{apiVersion}'
|
||||
compileOnly 'ch.andre601.asl-api:platform-bungeecord:{apiVersion}'
|
||||
compileOnly 'ch.andre601.asl-api:platform-velocity:{apiVersion}'
|
||||
}
|
||||
```
|
||||
///
|
||||
|
||||
/// tab | :simple-gradle: Gradle (KTS)
|
||||
```kotlin title="build.gradle.kts"
|
||||
repositories {
|
||||
maven("https://jitpack.io")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("ch.andre601.asl-api:api:{apiVersion}")
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>ch.andre601.asl-api</groupId>
|
||||
<artifactId>api</artifactId>
|
||||
<version>{version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Optional platform dependencies -->
|
||||
<dependency>
|
||||
<groupId>ch.andre601.asl-api</groupId>
|
||||
<artifactId>platform-bukkit</artifactId>
|
||||
<version>{version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.andre601.asl-api</groupId>
|
||||
<artifactId>platform-bungeecord</artifactId>
|
||||
<version>{version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.andre601.asl-api</groupId>
|
||||
<artifactId>platform-velocity</artifactId>
|
||||
<version>{version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
```
|
||||
=== ":simple-gradle: Gradle"
|
||||
|
||||
```groovy title="build.gradle"
|
||||
repositorories {
|
||||
maven { url = 'https://jitpack.io/' }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly 'ch.andre601.asl-api:api:{version}'
|
||||
|
||||
// Optional platform dependencies
|
||||
compileOnly 'ch.andre601.asl-api:platform-bukkit:{version}'
|
||||
compileOnly 'ch.andre601.asl-api:platform-bungeecord:{version}'
|
||||
compileOnly 'ch.andre601.asl-api:platform-velocity:{version}'
|
||||
}
|
||||
```
|
||||
=== ":simple-gradle: Gradle (KTS)"
|
||||
```kotlin title="build.gradle.kts"
|
||||
repositories {
|
||||
maven("https://jitpack.io")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("ch.andre601.asl-api:api:{version}")
|
||||
|
||||
// Optional platform dependencies
|
||||
compileOnly("ch.andre601.asl-api:platform-bukkit:{version}")
|
||||
compileOnly("ch.andre601.asl-api:platform-bungeecord:{version}")
|
||||
compileOnly("ch.andre601.asl-api:platform-velocity:{version}")
|
||||
}
|
||||
```
|
||||
// Optional platform dependencies
|
||||
compileOnly("ch.andre601.asl-api:platform-bukkit:{apiVersion}")
|
||||
compileOnly("ch.andre601.asl-api:platform-bungeecord:{apiVersion}")
|
||||
compileOnly("ch.andre601.asl-api:platform-velocity:{apiVersion}")
|
||||
}
|
||||
```
|
||||
///
|
||||
|
||||
## Adding your own Placeholders
|
||||
|
||||
@@ -108,13 +111,14 @@ public class MyPlaceholders extends PlaceholderProvider {
|
||||
}
|
||||
```
|
||||
|
||||
!!! tip
|
||||
You can replace the Constructor with a String argument with a no-args constructor and set the identifier directly in the `super`:
|
||||
```java
|
||||
public MyPlaceholders() {
|
||||
super("myplaceholders");
|
||||
}
|
||||
```
|
||||
/// tip
|
||||
You can replace the Constructor with a String argument with a no-args constructor and set the identifier directly in the `super`:
|
||||
```java
|
||||
public MyPlaceholders() {
|
||||
super("myplaceholders");
|
||||
}
|
||||
```
|
||||
///
|
||||
|
||||
The [`parsePlaceholder(String, GenericPlayer, GenericServer)`][parseplaceholder] method is used by AdvancedServerList to replace a matching placeholder with a value.
|
||||
What you return is completely up to you. Just keep in mind that returning `null` will be treated as an invalid placeholder by AdvancedServerList, resulting in the placeholder being returned as-is without any changes.
|
||||
@@ -122,23 +126,26 @@ What you return is completely up to you. Just keep in mind that returning `null`
|
||||
[placeholderprovider]: reference/api/ch.andre601.advancedserverlist.api/placeholderprovider.md
|
||||
[parseplaceholder]: reference/api/ch.andre601.advancedserverlist.api/placeholderprovider.md#parseplaceholder(string,-genericplayer,-genericserver)
|
||||
|
||||
??? example "Example of final class"
|
||||
```java
|
||||
public class MyPlaceholders extends PlaceholderProvider {
|
||||
|
||||
public MyPlaceholders() {
|
||||
super("myplaceholders");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server) {
|
||||
if(placeholder.equalsIgnoreCase("hello"))
|
||||
return "Hello " + player.getName();
|
||||
|
||||
return null;
|
||||
}
|
||||
/// details | Example of final class
|
||||
type: example
|
||||
|
||||
```java
|
||||
public class MyPlaceholders extends PlaceholderProvider {
|
||||
|
||||
public MyPlaceholders() {
|
||||
super("myplaceholders");
|
||||
}
|
||||
```
|
||||
|
||||
@Override
|
||||
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server) {
|
||||
if(placeholder.equalsIgnoreCase("hello"))
|
||||
return "Hello " + player.getName();
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
```
|
||||
///
|
||||
|
||||
### 2. Register the Placeholders
|
||||
|
||||
@@ -173,158 +180,181 @@ The final thing you should make sure is to define AdvancedServerList as a depend
|
||||
|
||||
Below are example setups for Spigot, Paper, BungeeCord and Velocity:
|
||||
|
||||
=== ":simple-spigotmc: Spigot"
|
||||
=== "Softdepend"
|
||||
```yaml title="plugin.yml"
|
||||
name: "MyPlugin"
|
||||
author: "author"
|
||||
version: "1.0.0"
|
||||
|
||||
main: "com.example.plugin.ExamplePlugin"
|
||||
|
||||
softdepend:
|
||||
- AdvancedServerList
|
||||
```
|
||||
=== "Depend"
|
||||
```yaml title="plugin.yml"
|
||||
name: "MyPlugin"
|
||||
author: "author"
|
||||
version: "1.0.0"
|
||||
|
||||
main: "com.example.plugin.ExamplePlugin"
|
||||
|
||||
depend:
|
||||
- AdvancedServerList
|
||||
```
|
||||
=== ":fontawesome-solid-paper-plane: Paper"
|
||||
=== "Softdepend"
|
||||
```yaml title="paper-plugin.yml"
|
||||
name: "MyPlugin"
|
||||
author: "author"
|
||||
version: "1.0.0"
|
||||
|
||||
main: "com.example.plugin.ExamplePlugin"
|
||||
|
||||
dependencies:
|
||||
server:
|
||||
AdvancedServerList:
|
||||
load: BEFORE
|
||||
required: false # Default, not required
|
||||
```
|
||||
=== "Depend"
|
||||
```yaml title="paper-plugin.yml"
|
||||
name: "MyPlugin"
|
||||
author: "author"
|
||||
version: "1.0.0"
|
||||
|
||||
main: "com.example.plugin.ExamplePlugin"
|
||||
|
||||
dependencies:
|
||||
server:
|
||||
AdvancedServerList:
|
||||
load: BEFORE
|
||||
required: true
|
||||
```
|
||||
=== ":octicons-git-merge-24: BungeeCord"
|
||||
=== "Softdepend"
|
||||
```yaml title="bungee.yml"
|
||||
name: "MyPlugin"
|
||||
author: "author"
|
||||
version: "1.0.0"
|
||||
|
||||
main: "com.example.plugin.ExamplePlugin"
|
||||
|
||||
softDepends:
|
||||
- AdvancedServerList
|
||||
```
|
||||
=== "Depend"
|
||||
```yaml title="bungee.yml"
|
||||
name: "MyPlugin"
|
||||
author: "author"
|
||||
version: "1.0.0"
|
||||
|
||||
main: "com.example.plugin.ExamplePlugin"
|
||||
|
||||
depends:
|
||||
- AdvancedServerList
|
||||
```
|
||||
=== ":octicons-git-merge-24: Velocity"
|
||||
=== "Softdepend (File)"
|
||||
```json title="velocity-plugin.json"
|
||||
{
|
||||
"id": "myplugin",
|
||||
"name": "MyPlugin",
|
||||
"version": "1.0.0",
|
||||
"authors": [
|
||||
"author"
|
||||
],
|
||||
"main": "com.example.plugin.ExamplePlugin",
|
||||
"dependencies": [
|
||||
{
|
||||
"id": "advancedserverlist",
|
||||
"optional": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
=== "Depend (File)"
|
||||
```json title="velocity-plugin.json"
|
||||
{
|
||||
"id": "myplugin",
|
||||
"name": "MyPlugin",
|
||||
"version": "1.0.0",
|
||||
"authors": [
|
||||
"author"
|
||||
],
|
||||
"main": "com.example.plugin.ExamplePlugin",
|
||||
"dependencies": [
|
||||
{
|
||||
"id": "advancedserverlist",
|
||||
"optional": false
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
=== "Softdepend (Annotation)"
|
||||
```java title="MyPlugin.java"
|
||||
@Plugin(
|
||||
id = "myplugin",
|
||||
name = "MyPlugin",
|
||||
version = "1.0.0",
|
||||
authors = {"author"},
|
||||
dependencies = {
|
||||
@Dependency(
|
||||
id = "advancedserverlist",
|
||||
optional = true
|
||||
)
|
||||
}
|
||||
)
|
||||
public class MyPlugin {
|
||||
|
||||
// ...
|
||||
|
||||
}
|
||||
```
|
||||
=== "Depend (Annotation)"
|
||||
```java title="MyPlugin.java"
|
||||
@Plugin(
|
||||
id = "myplugin",
|
||||
name = "MyPlugin",
|
||||
version = "1.0.0",
|
||||
authors = {"author"},
|
||||
dependencies = {
|
||||
@Dependency(
|
||||
id = "advancedserverlist",
|
||||
optional = false // Default, not required
|
||||
)
|
||||
}
|
||||
)
|
||||
public class MyPlugin {
|
||||
|
||||
// ...
|
||||
|
||||
}
|
||||
```
|
||||
/// tab | :simple-spigotmc: Spigot
|
||||
//// tab | Softdepend
|
||||
```yaml title="plugin.yml"
|
||||
name: "MyPlugin"
|
||||
author: "author"
|
||||
version: "1.0.0"
|
||||
|
||||
main: "com.example.plugin.ExamplePlugin"
|
||||
|
||||
softdepend:
|
||||
- AdvancedServerList
|
||||
```
|
||||
////
|
||||
|
||||
//// tab | Depend
|
||||
```yaml title="plugin.yml"
|
||||
name: "MyPlugin"
|
||||
author: "author"
|
||||
version: "1.0.0"
|
||||
|
||||
main: "com.example.plugin.ExamplePlugin"
|
||||
|
||||
depend:
|
||||
- AdvancedServerList
|
||||
```
|
||||
////
|
||||
///
|
||||
|
||||
/// tab | :fontawesome-solid-paper-plane: Paper
|
||||
//// tab | Softdepend
|
||||
```yaml title="paper-plugin.yml"
|
||||
name: "MyPlugin"
|
||||
author: "author"
|
||||
version: "1.0.0"
|
||||
|
||||
main: "com.example.plugin.ExamplePlugin"
|
||||
|
||||
dependencies:
|
||||
server:
|
||||
AdvancedServerList:
|
||||
load: BEFORE
|
||||
required: false # Default, not required
|
||||
```
|
||||
////
|
||||
|
||||
//// tab | Depend
|
||||
```yaml title="paper-plugin.yml"
|
||||
name: "MyPlugin"
|
||||
author: "author"
|
||||
version: "1.0.0"
|
||||
|
||||
main: "com.example.plugin.ExamplePlugin"
|
||||
|
||||
dependencies:
|
||||
server:
|
||||
AdvancedServerList:
|
||||
load: BEFORE
|
||||
required: true
|
||||
```
|
||||
////
|
||||
///
|
||||
|
||||
/// tab | :octicons-git-merge-24: BungeeCord
|
||||
//// tab | Softdepend
|
||||
```yaml title="bungee.yml"
|
||||
name: "MyPlugin"
|
||||
author: "author"
|
||||
version: "1.0.0"
|
||||
|
||||
main: "com.example.plugin.ExamplePlugin"
|
||||
|
||||
softDepends:
|
||||
- AdvancedServerList
|
||||
```
|
||||
////
|
||||
|
||||
//// tab | Depend
|
||||
```yaml title="bungee.yml"
|
||||
name: "MyPlugin"
|
||||
author: "author"
|
||||
version: "1.0.0"
|
||||
|
||||
main: "com.example.plugin.ExamplePlugin"
|
||||
|
||||
depends:
|
||||
- AdvancedServerList
|
||||
```
|
||||
////
|
||||
///
|
||||
|
||||
/// tab | :octicons-git-merge-24: Velocity
|
||||
//// tab | Softdepend (File)
|
||||
```json title="velocity-plugin.json"
|
||||
{
|
||||
"id": "myplugin",
|
||||
"name": "MyPlugin",
|
||||
"version": "1.0.0",
|
||||
"authors": [
|
||||
"author"
|
||||
],
|
||||
"main": "com.example.plugin.ExamplePlugin",
|
||||
"dependencies": [
|
||||
{
|
||||
"id": "advancedserverlist",
|
||||
"optional": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
////
|
||||
|
||||
//// tab | Depend (File)
|
||||
```json title="velocity-plugin.json"
|
||||
{
|
||||
"id": "myplugin",
|
||||
"name": "MyPlugin",
|
||||
"version": "1.0.0",
|
||||
"authors": [
|
||||
"author"
|
||||
],
|
||||
"main": "com.example.plugin.ExamplePlugin",
|
||||
"dependencies": [
|
||||
{
|
||||
"id": "advancedserverlist",
|
||||
"optional": false // Default, not required
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
////
|
||||
|
||||
//// tab | Softdepend (Annotation)
|
||||
```java title="MyPlugin.java"
|
||||
@Plugin(
|
||||
id = "myplugin",
|
||||
name = "MyPlugin",
|
||||
version = "1.0.0",
|
||||
authors = {"author"},
|
||||
dependencies = {
|
||||
@Dependency(
|
||||
id = "advancedserverlist",
|
||||
optional = true
|
||||
)
|
||||
}
|
||||
)
|
||||
public class MyPlugin {
|
||||
|
||||
// ...
|
||||
|
||||
}
|
||||
```
|
||||
////
|
||||
|
||||
//// tab | Depend (Annotation)
|
||||
```java title="MyPlugin.java"
|
||||
@Plugin(
|
||||
id = "myplugin",
|
||||
name = "MyPlugin",
|
||||
version = "1.0.0",
|
||||
authors = {"author"},
|
||||
dependencies = {
|
||||
@Dependency(
|
||||
id = "advancedserverlist",
|
||||
optional = false // Default, not required
|
||||
)
|
||||
}
|
||||
)
|
||||
public class MyPlugin {
|
||||
|
||||
// ...
|
||||
|
||||
}
|
||||
```
|
||||
////
|
||||
///
|
||||
|
||||
### 4. You're done!
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
template: redirect.html
|
||||
|
||||
location: https://github.com/Andre601/asl-api
|
||||
|
||||
title: Source Code
|
||||
icon: octicons/mark-github-16
|
||||
---
|
||||
|
||||
<!-- Comment to trigger proper build -->
|
||||
@@ -28,13 +28,22 @@ document$.subscribe(async () => {
|
||||
|
||||
function loadApiInfo(data) {
|
||||
const version = data["version"];
|
||||
const versionToken = '{version}';
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
function loadPluginVersion(data) {
|
||||
const version = data["version"];
|
||||
const versionToken = '{version}'
|
||||
const entries = document.querySelectorAll('.md-content code');
|
||||
for(const entry of entries) {
|
||||
entry.innerHTML = entry.innerHTML.replace(new RegExp(versionToken, 'g'), version.substring(1));
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchApiInfo() {
|
||||
const tag = await fetch("https://api.github.com/repos/Andre601/asl-api/releases/latest").then(_ => _.json());
|
||||
|
||||
@@ -60,12 +69,14 @@ document$.subscribe(async () => {
|
||||
|
||||
__md_set("__git_repo", data, sessionStorage);
|
||||
loadCodebergInfo(data);
|
||||
loadPluginVersion(data);
|
||||
}
|
||||
|
||||
if(!document.querySelector('[data-md-component="source"] .md-source__facts')) {
|
||||
const cached = __md_get("__git_repo", sessionStorage);
|
||||
if((cached != null) && (cached["version"])) {
|
||||
loadCodebergInfo(cached);
|
||||
loadPluginVersion(cached);
|
||||
} else {
|
||||
fetchInfo();
|
||||
}
|
||||
|
||||
@@ -23,11 +23,13 @@
|
||||
--md-badge-bg--example: #7c4dff1a;
|
||||
--md-badge-fg--quote: #9e9e9e;
|
||||
--md-badge-bg--quote: #9e9e9e1a;
|
||||
--md-badge-fg--deprecated: #ff5252;
|
||||
--md-badge-bg--deprecated: #ff52521a;
|
||||
|
||||
--badge-icon--note: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M17.263 2.177a1.75 1.75 0 0 1 2.474 0l2.586 2.586a1.75 1.75 0 0 1 0 2.474L19.53 10.03l-.012.013L8.69 20.378a1.753 1.753 0 0 1-.699.409l-5.523 1.68a.748.748 0 0 1-.747-.188.748.748 0 0 1-.188-.747l1.673-5.5a1.75 1.75 0 0 1 .466-.756L14.476 4.963ZM4.708 16.361a.26.26 0 0 0-.067.108l-1.264 4.154 4.177-1.271a.253.253 0 0 0 .1-.059l10.273-9.806-2.94-2.939-10.279 9.813ZM19 8.44l2.263-2.262a.25.25 0 0 0 0-.354l-2.586-2.586a.25.25 0 0 0-.354 0L16.061 5.5Z"></path></svg>');
|
||||
--badge-icon--abstract: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M5.962 2.513a.75.75 0 0 1-.475.949l-.816.272a.25.25 0 0 0-.171.237V21.25c0 .138.112.25.25.25h14.5a.25.25 0 0 0 .25-.25V3.97a.25.25 0 0 0-.17-.236l-.817-.272a.75.75 0 0 1 .474-1.424l.816.273A1.751 1.751 0 0 1 21 3.97v17.28A1.75 1.75 0 0 1 19.25 23H4.75A1.75 1.75 0 0 1 3 21.25V3.97a1.75 1.75 0 0 1 1.197-1.66l.816-.272a.75.75 0 0 1 .949.475Z"></path><path d="M7 1.75C7 .784 7.784 0 8.75 0h6.5C16.216 0 17 .784 17 1.75v1.5A1.75 1.75 0 0 1 15.25 5h-6.5A1.75 1.75 0 0 1 7 3.25Zm1.75-.25a.25.25 0 0 0-.25.25v1.5c0 .138.112.25.25.25h6.5a.25.25 0 0 0 .25-.25v-1.5a.25.25 0 0 0-.25-.25Z"></path></svg>');
|
||||
--badge-icon--info: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M13 7.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0Zm-3 3.75a.75.75 0 0 1 .75-.75h1.5a.75.75 0 0 1 .75.75v4.25h.75a.75.75 0 0 1 0 1.5h-3a.75.75 0 0 1 0-1.5h.75V12h-.75a.75.75 0 0 1-.75-.75Z"></path><path d="M12 1c6.075 0 11 4.925 11 11s-4.925 11-11 11S1 18.075 1 12 5.925 1 12 1ZM2.5 12a9.5 9.5 0 0 0 9.5 9.5 9.5 9.5 0 0 0 9.5-9.5A9.5 9.5 0 0 0 12 2.5 9.5 9.5 0 0 0 2.5 12Z"></path></svg>');
|
||||
--badge-icon--tip: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M14.265 1.627c0 3.545 1.869 5.327 3.479 7.021 1.54 1.62 3.006 3.163 3.006 6.102 0 4.812-3.753 8.25-8.565 8.25-4.813 0-8.935-3.421-8.935-8.25 0-2.039.962-4.011 2.509-4.899.305-.175.672.007.803.334C7.563 12.684 8.797 12.64 9.437 12c.388-.387.47-1.116-.004-2.062-2.405-4.812 1.863-8.279 4.2-8.854.336-.082.615.198.632.543ZM12.185 21.5c4.059 0 7.065-2.84 7.065-6.75 0-2.337-1.093-3.489-2.678-5.158l-.021-.023c-1.44-1.517-3.139-3.351-3.649-6.557a6.148 6.148 0 0 0-1.911 1.76c-.787 1.144-1.147 2.633-.216 4.495.603 1.205.777 2.74-.277 3.794-.657.657-1.762 1.1-2.956.586-.752-.324-1.353-.955-1.838-1.79-.567.706-.954 1.74-.954 2.893 0 3.847 3.288 6.75 7.435 6.75Z"></path></svg>');
|
||||
--badge-icon--tip: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M12 2.5c-3.81 0-6.5 2.743-6.5 6.119 0 1.536.632 2.572 1.425 3.56.172.215.347.422.527.635l.096.112c.21.25.427.508.63.774.404.531.783 1.128.995 1.834a.75.75 0 0 1-1.436.432c-.138-.46-.397-.89-.753-1.357a18.111 18.111 0 0 0-.582-.714l-.092-.11c-.18-.212-.37-.436-.555-.667C4.87 12.016 4 10.651 4 8.618 4 4.363 7.415 1 12 1s8 3.362 8 7.619c0 2.032-.87 3.397-1.755 4.5-.185.23-.375.454-.555.667l-.092.109c-.21.248-.405.481-.582.714-.356.467-.615.898-.753 1.357a.751.751 0 0 1-1.437-.432c.213-.706.592-1.303.997-1.834.202-.266.419-.524.63-.774l.095-.112c.18-.213.355-.42.527-.634.793-.99 1.425-2.025 1.425-3.561C18.5 5.243 15.81 2.5 12 2.5ZM8.75 18h6.5a.75.75 0 0 1 0 1.5h-6.5a.75.75 0 0 1 0-1.5Zm.75 3.75a.75.75 0 0 1 .75-.75h3.5a.75.75 0 0 1 0 1.5h-3.5a.75.75 0 0 1-.75-.75Z"></path></svg>');
|
||||
--badge-icon--success: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M21.03 5.72a.75.75 0 0 1 0 1.06l-11.5 11.5a.747.747 0 0 1-1.072-.012l-5.5-5.75a.75.75 0 1 1 1.084-1.036l4.97 5.195L19.97 5.72a.75.75 0 0 1 1.06 0Z"></path></svg>');
|
||||
--badge-icon--question: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M10.97 8.265a1.45 1.45 0 0 0-.487.57.75.75 0 0 1-1.341-.67c.2-.402.513-.826.997-1.148C10.627 6.69 11.244 6.5 12 6.5c.658 0 1.369.195 1.934.619a2.45 2.45 0 0 1 1.004 2.006c0 1.033-.513 1.72-1.027 2.215-.19.183-.399.358-.579.508l-.147.123a4.329 4.329 0 0 0-.435.409v1.37a.75.75 0 1 1-1.5 0v-1.473c0-.237.067-.504.247-.736.22-.28.486-.517.718-.714l.183-.153.001-.001c.172-.143.324-.27.47-.412.368-.355.569-.676.569-1.136a.953.953 0 0 0-.404-.806C12.766 8.118 12.384 8 12 8c-.494 0-.814.121-1.03.265ZM13 17a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path><path d="M12 1c6.075 0 11 4.925 11 11s-4.925 11-11 11S1 18.075 1 12 5.925 1 12 1ZM2.5 12a9.5 9.5 0 0 0 9.5 9.5 9.5 9.5 0 0 0 9.5-9.5A9.5 9.5 0 0 0 12 2.5 9.5 9.5 0 0 0 2.5 12Z"></path></svg>');
|
||||
--badge-icon--warning: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M13 17.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0Zm-.25-8.25a.75.75 0 0 0-1.5 0v4.5a.75.75 0 0 0 1.5 0v-4.5Z"></path><path d="M9.836 3.244c.963-1.665 3.365-1.665 4.328 0l8.967 15.504c.963 1.667-.24 3.752-2.165 3.752H3.034c-1.926 0-3.128-2.085-2.165-3.752Zm3.03.751a1.002 1.002 0 0 0-1.732 0L2.168 19.499A1.002 1.002 0 0 0 3.034 21h17.932a1.002 1.002 0 0 0 .866-1.5L12.866 3.994Z"></path></svg>');
|
||||
@@ -36,22 +38,31 @@
|
||||
--badge-icon--bug: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M7.72.22a.75.75 0 0 1 1.06 0l1.204 1.203A4.98 4.98 0 0 1 12 1c.717 0 1.4.151 2.016.423L15.22.22a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-.971.972A4.991 4.991 0 0 1 17 6v1.104a2.755 2.755 0 0 1 1.917 1.974l1.998-.999a.75.75 0 0 1 .67 1.342L19 10.714V13.5l3.25.003a.75.75 0 0 1 0 1.5L19 15.001V16c0 .568-.068 1.134-.204 1.686l.04.018 2.75 1.375a.75.75 0 1 1-.671 1.342l-2.638-1.319A6.998 6.998 0 0 1 12 23a6.998 6.998 0 0 1-6.197-3.742l-2.758 1.181a.752.752 0 0 1-1.064-.776.752.752 0 0 1 .474-.602l2.795-1.199A6.976 6.976 0 0 1 5 16v-.996H1.75a.75.75 0 0 1 0-1.5H5v-2.79L2.415 9.42a.75.75 0 0 1 .67-1.342l1.998.999A2.756 2.756 0 0 1 7 7.104V6a4.99 4.99 0 0 1 1.69-3.748l-.97-.972a.75.75 0 0 1 0-1.06ZM6.5 9.75V16a5.5 5.5 0 1 0 11 0V9.75c0-.69-.56-1.25-1.25-1.25h-8.5c-.69 0-1.25.56-1.25 1.25ZM8.5 7h7V6a3.5 3.5 0 1 0-7 0Z"></path></svg>');
|
||||
--badge-icon--example: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M8 8.807V3.5h-.563a.75.75 0 0 1 0-1.5h9.125a.75.75 0 0 1 0 1.5H16v5.307l5.125 9.301c.964 1.75-.302 3.892-2.299 3.892H5.174c-1.998 0-3.263-2.142-2.3-3.892ZM4.189 18.832a1.123 1.123 0 0 0 .985 1.668h13.652a1.123 1.123 0 0 0 .985-1.668L17.7 15H6.3ZM14.5 3.5h-5V9a.75.75 0 0 1-.093.362L7.127 13.5h9.746l-2.28-4.138A.75.75 0 0 1 14.5 9Z"></path></svg>');
|
||||
--badge-icon--quote: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M3 6.25a.75.75 0 0 1 .75-.75h13.5a.75.75 0 0 1 0 1.5H3.75A.75.75 0 0 1 3 6.25Zm5 6.063a.75.75 0 0 1 .75-.75h11.5a.75.75 0 0 1 0 1.5H8.75a.75.75 0 0 1-.75-.75Zm0 5.937a.75.75 0 0 1 .75-.75h11.5a.75.75 0 0 1 0 1.5H8.75a.75.75 0 0 1-.75-.75ZM3.75 11a.75.75 0 0 1 .75.75v7a.75.75 0 0 1-1.5 0v-7a.75.75 0 0 1 .75-.75Z"></path></svg>');
|
||||
--badge-icon--deprecated: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M16 1.75V3h5.25a.75.75 0 0 1 0 1.5H2.75a.75.75 0 0 1 0-1.5H8V1.75C8 .784 8.784 0 9.75 0h4.5C15.216 0 16 .784 16 1.75Zm-6.5 0V3h5V1.75a.25.25 0 0 0-.25-.25h-4.5a.25.25 0 0 0-.25.25ZM4.997 6.178a.75.75 0 1 0-1.493.144L4.916 20.92a1.75 1.75 0 0 0 1.742 1.58h10.684a1.75 1.75 0 0 0 1.742-1.581l1.413-14.597a.75.75 0 0 0-1.494-.144l-1.412 14.596a.25.25 0 0 1-.249.226H6.658a.25.25 0 0 1-.249-.226L4.997 6.178Z"></path><path d="M9.206 7.501a.75.75 0 0 1 .793.705l.5 8.5A.75.75 0 1 1 9 16.794l-.5-8.5a.75.75 0 0 1 .705-.793Zm6.293.793A.75.75 0 1 0 14 8.206l-.5 8.5a.75.75 0 0 0 1.498.088l.5-8.5Z"></path></svg>');
|
||||
}
|
||||
|
||||
.md-typeset .mdx-badge {
|
||||
font-size: .85em;
|
||||
/*
|
||||
* Grid stuff
|
||||
*/
|
||||
.mdx-grid-wrapper {
|
||||
display: grid;
|
||||
grid-template-columns: .5fr 9fr;
|
||||
gap: 1rem;
|
||||
|
||||
border: .075rem solid var(--md-badge-fg--note);
|
||||
border-radius: .1rem;
|
||||
padding: .3rem;
|
||||
border-radius: .2rem;
|
||||
}
|
||||
|
||||
.md-typeset .mdx-badge .mdx-badge__icon {
|
||||
background: var(--md-accent-fg-color--transparent);
|
||||
padding: .5rem .3rem;
|
||||
margin-left: -.3rem;
|
||||
.mdx-grid-child {
|
||||
align-self: center;
|
||||
font-size: .64rem;
|
||||
}
|
||||
|
||||
.md-typeset .mdx-badge .mdx-badge__icon::before {
|
||||
.mdx-grid-child.mdx-grid-child--icon {
|
||||
background-color: var(--md-badge-bg--note);
|
||||
}
|
||||
|
||||
.mdx-grid-child.mdx-grid-child--icon::before {
|
||||
content: "";
|
||||
|
||||
background-color: var(--md-badge-fg--note);
|
||||
@@ -60,198 +71,209 @@
|
||||
mask-repeat: no-repeat;
|
||||
mask-size: contain;
|
||||
|
||||
display: inline-block;
|
||||
|
||||
height: 1rem;
|
||||
width: 1rem;
|
||||
|
||||
vertical-align: middle;
|
||||
margin: .4rem;
|
||||
|
||||
display: block;
|
||||
|
||||
-webkit-mask-image: var(--badge-icon--note);
|
||||
mask-image: var(--badge-icon--note);
|
||||
}
|
||||
|
||||
.md-typeset .mdx-badge__text {
|
||||
padding: .3rem .3rem;
|
||||
margin: .3rem;
|
||||
}
|
||||
|
||||
/*
|
||||
* Types
|
||||
*/
|
||||
|
||||
/* Abstract */
|
||||
.md-typeset .mdx-badge.mdx-badge--abstract {
|
||||
.mdx-admo--abstract {
|
||||
border-color: var(--md-badge-fg--abstract);
|
||||
}
|
||||
|
||||
.md-typeset .mdx-badge .mdx-badge__icon.mdx-badge--abstract {
|
||||
.mdx-admo--abstract .mdx-grid-child--icon {
|
||||
background-color: var(--md-badge-bg--abstract);
|
||||
}
|
||||
|
||||
.md-typeset .mdx-badge .mdx-badge__icon.mdx-badge--abstract::before {
|
||||
.mdx-admo--abstract .mdx-grid-child--icon::before {
|
||||
background-color: var(--md-badge-fg--abstract);
|
||||
|
||||
mask-image: var(--badge-icon--abstract);
|
||||
-webkit-mask-image: var(--badge-icon--abstract);
|
||||
mask-image: var(--badge-icon--abstract);
|
||||
}
|
||||
|
||||
/* Info */
|
||||
.md-typeset .mdx-badge.mdx-badge--info {
|
||||
.mdx-admo--info {
|
||||
border-color: var(--md-badge-fg--info);
|
||||
}
|
||||
|
||||
.md-typeset .mdx-badge .mdx-badge__icon.mdx-badge--info {
|
||||
.mdx-admo--info .mdx-grid-child--icon {
|
||||
background-color: var(--md-badge-bg--info);
|
||||
}
|
||||
|
||||
.md-typeset .mdx-badge .mdx-badge__icon.mdx-badge--info::before {
|
||||
.mdx-admo--info .mdx-grid-child--icon::before {
|
||||
background-color: var(--md-badge-fg--info);
|
||||
|
||||
mask-image: var(--badge-icon--info);
|
||||
-webkit-mask-image: var(--badge-icon--info);
|
||||
mask-image: var(--badge-icon--info);
|
||||
}
|
||||
|
||||
/* Tip */
|
||||
.md-typeset .mdx-badge.mdx-badge--tip {
|
||||
.mdx-admo--tip {
|
||||
border-color: var(--md-badge-fg--tip);
|
||||
}
|
||||
|
||||
.md-typeset .mdx-badge .mdx-badge__icon.mdx-badge--tip {
|
||||
.mdx-admo--tip .mdx-grid-child--icon {
|
||||
background-color: var(--md-badge-bg--tip);
|
||||
}
|
||||
|
||||
.md-typeset .mdx-badge .mdx-badge__icon.mdx-badge--tip::before {
|
||||
.mdx-admo--tip .mdx-grid-child--icon::before {
|
||||
background-color: var(--md-badge-fg--tip);
|
||||
|
||||
mask-image: var(--badge-icon--tip);
|
||||
-webkit-mask-image: var(--badge-icon--tip);
|
||||
mask-image: var(--badge-icon--tip);
|
||||
}
|
||||
|
||||
/* Success */
|
||||
.md-typeset .mdx-badge.mdx-badge--success {
|
||||
.mdx-admo--success {
|
||||
border-color: var(--md-badge-fg--success);
|
||||
}
|
||||
|
||||
.md-typeset .mdx-badge .mdx-badge__icon.mdx-badge--success {
|
||||
.mdx-admo--success .mdx-grid-child--icon {
|
||||
background-color: var(--md-badge-bg--success);
|
||||
}
|
||||
|
||||
.md-typeset .mdx-badge .mdx-badge__icon.mdx-badge--success::before {
|
||||
.mdx-admo--success .mdx-grid-child--icon::before {
|
||||
background-color: var(--md-badge-fg--success);
|
||||
|
||||
mask-image: var(--badge-icon--success);
|
||||
-webkit-mask-image: var(--badge-icon--success);
|
||||
mask-image: var(--badge-icon--success);
|
||||
}
|
||||
|
||||
/* Question */
|
||||
.md-typeset .mdx-badge.mdx-badge--question {
|
||||
.mdx-admo--question {
|
||||
border-color: var(--md-badge-fg--question);
|
||||
}
|
||||
|
||||
.md-typeset .mdx-badge .mdx-badge__icon.mdx-badge--question {
|
||||
.mdx-admo--question .mdx-grid-child--icon {
|
||||
background-color: var(--md-badge-bg--question);
|
||||
}
|
||||
|
||||
.md-typeset .mdx-badge .mdx-badge__icon.mdx-badge--question::before {
|
||||
.mdx-admo--question .mdx-grid-child--icon::before {
|
||||
background-color: var(--md-badge-fg--question);
|
||||
|
||||
mask-image: var(--badge-icon--question);
|
||||
-webkit-mask-image: var(--badge-icon--question);
|
||||
mask-image: var(--badge-icon--question);
|
||||
}
|
||||
|
||||
/* Warning */
|
||||
.md-typeset .mdx-badge.mdx-badge--warning {
|
||||
.mdx-admo--warning {
|
||||
border-color: var(--md-badge-fg--warning);
|
||||
}
|
||||
|
||||
.md-typeset .mdx-badge .mdx-badge__icon.mdx-badge--warning {
|
||||
.mdx-admo--warning .mdx-grid-child--icon {
|
||||
background-color: var(--md-badge-bg--warning);
|
||||
}
|
||||
|
||||
.md-typeset .mdx-badge .mdx-badge__icon.mdx-badge--warning::before {
|
||||
.mdx-admo--warning .mdx-grid-child--icon::before {
|
||||
background-color: var(--md-badge-fg--warning);
|
||||
|
||||
mask-image: var(--badge-icon--warning);
|
||||
-webkit-mask-image: var(--badge-icon--warning);
|
||||
mask-image: var(--badge-icon--warning);
|
||||
}
|
||||
|
||||
/* Failure */
|
||||
.md-typeset .mdx-badge.mdx-badge--failure {
|
||||
.mdx-admo--failure {
|
||||
border-color: var(--md-badge-fg--failure);
|
||||
}
|
||||
|
||||
.md-typeset .mdx-badge .mdx-badge__icon.mdx-badge--failure {
|
||||
.mdx-admo--failure .mdx-grid-child--icon {
|
||||
background-color: var(--md-badge-bg--failure);
|
||||
}
|
||||
|
||||
.md-typeset .mdx-badge .mdx-badge__icon.mdx-badge--failure::before {
|
||||
.mdx-admo--failure .mdx-grid-child--icon::before {
|
||||
background-color: var(--md-badge-fg--failure);
|
||||
|
||||
mask-image: var(--badge-icon--failure);
|
||||
-webkit-mask-image: var(--badge-icon--failure);
|
||||
mask-image: var(--badge-icon--failure);
|
||||
}
|
||||
|
||||
/* Danger */
|
||||
.md-typeset .mdx-badge.mdx-badge--danger {
|
||||
.mdx-admo--danger {
|
||||
border-color: var(--md-badge-fg--danger);
|
||||
}
|
||||
|
||||
.md-typeset .mdx-badge .mdx-badge__icon.mdx-badge--danger {
|
||||
.mdx-admo--danger .mdx-grid-child--icon {
|
||||
background-color: var(--md-badge-bg--danger);
|
||||
}
|
||||
|
||||
.md-typeset .mdx-badge .mdx-badge__icon.mdx-badge--danger::before {
|
||||
.mdx-admo--danger .mdx-grid-child--icon::before {
|
||||
background-color: var(--md-badge-fg--danger);
|
||||
|
||||
mask-image: var(--badge-icon--danger);
|
||||
-webkit-mask-image: var(--badge-icon--danger);
|
||||
mask-image: var(--badge-icon--danger);
|
||||
}
|
||||
|
||||
/* Bug */
|
||||
.md-typeset .mdx-badge.mdx-badge--bug {
|
||||
.mdx-admo--bug {
|
||||
border-color: var(--md-badge-fg--bug);
|
||||
}
|
||||
|
||||
.md-typeset .mdx-badge .mdx-badge__icon.mdx-badge--bug {
|
||||
.mdx-admo--bug .mdx-grid-child--icon {
|
||||
background-color: var(--md-badge-bg--bug);
|
||||
}
|
||||
|
||||
.md-typeset .mdx-badge .mdx-badge__icon.mdx-badge--bug::before {
|
||||
.mdx-admo--bug .mdx-grid-child--icon::before {
|
||||
background-color: var(--md-badge-fg--bug);
|
||||
|
||||
mask-image: var(--badge-icon--bug);
|
||||
-webkit-mask-image: var(--badge-icon--bug);
|
||||
mask-image: var(--badge-icon--bug);
|
||||
}
|
||||
|
||||
/* Example */
|
||||
.md-typeset .mdx-badge.mdx-badge--example {
|
||||
.mdx-admo--example {
|
||||
border-color: var(--md-badge-fg--example);
|
||||
}
|
||||
|
||||
.md-typeset .mdx-badge .mdx-badge__icon.mdx-badge--example {
|
||||
.mdx-admo--example .mdx-grid-child--icon {
|
||||
background-color: var(--md-badge-bg--example);
|
||||
}
|
||||
|
||||
.md-typeset .mdx-badge .mdx-badge__icon.mdx-badge--example::before {
|
||||
.mdx-admo--example .mdx-grid-child--icon::before {
|
||||
background-color: var(--md-badge-fg--example);
|
||||
|
||||
mask-image: var(--badge-icon--example);
|
||||
-webkit-mask-image: var(--badge-icon--example);
|
||||
mask-image: var(--badge-icon--example);
|
||||
}
|
||||
|
||||
/* Quote */
|
||||
.md-typeset .mdx-badge.mdx-badge--quote {
|
||||
.mdx-admo--quote {
|
||||
border-color: var(--md-badge-fg--quote);
|
||||
}
|
||||
|
||||
.md-typeset .mdx-badge .mdx-badge__icon.mdx-badge--quote {
|
||||
.mdx-admo--quote .mdx-grid-child--icon {
|
||||
background-color: var(--md-badge-bg--quote);
|
||||
}
|
||||
|
||||
.md-typeset .mdx-badge .mdx-badge__icon.mdx-badge--quote::before {
|
||||
.mdx-admo--quote .mdx-grid-child--icon::before {
|
||||
background-color: var(--md-badge-fg--quote);
|
||||
|
||||
mask-image: var(--badge-icon--quote);
|
||||
-webkit-mask-image: var(--badge-icon--quote);
|
||||
mask-image: var(--badge-icon--quote);
|
||||
}
|
||||
|
||||
/* Deprecated */
|
||||
.mdx-admo--deprecated {
|
||||
border-color: var(--md-badge-fg--deprecated);
|
||||
}
|
||||
|
||||
.mdx-admo--deprecated .mdx-grid-child--icon {
|
||||
background-color: var(--md-badge-bg--deprecated);
|
||||
}
|
||||
|
||||
.mdx-admo--deprecated .mdx-grid-child--icon::before {
|
||||
background-color: var(--md-badge-fg--deprecated);
|
||||
|
||||
-webkit-mask-image: var(--badge-icon--deprecated);
|
||||
mask-image: var(--badge-icon--deprecated);
|
||||
}
|
||||
+31
-15
@@ -6,7 +6,7 @@ icon: octicons/list-unordered-24
|
||||
|
||||
## About
|
||||
|
||||
<!-- admo:info The below examples may only work in v1.10.0 or newer! -->
|
||||
<!-- admo:info The below examples may only work in v3.7.0 or newer! -->
|
||||
|
||||
This page lists some examples you may want to use for your proxy or server.
|
||||
|
||||
@@ -17,7 +17,9 @@ Feel free to suggest additional examples on my [Discord Server](https://discord.
|
||||
- [Versions](#versions)
|
||||
- [Different List for outdated Clients](#different-list-for-outdated-clients)
|
||||
- [Different MOTD for < 1.16](#different-motd-for-116)
|
||||
- [Spigot/PaperMC](#spigotpapermc)
|
||||
- [BungeeCord/Velocity](#bungeecordvelocity)
|
||||
- [Display MOTD for a set of subdomains](#display-motd-for-a-set-of-subdomains)
|
||||
- [PaperMC](#papermc)
|
||||
- [Different profile for banned Player](#different-profile-for-banned-player)
|
||||
- [Other](#other)
|
||||
- [Different profile for different host](#different-profile-for-different-host)
|
||||
@@ -38,8 +40,7 @@ This example here shows a separate MOTD and player count message for when the pl
|
||||
priority: 1
|
||||
|
||||
# Display this profile, if the version of the player is below 760 (1.19.1)
|
||||
conditions:
|
||||
- '${player protocol} < 760'
|
||||
condition: '${player protocol} < 760'
|
||||
|
||||
motd:
|
||||
- '<red>You are using an outdated client!'
|
||||
@@ -57,8 +58,7 @@ This profile would display a MOTD without HEX colours if the player's version is
|
||||
priority: 1
|
||||
|
||||
# Display this profile, if the version of the player is below 735 (1.16)
|
||||
conditions:
|
||||
- '${player protocol} < 735'
|
||||
condition: '${player protocol} < 735'
|
||||
|
||||
motd:
|
||||
- '<grey>Welcome to <aqua>YourServer.com</aqua>!'
|
||||
@@ -66,9 +66,28 @@ motd:
|
||||
```
|
||||
|
||||
----
|
||||
## Spigot/PaperMC
|
||||
## BungeeCord/Velocity
|
||||
|
||||
Examples that can be used with the Spigot or PaperMC version.
|
||||
Examples usable on the BungeeCord and Velocity version.
|
||||
|
||||
### Display MOTD for a set of subdomains
|
||||
|
||||
Displays the same MOTDs for the server when pinged on any sub-domain starting with `lobby` (i.e. `lobby-1.example.com`).
|
||||
|
||||
```yaml title="lobby-motd.yml"
|
||||
priority: 1
|
||||
|
||||
condition: '${server host} |- "lobby"'
|
||||
|
||||
motd:
|
||||
- '<green>Lobby Server'
|
||||
- '<grey>Example Server'
|
||||
```
|
||||
|
||||
----
|
||||
## PaperMC
|
||||
|
||||
Examples that can be used with the PaperMC version.
|
||||
|
||||
### Different profile for banned Player
|
||||
|
||||
@@ -79,8 +98,7 @@ Displays a separate profile for when the player has been banned from the server.
|
||||
```yaml title="banned.yml"
|
||||
priority: 1
|
||||
|
||||
conditions:
|
||||
- '${player isBanned} = true'
|
||||
condition: '${player isBanned}'
|
||||
|
||||
motd:
|
||||
- '<red>You have been <bold>BANNED</bold>!'
|
||||
@@ -103,8 +121,7 @@ Display a different profile when the playing pings a specific domain/IP.
|
||||
```yaml title="specific-host.yml"
|
||||
priority: 1
|
||||
|
||||
conditions:
|
||||
- '${server host} = other.example.com'
|
||||
condition: '${server host} = "host.example.com"'
|
||||
|
||||
motd:
|
||||
- '<grey>Please use <aqua>mc.example.com'
|
||||
@@ -118,12 +135,11 @@ Display a different profile, if the player pinging the server is "known" by Adva
|
||||
```yaml title="personalized.yml"
|
||||
priority: 1
|
||||
|
||||
conditions:
|
||||
- `${player name} != Anonymous` # "Anonymous" should be replaced with whatever you use in 'unknown_player'
|
||||
condition: '${player name} != "Anonymous"' # "Anonymous" would be the value from the "unknownPlayer > name" option.
|
||||
|
||||
motd:
|
||||
- '<grey>Hello there <aqua>${player name}</aqua>!'
|
||||
- '<grey>It's nice to see you again.'
|
||||
- '<grey>It''s nice to see you again.'
|
||||
|
||||
playerCount:
|
||||
hover:
|
||||
|
||||
@@ -0,0 +1,438 @@
|
||||
---
|
||||
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.
|
||||
|
||||
## 1. Download the plugin { #download-the-plugin }
|
||||
|
||||
The first step would be to download the plugin from a download page of your choice.
|
||||
AdvancedServerList is available on the following places (Please note the current status!):
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- [:simple-modrinth: **Modrinth**][modrinth]
|
||||
|
||||
----
|
||||
|
||||
:octicons-check-24:{ style="color: var(--md-badge-fg--success);" } **Actively updated!**
|
||||
|
||||
- [:simple-codeberg: **Codeberg**][codeberg]
|
||||
|
||||
----
|
||||
|
||||
:octicons-check-24:{ style="color: var(--md-badge-fg--success);" } **Actively updated!**
|
||||
|
||||
- [:fontawesome-solid-paper-plane: **HangarMC**][hangar]
|
||||
|
||||
----
|
||||
|
||||
:octicons-check-24:{ style="color: var(--md-badge-fg--success);" } **Actively updated!**
|
||||
|
||||
|
||||
- [:simple-spigotmc: **SpigotMC**][spigot]
|
||||
|
||||
----
|
||||
|
||||
:octicons-alert-24:{ style="color: var(--md-badge-fg--warning);" } **Discontinued!**
|
||||
|
||||
</div>
|
||||
|
||||
[modrinth]: https://modrinth.com/plugin/advancedserverlist
|
||||
[codeberg]: https://codeberg.org/Andre601/AdvancedServerList
|
||||
[spigot]: https://www.spigotmc.org/resources/102910/
|
||||
[hangar]: https://hangar.papermc.io/Andre_601/AdvancedServerList
|
||||
|
||||
The plugin is available for Paper, BungeeCord, Waterfall and Velocity, and has been tested on these platforms. It may support additional forks, but this is not guaranteed.
|
||||
|
||||
The plugin also supports these additional plugins. They are all optional.
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- [**PlaceholderAPI**][placeholderapi]
|
||||
|
||||
----
|
||||
|
||||
Supported on:
|
||||
|
||||
- :fontawesome-solid-paper-plane: Paper
|
||||
|
||||
- [**ViaVersion**][viaversion]
|
||||
|
||||
----
|
||||
|
||||
Supported on:
|
||||
|
||||
- :fontawesome-solid-paper-plane: Paper
|
||||
|
||||
- [**PAPIProxyBridge**][papiproxybridge]
|
||||
|
||||
----
|
||||
|
||||
Supported on:
|
||||
|
||||
- :simple-spigotmc: BungeeCord
|
||||
- :fontawesome-solid-paper-plane: Velocity
|
||||
|
||||
- [**Maintenance**][maintenance]
|
||||
|
||||
----
|
||||
|
||||
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
|
||||
|
||||
## 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.
|
||||
Here is a quick table showing the jar file name with the platforms it is made for:
|
||||
|
||||
| Jar file name | Platforms |
|
||||
|-----------------------------------------------|-----------------------|
|
||||
| `AdvancedServerList-Paper-{version}.jar` | Paper |
|
||||
| `AdvancedServerList-BungeeCord-{version}.jar` | BungeeCord, Waterfall |
|
||||
| `AdvancedServerList-Velocity-{version}.jar` | Velocity |
|
||||
|
||||
After you added it to your plugins folder - alongside any other dependency you may want - (re)start your server or proxy to enable the plugin.
|
||||
If everything goes well should AdvancedServerList create a folder named `AdvancedServerList` (`advancedserverlist` on Velocity) with additional files and folders inside of it.
|
||||
|
||||
### Folder structure
|
||||
|
||||
When you install AdvancedServerList for the first time should it have created the following file structure inside the plugins folder of your Server or Proxy:
|
||||
```
|
||||
AdvancedServerList/
|
||||
├── favicons/
|
||||
├── profiles/
|
||||
│ └── default.yml
|
||||
└── config.yml
|
||||
```
|
||||
Let's cover the files and folders...
|
||||
|
||||
#### Favicons folder
|
||||
|
||||
This folder allows you to store PNG images that should be used as favicons by the plugin. A favicon from this folder can be used by referencing the name (Including the `.png` file extension) in the [`favicon` option of the server list profile](../profiles/index.md#favicon).
|
||||
|
||||
#### Profiles folder and default.yml { #profiles-folder-and-default-yml }
|
||||
|
||||
The profiles folder is home of the server list profile files which allow you to modify the server list entry of your server in a player's multiplayer screen.
|
||||
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
|
||||
```yaml
|
||||
#
|
||||
# Set the priority of this profile.
|
||||
# Higher number = Higher priority.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#priority
|
||||
#
|
||||
priority: 0
|
||||
|
||||
#
|
||||
# Set conditions that need to me met to show this profile.
|
||||
# You can use keywords 'and' or 'or' (Or alternatively '&&' or `||`) to make more complex condition sets.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#condition
|
||||
#
|
||||
# condition: '${player protocol} < 759'
|
||||
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# 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
|
||||
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#motd
|
||||
#
|
||||
motd:
|
||||
- '<grey>Line 1'
|
||||
- '<grey>Line 2'
|
||||
|
||||
#
|
||||
# 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
|
||||
#
|
||||
# Remove this option or set to favicon: '' to not replace 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).
|
||||
#
|
||||
# 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>
|
||||
#
|
||||
# Note that when this is enabled will all other options, except for 'extraPlayers', be ignored.
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#hideplayers
|
||||
#
|
||||
hidePlayers: false
|
||||
#
|
||||
# Sets the text displayed when hovering over the player count.
|
||||
#
|
||||
# Remove this option or set it to hover: [] to not modify the player samples on the player count.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#hover
|
||||
#
|
||||
hover:
|
||||
- '<grey>Line 1'
|
||||
- '<grey>Line 2'
|
||||
- '<grey>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.
|
||||
#
|
||||
# Remove this option or set it to text: '' to not modify the player count text.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#text
|
||||
#
|
||||
text: ''
|
||||
#
|
||||
# Allows you to modify the max player count displayed.
|
||||
# Note that this will affect ${server playersMax} (Except for when used in conditions).
|
||||
#
|
||||
# Read more: https://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'
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# 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'
|
||||
#
|
||||
# Defaults to 0 when not present.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#extraplayers-amount
|
||||
#
|
||||
amount: 0
|
||||
#
|
||||
# Allows you to set the max players that could join your server.
|
||||
# Note that this option influences the '${server playersMax}' placeholder.
|
||||
#
|
||||
# The settings of this option have no effect should 'extraPlayers' be enabled
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#maxplayers
|
||||
#
|
||||
maxPlayers:
|
||||
#
|
||||
# Enables/Disables the maxPlayers option.
|
||||
# When enabled will the total amount of players allowed to join be changed to what 'amount' is set to.
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#maxplayers-enabled
|
||||
#
|
||||
enabled: false
|
||||
#
|
||||
# Sets the number to display for the max number of players allowed to join your server.
|
||||
#
|
||||
# Example:
|
||||
# Setting this option to 0 (Default) while 1 player is online would display '1/0'
|
||||
#
|
||||
# Defaults to 0 if not set.
|
||||
#
|
||||
# Read more: https://asl.andre601.ch/profiles/#maxplayers-amount
|
||||
#
|
||||
amount: 0
|
||||
```
|
||||
///
|
||||
|
||||
#### Config.yml
|
||||
|
||||
The config.yml file contains settings related to the plugin itself and some of its functionality.
|
||||
These functions include, but aren't limited to:
|
||||
|
||||
- Setting the default name and UUID used for an unknown (Not cached) player.
|
||||
- Disabling/Enabling caching of players.
|
||||
- Disabling/Enabling checking for updates.
|
||||
- Disabling/Enabling debug mode.
|
||||
- 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.
|
||||
|
||||
/// details | default config.yml content
|
||||
```yaml
|
||||
#
|
||||
# Used for when AdvancedServerList doesn't have a cached player to use for player placeholders.
|
||||
#
|
||||
unknownPlayer:
|
||||
#
|
||||
# The name to use. Defaults to Anonymous.
|
||||
#
|
||||
name: "Anonymous"
|
||||
#
|
||||
# The UUID to use. Defaults to 606e2ff0-ed77-4842-9d6c-e1d3321c7838 (UUID of MHF_Question).
|
||||
#
|
||||
uuid: "606e2ff0-ed77-4842-9d6c-e1d3321c7838"
|
||||
|
||||
#
|
||||
# Should the Caching of players be disabled?
|
||||
#
|
||||
# When set to true will AdvancedServerList not load any players from the cache.data file (if present) nor save any to it.
|
||||
# Placeholders that rely on the player being cached (such as ${player name}) will not work while this option is enabled.
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
#
|
||||
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.
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
#
|
||||
checkUpdates: true
|
||||
|
||||
#
|
||||
# Should debug mode be enabled?
|
||||
#
|
||||
# When set to true will AdvancedServerList print additional messages to the console prefixed with "[DEBUG]".
|
||||
# It is recommended to only enable this when having problems or when being told to by the plugin dev, as it could
|
||||
# otherwise cause significant spam in your console.
|
||||
#
|
||||
# Defaults to false when not present.
|
||||
#
|
||||
debug: false
|
||||
|
||||
#
|
||||
# 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
|
||||
```
|
||||
///
|
||||
|
||||
#### Additionally 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 `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.
|
||||
|
||||
## 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).
|
||||
|
||||
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.
|
||||
|
||||
To give an example is here a basic profile that only modifies the MOTD and nothing else:
|
||||
```yaml title="default.yml"
|
||||
priority: 0
|
||||
|
||||
motd:
|
||||
- 'Hello'
|
||||
- 'World!'
|
||||
```
|
||||
|
||||
### 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.
|
||||
|
||||
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.
|
||||
|
||||
/// 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.
|
||||
///
|
||||
|
||||
Here is another example profile using conditions to show it when the player was banned on the server:
|
||||
```yaml title="other_profile.yml"
|
||||
priority: 1
|
||||
|
||||
condition: '${player isBanned}'
|
||||
|
||||
motd:
|
||||
- '<red>You got <bold>banned</bold> from this server.'
|
||||
```
|
||||
|
||||
### Further examples
|
||||
|
||||
The [Examples page](../examples/index.md) contains more examples of different server list profiles for all kinds of situations.
|
||||
|
||||
## 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.
|
||||
|
||||
The plugin should then load any valid YAML file inside the `profiles` folder to then use.
|
||||
|
||||
And that's already it! You now have a working server list profile for your server.
|
||||
+19
-15
@@ -24,13 +24,11 @@ If you're new to the plugin is it recommended to check out the [Profiles page](p
|
||||
|
||||
AdvancedServerList supports the following platforms:
|
||||
|
||||
[![spigot-img]{ width="64" loading="lazy" }][spigot]
|
||||
[![paper-img]{ width="64" loading="lazy" }][paper]
|
||||
[![bungeecord-img]{ width="64" loading="lazy" }][spigot]
|
||||
[![waterfall-img]{ width="64" loading="lazy" }][paper]
|
||||
[![velocity-img]{ width="64" loading="lazy" }][velocity]
|
||||
|
||||
[spigot-img]: https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact-minimal/supported/spigot_vector.svg "Tested on Spigot"
|
||||
[paper-img]: https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact-minimal/supported/paper_vector.svg "Tested on Paper"
|
||||
[bungeecord-img]: https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact-minimal/supported/bungeecord_vector.svg "Tested on BungeeCord"
|
||||
[waterfall-img]: https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact-minimal/supported/waterfall_vector.svg "Tested on Waterfall"
|
||||
@@ -42,30 +40,36 @@ AdvancedServerList supports the following platforms:
|
||||
|
||||
## Dependencies
|
||||
|
||||
| Dependency | Platforms | Required? |
|
||||
|-------------------------------------------------------------------------|----------------------|-----------|
|
||||
| [ProtocolLib]{ target="_blank" rel="noreferrer nofollow noopener" } | Spigot | Yes |
|
||||
| [PlaceholderAPI]{ target="_blank" rel="noreferrer nofollow noopener" } | Spigot, Paper | No |
|
||||
| [ViaVersion]{ target="_blank" rel="noreferrer nofollow noopener" } | Spigot, Paper | No |
|
||||
| [PAPIProxyBridge]{ target="_blank" rel="noreferrer nofollow noopener" } | BungeeCord, Velocity | No |
|
||||
| [Maintenance]{ target="_blank" rel="noreferrer nofollow noopener" } | All | No |
|
||||
/// info
|
||||
All listed dependencies are optional.
|
||||
///
|
||||
|
||||
[protocollib]: https://www.spigotmc.org/resources/1997/
|
||||
[placeholderapi]: https://www.spigotmc.org/resources/6245/
|
||||
[viaversion]: https://www.spigotmc.org/resources/19254/
|
||||
| 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)
|
||||
- [API](api/index.md)
|
||||
- [Changelog](api/changelog.md)
|
||||
- [Reference](api/reference/index.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)
|
||||
@@ -0,0 +1,7 @@
|
||||
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
|
||||
+27
-1
@@ -10,4 +10,30 @@ Note that these pages only cover server list profile files. The config.yml is au
|
||||
|
||||
## Pages
|
||||
|
||||
{nav}
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- [**v3.7.0 to v3.8.0**](v3_7_0-to-v3_8_0.md)
|
||||
|
||||
----
|
||||
|
||||
Migrating from version 3.7.0 to 3.8.0.
|
||||
|
||||
- [**< v3.7.0 to v3.7.0**](pre-v3_7_0-to-v3_7_0.md)
|
||||
|
||||
----
|
||||
|
||||
Migrate from any version prior to 3.7.0 to 3.7.0 or newer.
|
||||
|
||||
- [**v1.9.0 to v1.10.0**](v1_9_0-to-v1_10_0.md)
|
||||
|
||||
----
|
||||
|
||||
Migrate from version 1.9.0 to 1.10.0.
|
||||
|
||||
- [**v1.5.3 to v1.6.0**](v1_5_3-to-v1_6_0.md)
|
||||
|
||||
----
|
||||
|
||||
Migrate from version 1.5.3 to 1.6.0.
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,56 @@
|
||||
---
|
||||
icon: octicons/arrow-right-24
|
||||
---
|
||||
|
||||
# < v3.7.0 to v3.7.0
|
||||
|
||||
Version 3.7.0 of AdvancedServerList brought significant changes to its conditions system.
|
||||
Namely, the `conditions` option is now deprecated and planned for removal in a future release of the Plugin, and the new [`condition`](../profiles/index.md#condition) option should now be used instead.
|
||||
|
||||
## Migration
|
||||
|
||||
To migrate, all you have to do is take the entries of the old conditions option and convert them into a single String connected with `and` operators in between. See the [Example below](#example).
|
||||
|
||||
## Example
|
||||
|
||||
Here is a before and after example to help visualize the change:
|
||||
|
||||
/// tab | Before
|
||||
```yaml
|
||||
priority: 0
|
||||
|
||||
conditions:
|
||||
- '${player protocol} > 763'
|
||||
- '${player isWhitelisted} == true'
|
||||
|
||||
motd:
|
||||
- 'Welcome ${player name}!'
|
||||
```
|
||||
///
|
||||
|
||||
/// tab | After
|
||||
```yaml
|
||||
priority: 0
|
||||
|
||||
# The text can all be in one line. This is only for better readability.
|
||||
condition: |
|
||||
${player protocol} >= 763 and
|
||||
${player isWhitelisted}
|
||||
|
||||
motd:
|
||||
- 'Welcome ${player name}!'
|
||||
```
|
||||
///
|
||||
|
||||
/// tab | Diff View
|
||||
```diff
|
||||
priority: 0
|
||||
|
||||
-conditions:
|
||||
- - '${player protocol} >= 763'
|
||||
- - '${player isWhitelisted} == true'
|
||||
+condition: |
|
||||
+ ${player protocol} >= 763 and
|
||||
+ ${player isWhitelisted}
|
||||
```
|
||||
///
|
||||
@@ -22,82 +22,87 @@ The migration should be fairly simple. [An example](#example) is available to lo
|
||||
|
||||
Here is a before and after example to help visualize the change:
|
||||
|
||||
=== "Before"
|
||||
```yaml
|
||||
priority: 0
|
||||
|
||||
motd:
|
||||
- 'Line 1'
|
||||
- 'Line 2'
|
||||
|
||||
favicon: '${player name}'
|
||||
|
||||
hidePlayers: false
|
||||
|
||||
players:
|
||||
- 'Line 1'
|
||||
- 'Line 2'
|
||||
- 'Line 3'
|
||||
|
||||
playerCount: '<grey>Hover Me!'
|
||||
|
||||
xMore: 1
|
||||
```
|
||||
=== "After"
|
||||
```yaml
|
||||
priority: 0
|
||||
|
||||
motd:
|
||||
- 'Line 1'
|
||||
- 'Line 2'
|
||||
|
||||
favicon: '${player name}'
|
||||
|
||||
playerCount:
|
||||
hidePlayers: false
|
||||
|
||||
hover:
|
||||
- 'Line 1'
|
||||
- 'Line 2'
|
||||
- 'Line 3'
|
||||
|
||||
text: '<grey>Hover Me!'
|
||||
|
||||
extraPlayers:
|
||||
enabled: true
|
||||
amount: 1
|
||||
```
|
||||
=== "Diff view"
|
||||
```diff
|
||||
priority: 0
|
||||
|
||||
motd:
|
||||
- 'Line 1'
|
||||
- 'Line 2'
|
||||
|
||||
favicon: '${player name}'
|
||||
|
||||
-hidePlayers: false
|
||||
-
|
||||
-players:
|
||||
- - 'Line 1'
|
||||
- - 'Line 2'
|
||||
- - 'Line 3'
|
||||
-
|
||||
-playerCount: '<grey>Hover Me!'
|
||||
-
|
||||
-xMore: 1
|
||||
+playerCount:
|
||||
+ hidePlayers: false
|
||||
+
|
||||
+ hover:
|
||||
+ - 'Line 1'
|
||||
+ - 'Line 2'
|
||||
+ - 'Line 3'
|
||||
+
|
||||
+ text: '<grey>Hover Me!'
|
||||
+
|
||||
+ extraPlayers:
|
||||
+ enabled: true
|
||||
+ amount: 1
|
||||
```
|
||||
/// tab | Before
|
||||
```yaml
|
||||
priority: 0
|
||||
|
||||
motd:
|
||||
- 'Line 1'
|
||||
- 'Line 2'
|
||||
|
||||
favicon: '${player name}'
|
||||
|
||||
hidePlayers: false
|
||||
|
||||
players:
|
||||
- 'Line 1'
|
||||
- 'Line 2'
|
||||
- 'Line 3'
|
||||
|
||||
playerCount: '<grey>Hover Me!'
|
||||
|
||||
xMore: 1
|
||||
```
|
||||
///
|
||||
|
||||
/// tab | After
|
||||
```yaml
|
||||
priority: 0
|
||||
|
||||
motd:
|
||||
- 'Line 1'
|
||||
- 'Line 2'
|
||||
|
||||
favicon: '${player name}'
|
||||
|
||||
playerCount:
|
||||
hidePlayers: false
|
||||
|
||||
hover:
|
||||
- 'Line 1'
|
||||
- 'Line 2'
|
||||
- 'Line 3'
|
||||
|
||||
text: '<grey>Hover Me!'
|
||||
|
||||
extraPlayers:
|
||||
enabled: true
|
||||
amount: 1
|
||||
```
|
||||
///
|
||||
|
||||
/// tab | Diff View
|
||||
```diff
|
||||
priority: 0
|
||||
|
||||
motd:
|
||||
- 'Line 1'
|
||||
- 'Line 2'
|
||||
|
||||
favicon: '${player name}'
|
||||
|
||||
-hidePlayers: false
|
||||
-
|
||||
-players:
|
||||
- - 'Line 1'
|
||||
- - 'Line 2'
|
||||
- - 'Line 3'
|
||||
-
|
||||
-playerCount: '<grey>Hover Me!'
|
||||
-
|
||||
-xMore: 1
|
||||
+playerCount:
|
||||
+ hidePlayers: false
|
||||
+
|
||||
+ hover:
|
||||
+ - 'Line 1'
|
||||
+ - 'Line 2'
|
||||
+ - 'Line 3'
|
||||
+
|
||||
+ text: '<grey>Hover Me!'
|
||||
+
|
||||
+ extraPlayers:
|
||||
+ enabled: true
|
||||
+ amount: 1
|
||||
```
|
||||
///
|
||||
@@ -15,89 +15,94 @@ To migrate all you have to do is use the new `profiles` option and add separate
|
||||
|
||||
Here is a before and after example to help visualize the change:
|
||||
|
||||
=== "Before"
|
||||
```yaml
|
||||
priority: 0
|
||||
/// tab | Before
|
||||
```yaml
|
||||
priority: 0
|
||||
|
||||
motds:
|
||||
- |-
|
||||
Line 1
|
||||
Line 2
|
||||
- |-
|
||||
Line A
|
||||
Line B
|
||||
|
||||
favicon: '${player name}'
|
||||
motds:
|
||||
- |-
|
||||
Line 1
|
||||
Line 2
|
||||
- |-
|
||||
Line A
|
||||
Line B
|
||||
|
||||
playerCount:
|
||||
hidePlayers: false
|
||||
players:
|
||||
- 'Line 1'
|
||||
- 'Line 2'
|
||||
- 'Line 3'
|
||||
text: '<grey>Hover Me!'
|
||||
extraPlayers:
|
||||
enabled: false
|
||||
amount: 0
|
||||
```
|
||||
=== "After"
|
||||
```yaml
|
||||
priority: 0
|
||||
|
||||
profiles:
|
||||
# You can also use motd: ['Line 1', 'Line 2']
|
||||
- motd:
|
||||
- 'Line 1'
|
||||
- 'Line 2'
|
||||
# You can also use motd: ['Line A', 'Line B']
|
||||
- motd:
|
||||
- 'Line A'
|
||||
- 'Line B'
|
||||
|
||||
favicon: '${player name}'
|
||||
|
||||
playerCount:
|
||||
hidePlayers: false
|
||||
players:
|
||||
- 'Line 1'
|
||||
- 'Line 2'
|
||||
- 'Line 3'
|
||||
text: '<grey>Hover Me!'
|
||||
extraPlayers:
|
||||
enabled: false
|
||||
amount: 0
|
||||
```
|
||||
=== "Diff view"
|
||||
```diff
|
||||
priority: 0
|
||||
favicon: '${player name}'
|
||||
|
||||
-motds:
|
||||
- - |-
|
||||
- Line 1
|
||||
- Line 2
|
||||
- - |-
|
||||
- Line A
|
||||
- Line B
|
||||
+profiles:
|
||||
+ # You can also use motd: ['Line 1', 'Line 2']
|
||||
+ - motd:
|
||||
+ - 'Line 1'
|
||||
+ - 'Line 2'
|
||||
+ # You can also use motd: ['Line A', 'Line B']
|
||||
+ - motd:
|
||||
+ - 'Line A'
|
||||
+ - 'Line B'
|
||||
|
||||
favicon: '${player name}'
|
||||
|
||||
playerCount:
|
||||
hidePlayers: false
|
||||
players:
|
||||
- 'Line 1'
|
||||
- 'Line 2'
|
||||
- 'Line 3'
|
||||
text: '<grey>Hover Me!'
|
||||
extraPlayers:
|
||||
enabled: false
|
||||
amount: 0
|
||||
```
|
||||
playerCount:
|
||||
hidePlayers: false
|
||||
players:
|
||||
- 'Line 1'
|
||||
- 'Line 2'
|
||||
- 'Line 3'
|
||||
text: '<grey>Hover Me!'
|
||||
extraPlayers:
|
||||
enabled: false
|
||||
amount: 0
|
||||
```
|
||||
///
|
||||
|
||||
/// tab | After
|
||||
```yaml
|
||||
priority: 0
|
||||
|
||||
profiles:
|
||||
# You can also use motd: ['Line 1', 'Line 2']
|
||||
- motd:
|
||||
- 'Line 1'
|
||||
- 'Line 2'
|
||||
# You can also use motd: ['Line A', 'Line B']
|
||||
- motd:
|
||||
- 'Line A'
|
||||
- 'Line B'
|
||||
|
||||
favicon: '${player name}'
|
||||
|
||||
playerCount:
|
||||
hidePlayers: false
|
||||
players:
|
||||
- 'Line 1'
|
||||
- 'Line 2'
|
||||
- 'Line 3'
|
||||
text: '<grey>Hover Me!'
|
||||
extraPlayers:
|
||||
enabled: false
|
||||
amount: 0
|
||||
```
|
||||
///
|
||||
|
||||
/// tab | Diff View
|
||||
```diff
|
||||
priority: 0
|
||||
|
||||
-motds:
|
||||
- - |-
|
||||
- Line 1
|
||||
- Line 2
|
||||
- - |-
|
||||
- Line A
|
||||
- Line B
|
||||
+profiles:
|
||||
+ # You can also use motd: ['Line 1', 'Line 2']
|
||||
+ - motd:
|
||||
+ - 'Line 1'
|
||||
+ - 'Line 2'
|
||||
+ # You can also use motd: ['Line A', 'Line B']
|
||||
+ - motd:
|
||||
+ - 'Line A'
|
||||
+ - 'Line B'
|
||||
|
||||
favicon: '${player name}'
|
||||
|
||||
playerCount:
|
||||
hidePlayers: false
|
||||
players:
|
||||
- 'Line 1'
|
||||
- 'Line 2'
|
||||
- 'Line 3'
|
||||
text: '<grey>Hover Me!'
|
||||
extraPlayers:
|
||||
enabled: false
|
||||
amount: 0
|
||||
```
|
||||
///
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
icon: octicons/arrow-right-24
|
||||
---
|
||||
|
||||
# v3.7.0 to v3.8.0
|
||||
|
||||
v3.8.0 brought a small yet important change to the condition system, which is the change of the "contains" operand from `<-` to `<_` to avoid possible issues with numbers.
|
||||
|
||||
## Migration
|
||||
|
||||
To migrate, switch any appearances of `<-` with `<_`
|
||||
|
||||
## Example
|
||||
|
||||
Here is a before and after example to help visualize the change:
|
||||
|
||||
/// tab | Before
|
||||
```yaml
|
||||
priority: 0
|
||||
|
||||
conditions: '${server host} <- "survival"'
|
||||
|
||||
motd:
|
||||
- 'Welcome ${player name}!'
|
||||
```
|
||||
///
|
||||
|
||||
/// tab | After
|
||||
```yaml
|
||||
priority: 0
|
||||
|
||||
condition: '${server host} <_ "survival"'
|
||||
|
||||
motd:
|
||||
- 'Welcome ${player name}!'
|
||||
```
|
||||
///
|
||||
|
||||
/// tab | Diff View
|
||||
```diff
|
||||
priority: 0
|
||||
|
||||
-condition: '${server host} <- "survival"'
|
||||
+condition: '${server host} <_ "survival"'
|
||||
|
||||
motd:
|
||||
- 'Welcome ${player name}!'
|
||||
```
|
||||
///
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
icon: octicons/arrow-right-24
|
||||
---
|
||||
|
||||
# v3.8.0 to v3.9.0
|
||||
|
||||
v3.9.0 brings a small change to the `~=` operand by changing it to `=~` for sake of consistent pattern design. Additionally, was `~` added as a single-character equivalent to `=`.
|
||||
|
||||
## Migration
|
||||
|
||||
To migrate, switch any appearances of `~=` with `=~` or `~`.
|
||||
|
||||
## Example
|
||||
|
||||
Here is a before and after example to help visualize the change:
|
||||
|
||||
/// tab | Before
|
||||
```yaml
|
||||
priority: 0
|
||||
|
||||
conditions: '${player name} ~= "Someone"'
|
||||
|
||||
motd:
|
||||
- 'Welcome ${player name}!'
|
||||
```
|
||||
///
|
||||
|
||||
/// tab | After
|
||||
```yaml
|
||||
priority: 0
|
||||
|
||||
condition: '${player name} =~ "Someone"'
|
||||
|
||||
motd:
|
||||
- 'Welcome ${player name}!'
|
||||
```
|
||||
///
|
||||
|
||||
/// tab | Diff View
|
||||
```diff
|
||||
priority: 0
|
||||
|
||||
-condition: '${player name} ~= "Someone"'
|
||||
+condition: '${player name} =~ "Someone"'
|
||||
|
||||
motd:
|
||||
- 'Welcome ${player name}!'
|
||||
```
|
||||
///
|
||||
@@ -13,15 +13,16 @@ AdvancedServerList provides support for [PlaceholderAPI] placeholders to be used
|
||||
The below listed placeholders can be used through PlaceholderAPI in other plugins.
|
||||
Note that the values depend on the player it is used for, as AdvancedServerList will try and get a matching [Server List Profile](../profiles/index.md) to display values from.
|
||||
|
||||
| Placeholder | Description |
|
||||
|------------------------------|---------------------------------------------------------------------------------------------------------|
|
||||
| `%asl_favicon%` | Gives the value of `favicon` from a matching Profile. |
|
||||
| `%asl_extra_players_max%` | Gives the value of `playerCount -> extraPlayers -> amount` from a matching Profile. Can return `null`. |
|
||||
| `%asl_motd%` | Gives the value of `motd` in the matching Profile as a single String. |
|
||||
| `%asl_playercount_hover%` | Gives the value of `playerCount -> hover` from a matching Profile as a single String. |
|
||||
| `%asl_playercount_text%` | Gives the value of `playerCount -> text` from a matching Profile. |
|
||||
| `%asl_players_max%` | Gives the value of `playerCount -> maxPlayers -> amount` from a matching Profile. Can return `null`. |
|
||||
| `%asl_players_max_modified%` | Returns the output of `${server playersMax}`. |
|
||||
| Placeholder | Description |
|
||||
|----------------------------------|--------------------------------------------------------------------------------------------------------|
|
||||
| `%asl_favicon%` | Gives the value of `favicon` from a matching Profile. |
|
||||
| `%asl_extra_players_max%` | Gives the value of `playerCount -> extraPlayers -> amount` from a matching Profile. Can return `null`. |
|
||||
| `%asl_motd%` | Gives the value of `motd` in the matching Profile as a single String. |
|
||||
| `%asl_playercount_extraplayers%` | Gives the value of `playerCount -> extraPlayers -> amount` from a matching Profile. Can return `null`. |
|
||||
| `%asl_playercount_hover%` | Gives the value of `playerCount -> hover` from a matching Profile as a single String. |
|
||||
| `%asl_playercount_maxplayers%` | Gives the value of `playerCount -> maxPlayers -> amount` from a matching profile. Can return `null`. |
|
||||
| `%asl_playercount_text%` | Gives the value of `playerCount -> text` from a matching Profile. |
|
||||
| `%asl_server_playersmax%` | Gives the output of `${server playersMax}` |
|
||||
|
||||
## Using Placeholders in Server List profiles
|
||||
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
---
|
||||
icon: octicons/file-code-24
|
||||
---
|
||||
|
||||
Expressions are part of a Server List Profile's condition system and allows you to define when a profile should and should not be displayed.
|
||||
|
||||
This page covers what the Expression system of AdvancedServerList offers and can do.
|
||||
|
||||
## Content
|
||||
|
||||
- [Types](#types)
|
||||
- [Literals](#literals)
|
||||
- [Numbers](#numbers)
|
||||
- [Strings](#strings)
|
||||
- [Booleans](#booleans)
|
||||
- [Placeholders](#placeholders)
|
||||
- [Binary Operators](#binary-operators)
|
||||
- [Parenthesis](#parenthesis)
|
||||
- [Negation](#negation)
|
||||
- [Credits](#credits)
|
||||
|
||||
## Types
|
||||
|
||||
An expression contains different types of components that are evaluated to return a boolean output of either `true` or `false`.
|
||||
Depending on the type(s) will the output be differently understood and handled.
|
||||
|
||||
### Literals
|
||||
|
||||
The following cases are considered literal values:
|
||||
|
||||
#### Numbers
|
||||
|
||||
Any number is considered an expression, meaning the below examples are considered valid:
|
||||
|
||||
/// example | Examples
|
||||
```
|
||||
0
|
||||
1000
|
||||
-7
|
||||
47.2
|
||||
```
|
||||
///
|
||||
|
||||
#### Strings
|
||||
|
||||
A String in single or double quotes is a valid expression.
|
||||
|
||||
/// warning | Important
|
||||
Specific keywords will be treated as [Binary Operators](#binary-operators) even if they are part of a word.
|
||||
As an example, `Sand` would cause the expression engine to see `S AND` due to parts of the word matching `and`.
|
||||
|
||||
To avoid this is it very important to always surround Strings with single or double quotes, as that tells the expression engine to treat as a String.
|
||||
///
|
||||
|
||||
/// example | Examples
|
||||
```
|
||||
"Hello World!"
|
||||
""
|
||||
```
|
||||
///
|
||||
|
||||
#### Booleans
|
||||
|
||||
Strings `true` and `false` are treated as boolean literals.
|
||||
|
||||
### Placeholders
|
||||
|
||||
Any [placeholder](placeholders.md) is a valid expression.
|
||||
|
||||
/// example | Examples
|
||||
```
|
||||
${player protocol}
|
||||
${player name}
|
||||
|
||||
${server playersOnline}
|
||||
${server host}
|
||||
```
|
||||
///
|
||||
|
||||
### Binary Operators
|
||||
|
||||
`<expression> <binary operator> <expression>` is a valid expression.
|
||||
|
||||
The following binary operators can be used for boolean evaluation:
|
||||
|
||||
| Operator | True if |
|
||||
|---------------|-------------------------------------------------------------------------------------------------------------|
|
||||
| `and` / `&&` | Both expressions return true. |
|
||||
| `or` / `\|\|` | Either expression returns true. |
|
||||
| `==` / `=` | Both expressions are equal (Case sensitive). |
|
||||
| `=~` / `~` | Both expressions are equal (Not Case sensitive). |
|
||||
| `!=` | Both expressions are not equal (Case sensitive). |
|
||||
| `!~` | Both expressions are not equal (Not case sensitive). |
|
||||
| `\|-` | Left expression starts with right expression. |
|
||||
| `-\|` | Left expression ends with right expression. |
|
||||
| `<_` | Left expression contains right expression. |
|
||||
| `<` | Left expression is less than the right expression. Strings use their text length as number. |
|
||||
| `<=` | Left expression is less than, or equal to, the right expression. Strings use their text length as number. |
|
||||
| `>` | Left expression is larger than the right expression. Strings use their text length as number. |
|
||||
| `>=` | Left expression is larger than, or equal to, the right expression. Strings use their text length as number. |
|
||||
|
||||
These additional binary operators can also be used to perform certain actions:
|
||||
|
||||
| Operator | Semantic |
|
||||
|----------|-----------------------------------------------------------------------------|
|
||||
| `.` | Concatenates (merges) two Strings |
|
||||
| `+` | Adds two numbers. Strings use their text length as number. |
|
||||
| `-` | Subtracts one number from another. Strings use their text length as number. |
|
||||
| `*` | Multiplies two numbers. Strings use their text length as number. |
|
||||
| `/` | Divides one number by another. Strings use their text length as number. |
|
||||
|
||||
/// example | Examples
|
||||
```
|
||||
${player name} != "Anonymous"
|
||||
763 > ${player protocol} > 758
|
||||
${player hasPlayedBefore} and ${player isBanned} == "false"
|
||||
```
|
||||
///
|
||||
|
||||
### Parenthesis
|
||||
|
||||
`( <expression> )` is a valid expression.
|
||||
Parenthesis can be used to prevent ambiguities.
|
||||
|
||||
### Negation
|
||||
|
||||
`!` can be used to negate boolean expressions.
|
||||
|
||||
```
|
||||
!${player isWhitelisted}
|
||||
```
|
||||
|
||||
## Credits
|
||||
|
||||
This page, including some examples used, was adobted from [:octicons-book-24: CodeCrafter47/BungeeTabListPlus/wiki](https://github.com/CodeCrafter47/BungeeTabListPlus/wiki/Expressions){ target="_blank" rel="nofollow" }.
|
||||
@@ -6,14 +6,15 @@ icon: octicons/pencil-24
|
||||
|
||||
All text options, with exception of [`Conditions`](../index.md#conditions), allow the usage of formatting options using [MiniMessage].
|
||||
|
||||
!!! info "Online Tool"
|
||||
The devs of the Adventure library provide a handy online tool to create the right formatting codes to display the text properly.
|
||||
You can find the tool at https://webui.advntr.dev/
|
||||
/// info | Online Tool
|
||||
The devs of the Adventure library provide a handy online tool to create the right formatting codes to display the text properly.
|
||||
You can find the tool at https://webui.advntr.dev/
|
||||
///
|
||||
|
||||
## Before starting
|
||||
|
||||
Please make sure to surround your text with either single quotes (`'`) or double quotes (`"`) should they start with a color or formatting code.
|
||||
Not surrounding these lines with (double) quotes will make the YAML parser Configurate treat them as something other than a String.
|
||||
Please make sure to surround your text with either single quotes (`'`) or double quotes (`"`).
|
||||
This avoids possible issues where the YAML parser would treat lines starting with specific characters as special options (i.e. `<` would be treated as a scolar value).
|
||||
|
||||
```yaml title="Wrong formatting"
|
||||
motd:
|
||||
@@ -37,8 +38,18 @@ The following options are **not** supported, no matter what option they are used
|
||||
|
||||
## Colors
|
||||
|
||||
Color options (`<aqua>`, `<red>`, `<gray>`, etc.) are available for all text options.
|
||||
24-Bit HEX colors (`<#ff0000>`, `<#123abc>`, etc.) are only available for the [`Motd` option](../index.md#motd) for a 1.16+ Server/Proxy.
|
||||
### Default colors
|
||||
|
||||
Default colors such as `<red>`, `<green>`, `<aqua>`, etc. may be used in all text options.
|
||||
|
||||
### Hex Colors
|
||||
|
||||
Hexadecimal colors may be used in the [`motd`](index.md#motd) option using the `<#RRGGBB>` format.
|
||||
|
||||
### Gradients
|
||||
|
||||
Gradients can be created by using `<gradient:<color1>:<color2>>`, replacing `<color1>` with a starting color name or hex color value and `<color2>` with an ending color name or hex color value.
|
||||
Only the [`motd`](index.md#motd) option may support hex color gradients and in all other options will it be downsampled.
|
||||
|
||||
## Formatting
|
||||
|
||||
|
||||
+230
-213
@@ -2,300 +2,317 @@
|
||||
icon: octicons/note-24
|
||||
---
|
||||
|
||||
# Profiles { #profiles-settings }
|
||||
# Profiles { #profiles-file }
|
||||
|
||||
AdvancedServerList allows the creation of multiple profiles.
|
||||
A profile is a single YAML file located in the plugin's `profiles` directory containing multiple settings including [Conditions](#conditions) and [Priority](#priority).
|
||||
AdvancedServerList allows you to create multiple so called Server List Profiles.
|
||||
A Server List Profile is a YAML file located in the plugin's `profiles` folder. Each Server List Profile allows you to modify one or multiple aspects of your server's display in a Multiplayer Server list.
|
||||
|
||||
!!! info "Important"
|
||||
In order for a profile to be considered "valid" by AdvancedServerList will it need to meet the following conditions:
|
||||
|
||||
- Have a [`Priority`](#priority) set to a valid, whole number (i.e. `1`)
|
||||
- Have **at least one** of the following options set:
|
||||
- [`Profiles`](#profiles) with at least one entry containing one of the below option
|
||||
- [`Motd`](#motd) set with at least one line of text
|
||||
- [`Favicon`](#favicon) set with a non-empty String
|
||||
- [`HidePlayers`](#hideplayers) set to `true`
|
||||
- [`Hover`](#hover) set with at least one line of text
|
||||
- [`Text`](#text) set with a non-empty String
|
||||
Additionally can [Conditions](#condition) and a [Priority](#priority) be set to set when a specific profile should be displayed to a player.
|
||||
|
||||
## Required Options
|
||||
|
||||
For a Server List Profile to be valid, will it require the following options to be set:
|
||||
|
||||
- A valid [`priority`](#priority) option with a single, whole number.
|
||||
- **At least** one of the following options:
|
||||
- [`profiles`](#profiles) with at least one of the below options set.
|
||||
- [`motd`](#motd) with at least one line to display.
|
||||
- [`favicon`](#favicon) with a non-empty String.
|
||||
- [`playerCount -> hidePlayers`](#hideplayers) with value `true`.
|
||||
- [`playerCount -> hover`](#hover) with at least one line to display.
|
||||
- [`playerCount -> text`](#text) with a non-empty String.
|
||||
|
||||
## Priority
|
||||
|
||||
The priority option determines the order in which the profiles are checked by AdvancedServerList, starting with the highest number.
|
||||
The Priority option allows you to define what Server List Profile should be chosen first.
|
||||
The plugin will go highest value to lowest value and will select the first Profile that has a [`condition`](#condition) returning `true`.
|
||||
|
||||
It will go through each file until it finds one with [`conditions`](#conditions) returning true (Default if no conditions are set).
|
||||
This means that a profile with no conditions and a priority of `1` will be used before a profile with a condition and priority `0` even if the player is meeting the condition.
|
||||
Should AdvancedServerList not find any profile with a positive condition will it not modify the server list for the players.
|
||||
|
||||
## Conditions
|
||||
/// note
|
||||
It is important to note that should no [`condition`](#condition) option be set will it default to `true`, meaning that a profile with priority 1 and no condition will be chosen over a profile with priority 0 and a condition, even if said condition also returns true.
|
||||
///
|
||||
|
||||
A list of conditions can be set that need to be met in order to have this profile shown to the player.
|
||||
[Placeholders](formatting.md#placeholders) can be used to further customize the conditions (PlaceholderAPI placeholders are **not** supported).
|
||||
## Condition
|
||||
|
||||
Only when **all** conditions defined return true will the profile be displayed.
|
||||
The `condition` option allows you to define specific requirements that need to be met to display the profile in question.
|
||||
Not setting this option, or setting it to an empty String (`condition: ''`), will result in `true` being returned.
|
||||
|
||||
You can remove this option, or set it to an empty list (`conditions: []`) to always return true.
|
||||
|
||||
### Operands
|
||||
|
||||
The following operants are available and can be used in the conditions.
|
||||
|
||||
<!-- admo:warning Only one operant can be used per condition! -->
|
||||
|
||||
| Operand | Description |
|
||||
|---------|------------------------------------------------------------------------|
|
||||
| `<` | Checks if the left value is less than the right one.[^1] |
|
||||
| `<=` | Checks if the left value is less than or equal to the right one.[^1] |
|
||||
| `>` | Checks if the left value is more than the right one.[^1] |
|
||||
| `>=` | Checks if the left value is more than or equal to the right one.[^1] |
|
||||
| `=` | Checks if the left value is equal to the right one. |
|
||||
| `!=` | Checks if the left value is not equal to the right one. |
|
||||
| `~=` | Checks if the left value is equal to the right one, ignoring case. |
|
||||
| `!~` | Checks if the left value is not equal to the right one, ignoring case. |
|
||||
|
||||
[^1]:
|
||||
Should the provided value not be a number, will AdvancedServerList use the text length to compare.
|
||||
Example: `SomeString > String` would be translated to `10 > 6`.
|
||||
The condition option can hold one or multiple expressions. The Expression system is explained on the [Expressions page](expressions.md).
|
||||
|
||||
## Profiles
|
||||
|
||||
<!-- admo:warning Priority and Conditions can NOT be used within profiles -->
|
||||
The `profile` option allows you to define a list of all other options, with the exception of [`priority`](#priority), [`condition`](#condition) or itself.
|
||||
|
||||
The `profiles` option allows you to set multiple MOTDs, player counts, etc. which the plugin would randomly choose from.
|
||||
If an option such as motd is not present in an entry will it check the file for the option and use that if present.
|
||||
When multiple entries are defined will AdvancedServerList randomly select one.
|
||||
Should an option exist in the file itself (i.e. [`motd`](#motd)) but not in the selected profiles entry will it be used. This allows you to randomize only one aspect of a Server List Profile while keeping all other options the same.
|
||||
|
||||
??? example "Example"
|
||||
```yaml title="YAML file"
|
||||
priority: 0
|
||||
|
||||
profiles:
|
||||
- motd:
|
||||
- '<rainbow>Line 1</rainbow>'
|
||||
- '<rainbow:!>Line 2</rainbow>'
|
||||
playerCount:
|
||||
text: '<green><bold>Awesome!'
|
||||
- playerCount:
|
||||
text: '<yellow><bold>Also Awesome!'
|
||||
|
||||
motd:
|
||||
- '<rainbow:2>Line A</rainbow>'
|
||||
- '<rainbow:!2>Line B</rainbow>'
|
||||
```
|
||||
<div class="result">
|
||||
|
||||
{ loading="lazy" }
|
||||
{ loading="lazy" }
|
||||
/// details | Example
|
||||
type: example
|
||||
|
||||
</div>
|
||||
```yaml title="YAML file"
|
||||
priority: 0
|
||||
|
||||
profiles:
|
||||
- motd: # You can also use ['<rainbow>Line1</rainbow>','<rainbow:!>Line 2</rainbow>']
|
||||
- '<rainbow>Line 1</rainbow>'
|
||||
- '<rainbow:!>Line 2</rainbow>'
|
||||
playerCount:
|
||||
text: '<green><bold>Awesome!'
|
||||
- playerCount:
|
||||
text: '<yellow><bold>Also Awesome!'
|
||||
|
||||
# This MOTD is used when the second profiles entry is selected.
|
||||
motd:
|
||||
- '<rainbow:2>Line A</rainbow>'
|
||||
- '<rainbow:!2>Line B</rainbow>'
|
||||
```
|
||||
<div class="result" markdown>
|
||||
|
||||
{ loading="lazy" }
|
||||
{ loading="lazy" }
|
||||
|
||||
</div>
|
||||
///
|
||||
|
||||
## Motd
|
||||
|
||||
The motd option allows to set up to two lines to be displayed in an MOTD.
|
||||
Normal colour and formatting codes such as `<aqua>` or `<bold>` are supported. On 1.16 and newer can you also use HEX colours using either `<#rrggbb>` or `<color:#rrggbb>`.
|
||||
The `motd` option allows you to alter the "Message of the day" that is being displayed on a server in the multiplayer screen.
|
||||
Please see the [Formatting](formatting.md) for all supported formatting options.
|
||||
|
||||
If you want to display multiple MOTDs will you need to use the [`Profiles` option](#profiles)
|
||||
Multiple, randomly selected, MOTDs can be displayed by using the [`profiles`](#profiles) option.
|
||||
|
||||
??? example "Example"
|
||||
```yaml title="YAML file"
|
||||
priority: 0
|
||||
|
||||
motd:
|
||||
- '<rainbow:2>Rainbow Gradients</rainbow>'
|
||||
- '<rainbow:!2>|||||||||||||||||||||||||||||||||||||</rainbow>'
|
||||
```
|
||||
<div class="result">
|
||||
/// details | Example
|
||||
type: example
|
||||
|
||||
{ loading="lazy" }
|
||||
```yaml title="YAML file"
|
||||
priority: 0
|
||||
|
||||
</div>
|
||||
motd:
|
||||
- '<rainbow:2>Rainbow Gradient</rainbow>'
|
||||
- '<rainbow:!2>|||||||||||||||||||||||||||||||||||||</rainbow>'
|
||||
```
|
||||
<div class="result" markdown>
|
||||
|
||||
{ loading="lazy" }
|
||||
|
||||
</div>
|
||||
///
|
||||
|
||||
## Favicon
|
||||
|
||||
The favicon option allows you to customize the favicon and display one or multiple different images.
|
||||
<!-- admo:info Images will be resized to 64x64 pixels. -->
|
||||
|
||||
This option currently supports the following values:
|
||||
The `favicon` option can be used to define an image to display in the server list.
|
||||
|
||||
- A URL pointing to a `64x64` PNG image.
|
||||
- A name with `.png` extension that matches a PNG file in the `favicons` folder.
|
||||
- `${player uuid}` (or alternatively `${player name}`) to display the head of the player. The UUID/Name resolving is handled by https://mc-heads.net
|
||||
The Value can be one of three possible options, each being checked for in order:
|
||||
|
||||
Please note that AdvancedServerList will rescale the image to be 64x64 pixels, so be sure to provide images at that particular scale.
|
||||
- A URL pointing to an image file. The URL needs to start with `https://` to work.
|
||||
- A PNG filename, including `.png` file extension, matching a PNG file in the `favicons` folder.
|
||||
- A player name or UUID, or a [placeholder](placeholders.md) that resolves into one.
|
||||
|
||||
??? example "Example"
|
||||
```yaml title="YAML file"
|
||||
priority: 0
|
||||
|
||||
# We use just colour to hide the MOTD
|
||||
motd:
|
||||
- '<grey>'
|
||||
- '<grey>'
|
||||
|
||||
# Player is Andre_601
|
||||
favicon: ${player uuid}
|
||||
```
|
||||
<div class="result">
|
||||
Note that for the name/UUID, the site https://mc-heads.net is being used.
|
||||
Use the URL option with the `${player uuid}` placeholder if you want to use another service.
|
||||
|
||||
/// details | Example
|
||||
type: example
|
||||
|
||||
{ loading="lazy" }
|
||||
```yaml title="YAML file"
|
||||
priority: 0
|
||||
|
||||
</div>
|
||||
# Hides the MOTD for demonstration purposes
|
||||
motd:
|
||||
- '<grey>'
|
||||
- '<grey>'
|
||||
|
||||
# Placeholder resolves to UUID of Andre_601
|
||||
favicon: '${player uuid}'
|
||||
```
|
||||
<div class="result" markdown>
|
||||
|
||||
{ loading="lazy" }
|
||||
|
||||
</div>
|
||||
///
|
||||
|
||||
## PlayerCount
|
||||
|
||||
The `playerCount` option contains multiple different options all about the Player count itself.
|
||||
The `playerCount` option contains various other options that are used to modify the player count (The text next to the ping icon that shows the online and max players of a server).
|
||||
|
||||
### HidePlayers
|
||||
|
||||
Boolean option to set whether AdvancedServerList should hide the player count or not. When set to `true` will the player count be replaced with `???`.
|
||||
Additionally will the [`Text`](#text) and [`Hover`](#hover) option be ignored.
|
||||
The `playerCount -> hidePlayers` option takes a boolean (`true` or `false`) to set whether the player count should be hidden or not.
|
||||
|
||||
??? example "Example"
|
||||
```yaml title="YAML file"
|
||||
priority: 0
|
||||
|
||||
# We use just colour to hide the MOTD
|
||||
motd:
|
||||
- '<grey>'
|
||||
- '<grey>'
|
||||
|
||||
playerCount:
|
||||
hidePlayers: true
|
||||
```
|
||||
<div class="result">
|
||||
When set to true will the player count be replaced with `???`.
|
||||
In addition are the [`playerCount -> text`](#text) and [`playerCount -> hover`](#hover) options ignored.
|
||||
|
||||
{ loading="lazy" }
|
||||
If you want to not show any text at all, set this option to `false` (or remove it) and instead use the [`playerCount -> text`](#text) option.
|
||||
|
||||
/// details | Example
|
||||
type: example
|
||||
|
||||
</div>
|
||||
```yaml title="YAML file"
|
||||
priority: 0
|
||||
|
||||
# Hides the MOTD for demonstration purposes
|
||||
motd:
|
||||
- '<grey>'
|
||||
- '<grey>'
|
||||
|
||||
playerCount:
|
||||
hidePlayers: true
|
||||
```
|
||||
<div class="result" markdown>
|
||||
|
||||
{ loading="lazy" }
|
||||
|
||||
</div>
|
||||
///
|
||||
|
||||
### Hover
|
||||
|
||||
This option allows to override the hover text usually displaying the players on the server when hovering over the player count.
|
||||
The `playerCount -> hover` option allows you to define lines of text to show when a player hovers over the player count with their cursor.
|
||||
|
||||
You can either remove this option or set to an empty list (`hover: []`) to not override the hover.
|
||||
Note that this option only accepts basic colors such as `<blue>` or `<grey>` and that HEX colors are not supported.
|
||||
|
||||
/// details | Example
|
||||
type: example
|
||||
|
||||
??? example "Example"
|
||||
```yaml title="YAML file"
|
||||
priority: 0
|
||||
|
||||
# We use just colour to hide the MOTD
|
||||
motd:
|
||||
- '<grey>'
|
||||
- '<grey>'
|
||||
|
||||
playerCount:
|
||||
hover:
|
||||
- '<grey>Line 1'
|
||||
- '<aqua>Line 2'
|
||||
- '<gold>Line 3'
|
||||
```
|
||||
<div class="result">
|
||||
```yaml title="YAML file"
|
||||
priority: 0
|
||||
|
||||
{ loading="lazy" }
|
||||
# Hides the MOTD for demonstration purposes
|
||||
motd:
|
||||
- '<grey>'
|
||||
- '<grey>'
|
||||
|
||||
</div>
|
||||
playerCount:
|
||||
hover:
|
||||
- '<grey>Line 1'
|
||||
- '<aqua>Line 2'
|
||||
- '<gold>Line 3'
|
||||
```
|
||||
<div class="result" markdown>
|
||||
|
||||
{ loading="lazy" }
|
||||
|
||||
</div>
|
||||
///
|
||||
|
||||
### Text
|
||||
|
||||
This option allows to override the text usually displaying the online players and total players that can join.
|
||||
Note that AdvancedServerList will not add the `<online>/<max>` text to the player count. Instead will you need to use [`${server playersOnline}`](placeholders.md#server) and [`${server playersMax}`](placeholders.md#server)
|
||||
The `playerCount -> text` option allows you to define a custom text to display instead of the usual `<online>/<max>`.
|
||||
|
||||
!!! info "Note"
|
||||
This feature works by changing the "outdated server" message followed by altering the protocol version of the server.
|
||||
Due to this will your server appear as "outdated" to the client (Have the ping icon crossed out). This is nothing that can be changed unfortunately.
|
||||
Please take note of the following caveats:
|
||||
|
||||
To not override the player count, remove this option or set it to an empty String (`text: ''`).
|
||||
- The plugin won't automatically add the `<online>/<max>` back to the text you set. Instead you'll have to use `${server playersOnline}/${server playersMax}` to recreate this.
|
||||
- The override is done by using the "outdated server" text displayed when a client pings a server that is not compatible. This means that the ping icon will appear crossed out and your server will be seen as "outdated" by the client (When hovering over the ping icon). This can't be avoided nor fixed by the plugin.
|
||||
|
||||
??? example "Example"
|
||||
```yaml title="YAML file"
|
||||
priority: 0
|
||||
|
||||
# We use just colour to hide the MOTD
|
||||
motd:
|
||||
- '<grey>'
|
||||
- '<grey>'
|
||||
|
||||
playerCount:
|
||||
text: '<yellow><bold>Cool text!'
|
||||
```
|
||||
<div class="result">
|
||||
If you want to not show any text, just use a single color (i.e. `text: '<grey>'`) to do so.
|
||||
|
||||
{ loading="lazy" }
|
||||
This option only supports basic colors and no HEX colors.
|
||||
|
||||
/// details | Example
|
||||
type: example
|
||||
|
||||
</div>
|
||||
```yaml title="YAML file"
|
||||
priority: 0
|
||||
|
||||
# Hides the MOTD for demonstration purposes
|
||||
motd:
|
||||
- '<grey>'
|
||||
- '<grey>'
|
||||
|
||||
playerCount:
|
||||
text: '<yellow><bold>Cool text!'
|
||||
```
|
||||
<div class="result" markdown>
|
||||
|
||||
{ loading="lazy" }
|
||||
|
||||
</div>
|
||||
///
|
||||
|
||||
### ExtraPlayers
|
||||
|
||||
Contains options to modify how the `<max>` number in the player count should look like.
|
||||
<!-- admo:warning Using this option overrides the output of the <code>${server playersMax}</code> placeholder (Except in condition). -->
|
||||
|
||||
<!-- admo:warning Using this option will modify the `${server playersMax}` placeholder (Except when used in conditions) -->
|
||||
The `playerCount -> extraPlayers` option contains settings for the "extra players" feature, which adds X to the current online player count and sets it as the server's max player count.
|
||||
|
||||
#### Enabled { #extraplayers-enabled }
|
||||
|
||||
Boolean option to set whether the extra players feature should be used or not.
|
||||
When set to `true` will the max amount of players be modified by taking the current amount of online players, add [`Amount`](#amount) more to it and use it.
|
||||
Enables the extraPlayers feature.
|
||||
Use the [`playerCount -> extraPlayers -> amount`](#extraplayers-amount) option to set how much to add to the max players count.
|
||||
|
||||
#### Amount { #extraplayers-amount }
|
||||
|
||||
Sets the number to add to the current online players to then use as the new max players count.
|
||||
<!-- admo:info This option does nothing when <code>playerCount -> hidePlayers</code> is enabled. -->
|
||||
|
||||
As an example, setting this to `1` while `10` players are online will display `11`, while `-1` would display `9`.
|
||||
The `playerCount -> extraPlayers -> amount` option defines how much should be added to the current online player count to then use as max player count.
|
||||
|
||||
??? example "Example"
|
||||
```yaml title="YAML file"
|
||||
priority: 0
|
||||
|
||||
# We use just colour to hide the MOTD
|
||||
motd:
|
||||
- '<grey>'
|
||||
- '<grey>'
|
||||
|
||||
playerCount:
|
||||
extraPlayers:
|
||||
enabled: true
|
||||
amount: 1
|
||||
```
|
||||
<div class="result">
|
||||
Example: Setting this option to `1` while currently 10 players are online will result in `10/11` being displayed on the player count (Assuming it is not being overriden by the [`playerCount -> text`](#text) option).
|
||||
|
||||
/// details | Example
|
||||
type: example
|
||||
|
||||
{ loading="lazy" }
|
||||
```yaml title="YAML file"
|
||||
priority: 0
|
||||
|
||||
</div>
|
||||
# Hides the MOTD for demonstration purposes
|
||||
motd:
|
||||
- '<grey>'
|
||||
- '<grey>'
|
||||
|
||||
playerCount:
|
||||
extraPlayers:
|
||||
enabled: true
|
||||
amount: 1
|
||||
```
|
||||
<div class="result" markdown>
|
||||
|
||||
{ loading="lazy" }
|
||||
|
||||
</div>
|
||||
///
|
||||
|
||||
### MaxPlayers
|
||||
|
||||
Contains options to set the max number of players allowed to join the server. This has only a visual effect and won't actually influence how many players can join your server.
|
||||
<!-- admo:info This feature is ignored should <code>playerCount -> extraPlayers</code> be enabled. -->
|
||||
<!-- admo:warning Using this option overrides the output of the <code>${server playersMax}</code> placeholder (Except in condition). -->
|
||||
|
||||
Note that this feature is ignored should [`extraPlayers`](#extraplayers) be enabled.
|
||||
|
||||
In case [`hidePlayers`](#hideplayers) is enabled will the max player count not be displayed, but still changed by this option.
|
||||
Should [`text`](#text) be set to a non-empty String will the max player count only be displayed when `${server playersMax}` is used.
|
||||
|
||||
<!-- admo:warning Using this option will modify the `${server playersMax}` placeholder (Except when used in conditions) -->
|
||||
The `playerCount -> maxPlayers` option is similar in nature to the [`playerCount -> extraPlayers`](#extraplayers) option, with the difference that the number set is being used as the max player count, instead of adding it together with the online player count first.
|
||||
|
||||
#### Enabled { #maxplayers-enabled }
|
||||
|
||||
Boolean option to set whether the max players feature should be used or not.
|
||||
When set to `true` will the value usually displaying how many players can join be changed to what you've set in the [`amount`](#maxplayers-amount) option.
|
||||
Enables the maxPlayers feature.
|
||||
Use the [`playerCount -> maxPlayers -> amount`](#maxplayers-amount) option to set the max player count itself.
|
||||
|
||||
#### Amount { #maxplayers-amount }
|
||||
|
||||
Sets the number to display as the max number of players allowed to join your server.
|
||||
Note that this will also affect the `${server playersMax}` placeholder, except when it is used inside conditions.
|
||||
<!-- admo:info This option does nothing when <code>playerCount -> hidePlayers</code> is enabled. -->
|
||||
|
||||
??? example "Example"
|
||||
```yaml title="YAML file"
|
||||
priority: 0
|
||||
|
||||
# We use just colour to hide the MOTD
|
||||
motd:
|
||||
- '<grey>'
|
||||
- '<grey>'
|
||||
|
||||
playerCount:
|
||||
maxPlayers:
|
||||
enabled: true
|
||||
amount: -1
|
||||
```
|
||||
<div class="result">
|
||||
The `playerCount -> maxPlayers -> amount` option defines the number to use as the server's max players count.
|
||||
Unlike the [`playerCount -> extraPlayers -> amount`](#extraplayers-amount) option does this one not first add the current online player count to the number to then set.
|
||||
|
||||
/// details | Example
|
||||
type: example
|
||||
|
||||
{ loading="lazy" }
|
||||
```yaml title="YAML file"
|
||||
priority: 0
|
||||
|
||||
</div>
|
||||
# Hides the MOTD for demonstration purposes
|
||||
motd:
|
||||
- '<grey>'
|
||||
- '<grey>'
|
||||
|
||||
playerCount:
|
||||
maxPlayers:
|
||||
enabled: true
|
||||
amount: -1
|
||||
```
|
||||
<div class="result" markdown>
|
||||
|
||||
{ loading="lazy" }
|
||||
|
||||
</div>
|
||||
///
|
||||
@@ -21,9 +21,9 @@ These placeholders use the player who pinged the server, to return values. They
|
||||
| `${player protocol}` | The protocol version of the player. | All | No |
|
||||
| `${player uuid}` | The UUID of the player. | All | Yes[^3] |
|
||||
| `${player version}` | The protocol version of the player as readable MC version. | Velocity | No |
|
||||
| `${player hasPlayedBefore}` | Boolean for whether the player has played on the server before. | Spigot/Paper | Yes |
|
||||
| `${player isBanned}` | Boolean for whether the player has been banned from the server. | Spigot/Paper | Yes |
|
||||
| `${player isWhitelisted}` | Boolean for whether the player is whitelisted on the server. | Spigot/Paper | Yes |
|
||||
| `${player hasPlayedBefore}` | Boolean for whether the player has played on the server before. | Paper | Yes |
|
||||
| `${player isBanned}` | Boolean for whether the player has been banned from the server. | Paper | Yes |
|
||||
| `${player isWhitelisted}` | Boolean for whether the player is whitelisted on the server. | Paper | Yes |
|
||||
|
||||
[^1]:
|
||||
Whether this placeholder requires the player to have joined before while AdvancedServerList was running.
|
||||
@@ -35,22 +35,22 @@ These placeholders use the player who pinged the server, to return values. They
|
||||
|
||||
These placeholders use values given by the server/proxy AdvancedServerList runs on.
|
||||
|
||||
| Placeholder | Description |
|
||||
|------------------------------|-------------------------------------------------------------------------|
|
||||
| `${server playersOnline}` | The number of players online on this proxy/server.[^4] |
|
||||
| `${server playersMax}` | The total number of players that can join this server.[^5] |
|
||||
| `${server host}` | The domain/IP the player pinged.[^6] |
|
||||
| `${server whitelistEnabled}` | Whether the whitelist is enabled or not. Only available on Spigot/Paper |
|
||||
| Placeholder | Description | Platforms |
|
||||
|------------------------------|------------------------------------------------------------|-----------|
|
||||
| `${server playersOnline}` | The number of players online on this proxy/server.[^4] | All |
|
||||
| `${server playersMax}` | The total number of players that can join this server.[^5] | All |
|
||||
| `${server host}` | The domain/IP the player pinged.[^6] | All |
|
||||
| `${server whitelistEnabled}` | Whether the whitelist is enabled or not. | Paper |
|
||||
|
||||
[^4]:
|
||||
An space-separated list of worlds (Spigot/Paper) or Servers (BungeeCord/Velocity) can be provided to display the number of players in these worlds/servers.
|
||||
Example: `${server playersOnline lobby1 lobby2}` will display the numbers of players online on the servers `lobby1` and `lobby2`.
|
||||
A comma-separated list of world (On Paper) or Server (On BungeeCord/Velocity) names can be provided to display the added numbers of players in these worlds/servers.
|
||||
**Example:** `${server playersOnline lobby1,lobby2}` will display the collective numbers of players in the servers `lobby1` and `lobby2`.
|
||||
[^5]:
|
||||
When the [`amount` option](../index.md#amount) is used will this placeholder display the modified max players count.
|
||||
The only exception is [`conditions`](../index.md#conditions) where it uses the actual max players of the server/proxy.
|
||||
Using either the [extraPlayers' `amount`](index.md#extraplayers-amount) or [maxPlayers' `amount`](index.md#maxplayers-amount) option will make this placeholder return the modified max players count.
|
||||
Only exception to this rule is when the placeholder is used in the [`condition`](index.md#condition) option in which case it returns the actual max player count of the proxy/server.
|
||||
[^6]:
|
||||
An optional server name can be provided to display the IP/Domain associated with that server. Only works on BungeeCord/Velocity.
|
||||
Example: `${server host survival}` would display the IP/Domain associated with the `survival` server.
|
||||
An optional server name can be provided to display the IP/Domain associated with that server. This only works on BungeeCord or Velocity.
|
||||
**Example:** `${server host survival}` would display the IP/Domain associated with the `survival` server.
|
||||
|
||||
## PlaceholderAPI
|
||||
|
||||
|
||||
+21
-6
@@ -29,14 +29,15 @@ theme:
|
||||
- navigation.tabs
|
||||
- navigation.tabs.sticky
|
||||
- content.code.copy
|
||||
- content.tooltips
|
||||
|
||||
icon:
|
||||
repo: 'simple/codeberg'
|
||||
admonition:
|
||||
note: 'octicons/tag-24'
|
||||
note: 'octicons/pencil-24'
|
||||
abstract: 'octicons/checklist-24'
|
||||
info: 'octicons/info-24'
|
||||
tip: 'octicons/flame-24'
|
||||
tip: 'octicons/light-bulb-24'
|
||||
success: 'octicons/check-24'
|
||||
question: 'octicons/question-24'
|
||||
warning: 'octicons/alert-24'
|
||||
@@ -72,7 +73,6 @@ plugins:
|
||||
- pagenav-generator
|
||||
|
||||
markdown_extensions:
|
||||
- markdown.extensions.admonition:
|
||||
- markdown.extensions.toc:
|
||||
permalink: true
|
||||
- markdown.extensions.attr_list:
|
||||
@@ -84,11 +84,26 @@ markdown_extensions:
|
||||
- pymdownx.highlight:
|
||||
- pymdownx.magiclink:
|
||||
- pymdownx.superfences:
|
||||
- pymdownx.tabbed:
|
||||
alternate_style: true
|
||||
- pymdownx.details:
|
||||
- pymdownx.snippets:
|
||||
base_path: docs/.snippets
|
||||
- pymdownx.blocks.admonition:
|
||||
types:
|
||||
- note
|
||||
- abstract
|
||||
- info
|
||||
- tip
|
||||
- success
|
||||
- question
|
||||
- warning
|
||||
- failure
|
||||
- danger
|
||||
- bug
|
||||
- example
|
||||
- quote
|
||||
- pymdownx.blocks.tab:
|
||||
alternate_style: true
|
||||
- pymdownx.blocks.details:
|
||||
|
||||
hooks:
|
||||
- docs/.hooks/badges.py
|
||||
- docs/.hooks/replacer.py
|
||||
@@ -34,7 +34,7 @@
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>bukkit</artifactId>
|
||||
<artifactId>paper</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>${plugin.version}</version>
|
||||
|
||||
@@ -48,14 +48,6 @@
|
||||
<id>papermc</id>
|
||||
<url>https://papermc.io/repo/repository/maven-public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spigot</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>protocollib-repo</id>
|
||||
<url>https://repo.dmulloy2.net/repository/public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>placeholderapi-repo</id>
|
||||
<url>https://repo.extendedclip.com/content/repositories/placeholderapi/</url>
|
||||
@@ -85,24 +77,6 @@
|
||||
<version>1.20-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.20-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.kyori</groupId>
|
||||
<artifactId>adventure-platform-bukkit</artifactId>
|
||||
<version>4.3.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.comphenix.protocol</groupId>
|
||||
<artifactId>ProtocolLib</artifactId>
|
||||
<version>5.1.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bstats</groupId>
|
||||
<artifactId>bstats-bukkit</artifactId>
|
||||
@@ -112,19 +86,19 @@
|
||||
<dependency>
|
||||
<groupId>me.clip</groupId>
|
||||
<artifactId>placeholderapi</artifactId>
|
||||
<version>2.11.4</version>
|
||||
<version>2.11.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.viaversion</groupId>
|
||||
<artifactId>viaversion-api</artifactId>
|
||||
<version>4.8.1</version>
|
||||
<version>4.9.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>AdvancedServerList-Bukkit-${plugin.version}</finalName>
|
||||
<finalName>AdvancedServerList-Paper-${plugin.version}</finalName>
|
||||
<resources>
|
||||
<resource>
|
||||
<filtering>true</filtering>
|
||||
@@ -135,7 +109,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.11.0</version>
|
||||
<version>3.12.1</version>
|
||||
<configuration>
|
||||
<release>16</release>
|
||||
</configuration>
|
||||
@@ -143,7 +117,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<version>3.5.2</version>
|
||||
<configuration>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<relocations>
|
||||
+60
-19
@@ -25,41 +25,53 @@
|
||||
|
||||
package ch.andre601.advancedserverlist.paper;
|
||||
|
||||
import ch.andre601.advancedserverlist.bukkit.BukkitCore;
|
||||
import ch.andre601.advancedserverlist.bukkit.commands.CmdAdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.bukkit.listeners.JoinEvent;
|
||||
import ch.andre601.advancedserverlist.bukkit.listeners.LoadEvent;
|
||||
import ch.andre601.advancedserverlist.bukkit.listeners.WorldEvents;
|
||||
import ch.andre601.advancedserverlist.bukkit.logging.BukkitLogger;
|
||||
import ch.andre601.advancedserverlist.bukkit.objects.placeholders.BukkitPlayerPlaceholders;
|
||||
import ch.andre601.advancedserverlist.bukkit.objects.placeholders.BukkitServerPlaceholders;
|
||||
import ch.andre601.advancedserverlist.bukkit.objects.placeholders.PAPIPlaceholders;
|
||||
import ch.andre601.advancedserverlist.bukkit.objects.WorldCache;
|
||||
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 ch.andre601.advancedserverlist.paper.listeners.PaperPingEvent;
|
||||
import ch.andre601.advancedserverlist.paper.commands.CmdAdvancedServerList;
|
||||
import ch.andre601.advancedserverlist.paper.listeners.LoadEvent;
|
||||
import ch.andre601.advancedserverlist.paper.logging.PaperLogger;
|
||||
import ch.andre601.advancedserverlist.paper.objects.WorldCache;
|
||||
import ch.andre601.advancedserverlist.paper.objects.placeholders.PAPIPlaceholders;
|
||||
import ch.andre601.advancedserverlist.paper.objects.placeholders.PaperPlayerPlaceholders;
|
||||
import ch.andre601.advancedserverlist.paper.objects.placeholders.PaperServerPlaceholders;
|
||||
import org.bstats.bukkit.Metrics;
|
||||
import org.bstats.charts.SimplePie;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.util.CachedServerIcon;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class PaperCore extends BukkitCore<CachedServerIcon>{
|
||||
public class PaperCore extends JavaPlugin implements PluginCore<CachedServerIcon>{
|
||||
|
||||
private final PluginLogger logger = new BukkitLogger(getLogger());
|
||||
private final PluginLogger logger = new PaperLogger(this);
|
||||
|
||||
private AdvancedServerList<CachedServerIcon> core;
|
||||
private FaviconHandler<CachedServerIcon> faviconHandler = null;
|
||||
private PAPIPlaceholders<CachedServerIcon> papiPlaceholders = null;
|
||||
private PAPIPlaceholders papiPlaceholders = null;
|
||||
private WorldCache worldCache = null;
|
||||
|
||||
@Override
|
||||
public void onEnable(){
|
||||
this.core = AdvancedServerList.init(this, BukkitPlayerPlaceholders.init(), BukkitServerPlaceholders.init());
|
||||
try{
|
||||
Class.forName("io.papermc.paper.configuration.ConfigurationLoaders");
|
||||
}catch(ClassNotFoundException ignored){
|
||||
try{
|
||||
// Above class only exists since 1.19+. This is a fallback to see if an older version is used.
|
||||
Class.forName("com.destroystokyo.paper.PaperConfig");
|
||||
}catch(ClassNotFoundException ex){
|
||||
printNoPaperWarning();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.core = AdvancedServerList.init(this, new PaperPlayerPlaceholders(), new PaperServerPlaceholders());
|
||||
|
||||
if(getServer().getPluginManager().isPluginEnabled("PlaceholderAPI"))
|
||||
papiPlaceholders = PAPIPlaceholders.init(this);
|
||||
papiPlaceholders = new PAPIPlaceholders(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -86,8 +98,7 @@ public class PaperCore extends BukkitCore<CachedServerIcon>{
|
||||
|
||||
@Override
|
||||
public void loadEvents(){
|
||||
LoadEvent.init(this);
|
||||
PaperPingEvent.init(this);
|
||||
new LoadEvent(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -97,12 +108,17 @@ public class PaperCore extends BukkitCore<CachedServerIcon>{
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadFaviconHandler(AdvancedServerList<CachedServerIcon> core){
|
||||
faviconHandler = new FaviconHandler<>(core);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearFaviconCache(){
|
||||
if(faviconHandler == null)
|
||||
return;
|
||||
|
||||
faviconHandler.clearCache();
|
||||
faviconHandler.cleanCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -144,10 +160,35 @@ public class PaperCore extends BukkitCore<CachedServerIcon>{
|
||||
}
|
||||
|
||||
@Override
|
||||
public CachedServerIcon createFavicon(BufferedImage image) throws Exception{
|
||||
return Bukkit.loadServerIcon(image);
|
||||
}
|
||||
|
||||
public WorldCache getWorldCache(){
|
||||
if(worldCache != null)
|
||||
return worldCache;
|
||||
|
||||
return (worldCache = new WorldCache());
|
||||
}
|
||||
|
||||
private void printNoPaperWarning(){
|
||||
getPluginLogger().warn("======================================================================================");
|
||||
getPluginLogger().warn("THIS SERVER DOES NOT USE PAPER OR A COMPATIBLE FORK!");
|
||||
getPluginLogger().warn("");
|
||||
getPluginLogger().warn("AdvancedServerList 3.6.0 has dropped support for Spigot-based servers.");
|
||||
getPluginLogger().warn("This means that only servers using Paper or a Paper-compatible fork may work.");
|
||||
getPluginLogger().warn("");
|
||||
getPluginLogger().warn("Reasons for this removal:");
|
||||
getPluginLogger().warn(" - Reliance on a different plugin for core functionalities.");
|
||||
getPluginLogger().warn(" - Bad dependency loading limited to MavenCentral only.");
|
||||
getPluginLogger().warn("");
|
||||
getPluginLogger().warn("Please consider switching to Paper or one of the Paper-compatible forks to benefit");
|
||||
getPluginLogger().warn("from overall performance improvements amongst other things.");
|
||||
getPluginLogger().warn("");
|
||||
getPluginLogger().warn("Disabling AdvancedServerList. If you believe this is an error, report it on");
|
||||
getPluginLogger().warn("Codeberg: https://codeberg.org/Andre601/AdvancedServerList");
|
||||
getPluginLogger().warn("======================================================================================");
|
||||
|
||||
Bukkit.getPluginManager().disablePlugin(this);
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 Andre_601
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.paper.commands;
|
||||
|
||||
import ch.andre601.advancedserverlist.paper.PaperCore;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
public class CmdAdvancedServerList extends Command{
|
||||
|
||||
private final PaperCore plugin;
|
||||
|
||||
public CmdAdvancedServerList(PaperCore plugin){
|
||||
super(
|
||||
"advancedserverlist",
|
||||
"Main command of the plugin",
|
||||
"/asl [reload|help|clearCache]",
|
||||
Collections.singletonList("asl")
|
||||
);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(@NotNull CommandSender sender, @NotNull String s, @NotNull String[] args){
|
||||
plugin.getCore().getCommandHandler().handle(new PaperCmdSender(sender), args);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
File renamed without changes.
+5
-9
@@ -23,9 +23,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.bukkit.listeners;
|
||||
package ch.andre601.advancedserverlist.paper.listeners;
|
||||
|
||||
import ch.andre601.advancedserverlist.bukkit.BukkitCore;
|
||||
import ch.andre601.advancedserverlist.paper.PaperCore;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
@@ -34,19 +34,15 @@ import org.bukkit.event.player.PlayerJoinEvent;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
public class JoinEvent<F> implements Listener{
|
||||
public class JoinEvent implements Listener{
|
||||
|
||||
private final BukkitCore<F> plugin;
|
||||
private final PaperCore plugin;
|
||||
|
||||
private JoinEvent(BukkitCore<F> plugin){
|
||||
public JoinEvent(PaperCore plugin){
|
||||
this.plugin = plugin;
|
||||
Bukkit.getPluginManager().registerEvents(this, plugin);
|
||||
}
|
||||
|
||||
public static <F> void init(BukkitCore<F> plugin){
|
||||
new JoinEvent<>(plugin);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onJoin(PlayerJoinEvent event){
|
||||
InetSocketAddress address = event.getPlayer().getAddress();
|
||||
+25
-12
@@ -23,17 +23,30 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.bukkit;
|
||||
package ch.andre601.advancedserverlist.paper.listeners;
|
||||
|
||||
import ch.andre601.advancedserverlist.bukkit.objects.WorldCache;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import ch.andre601.advancedserverlist.paper.PaperCore;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.server.ServerLoadEvent;
|
||||
|
||||
/*
|
||||
* Small convenience class to "merge" the PluginCore and JavaPlugin classes.
|
||||
* Allows me to have BukkitCore<?> for whenever I also need a JavaPlugin (i.e. registering events).
|
||||
* See JoinEvent class for an example.
|
||||
*/
|
||||
public abstract class BukkitCore<F> extends JavaPlugin implements PluginCore<F>{
|
||||
public abstract WorldCache getWorldCache();
|
||||
}
|
||||
public class LoadEvent implements Listener{
|
||||
|
||||
private final PaperCore plugin;
|
||||
|
||||
public LoadEvent(PaperCore plugin){
|
||||
this.plugin = plugin;
|
||||
Bukkit.getPluginManager().registerEvents(this, plugin);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onLoad(ServerLoadEvent event){
|
||||
new JoinEvent(plugin);
|
||||
new PingEvent(plugin);
|
||||
new WorldEvents(plugin);
|
||||
|
||||
// Load currently loaded worlds into the WorldCache
|
||||
Bukkit.getWorlds().forEach(world -> plugin.getWorldCache().addWorld(world));
|
||||
}
|
||||
}
|
||||
+13
-18
@@ -28,16 +28,15 @@ package ch.andre601.advancedserverlist.paper.listeners;
|
||||
import ch.andre601.advancedserverlist.api.events.GenericServerListEvent;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.bukkit.BukkitCore;
|
||||
import ch.andre601.advancedserverlist.bukkit.listeners.PreServerListSetEventImpl;
|
||||
import ch.andre601.advancedserverlist.bukkit.objects.impl.BukkitServerImpl;
|
||||
import ch.andre601.advancedserverlist.bukkit.objects.impl.BukkitPlayerImpl;
|
||||
import ch.andre601.advancedserverlist.core.events.PingEventHandler;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
|
||||
import ch.andre601.advancedserverlist.core.interfaces.events.GenericEventWrapper;
|
||||
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
|
||||
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
|
||||
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
|
||||
import ch.andre601.advancedserverlist.paper.PaperCore;
|
||||
import ch.andre601.advancedserverlist.paper.objects.impl.PaperPlayerImpl;
|
||||
import ch.andre601.advancedserverlist.paper.objects.impl.PaperServerImpl;
|
||||
import com.destroystokyo.paper.event.server.PaperServerListPingEvent;
|
||||
import com.destroystokyo.paper.profile.PlayerProfile;
|
||||
import me.clip.placeholderapi.PlaceholderAPI;
|
||||
@@ -46,10 +45,11 @@ import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.util.CachedServerIcon;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon, BukkitPlayerImpl>{
|
||||
public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon, PaperPlayerImpl>{
|
||||
|
||||
private final PaperCore plugin;
|
||||
private final PaperServerListPingEvent event;
|
||||
@@ -89,7 +89,7 @@ public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon,
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayers(List<String> lines, BukkitPlayerImpl player, GenericServer server){
|
||||
public void setPlayers(List<String> lines, PaperPlayerImpl player, GenericServer server){
|
||||
event.getPlayerSample().clear();
|
||||
List<PlayerProfile> players = new ArrayList<>(lines.size());
|
||||
|
||||
@@ -159,7 +159,7 @@ public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon,
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parsePAPIPlaceholders(String text, BukkitPlayerImpl player){
|
||||
public String parsePAPIPlaceholders(String text, PaperPlayerImpl player){
|
||||
if(plugin.getServer().getPluginManager().isPluginEnabled("PlaceholderAPI"))
|
||||
return PlaceholderAPI.setPlaceholders(player.getPlayer(), text);
|
||||
|
||||
@@ -172,24 +172,19 @@ public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon,
|
||||
}
|
||||
|
||||
@Override
|
||||
public BukkitCore<CachedServerIcon> getPlugin(){
|
||||
public PluginCore<CachedServerIcon> getPlugin(){
|
||||
return plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BukkitPlayerImpl createPlayer(CachedPlayer player, int protocol){
|
||||
public PaperPlayerImpl createPlayer(CachedPlayer player, int protocol){
|
||||
OfflinePlayer pl = Bukkit.getOfflinePlayer(player.getUuid());
|
||||
|
||||
return new BukkitPlayerImpl(pl.hasPlayedBefore() ? pl : null, player, protocol);
|
||||
return new PaperPlayerImpl(pl.hasPlayedBefore() ? pl : null, player, protocol);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GenericServer createGenericServer(int playersOnline, int playersMax, String host){
|
||||
return new BukkitServerImpl(plugin.getWorldCache().worlds(), playersOnline, playersMax, host);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CachedServerIcon createFavicon(BufferedImage image) throws Exception{
|
||||
return Bukkit.loadServerIcon(image);
|
||||
return new PaperServerImpl(plugin.getWorldCache().worlds(), playersOnline, playersMax, host);
|
||||
}
|
||||
}
|
||||
+2
-6
@@ -31,19 +31,15 @@ import com.destroystokyo.paper.event.server.PaperServerListPingEvent;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
public class PaperPingEvent implements Listener{
|
||||
public class PingEvent implements Listener{
|
||||
|
||||
private final PaperCore plugin;
|
||||
|
||||
private PaperPingEvent(PaperCore plugin){
|
||||
public PingEvent(PaperCore plugin){
|
||||
this.plugin = plugin;
|
||||
plugin.getServer().getPluginManager().registerEvents(this, plugin);
|
||||
}
|
||||
|
||||
public static void init(PaperCore plugin){
|
||||
new PaperPingEvent(plugin);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPaperServerListPing(PaperServerListPingEvent event){
|
||||
PingEventHandler.handleEvent(new PaperEventWrapper(plugin, event));
|
||||
+1
-1
@@ -23,7 +23,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.bukkit.listeners;
|
||||
package ch.andre601.advancedserverlist.paper.listeners;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.bukkit.events.PreServerListSetEvent;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
+5
-11
@@ -23,10 +23,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.bukkit.listeners;
|
||||
package ch.andre601.advancedserverlist.paper.listeners;
|
||||
|
||||
import ch.andre601.advancedserverlist.bukkit.BukkitCore;
|
||||
import org.bukkit.Bukkit;
|
||||
import ch.andre601.advancedserverlist.paper.PaperCore;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.world.WorldLoadEvent;
|
||||
@@ -34,20 +33,15 @@ import org.bukkit.event.world.WorldUnloadEvent;
|
||||
|
||||
public class WorldEvents implements Listener{
|
||||
|
||||
private final BukkitCore<?> plugin;
|
||||
private final PaperCore plugin;
|
||||
|
||||
private WorldEvents(BukkitCore<?> plugin){
|
||||
public WorldEvents(PaperCore plugin){
|
||||
this.plugin = plugin;
|
||||
Bukkit.getPluginManager().registerEvents(this, plugin);
|
||||
}
|
||||
|
||||
public static void init(BukkitCore<?> plugin){
|
||||
new WorldEvents(plugin);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onWorldLoad(WorldLoadEvent event){
|
||||
plugin.getWorldCache().addWorld(event.getWorld().getName(), event.getWorld());
|
||||
plugin.getWorldCache().addWorld(event.getWorld());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
+19
-4
@@ -23,19 +23,34 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.bukkit.logging;
|
||||
package ch.andre601.advancedserverlist.paper.logging;
|
||||
|
||||
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
|
||||
import ch.andre601.advancedserverlist.paper.PaperCore;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class BukkitLogger implements PluginLogger{
|
||||
public class PaperLogger implements PluginLogger{
|
||||
|
||||
private final PaperCore plugin;
|
||||
private final Logger logger;
|
||||
|
||||
public BukkitLogger(Logger logger){
|
||||
this.logger = logger;
|
||||
public PaperLogger(PaperCore plugin){
|
||||
this.plugin = plugin;
|
||||
this.logger = plugin.getLogger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Class<?> clazz, String msg, Object... args){
|
||||
if(plugin.isDebugEnabled())
|
||||
info("[DEBUG] [" + clazz.getSimpleName() + "] " + msg, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debugWarn(Class<?> clazz, String msg, Object... args){
|
||||
if(plugin.isDebugEnabled())
|
||||
warn("[DEBUG] [" + clazz.getSimpleName() + "] " + msg, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
+7
-7
@@ -23,7 +23,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.bukkit.objects;
|
||||
package ch.andre601.advancedserverlist.paper.objects;
|
||||
|
||||
import org.bukkit.World;
|
||||
|
||||
@@ -36,15 +36,15 @@ public record WorldCache(Map<String, World> worlds){
|
||||
this(new HashMap<>());
|
||||
}
|
||||
|
||||
public boolean containsWorld(String key){
|
||||
return worlds().containsKey(key);
|
||||
public boolean containsWorld(String name){
|
||||
return this.worlds.containsKey(name);
|
||||
}
|
||||
|
||||
public void addWorld(String key, World world){
|
||||
worlds().put(key, world);
|
||||
public void addWorld(World world){
|
||||
this.worlds.put(world.getName(), world);
|
||||
}
|
||||
|
||||
public void removeWorld(String key){
|
||||
worlds().remove(key);
|
||||
public void removeWorld(String name){
|
||||
this.worlds.remove(name);
|
||||
}
|
||||
}
|
||||
+6
-7
@@ -23,31 +23,30 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.bukkit.objects.impl;
|
||||
package ch.andre601.advancedserverlist.paper.objects.impl;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.bukkit.objects.BukkitPlayer;
|
||||
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
|
||||
import ch.andre601.advancedserverlist.core.profiles.players.GenericPlayerImpl;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
|
||||
public class BukkitPlayerImpl extends GenericPlayerImpl implements BukkitPlayer{
|
||||
public class PaperPlayerImpl extends GenericPlayerImpl implements BukkitPlayer{
|
||||
|
||||
private final OfflinePlayer player;
|
||||
private boolean playedBefore = false;
|
||||
private boolean banned = false;
|
||||
private boolean whitelisted = false;
|
||||
|
||||
public BukkitPlayerImpl(OfflinePlayer player, CachedPlayer cachedPlayer, int protocol){
|
||||
public PaperPlayerImpl(OfflinePlayer player, CachedPlayer cachedPlayer, int protocol){
|
||||
this.player = player;
|
||||
|
||||
|
||||
this.name = player == null ? cachedPlayer.getName() : player.getName();
|
||||
this.protocol = protocol;
|
||||
|
||||
this.uuid = player == null ? cachedPlayer.getUuid() : player.getUniqueId();
|
||||
|
||||
|
||||
if(player == null)
|
||||
return;
|
||||
|
||||
|
||||
this.playedBefore = player.hasPlayedBefore();
|
||||
this.banned = player.isBanned();
|
||||
this.whitelisted = player.isWhitelisted();
|
||||
+2
-3
@@ -23,15 +23,14 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.bukkit.objects.impl;
|
||||
package ch.andre601.advancedserverlist.paper.objects.impl;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.bukkit.objects.BukkitServer;
|
||||
import org.bukkit.World;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public record BukkitServerImpl(Map<String, World> worlds, int playersOnline, int playersMax, String host) implements BukkitServer{
|
||||
|
||||
public record PaperServerImpl(Map<String, World> worlds, int playersOnline, int playersMax, String host) implements BukkitServer {
|
||||
@Override
|
||||
public Map<String, World> getWorlds(){
|
||||
return worlds;
|
||||
+28
-56
@@ -23,23 +23,19 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.bukkit.objects.placeholders;
|
||||
package ch.andre601.advancedserverlist.paper.objects.placeholders;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.bukkit.objects.BukkitPlayer;
|
||||
import ch.andre601.advancedserverlist.api.bukkit.objects.BukkitServer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
|
||||
import ch.andre601.advancedserverlist.bukkit.BukkitCore;
|
||||
import ch.andre601.advancedserverlist.bukkit.objects.impl.BukkitPlayerImpl;
|
||||
import ch.andre601.advancedserverlist.bukkit.objects.impl.BukkitServerImpl;
|
||||
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
|
||||
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
|
||||
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
|
||||
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileManager;
|
||||
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
|
||||
import ch.andre601.advancedserverlist.spigot.SpigotCore;
|
||||
import ch.andre601.advancedserverlist.spigot.listeners.ProtocolLibEvents;
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import ch.andre601.advancedserverlist.paper.PaperCore;
|
||||
import ch.andre601.advancedserverlist.paper.objects.impl.PaperPlayerImpl;
|
||||
import ch.andre601.advancedserverlist.paper.objects.impl.PaperServerImpl;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import me.clip.placeholderapi.PlaceholderAPI;
|
||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||
@@ -47,22 +43,19 @@ import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.*;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class PAPIPlaceholders<F> extends PlaceholderExpansion{
|
||||
public class PAPIPlaceholders extends PlaceholderExpansion{
|
||||
|
||||
private final BukkitCore<F> plugin;
|
||||
private final PaperCore plugin;
|
||||
|
||||
private PAPIPlaceholders(BukkitCore<F> plugin){
|
||||
public PAPIPlaceholders(PaperCore plugin){
|
||||
this.plugin = plugin;
|
||||
this.register();
|
||||
}
|
||||
|
||||
public static <F> PAPIPlaceholders<F> init(BukkitCore<F> plugin){
|
||||
return new PAPIPlaceholders<>(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getIdentifier(){
|
||||
return "asl";
|
||||
@@ -85,16 +78,15 @@ public class PAPIPlaceholders<F> extends PlaceholderExpansion{
|
||||
|
||||
@Override
|
||||
public String onPlaceholderRequest(Player pl, @NotNull String identifier){
|
||||
InetSocketAddress address = pl.getAddress();
|
||||
|
||||
String host = resolveVirtualHost(pl, address);
|
||||
String host = pl.getVirtualHost() == null ? null : pl.getVirtualHost().getHostString();
|
||||
CachedPlayer cached = plugin.getCore().getPlayerHandler().getCachedPlayer(pl.getUniqueId());
|
||||
|
||||
int protocol = resolveProtocol(pl);
|
||||
int online = Bukkit.getOnlinePlayers().size();
|
||||
int max = Bukkit.getMaxPlayers();
|
||||
BukkitServer server = new BukkitServerImpl(plugin.getWorldCache().worlds(), online, max, host);
|
||||
GenericPlayer player = new BukkitPlayerImpl(pl, cached, protocol);
|
||||
|
||||
BukkitServer server = new PaperServerImpl(plugin.getWorldCache().worlds(), online, max, host);
|
||||
BukkitPlayer player = new PaperPlayerImpl(pl, cached, protocol);
|
||||
|
||||
ServerListProfile profile = ProfileManager.resolveProfile(plugin.getCore(), player, server);
|
||||
if(profile == null)
|
||||
@@ -114,56 +106,36 @@ public class PAPIPlaceholders<F> extends PlaceholderExpansion{
|
||||
extraPlayers = entry.extraPlayersCount();
|
||||
}
|
||||
|
||||
BukkitServer finalServer = new BukkitServerImpl(plugin.getWorldCache().worlds(), online, max, host);
|
||||
|
||||
BukkitServer finalServer = new PaperServerImpl(plugin.getWorldCache().worlds(), online, max, host);
|
||||
return switch(identifier.toLowerCase(Locale.ROOT)){
|
||||
case "motd" -> getOption(entry.motd(), pl, player, finalServer);
|
||||
case "favicon" -> getOption(entry.favicon(), pl, player, finalServer);
|
||||
case "playercount_hover" -> getOption(entry.players(), pl, player, finalServer);
|
||||
case "playercount_text" -> getOption(entry.playerCountText(), pl, player, finalServer);
|
||||
// TODO: Remove extra_players_max in future release
|
||||
case "extra_players_max", "playercount_extraplayers" -> extraPlayers == null ? "null" : String.valueOf(extraPlayers);
|
||||
case "playercount_extraplayers" -> extraPlayers == null ? "null" : String.valueOf(extraPlayers);
|
||||
case "playercount_maxplayers" -> maxPlayers == null ? "null" : String.valueOf(maxPlayers);
|
||||
case "server_playersmax" -> String.valueOf(max);
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
private String getOption(String str, Player pl, GenericPlayer player, GenericServer server){
|
||||
private int resolveProtocol(Player player){
|
||||
if(Bukkit.getPluginManager().isPluginEnabled("ViaVersion"))
|
||||
return Via.getAPI().getPlayerVersion(player.getUniqueId());
|
||||
|
||||
// Since ViaVersion isn't installed is the player's protocol version the same as the server.
|
||||
//noinspection deprecation
|
||||
return Bukkit.getUnsafe().getProtocolVersion();
|
||||
}
|
||||
|
||||
private String getOption(String str, Player pl, BukkitPlayer player, BukkitServer server){
|
||||
return getOption(Collections.singletonList(str), pl, player, server);
|
||||
}
|
||||
|
||||
private String getOption(List<String> list, Player pl, GenericPlayer player, GenericServer server){
|
||||
private String getOption(List<String> list, Player pl, BukkitPlayer player, BukkitServer server){
|
||||
return ComponentParser.list(list)
|
||||
.modifyText(text -> PlaceholderAPI.setPlaceholders(pl, text))
|
||||
.modifyText(text -> StringReplacer.replace(text, player, server))
|
||||
.toString();
|
||||
}
|
||||
|
||||
private int resolveProtocol(Player player){
|
||||
if(Bukkit.getPluginManager().isPluginEnabled("ViaVersion"))
|
||||
return Via.getAPI().getPlayerVersion(player.getUniqueId());
|
||||
|
||||
// Since Spigot version requires ProtocolLib can we use it here safely if the plugin instance is SpigotCore.
|
||||
if(plugin instanceof SpigotCore)
|
||||
return ProtocolLibrary.getProtocolManager().getProtocolVersion(player);
|
||||
|
||||
// getProtocolVersion is only in Paper, so this is only called when main class isn't SpigotCore.
|
||||
// Also, ViaVersion is not present, so the player protocol *should* be the same as the server.
|
||||
//noinspection deprecation
|
||||
return Bukkit.getUnsafe().getProtocolVersion();
|
||||
}
|
||||
|
||||
private String resolveVirtualHost(Player player, InetSocketAddress address){
|
||||
try {
|
||||
// Server is a Paper Server with Player#getVirtualHost()
|
||||
Class.forName("com.destroystokyo.paper.network.NetworkClient");
|
||||
return player.getVirtualHost() == null ? null : player.getVirtualHost().getHostString();
|
||||
}catch(ClassNotFoundException ignored){}
|
||||
|
||||
if(address == null)
|
||||
return null;
|
||||
|
||||
return ProtocolLibEvents.getHostAddresses().get(address.getHostString());
|
||||
}
|
||||
}
|
||||
+11
-19
@@ -23,40 +23,32 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.bukkit.objects.placeholders;
|
||||
package ch.andre601.advancedserverlist.paper.objects.placeholders;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.api.bukkit.objects.BukkitPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.paper.objects.impl.PaperPlayerImpl;
|
||||
|
||||
public class BukkitPlayerPlaceholders extends PlaceholderProvider{
|
||||
public class PaperPlayerPlaceholders extends PlaceholderProvider{
|
||||
|
||||
private BukkitPlayerPlaceholders(){
|
||||
public PaperPlayerPlaceholders(){
|
||||
super("player");
|
||||
}
|
||||
|
||||
public static BukkitPlayerPlaceholders init(){
|
||||
return new BukkitPlayerPlaceholders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
|
||||
if(!(player instanceof BukkitPlayer bukkitPlayer))
|
||||
if(!(player instanceof PaperPlayerImpl paperPlayer))
|
||||
return null;
|
||||
|
||||
return switch(placeholder){
|
||||
case "name" -> bukkitPlayer.getName();
|
||||
case "protocol" -> String.valueOf(bukkitPlayer.getProtocol());
|
||||
case "uuid" -> bukkitPlayer.getUUID().toString();
|
||||
case "hasPlayedBefore" -> returnValue(bukkitPlayer, bukkitPlayer.hasPlayedBefore());
|
||||
case "isBanned" -> returnValue(bukkitPlayer, bukkitPlayer.isBanned());
|
||||
case "isWhitelisted" -> returnValue(bukkitPlayer, bukkitPlayer.isWhitelisted());
|
||||
case "name" -> paperPlayer.getName();
|
||||
case "protocol" -> String.valueOf(paperPlayer.getProtocol());
|
||||
case "uuid" -> paperPlayer.getUUID().toString();
|
||||
case "hasPlayedBefore" -> String.valueOf(paperPlayer.hasPlayedBefore());
|
||||
case "isBanned" -> String.valueOf(paperPlayer.isBanned());
|
||||
case "isWhitelisted" -> String.valueOf(paperPlayer.isWhitelisted());
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
private String returnValue(BukkitPlayer player, Object value){
|
||||
return player.getPlayer() == null ? null : String.valueOf(value);
|
||||
}
|
||||
}
|
||||
+17
-17
@@ -23,38 +23,38 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package ch.andre601.advancedserverlist.bukkit.objects.placeholders;
|
||||
package ch.andre601.advancedserverlist.paper.objects.placeholders;
|
||||
|
||||
import ch.andre601.advancedserverlist.api.bukkit.objects.BukkitServer;
|
||||
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
|
||||
import ch.andre601.advancedserverlist.api.objects.GenericServer;
|
||||
import ch.andre601.advancedserverlist.paper.objects.impl.PaperServerImpl;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
|
||||
public class BukkitServerPlaceholders extends PlaceholderProvider{
|
||||
public class PaperServerPlaceholders extends PlaceholderProvider{
|
||||
|
||||
private BukkitServerPlaceholders(){
|
||||
public PaperServerPlaceholders(){
|
||||
super("server");
|
||||
}
|
||||
|
||||
public static BukkitServerPlaceholders init(){
|
||||
return new BukkitServerPlaceholders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parsePlaceholder(String placeholders, GenericPlayer player, GenericServer server){
|
||||
if(!(server instanceof BukkitServer bukkitServer))
|
||||
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
|
||||
if(!(server instanceof PaperServerImpl paperServer))
|
||||
return null;
|
||||
|
||||
String[] args = placeholders.split("\\s", 2);
|
||||
String[] args = placeholder.split("\\s", 2);
|
||||
|
||||
return switch(args[0]){
|
||||
case "playersOnline" -> {
|
||||
if(args.length >= 2){
|
||||
String[] worlds = args[1].split(",");
|
||||
|
||||
int players = 0;
|
||||
for(int i = 1; i < args.length; i++){
|
||||
World world = bukkitServer.getWorlds().get(args[i]);
|
||||
for(String worldName : worlds){
|
||||
if(worldName.isEmpty())
|
||||
continue;
|
||||
|
||||
World world = paperServer.worlds().get(worldName.strip());
|
||||
if(world == null)
|
||||
continue;
|
||||
|
||||
@@ -64,19 +64,19 @@ public class BukkitServerPlaceholders extends PlaceholderProvider{
|
||||
yield String.valueOf(players);
|
||||
}
|
||||
|
||||
yield String.valueOf(bukkitServer.getPlayersOnline());
|
||||
yield String.valueOf(paperServer.playersOnline());
|
||||
}
|
||||
case "playersMax" -> {
|
||||
if(args.length >= 2)
|
||||
yield null;
|
||||
|
||||
yield String.valueOf(bukkitServer.getPlayersMax());
|
||||
yield String.valueOf(paperServer.getPlayersMax());
|
||||
}
|
||||
case "host" -> {
|
||||
if(args.length >= 2)
|
||||
yield null;
|
||||
|
||||
yield bukkitServer.getHost();
|
||||
yield paperServer.getHost();
|
||||
}
|
||||
case "whitelistEnabled" -> {
|
||||
if(args.length >= 2)
|
||||
@@ -4,7 +4,6 @@ version: '${plugin.version}'
|
||||
description: '${plugin.description}'
|
||||
|
||||
main: 'ch.andre601.advancedserverlist.paper.PaperCore'
|
||||
loader: 'ch.andre601.advancedserverlist.paper.ASLLoader'
|
||||
|
||||
api-version: '1.19'
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
#
|
||||
# This file is kept for Folia support.
|
||||
#
|
||||
|
||||
name: 'AdvancedServerList'
|
||||
author: 'Andre_601'
|
||||
version: '${plugin.version}'
|
||||
description: '${plugin.description}'
|
||||
|
||||
main: 'ch.andre601.advancedserverlist.spigot.SpigotCore'
|
||||
main: 'ch.andre601.advancedserverlist.paper.PaperCore'
|
||||
|
||||
api-version: 1.19
|
||||
api-version: '1.19'
|
||||
|
||||
folia-supported: true
|
||||
|
||||
libraries:
|
||||
- 'org.spongepowered:configurate-yaml:4.1.2'
|
||||
- 'net.kyori:adventure-api:4.12.0'
|
||||
- 'net.kyori:adventure-text-minimessage:4.12.0'
|
||||
- 'net.kyori:adventure-text-serializer-legacy:4.12.0'
|
||||
- 'net.kyori:adventure-platform-bukkit:4.2.0'
|
||||
- 'com.squareup.okhttp3:okhttp:4.10.0'
|
||||
|
||||
softdepend:
|
||||
- 'ProtocolLib'
|
||||
- 'PlaceholderAPI'
|
||||
- 'Maintenance'
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.build.commit/>
|
||||
|
||||
<plugin.version>3.5.1</plugin.version>
|
||||
<plugin.version>4.2.0</plugin.version>
|
||||
<plugin.description>Create multiple Server lists based on conditions.</plugin.description>
|
||||
|
||||
<api.version>v3.1.0</api.version>
|
||||
@@ -57,8 +57,9 @@
|
||||
<modules>
|
||||
<module>core</module>
|
||||
<module>bungeecord</module>
|
||||
<module>bukkit</module>
|
||||
<module>paper</module>
|
||||
<module>velocity</module>
|
||||
<module>version-uploader</module>
|
||||
<module>addons/banplugins</module>
|
||||
</modules>
|
||||
</project>
|
||||
+2
-1
@@ -12,7 +12,8 @@
|
||||
"ch.andre601.asl-api:platform-bukkit",
|
||||
"ch.andre601.asl-api:platform-bungeecord",
|
||||
"ch.andre601.asl-api:platform-velocity",
|
||||
"ch.andre601.asl-api:api"
|
||||
"ch.andre601.asl-api:api",
|
||||
"com.github.DevLeoko:AdvancedBan"
|
||||
],
|
||||
"registryUrls": [
|
||||
"https://jitpack.io"
|
||||
|
||||
Loaded 100 of 113 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user