Compare commits

...
69 Commits
Author SHA1 Message Date
Andre_601 6dedd9368f Use release-title 2022-09-05 13:33:55 +02:00
Andre601 f2df3727a7 Add getFaviconHandler to PluginCore
Also, make bStats rely on global config
2022-09-05 13:29:10 +02:00
Andre_601 2b7c24daa4 Create FUNDING.yml 2022-09-04 15:15:54 +02:00
Andre_601 1e042461ac Update README.md 2022-09-04 14:17:42 +02:00
Andre_601 599c2db2bc Re-add modrinth 2022-09-03 16:56:38 +02:00
Andre_601 87505f820c try upload/download artifact 2022-09-03 16:27:44 +02:00
Andre_601 28109c8b5b Add needs to second job 2022-09-03 16:02:45 +02:00
Andre_601 243854592d Merge pull request #15 from Andre601/feature/action-improvements
Make Jar build only happen once
2022-09-03 16:01:05 +02:00
Andre_601 4648bc30e9 test out with github only for now... 2022-09-03 16:00:57 +02:00
Andre_601 f9a96e5525 typo 2022-09-03 00:28:50 +02:00
Andre_601 d158fb852f Update release.yml 2022-09-03 00:14:11 +02:00
Andre_601 77f95900e2 Use cache 2022-09-03 00:10:00 +02:00
Andre_601 912fec1875 Make Jar build only happen once 2022-09-02 23:44:51 +02:00
Andre_601 dba9ca20a4 Merge pull request #14 from Andre601/dependabot/github_actions/Kir-Antipov/mc-publish-3.2
Bump Kir-Antipov/mc-publish from 3.1 to 3.2
2022-09-02 18:35:37 +02:00
dependabot[bot] 7b94ae52db Bump Kir-Antipov/mc-publish from 3.1 to 3.2
Bumps [Kir-Antipov/mc-publish](https://github.com/Kir-Antipov/mc-publish) from 3.1 to 3.2.
- [Release notes](https://github.com/Kir-Antipov/mc-publish/releases)
- [Commits](https://github.com/Kir-Antipov/mc-publish/compare/v3.1...v3.2)

---
updated-dependencies:
- dependency-name: Kir-Antipov/mc-publish
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-02 15:40:17 +00:00
Andre601 6d3bf50278 Actually bump version -_- 2022-09-02 04:27:50 +02:00
Andre_601 8039088fb9 typo -_- 2022-09-02 03:43:39 +02:00
Andre601 ecaaf7bbf3 get rid of abstraction in ExpressionResult + better command output 2022-09-02 03:37:50 +02:00
Andre_601 dd970cfabf Merge pull request #13 from Andre601/feature/auto-publish-action
Create action for auto-publishing to Modrinth
2022-09-02 03:04:06 +02:00
Andre_601 a888481674 Use | definition for loaders. 2022-09-02 02:25:29 +02:00
Andre_601 ee68eafc63 Don't define changelog (Is added automatically) 2022-09-02 02:24:21 +02:00
Andre_601 f22313a5c8 Add proper credits 2022-09-02 02:01:14 +02:00
Andre_601 9603155722 Create action for auto-publishing to Modrinth 2022-09-02 01:57:53 +02:00
Andre_601 df938485b2 It's JDK 16 2022-08-30 21:32:25 +02:00
Andre_601 0ddda8bd78 Update README.md 2022-08-28 16:39:36 +02:00
Andre_601 56a83e88fb Add files via upload 2022-08-28 16:37:54 +02:00
Andre_601 1947f627ef Update README.md 2022-08-28 01:32:38 +02:00
Andre_601 3c344f9a5d Merge pull request #11 from Andre601/feature/improved-favicon-handling
Better Favicon handling
2022-08-27 21:32:01 +02:00
Andre601 8e2004cb81 Move relocations to platform modules 2022-08-27 21:29:57 +02:00
Andre601 004d723c81 Remove minimizeJar to fix ClassNotFoundExceptions 2022-08-27 21:08:24 +02:00
Andre601 90fb6a2654 Add clear favicon function and better favicon handling 2022-08-26 23:33:30 +02:00
Andre_601 0eb5daac81 Update README.md 2022-08-23 00:39:50 +02:00
Andre_601 f23f282ba9 Merge pull request #10 from Andre601/dependabot/maven/core/com.github.ben-manes.caffeine-caffeine-3.1.1
Bump caffeine from 1.3.3 to 3.1.1 in /core
2022-08-22 17:48:41 +02:00
dependabot[bot] df705c0c14 Bump caffeine from 1.3.3 to 3.1.1 in /core
Bumps [caffeine](https://github.com/ben-manes/caffeine) from 1.3.3 to 3.1.1.
- [Release notes](https://github.com/ben-manes/caffeine/releases)
- [Commits](https://github.com/ben-manes/caffeine/compare/v1.3.3...v3.1.1)

---
updated-dependencies:
- dependency-name: com.github.ben-manes.caffeine:caffeine
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-22 15:47:24 +00:00
Andre_601 f27202f2df Update README.md 2022-08-22 00:25:32 +02:00
Andre_601 0d84335db9 Merge pull request #9 from Andre601/feature/favicon-support
Add Favicon support for Server list profiles.
2022-08-21 23:32:46 +02:00
Andre601 50f878e39c Add assets 2022-08-21 23:30:59 +02:00
Andre601 b88ee87c96 Add notes to favicon setting 2022-08-21 23:28:11 +02:00
Andre601 a5f6e689f0 Shade in Caffeine 2022-08-21 01:31:20 +02:00
Andre601 dd0bc8a43a Cache the bytes array 2022-08-20 23:53:32 +02:00
Andre601 563362504f Use some kind of caching... I guess? 2022-08-20 23:43:55 +02:00
Andre601 bd95be080e Add missing profile comments 2022-08-18 16:11:04 +02:00
Andre601 2d02d48d3c Add Favicon support for Server list profiles. 2022-08-18 16:05:00 +02:00
Andre_601 15f7b5def3 Update README.md 2022-08-18 00:02:49 +02:00
Andre_601 f37813d5b7 Merge pull request #8 from Andre601/feature/xMore-option
Add xMore profile option
2022-08-17 21:26:17 +02:00
Andre601 93c2dda56b Add xMore profile option 2022-08-17 21:19:38 +02:00
Andre601 55f5132b37 Add oneMore profile option. 2022-08-17 13:55:25 +02:00
Andre_601 f1e48c2a9c Update README.md 2022-08-14 22:08:18 +02:00
Andre_601 de01db4c12 Update README.md 2022-08-12 00:51:51 +02:00
Andre_601 eefb2b44dd Doesn't work 2022-08-12 00:39:16 +02:00
Andre_601 799d06dee1 Add files via upload 2022-08-12 00:38:19 +02:00
Andre_601 b9338a43e0 Create tmp 2022-08-12 00:38:03 +02:00
Andre601 c89c5f0b49 Make naming bit more consistent 2022-08-04 22:06:39 +02:00
Andre601 1fac910ca1 Keep BufferedWriter at default cache size 2022-08-04 22:04:13 +02:00
Andre601 69061f1a75 Bump version 2022-08-04 22:01:30 +02:00
Andre_601 0d93dcf00d Merge pull request #6 from Andre601/feature/better-placeholder-handling
Better placeholder handling (Hopefully)
2022-08-04 22:00:09 +02:00
Andre601 bb2828e47d Use a BufferedWriter for cache file saving. 2022-08-04 21:58:06 +02:00
Andre601 cdcc872f3a Improve a bit 2022-08-04 20:57:39 +02:00
Andre601 f9192001ba Better placeholder handling (Hopefully) 2022-08-04 18:23:17 +02:00
Andre_601 0bd92862db Update README.md 2022-08-04 14:52:19 +02:00
Andre_601 773fbb55c3 Update README.md 2022-08-04 14:50:59 +02:00
Andre_601 ad4c69a269 Merge pull request #5 from Andre601/dependabot/maven/spigot/me.clip-placeholderapi-2.11.2
Bump placeholderapi from 2.11.1 to 2.11.2 in /spigot
2022-08-04 13:24:42 +02:00
Andre_601 b7a2599178 Merge pull request #4 from Andre601/dependabot/maven/paper/me.clip-placeholderapi-2.11.2
Bump placeholderapi from 2.11.1 to 2.11.2 in /paper
2022-08-04 13:24:21 +02:00
dependabot[bot] bd279d3673 Bump placeholderapi from 2.11.1 to 2.11.2 in /spigot
Bumps placeholderapi from 2.11.1 to 2.11.2.

---
updated-dependencies:
- dependency-name: me.clip:placeholderapi
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-04 11:21:00 +00:00
dependabot[bot] 5882372ce6 Bump placeholderapi from 2.11.1 to 2.11.2 in /paper
Bumps placeholderapi from 2.11.1 to 2.11.2.

---
updated-dependencies:
- dependency-name: me.clip:placeholderapi
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-04 11:20:29 +00:00
Andre_601 55d74f1abe Create dependabot.yml 2022-08-04 13:17:50 +02:00
Andre_601 0056a0e958 Delete dependabot.yml 2022-08-04 13:15:04 +02:00
Andre_601 06396a1622 Create dependabot.yml 2022-08-03 22:57:29 +02:00
Andre601 8d7df60398 Update dependencies 2022-08-03 22:43:36 +02:00
48 changed files with 1169 additions and 352 deletions

No files matched your search

+2
View File
@@ -0,0 +1,2 @@
patreon: andre_601
ko_fi: andre_601
Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

+50
View File
@@ -0,0 +1,50 @@
version: 2
updates:
- package-ecosystem: maven
directory: "/bungeecord"
schedule:
interval: daily
open-pull-requests-limit: 10
labels:
- 'Type: Update Dependency'
- 'Target: BungeeCord'
- package-ecosystem: maven
directory: "/core"
schedule:
interval: daily
open-pull-requests-limit: 10
labels:
- 'Type: Update Dependency'
- 'Target: Core'
- package-ecosystem: maven
directory: "/paper"
schedule:
interval: daily
open-pull-requests-limit: 10
labels:
- 'Type: Update Dependency'
- 'Target: PaperMC'
- package-ecosystem: maven
directory: "/spigot"
schedule:
interval: daily
open-pull-requests-limit: 10
labels:
- 'Type: Update Dependency'
- 'Target: Spigot'
- package-ecosystem: maven
directory: "/velocity"
schedule:
interval: daily
open-pull-requests-limit: 10
labels:
- 'Type: Update Dependency'
- 'Target: Velocity'
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 10
labels:
- 'Type: Update Dependency'
- 'Target: GitHub Action'
+80 -8
View File
@@ -1,23 +1,95 @@
name: Build Jars
#
# Big thank you to @Kir-Antipov for providing this workflow file.
# Check out his mc-publish action here: https://github.com/Kir-Antipov/mc-publish
#
name: Publish Assets
on:
release:
types: [published]
jobs:
build:
buildJars:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 1.11
- name: Set up JDK 1.16
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '16'
- name: Build jar
cache: 'maven'
- name: Build Jar files
run: mvn clean install
- name: Upload jar
uses: AButler/upload-release-assets@v2.0
- name: Save BungeeCord Jar file
uses: actions/upload-artifact@v3
with:
files: 'bungeecord/target/AdvancedServerList-*.jar;paper/target/AdvancedServerList-*.jar;spigot/target/AdvancedServerList-*.jar;velocity/target/AdvancedServerList-*.jar'
repo-token: ${{ secrets.GITHUB_TOKEN }}
name: asl-bungeecord
path: bungeecord/target/AdvancedServerList-*.jar
if-no-files-found: error
retention-days: 1
- name: Save Paper Jar file
uses: actions/upload-artifact@v3
with:
name: asl-paper
path: paper/target/AdvancedServerList-*.jar
if-no-files-found: error
retention-days: 1
- name: Save Spigot Jar file
uses: actions/upload-artifact@v3
with:
name: asl-spigot
path: spigot/target/AdvancedServerList-*.jar
if-no-files-found: error
retention-days: 1
- name: Save Velocity Jar file
uses: actions/upload-artifact@v3
with:
name: asl-velocity
path: velocity/target/AdvancedServerList-*.jar
if-no-files-found: error
retention-days: 1
publish:
needs: [buildJars]
strategy:
matrix:
include:
- directory: bungeecord
loaders: |
bungeecord
waterfall
- directory: paper
loaders: paper
- directory: spigot
loaders: spigot
- directory: velocity
loaders: velocity
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Get Jar files
uses: actions/download-artifact@v3
with:
name: asl-${{ matrix.directory }}
path: ${{ matrix.directory }}/target
- name: Get Version
id: github-release
run: |
version=$(echo ${{ github.event.release.tag_name }} | cut -d'v' -f2)
echo "::set-output name=version::$version"
- name: Upload AdvancedServerList (${{ matrix.loaders }}) to GitHub and Modrinth
uses: Kir-Antipov/mc-publish@v3.2
with:
name: ${{ github.event.release.name }}
version: ${{ steps.github-release.outputs.version }}
version-type: release
files: ${{ matrix.directory}}/target/AdvancedServerList-*.jar
files-secondary: ""
loaders: ${{ matrix.loaders }}
version-resolver: releases
game-versions: '1.19'
java: 16
modrinth-id: xss83sOY
modrinth-token: ${{ secrets.MODRINTH_TOKEN }}
github-token: ${{ secrets.GITHUB_TOKEN }}
+79 -49
View File
@@ -1,60 +1,90 @@
<!-- Badges -->
[platforms]: https://img.shields.io/badge/Platforms-Spigot%20%7C%20PaperMC%20%7C%20BungeeCord%20%7C%20Velocity-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiBmaWxsPSJ3aGl0ZSI+PHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMTEuMDYzIDEuNDU2YTEuNzUgMS43NSAwIDAxMS44NzQgMGw4LjM4MyA1LjMxNmExLjc1IDEuNzUgMCAwMTAgMi45NTZsLTguMzgzIDUuMzE2YTEuNzUgMS43NSAwIDAxLTEuODc0IDBMMi42OCA5LjcyOGExLjc1IDEuNzUgMCAwMTAtMi45NTZsOC4zODMtNS4zMTZ6bTEuMDcxIDEuMjY3YS4yNS4yNSAwIDAwLS4yNjggMEwzLjQ4MyA4LjAzOWEuMjUuMjUgMCAwMDAgLjQyMmw4LjM4MyA1LjMxNmEuMjUuMjUgMCAwMC4yNjggMGw4LjM4My01LjMxNmEuMjUuMjUgMCAwMDAtLjQyMmwtOC4zODMtNS4zMTZ6Ij48L3BhdGg+PHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMS44NjcgMTIuMzI0YS43NS43NSAwIDAxMS4wMzUtLjIzMmw4Ljk2NCA1LjY4NWEuMjUuMjUgMCAwMC4yNjggMGw4Ljk2NC01LjY4NWEuNzUuNzUgMCAwMS44MDQgMS4yNjdsLTguOTY1IDUuNjg1YTEuNzUgMS43NSAwIDAxLTEuODc0IDBsLTguOTY1LTUuNjg1YS43NS43NSAwIDAxLS4yMzEtMS4wMzV6Ij48L3BhdGg+PHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMS44NjcgMTYuMzI0YS43NS43NSAwIDAxMS4wMzUtLjIzMmw4Ljk2NCA1LjY4NWEuMjUuMjUgMCAwMC4yNjggMGw4Ljk2NC01LjY4NWEuNzUuNzUgMCAwMS44MDQgMS4yNjdsLTguOTY1IDUuNjg1YTEuNzUgMS43NSAwIDAxLTEuODc0IDBsLTguOTY1LTUuNjg1YS43NS43NSAwIDAxLS4yMzEtMS4wMzV6Ij48L3BhdGg+PC9zdmc+
[tested]: https://img.shields.io/badge/Tested%20Versions-1.19-blue?style=for-the-badge&logo=image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiBmaWxsPSJ3aGl0ZSI+PHBhdGggZD0iTTE3LjI4IDkuMjhhLjc1Ljc1IDAgMDAtMS4wNi0xLjA2bC01Ljk3IDUuOTctMi40Ny0yLjQ3YS43NS43NSAwIDAwLTEuMDYgMS4wNmwzIDNhLjc1Ljc1IDAgMDAxLjA2IDBsNi41LTYuNXoiPjwvcGF0aD48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0zLjc1IDJBMS43NSAxLjc1IDAgMDAyIDMuNzV2MTYuNWMwIC45NjYuNzg0IDEuNzUgMS43NSAxLjc1aDE2LjVBMS43NSAxLjc1IDAgMDAyMiAyMC4yNVYzLjc1QTEuNzUgMS43NSAwIDAwMjAuMjUgMkgzLjc1ek0zLjUgMy43NWEuMjUuMjUgMCAwMS4yNS0uMjVoMTYuNWEuMjUuMjUgMCAwMS4yNS4yNXYxNi41YS4yNS4yNSAwIDAxLS4yNS4yNUgzLjc1YS4yNS4yNSAwIDAxLS4yNS0uMjVWMy43NXoiPjwvcGF0aD48L3N2Zz4=
[download modrinth]: https://img.shields.io/badge/Modrinth%20(Coming%20Soon)-30b27b?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLW1pdGVybGltaXQ9IjEuNSIgY2xpcC1ydWxlPSJldmVub2RkIiB2aWV3Qm94PSIwIDAgNjggNjgiPjxwYXRoIGZpbGw9Im5vbmUiIGQ9Ik0uMDUgMGg2NnY2NmgtNjZ6Ii8+PGNsaXBQYXRoIGlkPSJhIj48cGF0aCBkPSJNLjA1IDBoNjZ2NjZoLTY2eiIvPjwvY2xpcFBhdGg+PGcgY2xpcC1wYXRoPSJ1cmwoI2EpIj48Y2xpcFBhdGggaWQ9ImIiPjxjaXJjbGUgY3g9IjMzLjA1IiBjeT0iMzMiIHI9IjMzIi8+PC9jbGlwUGF0aD48ZyBjbGlwLXBhdGg9InVybCgjYikiPjxjbGlwUGF0aCBpZD0iYyI+PHBhdGggZD0iTTgzLjA1LTE3aC0xMDBWODNoMTAwVi0xN1pNMjkuMDUxIDMyLjI5NWwuMDc3IDEuNzU3IDguODI5IDMyLjk2MyA3Ljg0NC0yLjEwMi04LjU5Ny0zMi4wOTRMNDMuMDA5LS4xMTNsLTcuOTk3LTEuNDEtNS45NjEgMzMuODE4WiIvPjwvY2xpcFBhdGg+PGcgY2xpcC1wYXRoPSJ1cmwoI2MpIj48cGF0aCBmaWxsPSIjRkZGIiBkPSJNMzMuMDUgMGMxOC4yMDYgMCAzMi45ODggMTQuNzg3IDMyLjk4OCAzM1M1MS4yNTYgNjYgMzMuMDUgNjZDMTQuODQzIDY2IC4wNjEgNTEuMjEzLjA2MSAzM1MxNC44NDMgMCAzMy4wNSAwWm0wIDljMTMuMjQgMCAyMy45ODggMTAuNzU1IDIzLjk4OCAyNFM0Ni4yOSA1NyAzMy4wNSA1N0MxOS44MDkgNTcgOS4wNjEgNDYuMjQ1IDkuMDYxIDMzUzE5LjgwOSA5IDMzLjA1IDlaIi8+PC9nPjxjbGlwUGF0aCBpZD0iZCI+PHBhdGggZD0iTS0xNi45NS0xN3Y0Nmg1MGwxLjM2OC4yNDFMODIuMDUgNDYuNTc4bC0yLjczNyA3LjUxN0wzMi4zNDQgMzdILTE2Ljk1djQ2aDEwMFYtMTdoLTEwMFoiLz48L2NsaXBQYXRoPjxnIGNsaXAtcGF0aD0idXJsKCNkKSI+PHBhdGggZmlsbD0iI0ZGRiIgZD0iTTMzLjA1LTE3YzI3LjU5NSAwIDUwIDIyLjQwNCA1MCA1MHMtMjIuNDA1IDUwLTUwIDUwYy0yNy41OTYgMC01MC0yMi40MDQtNTAtNTBzMjIuNDA0LTUwIDUwLTUwWm0wIDljMjIuNjI4IDAgNDEgMTguMzcxIDQxIDQxcy0xOC4zNzIgNDEtNDEgNDFjLTIyLjYyOSAwLTQxLTE4LjM3MS00MS00MXMxOC4zNzEtNDEgNDEtNDFaIi8+PC9nPjxjbGlwUGF0aCBpZD0iZSI+PHBhdGggZD0iTTMzLjA1LTE3YzI3LjU5NSAwIDUwIDIyLjQwNCA1MCA1MHMtMjIuNDA1IDUwLTUwIDUwYy0yNy41OTYgMC01MC0yMi40MDQtNTAtNTBzMjIuNDA0LTUwIDUwLTUwWm0wIDM5LjU0OWM1Ljc2NyAwIDEwLjQ1IDQuNjgzIDEwLjQ1IDEwLjQ1MSAwIDUuNzY4LTQuNjgzIDEwLjQ1MS0xMC40NSAxMC40NTEtNS43NjggMC0xMC40NTEtNC42ODMtMTAuNDUxLTEwLjQ1MSAwLTUuNzY4IDQuNjgzLTEwLjQ1MSAxMC40NTEtMTAuNDUxWiIvPjwvY2xpcFBhdGg+PGcgY2xpcC1wYXRoPSJ1cmwoI2UpIj48cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IiNGRkYiIHN0cm9rZS13aWR0aD0iOSIgZD0ibTMzLjA1IDMzLTQ0LjgyOSAyNS44ODIiLz48L2c+PGNsaXBQYXRoIGlkPSJmIj48cGF0aCBkPSJNMzMuMDUtMTdjMjcuNTk1IDAgNTAgMjIuNDA0IDUwIDUwcy0yMi40MDUgNTAtNTAgNTBjLTI3LjU5NiAwLTUwLTIyLjQwNC01MC01MHMyMi40MDQtNTAgNTAtNTBabTAgMjUuMzZjMTMuNTk5IDAgMjQuNjQgMTEuMDQxIDI0LjY0IDI0LjY0UzQ2LjY0OSA1Ny42NCAzMy4wNSA1Ny42NEMxOS40NSA1Ny42NCA4LjQwOSA0Ni41OTkgOC40MDkgMzNTMTkuNDUgOC4zNiAzMy4wNSA4LjM2WiIvPjwvY2xpcFBhdGg+PGcgY2xpcC1wYXRoPSJ1cmwoI2YpIj48cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IiNGRkYiIHN0cm9rZS13aWR0aD0iOSIgZD0ibTMzLjA1IDMzIDUwLTEzLjM5NyIvPjwvZz48cGF0aCBmaWxsPSIjRkZGIiBkPSJNMjAuMjkzIDM1Ljc0NiAxOC4wNSAyOGw4LTkgMTEtMyA0IDQtNiA2LTQgMS0zIDQgMS4xMiA0LjI0IDMuMTEyIDMuMDkgNC45NjQtLjU5OCAyLjg2Ni0yLjk2NCA4LjE5Ni0yLjE5NiAxLjQ2NCA1LjQ2NC04LjA5OCA4LjAyNkwyOS44OCA0OC40OWwtNS41ODctNS44MTUtNC02LjkyOVoiLz48L2c+PC9nPjwvc3ZnPg==
[download spigot]: https://img.shields.io/badge/Spigot-ed8106?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiBmaWxsPSIjRkZGIj48cGF0aCBkPSJNNDE2IDQ4MGMwIDE3LjYyIDE0LjM4IDMyIDMyIDMyczMyLTE0LjM4IDMyLTMycy0zMi02NC0zMi02NFM0MTYgNDYyLjQgNDE2IDQ4MHpNMzUyIDE5MmgtMzguNTRDMjk3LjcgMTc4LjUgMjc3LjkgMTY4LjkgMjU2IDE2NFYxMTYuNUwyMjQgMTEzTDE5MiAxMTYuNVYxNjRDMTcwLjEgMTY5IDE1MC4zIDE3OC42IDEzNC41IDE5MkgxNkM3LjEyNSAxOTIgMCAxOTkuMSAwIDIwOHY5NkMwIDMxMi45IDcuMTI1IDMyMCAxNiAzMjBoOTIuNzhDMTI5LjQgMzU3LjggMTczIDM4NCAyMjQgMzg0czk0LjU5LTI2LjI1IDExNS4yLTY0SDM1MmMxNy42MiAwIDMyIDE0LjI5IDMyIDMxLjkxUzM5OC40IDM4NCA0MTYgMzg0aDY0YzE3LjYyIDAgMzItMTQuMzggMzItMzJDNTEyIDI2My42IDQ0MC40IDE5MiAzNTIgMTkyek04MS42MyA5NS44OEwyMjQgODAuODhsMTQyLjQgMTVDMzc1LjkgOTYuODggMzg0IDg5LjEyIDM4NCA3OS4xMlY0OC44OWMwLTEwLTguMTI1LTE3Ljc0LTE3LjYyLTE2Ljc0TDI1NiA0My43NVYxNkMyNTYgNy4xMjUgMjQ4LjkgMCAyNDAgMGgtMzJDMTk5LjEgMCAxOTIgNy4xMjUgMTkyIDE2djI3Ljc1TDgxLjYzIDMyLjE0QzcyLjEzIDMxLjE0IDY0IDM4Ljg5IDY0IDQ4Ljg5Vjc5LjEyQzY0IDg5LjEyIDcyLjEzIDk2Ljg4IDgxLjYzIDk1Ljg4eiIvPjwvc3ZnPg==
[download hangar]: https://img.shields.io/badge/Hangar%20(Beta)-444?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNDEgMjI0LjUiPjxkZWZzPjxzdHlsZT4uYXtmaWxsOm5vbmU7fS5iLC5se2ZpbGw6I2ZmZjt9LmIsLmMsLmQsLmUsLmYsLmcsLmgsLmksLmp7ZmlsbC1ydWxlOmV2ZW5vZGQ7fS5je2ZpbGw6I2ZhMDt9LmR7ZmlsbDojYWFhO30uZXtmaWxsOiM1NWY7fS5me2ZpbGw6IzVmNTt9Lmd7ZmlsbDojNjdjYmRmO30uaHtmaWxsOiNmNTU7fS5pe2ZpbGw6I2Y1Zjt9Lmp7ZmlsbDojZmY1O30ua3tmaWxsOiM0NDQ7fTwvc3R5bGU+PC9kZWZzPjxyZWN0IGNsYXNzPSJhIiB4PSIyMS4yIiB5PSIxMy42IiB3aWR0aD0iMjE0LjciIGhlaWdodD0iMTk5Ljk0Ii8+PHBhdGggY2xhc3M9ImIiIGQ9Ik01NTAuOCwzOTkuNSwzOTEuMiw0NzUuMyw0NzIuNSw2MjRsMTU5LjYtNzUuOEw1NTAuOCwzOTkuNVoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0zOTEuMiAtMzk5LjUpIi8+PHBhdGggY2xhc3M9ImMiIGQ9Ik01NTcsNDAxLjYsMzkzLjQsNDY5LjVsNzIuOCwxNTIuNEw2MjkuOSw1NTRaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMzkxLjIgLTM5OS41KSIvPjxwYXRoIGNsYXNzPSJkIiBkPSJNNTYzLjIsNDA0LDM5NS45LDQ2My44bDY0LjIsMTU1LjgsMTY3LjMtNTkuOFoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0zOTEuMiAtMzk5LjUpIi8+PHBhdGggY2xhc3M9ImUiIGQ9Ik01NjkuMiw0MDYuNiwzOTguOCw0NTguMmw1NS4zLDE1OC43LDE3MC40LTUxLjZMNTY5LjIsNDA2LjZaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMzkxLjIgLTM5OS41KSIvPjxwYXRoIGNsYXNzPSJmIiBkPSJNNTc1LDQwOS42LDQwMiw0NTIuOGw0Ni4zLDE2MS4xLDE3My4xLTQzLjFaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMzkxLjIgLTM5OS41KSIvPjxwYXRoIGNsYXNzPSJnIiBkPSJNNTgxLjEsNDEyLjVsLTE3NS41LDM1TDQ0My4yLDYxMWwxNzUuNS0zNUw1ODEuMSw0MTIuNVoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0zOTEuMiAtMzk5LjUpIi8+PHBhdGggY2xhc3M9ImgiIGQ9Ik01ODYuMSw0MTYuMyw0MDkuMiw0NDIuNGwyOCwxNjQuOCwxNzYuOS0yNi4xLTI4LTE2NC44WiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTM5MS4yIC0zOTkuNSkiLz48cGF0aCBjbGFzcz0iaSIgZD0iTTU5MS40LDQyMC4xLDQxMy4yLDQzNy41bDE4LjcsMTY2TDYxMC4xLDU4Niw1OTEuNCw0MjAuMVoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0zOTEuMiAtMzk5LjUpIi8+PHBhdGggY2xhc3M9ImoiIGQ9Ik01OTYuNCw0MjQuMWwtMTc4LjksOC43LDkuNCwxNjYuNiwxNzguOS04LjctOS40LTE2Ni42WiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTM5MS4yIC0zOTkuNSkiLz48cmVjdCBjbGFzcz0iayIgeD0iMzAuOSIgeT0iMjguOCIgd2lkdGg9IjE3OS4yIiBoZWlnaHQ9IjE2Ni44OCIvPjxwYXRoIGNsYXNzPSJsIiBkPSJNNTU0LjcsNTAyLjdjLTkuNy0zLjYtMjQsMTAuMi0zMSwzMS40YTgzLjksODMuOSwwLDAsMC0zLjUsMzUuOWwtNC41LTEuOWMtOC42LTI2LjctMy44LTU1LjksMTEuMS03N1oiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0zOTEuMiAtMzk5LjUpIi8+PHBhdGggY2xhc3M9ImwiIGQ9Ik01NjEsNTQ4LjNsLTMzLjItMTMuN2M2LjEtMTguNSwxNy40LTI5LjYsMjQuNy0yOS42YTcuOCw3LjgsMCwwLDEsMi4yLjRsLjYuM2MyLjYsMS4yLDEwLjUsOCw1LjcsNDIuNiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTM5MS4yIC0zOTkuNSkiLz48cGF0aCBjbGFzcz0ibCIgZD0iTTU0OS4xLDQ2Ni4yYTczLjQsNzMuNCwwLDAsMC0yNS44LDIzLjRjLTE0LjYsMjEuMi0xOS42LDQ5LjktMTIsNzYuN2E4Mi4yLDgyLjIsMCwwLDAsMy4zLDkuNWwtNDQuNS0xOC40Yy0xNi44LTQxLjItMS40LTkwLjMsMzQuNS0xMDkuN1oiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0zOTEuMiAtMzk5LjUpIi8+PC9zdmc+Cg==
[download github]: https://img.shields.io/badge/GitHub-000?style=for-the-badge&logo=github
<!-- Wiki links -->
[wiki]: https://github.com/Andre601/AdvancedServerList/wiki
[minimessage]: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#minimessage
[placeholders]: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#placeholders
<!-- Download links -->
[modrinth]: https://modrinth.com
[spigot]: https://www.spigotmc.org/resources/102910/
[hangar]: https://hangar.benndorf.dev/Andre_601/AdvancedServerList
[github]: https://github.com/Andre601/AdvancedServerList/releases
<!-- Stats -->
[stats-spigot]: https://bstats.org/plugin/bukkit/AdvancedServerList/15584
[stats-bungeecord]: https://bstats.org/plugin/bungeecord/AdvancedServerList/15585
[stats-velocity]: https://bstats.org/plugin/velocity/AdvancedServerList/15587
<!-- Other -->
[license]: https://github.com/Andre601/AdvancedServerList/blob/master/LICENSE
# AdvancedServerList
![platform] ![tested]
![platforms] ![tested]
AdvancedServerList is a plugin made for SpigotMC, PaperMC, BungeeCord/Waterfall and Velocity. It allows you to create server list profiles to display based on priority and conditions.
AdvancedServerList is a server and proxy plugin that allows you to create custom MOTDs and more in your server list with priority and conditions.
## What is a Server List Profile?
A Server List Profile refers to a YAML file located in the plugin's `profiles` directory.
It allows you to configure specific aspects of the server display in the MC-Client's multiplayer server list, such as the MOTD, player count text, player count hover or Favicon.
> [*Read More*][profiles]
### Conditions
Thanks to conditions can you determine when a profile should be displayed in the player’s server list, to allow displaying specific text (i.e. a warning when they are using an outdated version).
When multiple profiles exist that have valid conditions will the one with the highest priority (Higher number = higher priority) be selected. Having no conditions makes the profile automatically return true.
> [*Read More*][conditions]
### Placeholders
Placeholders can be used within conditions to further customize them. They can also be used in any other text option (motd, playerCount and players) to display their respective values.
The format is `${<target> <identifier>}` which was adopted from BungeeTabListPlus. Depending on what platform you use the plugin on are only specific placeholders available.
When using the SpigotMC/PaperMC version can you also use placeholders from [PlaceholderAPI][placeholderapi] using its `%<identifier>_<values>%` placeholder format. PlaceholderAPI needs to be installed for that.
> [*Read More*][placeholders]
### Formatting
The plugin uses the MiniMessage format for a consistent, easy way of formatting your text.
Only certain options are usable for each option. As an example does motd support HEX colours and gradients, while the other options only support default colour codes.
> [*Read More*][minimessage]
## Downloads
AdvancedServerList can be downloaded from the following places:
You can download AdvancedServerList on the following locations:
[![dl-modrinth]][modrinth] [![dl-spigot]][spigot] [![dl-hangar]][hangar]
[![download modrinth]][modrinth] [![download spigot]][spigot] [![download hangar]][hangar] [![download github]][github]
## Dependencies
## Features
| Dependency | Platforms | Required? |
| ---------------- | ------------- | --------- |
| [ProtocolLib] | Spigot | Yes |
| [PlaceholderAPI] | Spigot, Paper | No |
- Create multiple profiles with
- Priority (Higher number = Higher Priority).
- Conditions for displaying the profile.
- Custom MOTD.
- Custom Player count text.
- Custom hover for the player count hover.
- Hide player count (Turn to `???`)
- MiniMessage formatting for MOTD, player count and player count hover [[Read More][minimessage]]
- Placeholder support [[Read More][placeholders]]
## Statistics
## Links
This plugin sends statistics to [bStats] to display.
You can disable this in the `config.yml` by setting `send_statistics` to `false`.
- [Wiki][wiki]
- Statistics
- [Spigot/PaperMC][stats-spigot]
- [BungeeCord][stats-bungeecord]
- [Velocity][stats-velocity]
- [License][license]
- [BungeeCord][bstats-bungee]
- [Paper/Spigot][bstats-spigot]
- [Velocity][bstats-velocity]
## Screenshots
Please see the [Gallery Tab][gallery] for some previews.
If you have any own screenshots, feel free to share them with me. I may add them to the Gallery if they are good.
<!-- Links -->
[profiles]: https://github.com/Andre601/AdvancedServerList/wiki/Profiles
[conditions]: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#conditions
[placeholders]: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#placeholders
[minimessage]: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#minimessage
[placeholderapi]: https://www.spigotmc.org/resources/6245/
[modrinth]: https://modrinth.com/plugin/advancedserverlist
[spigot]: https://www.spigotmc.org/resources/102910/
[hangar]: https://hangar.benndorf.dev/Andre_601/AdvancedServerList
[protocollib]: https://www.spigotmc.org/resources/1997/
[placeholderapi]: https://www.spigotmc.org/resources/6245/
[bstats]: https://bstats.org
[bstats-bungee]: https://bstats.org/plugin/bungeecord/AdvancedServerList/15585
[bstats-spigot]: https://bstats.org/plugin/bukkit/AdvancedServerList/15584
[bstats-velocity]: https://bstats.org/plugin/velocity/AdvancedServerList/15587
[gallery]: https://modrinth.com/mod/advancedserverlist/gallery
<!-- Badges -->
[platform]: https://img.shields.io/badge/Platforms-Spigot%20%7C%20Paper%20%7C%20BungeeCord%20%7C%20Velocity-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiBmaWxsPSJ3aGl0ZSI+PHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMTEuMDYzIDEuNDU2YTEuNzUgMS43NSAwIDAxMS44NzQgMGw4LjM4MyA1LjMxNmExLjc1IDEuNzUgMCAwMTAgMi45NTZsLTguMzgzIDUuMzE2YTEuNzUgMS43NSAwIDAxLTEuODc0IDBMMi42OCA5LjcyOGExLjc1IDEuNzUgMCAwMTAtMi45NTZsOC4zODMtNS4zMTZ6bTEuMDcxIDEuMjY3YS4yNS4yNSAwIDAwLS4yNjggMEwzLjQ4MyA4LjAzOWEuMjUuMjUgMCAwMDAgLjQyMmw4LjM4MyA1LjMxNmEuMjUuMjUgMCAwMC4yNjggMGw4LjM4My01LjMxNmEuMjUuMjUgMCAwMDAtLjQyMmwtOC4zODMtNS4zMTZ6Ij48L3BhdGg+PHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMS44NjcgMTIuMzI0YS43NS43NSAwIDAxMS4wMzUtLjIzMmw4Ljk2NCA1LjY4NWEuMjUuMjUgMCAwMC4yNjggMGw4Ljk2NC01LjY4NWEuNzUuNzUgMCAwMS44MDQgMS4yNjdsLTguOTY1IDUuNjg1YTEuNzUgMS43NSAwIDAxLTEuODc0IDBsLTguOTY1LTUuNjg1YS43NS43NSAwIDAxLS4yMzEtMS4wMzV6Ij48L3BhdGg+PHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMS44NjcgMTYuMzI0YS43NS43NSAwIDAxMS4wMzUtLjIzMmw4Ljk2NCA1LjY4NWEuMjUuMjUgMCAwMC4yNjggMGw4Ljk2NC01LjY4NWEuNzUuNzUgMCAwMS44MDQgMS4yNjdsLTguOTY1IDUuNjg1YTEuNzUgMS43NSAwIDAxLTEuODc0IDBsLTguOTY1LTUuNjg1YS43NS43NSAwIDAxLS4yMzEtMS4wMzV6Ij48L3BhdGg+PC9zdmc+
[tested]: https://img.shields.io/badge/Tested%20Versions-1.19%20%7C%201.19.1%20%7C%201.19.2-blue?style=for-the-badge&logo=image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiBmaWxsPSJ3aGl0ZSI+PHBhdGggZD0iTTE3LjI4IDkuMjhhLjc1Ljc1IDAgMDAtMS4wNi0xLjA2bC01Ljk3IDUuOTctMi40Ny0yLjQ3YS43NS43NSAwIDAwLTEuMDYgMS4wNmwzIDNhLjc1Ljc1IDAgMDAxLjA2IDBsNi41LTYuNXoiPjwvcGF0aD48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0zLjc1IDJBMS43NSAxLjc1IDAgMDAyIDMuNzV2MTYuNWMwIC45NjYuNzg0IDEuNzUgMS43NSAxLjc1aDE2LjVBMS43NSAxLjc1IDAgMDAyMiAyMC4yNVYzLjc1QTEuNzUgMS43NSAwIDAwMjAuMjUgMkgzLjc1ek0zLjUgMy43NWEuMjUuMjUgMCAwMS4yNS0uMjVoMTYuNWEuMjUuMjUgMCAwMS4yNS4yNXYxNi41YS4yNS4yNSAwIDAxLS4yNS4yNUgzLjc1YS4yNS4yNSAwIDAxLS4yNS0uMjVWMy43NXoiPjwvcGF0aD48L3N2Zz4=
[dl-modrinth]: https://img.shields.io/badge/Modrinth-30b27b?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIGZpbGwtcnVsZT0iZXZlbm9kZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLW1pdGVybGltaXQ9IjEuNSIgY2xpcC1ydWxlPSJldmVub2RkIiB2aWV3Qm94PSIwIDAgNjggNjgiPjxwYXRoIGZpbGw9Im5vbmUiIGQ9Ik0uMDUgMGg2NnY2NmgtNjZ6Ii8+PGNsaXBQYXRoIGlkPSJhIj48cGF0aCBkPSJNLjA1IDBoNjZ2NjZoLTY2eiIvPjwvY2xpcFBhdGg+PGcgY2xpcC1wYXRoPSJ1cmwoI2EpIj48Y2xpcFBhdGggaWQ9ImIiPjxjaXJjbGUgY3g9IjMzLjA1IiBjeT0iMzMiIHI9IjMzIi8+PC9jbGlwUGF0aD48ZyBjbGlwLXBhdGg9InVybCgjYikiPjxjbGlwUGF0aCBpZD0iYyI+PHBhdGggZD0iTTgzLjA1LTE3aC0xMDBWODNoMTAwVi0xN1pNMjkuMDUxIDMyLjI5NWwuMDc3IDEuNzU3IDguODI5IDMyLjk2MyA3Ljg0NC0yLjEwMi04LjU5Ny0zMi4wOTRMNDMuMDA5LS4xMTNsLTcuOTk3LTEuNDEtNS45NjEgMzMuODE4WiIvPjwvY2xpcFBhdGg+PGcgY2xpcC1wYXRoPSJ1cmwoI2MpIj48cGF0aCBmaWxsPSIjRkZGIiBkPSJNMzMuMDUgMGMxOC4yMDYgMCAzMi45ODggMTQuNzg3IDMyLjk4OCAzM1M1MS4yNTYgNjYgMzMuMDUgNjZDMTQuODQzIDY2IC4wNjEgNTEuMjEzLjA2MSAzM1MxNC44NDMgMCAzMy4wNSAwWm0wIDljMTMuMjQgMCAyMy45ODggMTAuNzU1IDIzLjk4OCAyNFM0Ni4yOSA1NyAzMy4wNSA1N0MxOS44MDkgNTcgOS4wNjEgNDYuMjQ1IDkuMDYxIDMzUzE5LjgwOSA5IDMzLjA1IDlaIi8+PC9nPjxjbGlwUGF0aCBpZD0iZCI+PHBhdGggZD0iTS0xNi45NS0xN3Y0Nmg1MGwxLjM2OC4yNDFMODIuMDUgNDYuNTc4bC0yLjczNyA3LjUxN0wzMi4zNDQgMzdILTE2Ljk1djQ2aDEwMFYtMTdoLTEwMFoiLz48L2NsaXBQYXRoPjxnIGNsaXAtcGF0aD0idXJsKCNkKSI+PHBhdGggZmlsbD0iI0ZGRiIgZD0iTTMzLjA1LTE3YzI3LjU5NSAwIDUwIDIyLjQwNCA1MCA1MHMtMjIuNDA1IDUwLTUwIDUwYy0yNy41OTYgMC01MC0yMi40MDQtNTAtNTBzMjIuNDA0LTUwIDUwLTUwWm0wIDljMjIuNjI4IDAgNDEgMTguMzcxIDQxIDQxcy0xOC4zNzIgNDEtNDEgNDFjLTIyLjYyOSAwLTQxLTE4LjM3MS00MS00MXMxOC4zNzEtNDEgNDEtNDFaIi8+PC9nPjxjbGlwUGF0aCBpZD0iZSI+PHBhdGggZD0iTTMzLjA1LTE3YzI3LjU5NSAwIDUwIDIyLjQwNCA1MCA1MHMtMjIuNDA1IDUwLTUwIDUwYy0yNy41OTYgMC01MC0yMi40MDQtNTAtNTBzMjIuNDA0LTUwIDUwLTUwWm0wIDM5LjU0OWM1Ljc2NyAwIDEwLjQ1IDQuNjgzIDEwLjQ1IDEwLjQ1MSAwIDUuNzY4LTQuNjgzIDEwLjQ1MS0xMC40NSAxMC40NTEtNS43NjggMC0xMC40NTEtNC42ODMtMTAuNDUxLTEwLjQ1MSAwLTUuNzY4IDQuNjgzLTEwLjQ1MSAxMC40NTEtMTAuNDUxWiIvPjwvY2xpcFBhdGg+PGcgY2xpcC1wYXRoPSJ1cmwoI2UpIj48cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IiNGRkYiIHN0cm9rZS13aWR0aD0iOSIgZD0ibTMzLjA1IDMzLTQ0LjgyOSAyNS44ODIiLz48L2c+PGNsaXBQYXRoIGlkPSJmIj48cGF0aCBkPSJNMzMuMDUtMTdjMjcuNTk1IDAgNTAgMjIuNDA0IDUwIDUwcy0yMi40MDUgNTAtNTAgNTBjLTI3LjU5NiAwLTUwLTIyLjQwNC01MC01MHMyMi40MDQtNTAgNTAtNTBabTAgMjUuMzZjMTMuNTk5IDAgMjQuNjQgMTEuMDQxIDI0LjY0IDI0LjY0UzQ2LjY0OSA1Ny42NCAzMy4wNSA1Ny42NEMxOS40NSA1Ny42NCA4LjQwOSA0Ni41OTkgOC40MDkgMzNTMTkuNDUgOC4zNiAzMy4wNSA4LjM2WiIvPjwvY2xpcFBhdGg+PGcgY2xpcC1wYXRoPSJ1cmwoI2YpIj48cGF0aCBmaWxsPSJub25lIiBzdHJva2U9IiNGRkYiIHN0cm9rZS13aWR0aD0iOSIgZD0ibTMzLjA1IDMzIDUwLTEzLjM5NyIvPjwvZz48cGF0aCBmaWxsPSIjRkZGIiBkPSJNMjAuMjkzIDM1Ljc0NiAxOC4wNSAyOGw4LTkgMTEtMyA0IDQtNiA2LTQgMS0zIDQgMS4xMiA0LjI0IDMuMTEyIDMuMDkgNC45NjQtLjU5OCAyLjg2Ni0yLjk2NCA4LjE5Ni0yLjE5NiAxLjQ2NCA1LjQ2NC04LjA5OCA4LjAyNkwyOS44OCA0OC40OWwtNS41ODctNS44MTUtNC02LjkyOVoiLz48L2c+PC9nPjwvc3ZnPg==
[dl-spigot]: https://img.shields.io/badge/Spigot-ed8106?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiBmaWxsPSIjRkZGIj48cGF0aCBkPSJNNDE2IDQ4MGMwIDE3LjYyIDE0LjM4IDMyIDMyIDMyczMyLTE0LjM4IDMyLTMycy0zMi02NC0zMi02NFM0MTYgNDYyLjQgNDE2IDQ4MHpNMzUyIDE5MmgtMzguNTRDMjk3LjcgMTc4LjUgMjc3LjkgMTY4LjkgMjU2IDE2NFYxMTYuNUwyMjQgMTEzTDE5MiAxMTYuNVYxNjRDMTcwLjEgMTY5IDE1MC4zIDE3OC42IDEzNC41IDE5MkgxNkM3LjEyNSAxOTIgMCAxOTkuMSAwIDIwOHY5NkMwIDMxMi45IDcuMTI1IDMyMCAxNiAzMjBoOTIuNzhDMTI5LjQgMzU3LjggMTczIDM4NCAyMjQgMzg0czk0LjU5LTI2LjI1IDExNS4yLTY0SDM1MmMxNy42MiAwIDMyIDE0LjI5IDMyIDMxLjkxUzM5OC40IDM4NCA0MTYgMzg0aDY0YzE3LjYyIDAgMzItMTQuMzggMzItMzJDNTEyIDI2My42IDQ0MC40IDE5MiAzNTIgMTkyek04MS42MyA5NS44OEwyMjQgODAuODhsMTQyLjQgMTVDMzc1LjkgOTYuODggMzg0IDg5LjEyIDM4NCA3OS4xMlY0OC44OWMwLTEwLTguMTI1LTE3Ljc0LTE3LjYyLTE2Ljc0TDI1NiA0My43NVYxNkMyNTYgNy4xMjUgMjQ4LjkgMCAyNDAgMGgtMzJDMTk5LjEgMCAxOTIgNy4xMjUgMTkyIDE2djI3Ljc1TDgxLjYzIDMyLjE0QzcyLjEzIDMxLjE0IDY0IDM4Ljg5IDY0IDQ4Ljg5Vjc5LjEyQzY0IDg5LjEyIDcyLjEzIDk2Ljg4IDgxLjYzIDk1Ljg4eiIvPjwvc3ZnPg==
[dl-hangar]: https://img.shields.io/badge/Hangar%20(Beta)-444?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNDEgMjI0LjUiPjxkZWZzPjxzdHlsZT4uYXtmaWxsOm5vbmU7fS5iLC5se2ZpbGw6I2ZmZjt9LmIsLmMsLmQsLmUsLmYsLmcsLmgsLmksLmp7ZmlsbC1ydWxlOmV2ZW5vZGQ7fS5je2ZpbGw6I2ZhMDt9LmR7ZmlsbDojYWFhO30uZXtmaWxsOiM1NWY7fS5me2ZpbGw6IzVmNTt9Lmd7ZmlsbDojNjdjYmRmO30uaHtmaWxsOiNmNTU7fS5pe2ZpbGw6I2Y1Zjt9Lmp7ZmlsbDojZmY1O30ua3tmaWxsOiM0NDQ7fTwvc3R5bGU+PC9kZWZzPjxyZWN0IGNsYXNzPSJhIiB4PSIyMS4yIiB5PSIxMy42IiB3aWR0aD0iMjE0LjciIGhlaWdodD0iMTk5Ljk0Ii8+PHBhdGggY2xhc3M9ImIiIGQ9Ik01NTAuOCwzOTkuNSwzOTEuMiw0NzUuMyw0NzIuNSw2MjRsMTU5LjYtNzUuOEw1NTAuOCwzOTkuNVoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0zOTEuMiAtMzk5LjUpIi8+PHBhdGggY2xhc3M9ImMiIGQ9Ik01NTcsNDAxLjYsMzkzLjQsNDY5LjVsNzIuOCwxNTIuNEw2MjkuOSw1NTRaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMzkxLjIgLTM5OS41KSIvPjxwYXRoIGNsYXNzPSJkIiBkPSJNNTYzLjIsNDA0LDM5NS45LDQ2My44bDY0LjIsMTU1LjgsMTY3LjMtNTkuOFoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0zOTEuMiAtMzk5LjUpIi8+PHBhdGggY2xhc3M9ImUiIGQ9Ik01NjkuMiw0MDYuNiwzOTguOCw0NTguMmw1NS4zLDE1OC43LDE3MC40LTUxLjZMNTY5LjIsNDA2LjZaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMzkxLjIgLTM5OS41KSIvPjxwYXRoIGNsYXNzPSJmIiBkPSJNNTc1LDQwOS42LDQwMiw0NTIuOGw0Ni4zLDE2MS4xLDE3My4xLTQzLjFaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMzkxLjIgLTM5OS41KSIvPjxwYXRoIGNsYXNzPSJnIiBkPSJNNTgxLjEsNDEyLjVsLTE3NS41LDM1TDQ0My4yLDYxMWwxNzUuNS0zNUw1ODEuMSw0MTIuNVoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0zOTEuMiAtMzk5LjUpIi8+PHBhdGggY2xhc3M9ImgiIGQ9Ik01ODYuMSw0MTYuMyw0MDkuMiw0NDIuNGwyOCwxNjQuOCwxNzYuOS0yNi4xLTI4LTE2NC44WiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTM5MS4yIC0zOTkuNSkiLz48cGF0aCBjbGFzcz0iaSIgZD0iTTU5MS40LDQyMC4xLDQxMy4yLDQzNy41bDE4LjcsMTY2TDYxMC4xLDU4Niw1OTEuNCw0MjAuMVoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0zOTEuMiAtMzk5LjUpIi8+PHBhdGggY2xhc3M9ImoiIGQ9Ik01OTYuNCw0MjQuMWwtMTc4LjksOC43LDkuNCwxNjYuNiwxNzguOS04LjctOS40LTE2Ni42WiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTM5MS4yIC0zOTkuNSkiLz48cmVjdCBjbGFzcz0iayIgeD0iMzAuOSIgeT0iMjguOCIgd2lkdGg9IjE3OS4yIiBoZWlnaHQ9IjE2Ni44OCIvPjxwYXRoIGNsYXNzPSJsIiBkPSJNNTU0LjcsNTAyLjdjLTkuNy0zLjYtMjQsMTAuMi0zMSwzMS40YTgzLjksODMuOSwwLDAsMC0zLjUsMzUuOWwtNC41LTEuOWMtOC42LTI2LjctMy44LTU1LjksMTEuMS03N1oiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0zOTEuMiAtMzk5LjUpIi8+PHBhdGggY2xhc3M9ImwiIGQ9Ik01NjEsNTQ4LjNsLTMzLjItMTMuN2M2LjEtMTguNSwxNy40LTI5LjYsMjQuNy0yOS42YTcuOCw3LjgsMCwwLDEsMi4yLjRsLjYuM2MyLjYsMS4yLDEwLjUsOCw1LjcsNDIuNiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTM5MS4yIC0zOTkuNSkiLz48cGF0aCBjbGFzcz0ibCIgZD0iTTU0OS4xLDQ2Ni4yYTczLjQsNzMuNCwwLDAsMC0yNS44LDIzLjRjLTE0LjYsMjEuMi0xOS42LDQ5LjktMTIsNzYuN2E4Mi4yLDgyLjIsMCwwLDAsMy4zLDkuNWwtNDQuNS0xOC40Yy0xNi44LTQxLjItMS40LTkwLjMsMzQuNS0xMDkuN1oiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0zOTEuMiAtMzk5LjUpIi8+PC9zdmc+Cg==
+9 -5
View File
@@ -75,7 +75,7 @@
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-platform-bungeecord</artifactId>
<version>4.1.0</version>
<version>4.1.2</version>
<scope>compile</scope>
</dependency>
<dependency>
@@ -105,20 +105,24 @@
<artifactId>maven-shade-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<minimizeJar>true</minimizeJar>
<createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
<relocation>
<pattern>org.spongepowered.configurate</pattern>
<shadedPattern>ch.andre601.advancedserverlist.velocity.depends.configurate</shadedPattern>
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.configurate</shadedPattern>
</relocation>
<relocation>
<pattern>net.kyori.adventure</pattern>
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.adventure</shadedPattern>
<pattern>net.kyori</pattern>
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.kyori</shadedPattern>
</relocation>
<relocation>
<pattern>org.bstats</pattern>
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.bstats</shadedPattern>
</relocation>
<relocation>
<pattern>com.github.benmanes.caffeine</pattern>
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.caffeine</shadedPattern>
</relocation>
</relocations>
<filters>
<filter>
@@ -32,15 +32,18 @@ import ch.andre601.advancedserverlist.bungeecord.logging.BungeeLogger;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.PluginCore;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.profiles.favicon.FaviconHandler;
import net.md_5.bungee.api.Favicon;
import net.md_5.bungee.api.plugin.Plugin;
import org.bstats.bungeecord.Metrics;
import org.bstats.charts.SimplePie;
import java.nio.file.Path;
public class BungeeCordCore extends Plugin implements PluginCore{
public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
private AdvancedServerList core;
private FaviconHandler<Favicon> faviconHandler = null;
private final PluginLogger logger = new BungeeLogger(getLogger());
@Override
@@ -72,6 +75,11 @@ public class BungeeCordCore extends Plugin implements PluginCore{
}
@Override
public void clearFaviconCache(){
faviconHandler.clearCache();
}
@Override
public AdvancedServerList getCore(){
return core;
@@ -87,6 +95,14 @@ public class BungeeCordCore extends Plugin implements PluginCore{
return logger;
}
@Override
public FaviconHandler<Favicon> getFaviconHandler(){
if(faviconHandler == null)
faviconHandler = new FaviconHandler<>(core);
return faviconHandler;
}
@Override
public String getPlatformName(){
return getProxy().getName();
@@ -0,0 +1,37 @@
/*
* MIT License
*
* Copyright (c) 2022 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.bungeecord;
import ch.andre601.advancedserverlist.core.profiles.players.GenericPlayer;
import net.md_5.bungee.api.connection.ProxiedPlayer;
public class BungeePlayer extends GenericPlayer<ProxiedPlayer>{
public BungeePlayer(String name, int protocol){
this.name = name;
this.protocol = protocol;
}
}
@@ -26,12 +26,16 @@
package ch.andre601.advancedserverlist.bungeecord.events;
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
import ch.andre601.advancedserverlist.bungeecord.BungeePlayer;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import ch.andre601.advancedserverlist.core.profiles.ProfileManager;
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
import ch.andre601.advancedserverlist.core.profiles.replacer.Placeholders;
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
import ch.andre601.advancedserverlist.core.profiles.replacer.placeholders.PlayerPlaceholders;
import ch.andre601.advancedserverlist.core.profiles.replacer.placeholders.ServerPlaceholders;
import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer;
import net.md_5.bungee.api.Favicon;
import net.md_5.bungee.api.ServerPing;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.event.ProxyPingEvent;
@@ -40,7 +44,6 @@ import net.md_5.bungee.event.EventHandler;
import net.md_5.bungee.event.EventPriority;
import java.net.InetSocketAddress;
import java.util.Map;
public class PingEvent implements Listener{
@@ -58,27 +61,37 @@ public class PingEvent implements Listener{
if(protocol == null)
return;
InetSocketAddress address = (InetSocketAddress)event.getConnection().getSocketAddress();
String playerName = plugin.getCore().getPlayerHandler().getPlayerByIp(
((InetSocketAddress)event.getConnection().getSocketAddress()).getHostString()
);
InetSocketAddress host = event.getConnection().getVirtualHost();
Map<String, Object> replacements = Placeholders.get(plugin.getCore())
.withProtocol(protocol.getProtocol())
.withPlayersOnline(ping.getPlayers().getOnline())
.withPlayersMax(ping.getPlayers().getMax())
.withPlayerName(address)
.withHostAddress(host)
.getReplacements();
int online = ping.getPlayers().getOnline();
int max = ping.getPlayers().getMax();
PlayerPlaceholders playerPlaceholders = new PlayerPlaceholders(new BungeePlayer(playerName, protocol.getProtocol()));
ServerPlaceholders serverPlaceholders = new ServerPlaceholders(online, max, host == null ? null : host.getHostString());
ServerListProfile profile = ProfileManager.get(plugin.getCore())
.replacements(replacements)
.replacements(playerPlaceholders)
.replacements(serverPlaceholders)
.getProfile();
if(profile == null)
return;
if(profile.getXMore() >= 0){
max = online + profile.getXMore();
ping.getPlayers().setMax(max);
}
serverPlaceholders = new ServerPlaceholders(online, max, host == null ? null : host.getHostString());
if(!profile.getMotd().isEmpty()){
TextComponent component = new TextComponent(BungeeComponentSerializer.get().serialize(
ComponentParser.list(profile.getMotd())
.replacements(replacements)
.replacements(playerPlaceholders)
.replacements(serverPlaceholders)
.toComponent()
));
@@ -97,7 +110,8 @@ public class PingEvent implements Listener{
if(!profile.getPlayerCount().isEmpty()){
protocol.setName(ComponentParser.text(profile.getPlayerCount())
.replacements(replacements)
.replacements(playerPlaceholders)
.replacements(serverPlaceholders)
.toString()
);
protocol.setProtocol(-1);
@@ -105,7 +119,8 @@ public class PingEvent implements Listener{
if(!profile.getPlayers().isEmpty()){
String players = ComponentParser.list(profile.getPlayers())
.replacements(replacements)
.replacements(playerPlaceholders)
.replacements(serverPlaceholders)
.toString();
ServerPing.PlayerInfo[] playerInfos = AdvancedServerList.getPlayers(ServerPing.PlayerInfo.class, players)
@@ -113,10 +128,27 @@ public class PingEvent implements Listener{
if(playerInfos.length > 0)
ping.getPlayers().setSample(playerInfos);
}
ping.setFavicon(ping.getFaviconObject());
if(!profile.getFavicon().isEmpty()){
String favName = StringReplacer.replace(profile.getFavicon(), playerPlaceholders.getReplacements());
Favicon favicon = plugin.getFaviconHandler().getFavicon(favName, image -> {
try{
return Favicon.create(image);
}catch(Exception ex){
return null;
}
});
if(favicon == null){
plugin.getPluginLogger().warn("Could not obtain valid Favicon to use.");
ping.setFavicon(ping.getFaviconObject());
}else{
ping.setFavicon(favicon);
}
}
ping.setVersion(protocol);
event.setResponse(ping);
+11 -5
View File
@@ -47,22 +47,28 @@
<dependency>
<groupId>org.spongepowered</groupId>
<artifactId>configurate-yaml</artifactId>
<version>${plugin.depend.configurate}</version>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-api</artifactId>
<version>${plugin.depend.kyori-adventure}</version>
<version>4.11.0</version>
</dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-text-minimessage</artifactId>
<version>${plugin.depend.kyori-minimessage}</version>
<version>4.11.0</version>
</dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-text-serializer-legacy</artifactId>
<version>${plugin.depend.kyori-legacy}</version>
<version>4.11.0</version>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>3.1.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
@@ -85,7 +91,7 @@
<artifactId>maven-shade-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<minimizeJar>true</minimizeJar>
<createDependencyReducedPom>false</createDependencyReducedPom>
<filters>
<filter>
<artifact>*:*</artifact>
@@ -81,6 +81,10 @@ public class AdvancedServerList{
getPluginLogger().info("AdvancedServerList disabled!");
}
public void clearFaviconCache(){
plugin.clearFaviconCache();
}
public PluginLogger getPluginLogger(){
return plugin.getPluginLogger();
}
@@ -111,7 +115,7 @@ public class AdvancedServerList{
getPluginLogger().info("Starting AdvancedServerList v%s...", version);
getPluginLogger().info("Proxy: " + plugin.getPlatformName() + " " + plugin.getPlatformVersion());
getPluginLogger().info("Platform: " + plugin.getPlatformName() + " " + plugin.getPlatformVersion());
if(getFileHandler().loadConfig()){
getPluginLogger().info("Successfully loaded config.yml!");
@@ -127,6 +131,9 @@ public class AdvancedServerList{
return;
}
if(!getPath().resolve("favicons").toFile().exists() && getPath().resolve("favicons").toFile().mkdirs())
getPluginLogger().info("Successfully created favicons folder.");
getPluginLogger().info("Loading Commands...");
plugin.loadCommands();
getPluginLogger().info("Commands loaded!");
@@ -138,13 +145,9 @@ public class AdvancedServerList{
getPluginLogger().info("Loading cache.data...");
getPlayerHandler().load();
getPluginLogger().info("Loading Metrics for bStats...");
if(getFileHandler().getBoolean("send_statistics")){
plugin.loadMetrics();
getPluginLogger().info("Metrics loaded!");
}else{
getPluginLogger().info("'send_statistics' disabled in config.yml. Not loading Metrics for bStats...");
}
getPluginLogger().info("Loading bStats metrics. Disable it in the global config under /plugins/bstats/");
plugin.loadMetrics();
getPluginLogger().info("Metrics loaded!");
getPluginLogger().info("AdvancedServerList is ready!");
}
@@ -37,37 +37,45 @@ public class CommandHandler{
}
public void handle(CmdSender sender, String[] args){
String errorPrefix = "<grey>[<gradient:dark_red:red>AdvancedServerList</gradient>]";
String prefix = "<grey>[<gradient:aqua:white>AdvancedServerList</gradient>]";
if(args.length == 0 || args[0].equalsIgnoreCase("help")){
if(sender.hasPermission("advancedserverlist.command.help")){
sender.sendMsg("AdvancedServerList Commands");
sender.sendMsg("%s - Commands", prefix);
sender.sendMsg();
sender.sendMsg("<aqua>/asl help <grey>- Shows this help.");
sender.sendMsg("<gradient:aqua:white>/asl help</gradient> <grey>- Shows this Help");
sender.sendMsg();
sender.sendMsg("<aqua>/asl reload <grey>- Reloads the config and profiles.");
sender.sendMsg("<gradient:aqua:white>/asl reload</gradient> <grey>- Reloads the plugin");
}else{
sender.sendMsg("<red>You do not have the permissions to execute this command!");
sender.sendMsg("%s <red>You do not have permissions to execute this command!", errorPrefix);
}
}else
if(args[0].equalsIgnoreCase("reload")){
if(sender.hasPermission("advancedserverlist.command.reload")){
sender.sendMsg("<grey>Reloading config.yml...");
sender.sendMsg("%s Reloading plugin...", prefix);
if(core.getFileHandler().reloadConfig()){
sender.sendMsg("<green>Successfully reloaded <grey>config.yml</grey>!");
sender.sendMsg("%s <green>Reloaded <grey>config.yml</grey>!", prefix);
}else{
sender.sendMsg("<red>Error while reloading the config.yml.");
sender.sendMsg("%s <red>Error while reloading the <grey>config.yml</grey>!", errorPrefix);
}
sender.sendMsg("<grey>Reloading Profiles...");
if(core.getFileHandler().reloadProfiles()){
sender.sendMsg("<green>Successfully loaded <grey>%d</grey> Profiles!", core.getFileHandler().getProfiles().size());
sender.sendMsg("%s <green>Loaded <grey>%s Profile(s)</grey>!", prefix, core.getFileHandler().getProfiles());
}else{
sender.sendMsg("<red>Error while reloading Profiles. No profiles have been loaded.");
sender.sendMsg("%s <red>Cannot load Profiles!", errorPrefix);
}
sender.sendMsg("<green>Reload complete!");
core.clearFaviconCache();
sender.sendMsg("%s <green>Successfully cleared Favicon cache!", prefix);
sender.sendMsg("%s <green>Reload complete!", prefix);
}else{
sender.sendMsg("%s <red>You do not have permissions to execute this command!", errorPrefix);
}
}else{
sender.sendMsg("<red>Unknown subcommand <grey>%s</grey>. Use <grey>/asl help</grey> for a list of commands.", args[0]);
sender.sendMsg("%s <red>Unknown subcommand <grey>%s</grey>. Use <grey>/asl help</grey> for a list of commands.", prefix, args[0]);
}
}
}
@@ -32,7 +32,6 @@ import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
@@ -43,8 +42,6 @@ import java.util.List;
public class FileHandler{
private final FilenameFilter profileFilter = (dir, name) -> name.endsWith(".yml");
private final AdvancedServerList plugin;
private final PluginLogger logger;
@@ -119,7 +116,7 @@ public class FileHandler{
public boolean reloadProfiles(){
profiles.clear();
File[] files = profilesFolder.toFile().listFiles(profileFilter);
File[] files = profilesFolder.toFile().listFiles(((dir, name) -> name.endsWith(".yml")));
if(files == null || files.length == 0){
logger.warn("Cannot load files from profiles folder! No valid YAML files present.");
return false;
@@ -159,8 +156,4 @@ public class FileHandler{
public String getString(String def, Object... path){
return node.node(path).getString(def);
}
public boolean getBoolean(Object... path){
return node.node(path).getBoolean(true);
}
}
@@ -25,8 +25,6 @@
package ch.andre601.advancedserverlist.core.interfaces;
import net.kyori.adventure.text.format.NamedTextColor;
public interface CmdSender{
boolean hasPermission(String permission);
@@ -26,10 +26,11 @@
package ch.andre601.advancedserverlist.core.interfaces;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.profiles.favicon.FaviconHandler;
import java.nio.file.Path;
public interface PluginCore{
public interface PluginCore<T>{
void loadCommands();
@@ -37,12 +38,16 @@ public interface PluginCore{
void loadMetrics();
void clearFaviconCache();
AdvancedServerList getCore();
Path getPath();
PluginLogger getPluginLogger();
FaviconHandler<T> getFaviconHandler();
String getPlatformName();
String getPlatformVersion();
@@ -26,12 +26,12 @@
package ch.andre601.advancedserverlist.core.parsing;
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
import ch.andre601.advancedserverlist.core.profiles.replacer.placeholders.Placeholders;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
public class ComponentParser{
@@ -58,8 +58,8 @@ public class ComponentParser{
return new ComponentParser(String.join("\n", lines));
}
public ComponentParser replacements(Map<String, Object> replacements){
text = StringReplacer.replace(text, replacements);
public ComponentParser replacements(Placeholders placeholders){
text = StringReplacer.replace(text, placeholders.getReplacements());
return this;
}
@@ -26,6 +26,7 @@
package ch.andre601.advancedserverlist.core.profiles;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.profiles.replacer.placeholders.Placeholders;
import java.util.HashMap;
import java.util.Map;
@@ -34,7 +35,7 @@ public class ProfileManager{
private final AdvancedServerList core;
private Map<String, Object> replacements = new HashMap<>();
private final Map<String, Object> replacements = new HashMap<>();
private ProfileManager(AdvancedServerList core){
this.core = core;
@@ -44,8 +45,8 @@ public class ProfileManager{
return new ProfileManager(core);
}
public ProfileManager replacements(Map<String, Object> replacements){
this.replacements = replacements;
public ProfileManager replacements(Placeholders placeholders){
this.replacements.putAll(placeholders.getReplacements());
return this;
}
@@ -43,7 +43,9 @@ public class ServerListProfile{
private final List<String> motd;
private final List<String> players;
private final String playerCount;
private final String favicon;
private final boolean hidePlayers;
private final int xMore;
public ServerListProfile(ConfigurationNode node, PluginLogger logger){
this.priority = node.node("priority").getInt();
@@ -52,7 +54,9 @@ public class ServerListProfile{
this.motd = getList(node, "motd", true);
this.players = getList(node, "players", false);
this.playerCount = node.node("playerCount").getString("");
this.favicon = node.node("favicon").getString("");
this.hidePlayers = node.node("hidePlayers").getBoolean();
this.xMore = node.node("xMore").getInt(-1);
}
public int getPriority(){
@@ -71,10 +75,18 @@ public class ServerListProfile{
return playerCount;
}
public String getFavicon(){
return favicon;
}
public boolean shouldHidePlayers(){
return hidePlayers;
}
public int getXMore(){
return xMore;
}
public boolean evalConditions(Map<String, Object> replacements){
if(expressions.isEmpty())
return true;
@@ -98,7 +98,7 @@ public class Expression{
}
public enum Operator{
LESS_THAN('<', '\0'){
LESS('<', '\0'){
@Override
public boolean evaluate(String left, String right){
int leftInt = Operator.getInt(left);
@@ -128,7 +128,7 @@ public class Expression{
return !left.equals(right);
}
},
GREATER_THAN('>', '\0'){
GREATER('>', '\0'){
@Override
public boolean evaluate(String left, String right){
int leftInt = Operator.getInt(left);
@@ -191,32 +191,20 @@ public class Expression{
}
public enum ExpressionResult{
VALID{
@Override
public String getMessage(){
return null;
}
},
VALID(null),
INVALID_NO_EXPRESSION{
@Override
public String getMessage(){
return "Received empty condition which isn't allowed!";
}
},
INVALID_DOUBLE_OPERATOR{
@Override
public String getMessage(){
return "Condition contained two operands.";
}
},
INVALID_EMPTY_PARTS{
@Override
public String getMessage(){
return "Received condition with either left or right part being empty.";
}
};
INVALID_NO_EXPRESSION ("Received empty condition which isn't allowed!"),
INVALID_DOUBLE_OPERATOR("Condition contained two operands."),
INVALID_EMPTY_PARTS ("Received condition with either left or right part being empty.");
public abstract String getMessage();
private final String message;
ExpressionResult(String message){
this.message = message;
}
public String getMessage(){
return message;
}
}
}
@@ -0,0 +1,138 @@
/*
* MIT License
*
* Copyright (c) 2022 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.favicon;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
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.util.Locale;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
public class FaviconHandler<T>{
private final Cache<String, T> favicons = Caffeine.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES)
.build();
private final AdvancedServerList core;
public FaviconHandler(AdvancedServerList core){
this.core = core;
}
public T getFavicon(String input, Function<BufferedImage, T> function){
return favicons.get(input, k -> {
BufferedImage image = resolveImage(core, input);
if(image == null)
return null;
return function.apply(image);
});
}
public void clearCache(){
favicons.invalidateAll();
}
private BufferedImage resolveImage(AdvancedServerList core, String input){
InputStream stream;
if(input.toLowerCase(Locale.ROOT).startsWith("https://")){
stream = getFromUrl(core, input);
}else
if(input.toLowerCase(Locale.ROOT).endsWith(".png")){
File folder = core.getPath().resolve("favicons").toFile();
if(!folder.exists()){
core.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.getPluginLogger().warn("Cannot create Favicon from File %s.", input);
core.getPluginLogger().warn("Cause: %s", ex.getMessage());
return null;
}
}else{
stream = getFromUrl(core, "https://mc-heads.net/avatar/" + input + "/64");
}
if(stream == null){
core.getPluginLogger().warn("Cannot create Favicon. InputStream was null.");
return null;
}
try{
BufferedImage original = ImageIO.read(stream);
if(original == null){
core.getPluginLogger().warn("Cannot create Favicon. Unable to create BufferedImage.");
return null;
}
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;
}catch(IOException ex){
core.getPluginLogger().warn("Unable to create Favicon. Encountered IOException during creation.");
core.getPluginLogger().warn("Cause: %s", ex.getMessage());
return null;
}
}
private InputStream getFromUrl(AdvancedServerList core, String url){
try{
URL faviconUrl = new URL(url);
URLConnection connection = faviconUrl.openConnection();
connection.setRequestProperty("User-Agent", "AdvancedServerList/" + core.getVersion());
connection.connect();
return connection.getInputStream();
}catch(IOException ex){
core.getPluginLogger().warn("Error while connecting to %s for Favicon creation.", url);
core.getPluginLogger().warn("Cause: %s", ex.getMessage());
return null;
}
}
}
@@ -0,0 +1,72 @@
/*
* MIT License
*
* Copyright (c) 2022 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.players;
import java.util.UUID;
public abstract class GenericPlayer<T>{
protected T player = null;
protected String name = null;
protected String version = null;
protected int protocol = -1;
protected boolean playedBefore = false;
protected boolean banned = false;
protected boolean whitelisted = false;
protected UUID uuid = null;
public T getPlayer(){
return player;
}
public String getName(){
return name;
}
public int getProtocol(){
return protocol;
}
public String getVersion(){
return version;
}
public boolean hasPlayedBefore(){
return playedBefore;
}
public boolean isBanned(){
return banned;
}
public boolean isWhitelisted(){
return whitelisted;
}
public UUID getUniqueId(){
return uuid;
}
}
@@ -28,13 +28,12 @@ package ch.andre601.advancedserverlist.core.profiles.players;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.profiles.replacer.EntryList;
import java.io.ByteArrayInputStream;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
@@ -55,7 +54,6 @@ public class PlayerHandler{
core.getPluginLogger().info("No cache.data present. Skipping...");
return;
}
List<String> lines;
try{
lines = Files.readAllLines(cache);
@@ -93,10 +91,14 @@ public class PlayerHandler{
for(Map.Entry<String, String> entry : players){
joiner.add(entry.getKey() + "=" + entry.getValue());
}
try(InputStream stream = new ByteArrayInputStream(joiner.toString().getBytes(StandardCharsets.UTF_8))){
Files.copy(stream, cache, StandardCopyOption.REPLACE_EXISTING);
core.getPluginLogger().info("Saved cache.data file.");
try{
BufferedWriter writer = Files.newBufferedWriter(cache, StandardCharsets.UTF_8, StandardOpenOption.WRITE);
writer.write(joiner.toString());
writer.close();
core.getPluginLogger().info("Successfully saved cache.data file.");
}catch(IOException ex){
core.getPluginLogger().warn("Cannot save player data to cache.data file!", ex);
}
@@ -41,7 +41,7 @@ public class EntryList<K, V> extends ArrayList<Map.Entry<K, V>>{
public boolean containsKey(K key){
for(Map.Entry<K, V> entry : this){
if(entry.getKey() == key)
if(entry.getKey().equals(key))
return true;
}
return false;
@@ -1,93 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 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.replacer;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;
public class Placeholders{
private final AdvancedServerList core;
private final Map<String, Object> replacements;
public Placeholders(AdvancedServerList core){
this.core = core;
this.replacements = new HashMap<>();
}
public static Placeholders get(AdvancedServerList core){
return new Placeholders(core);
}
public Placeholders withProtocol(int protocol){
this.replacements.put("${player protocol}", protocol);
return this;
}
public Placeholders withPlayersOnline(int online){
this.replacements.put("${players online}", online);
return this;
}
public Placeholders withPlayersMax(int max){
this.replacements.put("${players max}", max);
return this;
}
public Placeholders withPlayerName(InetSocketAddress playerAddress){
if(playerAddress != null)
this.replacements.put("${player name}", core.getPlayerHandler().getPlayerByIp(playerAddress.getHostString()));
return this;
}
public Placeholders withHostAddress(InetSocketAddress hostAddress){
if(hostAddress != null)
this.replacements.put("${server host}", hostAddress.getHostString());
return this;
}
public Placeholders withHostAddress(String hostAddress){
if(hostAddress != null)
this.replacements.put("${server host}", hostAddress);
return this;
}
public Placeholders withPlayerVersion(String version){
this.replacements.put("${player version}", version);
return this;
}
public Map<String, Object> getReplacements(){
return replacements;
}
}
@@ -0,0 +1,33 @@
/*
* MIT License
*
* Copyright (c) 2022 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.replacer.placeholders;
import java.util.Map;
public interface Placeholders{
Map<String, Object> getReplacements();
}
@@ -0,0 +1,57 @@
/*
* MIT License
*
* Copyright (c) 2022 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.replacer.placeholders;
import ch.andre601.advancedserverlist.core.profiles.players.GenericPlayer;
import java.util.HashMap;
import java.util.Map;
public class PlayerPlaceholders implements Placeholders{
private final Map<String, Object> replacements = new HashMap<>();
public PlayerPlaceholders(GenericPlayer<?> player){
this.replacements.put("${player name}", player.getName());
this.replacements.put("${player protocol}", player.getProtocol());
if(player.getVersion() != null)
this.replacements.put("${player version}", player.getVersion());
if(player.getPlayer() == null)
return;
this.replacements.put("${player hasPlayedBefore}", player.hasPlayedBefore());
this.replacements.put("${player isBanned}", player.isBanned());
this.replacements.put("${player isWhitelisted}", player.isWhitelisted());
this.replacements.put("${player uuid}", player.getUniqueId());
}
@Override
public Map<String, Object> getReplacements(){
return replacements;
}
}
@@ -0,0 +1,47 @@
/*
* MIT License
*
* Copyright (c) 2022 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.replacer.placeholders;
import java.util.HashMap;
import java.util.Map;
public class ServerPlaceholders implements Placeholders{
private final Map<String, Object> replacements = new HashMap<>();
public ServerPlaceholders(int online, int max, String host){
this.replacements.put("${server playersOnline}", online);
this.replacements.put("${server playersMax}", max);
if(host != null)
this.replacements.put("${server host}", host);
}
@Override
public Map<String, Object> getReplacements(){
return this.replacements;
}
}
+1 -5
View File
@@ -1,8 +1,4 @@
#
# Used for when AdvancedServerList doesn't have a cached player to use for ${player name}
#
unknown_player: "Anonymous"
#
# Whether statistics should be sent to bStats or not.
#
send_statistics: true
unknown_player: "Anonymous"
+30 -1
View File
@@ -57,4 +57,33 @@ players:
#
# Read more: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#playercount
#
playerCount: '<grey>Text'
playerCount: '<grey>Text'
#
# Allows you to override the default Favicon used by the Server/Proxy.
# You can provide three specific inputs:
# - A valid URL pointing to a PNG file.
# - ${player name} for a per-player avatar being displayed (Uses mc-heads.net)
# - Image file name (i.e. example.png) for a file in the "favicons" folder.
#
# NOTE:
# - The favicon will be cached for 5 minutes to avoid spam and rate limits.
# - BungeeCord/Waterfall may report issues that the plugin takes a long time to process.
# This is something I cannot really get improved without help.
#
# Read more: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#favicon
#
favicon: ''
#
# When set to 0 or higher will alter the max player count to the online count + xMore.
# Example: With 20 online players would 'xMore: 1' show 20/21 and 'xMore: 0' show 20/20
#
# Note that this will also manipulate the ${server playersMax} placeholder when used
# in motd, players or playerCount.
#
# Remove this option or set it to -1 to not alter the max player count.
#
# Read more: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#xmore
#
xMore: -1
+8 -4
View File
@@ -76,13 +76,13 @@
<dependency>
<groupId>me.clip</groupId>
<artifactId>placeholderapi</artifactId>
<version>2.11.1</version>
<version>2.11.2</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>AdvancedServerList-PaperMC-${plugin.version}</finalName>
<finalName>AdvancedServerList-Paper-${plugin.version}</finalName>
<resources>
<resource>
<filtering>true</filtering>
@@ -103,7 +103,7 @@
<artifactId>maven-shade-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<minimizeJar>true</minimizeJar>
<createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
<relocation>
<pattern>org.spongepowered.configurate</pattern>
@@ -111,7 +111,11 @@
</relocation>
<relocation>
<pattern>org.bstats</pattern>
<shadedPattern>ch.andre601.advancedserverlist.spigot.depends.bstats</shadedPattern>
<shadedPattern>ch.andre601.advancedserverlist.paper.depends.bstats</shadedPattern>
</relocation>
<relocation>
<pattern>com.github.benmanes.caffeine</pattern>
<shadedPattern>ch.andre601.advancedserverlist.paper.depends.caffeine</shadedPattern>
</relocation>
</relocations>
<filters>
@@ -28,6 +28,7 @@ package ch.andre601.advancedserverlist.paper;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.PluginCore;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.profiles.favicon.FaviconHandler;
import ch.andre601.advancedserverlist.paper.commands.CmdAdvancedServerList;
import ch.andre601.advancedserverlist.paper.events.JoinEvent;
import ch.andre601.advancedserverlist.paper.events.PingEvent;
@@ -36,23 +37,26 @@ import org.bstats.bukkit.Metrics;
import org.bstats.charts.SimplePie;
import org.bukkit.command.PluginCommand;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.util.CachedServerIcon;
import java.nio.file.Path;
public class PaperCore extends JavaPlugin implements PluginCore{
public class PaperCore extends JavaPlugin implements PluginCore<CachedServerIcon>{
private final PluginLogger logger = new PaperLogger(getLogger());
private AdvancedServerList core;
private FaviconHandler<CachedServerIcon> faviconHandler;
@Override
public void onEnable(){
try{
Class.forName("io.papermc.paper.configuration.ConfigurationLoaders");
this.core = new AdvancedServerList(this);
enable();
}catch(ClassNotFoundException ex){
try{
Class.forName("com.destroystokyo.paper.PaperConfig");
this.core = new AdvancedServerList(this);
enable();
}catch(ClassNotFoundException ex1){
getPluginLogger().warn("======================================== WARNING ========================================");
getPluginLogger().warn("");
@@ -102,6 +106,11 @@ public class PaperCore extends JavaPlugin implements PluginCore{
));
}
@Override
public void clearFaviconCache(){
faviconHandler.clearCache();
}
@Override
public AdvancedServerList getCore(){
return core;
@@ -117,6 +126,14 @@ public class PaperCore extends JavaPlugin implements PluginCore{
return logger;
}
@Override
public FaviconHandler<CachedServerIcon> getFaviconHandler(){
if(faviconHandler == null)
faviconHandler = new FaviconHandler<>(core);
return faviconHandler;
}
@Override
public String getPlatformName(){
return getServer().getName();
@@ -126,4 +143,8 @@ public class PaperCore extends JavaPlugin implements PluginCore{
public String getPlatformVersion(){
return getServer().getVersion();
}
private void enable(){
this.core = new AdvancedServerList(this);
}
}
@@ -0,0 +1,47 @@
/*
* MIT License
*
* Copyright (c) 2022 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.profiles.players.GenericPlayer;
import org.bukkit.OfflinePlayer;
public class PaperPlayer extends GenericPlayer<OfflinePlayer>{
public PaperPlayer(OfflinePlayer player, String name, int protocol){
this.player = player;
this.name = player == null ? name : player.getName();
this.protocol = protocol;
if(player == null)
return;
this.playedBefore = player.hasPlayedBefore();
this.banned = player.isBanned();
this.whitelisted = player.isWhitelisted();
this.uuid = player.getUniqueId();
}
}
@@ -28,8 +28,12 @@ package ch.andre601.advancedserverlist.paper.events;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import ch.andre601.advancedserverlist.core.profiles.ProfileManager;
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
import ch.andre601.advancedserverlist.core.profiles.replacer.Placeholders;
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
import ch.andre601.advancedserverlist.core.profiles.replacer.placeholders.Placeholders;
import ch.andre601.advancedserverlist.core.profiles.replacer.placeholders.PlayerPlaceholders;
import ch.andre601.advancedserverlist.core.profiles.replacer.placeholders.ServerPlaceholders;
import ch.andre601.advancedserverlist.paper.PaperCore;
import ch.andre601.advancedserverlist.paper.PaperPlayer;
import com.destroystokyo.paper.event.server.PaperServerListPingEvent;
import com.destroystokyo.paper.profile.PlayerProfile;
import me.clip.placeholderapi.PlaceholderAPI;
@@ -37,11 +41,11 @@ import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.util.CachedServerIcon;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
public class PingEvent implements Listener{
@@ -57,29 +61,37 @@ public class PingEvent implements Listener{
public void onServerPing(PaperServerListPingEvent event){
InetSocketAddress address = event.getClient().getAddress();
InetSocketAddress host = event.getClient().getVirtualHost();
Map<String, Object> replacements = Placeholders.get(plugin.getCore())
.withProtocol(event.getClient().getProtocolVersion())
.withPlayersOnline(event.getNumPlayers())
.withPlayersMax(event.getMaxPlayers())
.withPlayerName(address)
.withHostAddress(host)
.getReplacements();
PaperPlayer player = resolvePlayer(address, event.getClient().getProtocolVersion());
int online = event.getNumPlayers();
int max = event.getMaxPlayers();
PlayerPlaceholders playerPlaceholders = new PlayerPlaceholders(player);
ServerPlaceholders serverPlaceholders = new ServerPlaceholders(online, max, host == null ? null : host.getHostString());
ServerListProfile profile = ProfileManager.get(plugin.getCore())
.replacements(replacements)
.replacements(playerPlaceholders)
.replacements(serverPlaceholders)
.getProfile();
if(profile == null)
return;
OfflinePlayer player = resolvePlayer(address);
if(profile.getXMore() >= 0){
max = online + profile.getXMore();
event.setMaxPlayers(max);
}
serverPlaceholders = new ServerPlaceholders(online, max, host == null ? null : host.getHostString());
if(!profile.getMotd().isEmpty()){
event.motd(ComponentParser.list(profile.getMotd())
.replacements(replacements)
.replacements(playerPlaceholders)
.replacements(serverPlaceholders)
.modifyText(text -> {
if(plugin.getServer().getPluginManager().isPluginEnabled("PlaceholderAPI"))
return PlaceholderAPI.setPlaceholders(player, text);
return PlaceholderAPI.setPlaceholders(player.getPlayer(), text);
return text;
})
@@ -93,10 +105,11 @@ public class PingEvent implements Listener{
if(!profile.getPlayerCount().isEmpty()){
event.setVersion(ComponentParser.text(profile.getPlayerCount())
.replacements(replacements)
.replacements(playerPlaceholders)
.replacements(serverPlaceholders)
.modifyText(text -> {
if(plugin.getServer().getPluginManager().isPluginEnabled("PlaceholderAPI"))
return PlaceholderAPI.setPlaceholders(player, text);
return PlaceholderAPI.setPlaceholders(player.getPlayer(), text);
return text;
})
@@ -106,16 +119,35 @@ public class PingEvent implements Listener{
if(!profile.getPlayers().isEmpty()){
event.getPlayerSample().clear();
event.getPlayerSample().addAll(getPlayers(profile.getPlayers(), replacements, player));
event.getPlayerSample().addAll(getPlayers(profile.getPlayers(), playerPlaceholders, serverPlaceholders, player.getPlayer()));
}
event.setServerIcon(event.getServerIcon());
if(!profile.getFavicon().isEmpty()){
String favName = StringReplacer.replace(profile.getFavicon(), playerPlaceholders.getReplacements());
CachedServerIcon favicon = plugin.getFaviconHandler().getFavicon(favName, image -> {
try{
return Bukkit.loadServerIcon(image);
}catch(Exception ex){
return null;
}
});
if(favicon == null){
plugin.getPluginLogger().warn("Could not obtain valid Favicon to use.");
event.setServerIcon(event.getServerIcon());
}else{
event.setServerIcon(favicon);
}
}
}
private List<PlayerProfile> getPlayers(List<String> lines, Map<String, Object> replacements, OfflinePlayer player){
private List<PlayerProfile> getPlayers(List<String> lines, Placeholders playerPlaceholders, Placeholders serverPlaceholders, OfflinePlayer player){
List<PlayerProfile> players = new ArrayList<>();
lines.forEach(line -> players.add(Bukkit.createProfile(UUID.randomUUID(), ComponentParser.text(line)
.replacements(replacements)
.replacements(playerPlaceholders)
.replacements(serverPlaceholders)
.modifyText(text -> {
if(plugin.getServer().getPluginManager().isPluginEnabled("PlaceholderAPI"))
return PlaceholderAPI.setPlaceholders(player, text);
@@ -127,16 +159,16 @@ public class PingEvent implements Listener{
return players;
}
private OfflinePlayer resolvePlayer(InetSocketAddress address){
private PaperPlayer resolvePlayer(InetSocketAddress address, int protocol){
String playerName = plugin.getCore().getPlayerHandler().getPlayerByIp(address.getHostString());
OfflinePlayer player = Bukkit.getPlayerExact(playerName);
if(player == null){
player = Bukkit.getOfflinePlayer(playerName);
return player.hasPlayedBefore() ? player : null;
return new PaperPlayer(player.hasPlayedBefore() ? player : null, playerName, protocol);
}
return player;
return new PaperPlayer(player, playerName, protocol);
}
}
+1 -1
View File
@@ -13,7 +13,7 @@ softdepend:
commands:
advancedserverlist:
description: 'Main command of AdvancedServerList'
usage: '/<command> [reload]'
usage: '/<command> [help|reload]'
aliases:
- 'asl'
permission: 'advancedserverlist.admin'
+1 -12
View File
@@ -12,20 +12,9 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<plugin.version>1.2.0</plugin.version>
<plugin.version>1.5.3</plugin.version>
<plugin.description>Create multiple Server lists based on conditions.</plugin.description>
<plugin.depend.mc>1.19-R0.1-SNAPSHOT</plugin.depend.mc>
<plugin.depend.velocity>3.1.1-SNAPSHOT</plugin.depend.velocity>
<plugin.depend.configurate>4.1.2</plugin.depend.configurate>
<plugin.depend.kyori-adventure>4.11.0</plugin.depend.kyori-adventure>
<plugin.depend.kyori-minimessage>4.11.0</plugin.depend.kyori-minimessage>
<plugin.depend.kyori-legacy>4.11.0</plugin.depend.kyori-legacy>
<plugin.depend.kyori-platform-bungeecord>4.1.0</plugin.depend.kyori-platform-bungeecord>
<plugin.depend.kyori-platform-bukkit>4.1.1</plugin.depend.kyori-platform-bukkit>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
</properties>
+9 -5
View File
@@ -68,13 +68,13 @@
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>${plugin.depend.mc}</version>
<version>1.19-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-platform-bukkit</artifactId>
<version>${plugin.depend.kyori-platform-bukkit}</version>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>com.comphenix.protocol</groupId>
@@ -91,7 +91,7 @@
<dependency>
<groupId>me.clip</groupId>
<artifactId>placeholderapi</artifactId>
<version>2.11.1</version>
<version>2.11.2</version>
<scope>provided</scope>
</dependency>
</dependencies>
@@ -118,11 +118,15 @@
<artifactId>maven-shade-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<minimizeJar>true</minimizeJar>
<createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
<relocation>
<pattern>org.bstats</pattern>
<shadedPattern>ch.andre601.advancedserverlist.paper.depends.bstats</shadedPattern>
<shadedPattern>ch.andre601.advancedserverlist.spigot.depends.bstats</shadedPattern>
</relocation>
<relocation>
<pattern>com.github.benmanes.caffeine</pattern>
<shadedPattern>ch.andre601.advancedserverlist.spigot.depends.caffeine</shadedPattern>
</relocation>
</relocations>
<filters>
@@ -28,9 +28,11 @@ package ch.andre601.advancedserverlist.spigot;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.PluginCore;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.profiles.favicon.FaviconHandler;
import ch.andre601.advancedserverlist.spigot.commands.CmdAdvancedServerList;
import ch.andre601.advancedserverlist.spigot.events.LoadEvent;
import ch.andre601.advancedserverlist.spigot.logging.SpigotLogger;
import com.comphenix.protocol.wrappers.WrappedServerPing;
import org.bstats.bukkit.Metrics;
import org.bstats.charts.SimplePie;
import org.bukkit.command.PluginCommand;
@@ -38,10 +40,12 @@ import org.bukkit.plugin.java.JavaPlugin;
import java.nio.file.Path;
public class SpigotCore extends JavaPlugin implements PluginCore{
public class SpigotCore extends JavaPlugin implements PluginCore<WrappedServerPing.CompressedImage>{
private final PluginLogger logger = new SpigotLogger(getLogger());
private AdvancedServerList core;
private final PluginLogger logger = new SpigotLogger(getLogger());
FaviconHandler<WrappedServerPing.CompressedImage> faviconHandler = null;
@Override
public void onEnable(){
@@ -88,6 +92,11 @@ public class SpigotCore extends JavaPlugin implements PluginCore{
));
}
@Override
public void clearFaviconCache(){
faviconHandler.clearCache();
}
@Override
public AdvancedServerList getCore(){
return core;
@@ -103,6 +112,14 @@ public class SpigotCore extends JavaPlugin implements PluginCore{
return logger;
}
@Override
public FaviconHandler<WrappedServerPing.CompressedImage> getFaviconHandler(){
if(faviconHandler == null)
faviconHandler = new FaviconHandler<>(core);
return faviconHandler;
}
@Override
public String getPlatformName(){
return getServer().getName();
@@ -0,0 +1,47 @@
/*
* MIT License
*
* Copyright (c) 2022 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.core.profiles.players.GenericPlayer;
import org.bukkit.OfflinePlayer;
public class SpigotPlayer extends GenericPlayer<OfflinePlayer>{
public SpigotPlayer(OfflinePlayer player, String name, int protocol){
this.player = player;
this.name = player == null ? name : player.getName();
this.protocol = protocol;
if(player == null)
return;
this.playedBefore = player.hasPlayedBefore();
this.banned = player.isBanned();
this.whitelisted = player.isWhitelisted();
this.uuid = player.getUniqueId();
}
}
@@ -28,8 +28,11 @@ package ch.andre601.advancedserverlist.spigot.events;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import ch.andre601.advancedserverlist.core.profiles.ProfileManager;
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
import ch.andre601.advancedserverlist.core.profiles.replacer.Placeholders;
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
import ch.andre601.advancedserverlist.core.profiles.replacer.placeholders.PlayerPlaceholders;
import ch.andre601.advancedserverlist.core.profiles.replacer.placeholders.ServerPlaceholders;
import ch.andre601.advancedserverlist.spigot.SpigotCore;
import ch.andre601.advancedserverlist.spigot.SpigotPlayer;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolManager;
import com.comphenix.protocol.events.ListenerPriority;
@@ -82,32 +85,37 @@ public class PingEvent implements Listener{
InetSocketAddress address = event.getPlayer().getAddress();
if(address == null)
return;
Map<String, Object> replacements = Placeholders.get(spigotPlugin.getCore())
.withProtocol(ping.getVersionProtocol())
.withPlayersOnline(ping.getPlayersOnline())
.withPlayersMax(ping.getPlayersMaximum())
.withPlayerName(address)
.withHostAddress(hostAddresses.get(address.getHostString()))
.getReplacements();
spigotPlugin.getPluginLogger().info(hostAddresses.get(address.getHostString()));
SpigotPlayer player = resolvePlayer(address, ping.getVersionProtocol());
int online = ping.getPlayersOnline();
int max = ping.getPlayersMaximum();
PlayerPlaceholders playerPlaceholders = new PlayerPlaceholders(player);
ServerPlaceholders serverPlaceholders = new ServerPlaceholders(online, max, hostAddresses.get(address.getHostString()));
ServerListProfile profile = ProfileManager.get(spigotPlugin.getCore())
.replacements(replacements)
.replacements(playerPlaceholders)
.replacements(serverPlaceholders)
.getProfile();
if(profile == null)
return;
OfflinePlayer player = resolvePlayer(address);
if(profile.getXMore() >= 0){
max = online + profile.getXMore();
ping.setPlayersMaximum(max);
}
serverPlaceholders = new ServerPlaceholders(online, max, hostAddresses.get(address.getHostString()));
if(!profile.getMotd().isEmpty()){
Component component = ComponentParser.list(profile.getMotd())
.replacements(replacements)
.replacements(playerPlaceholders)
.replacements(serverPlaceholders)
.modifyText(text -> {
if(plugin.getServer().getPluginManager().isPluginEnabled("PlaceholderAPI"))
return PlaceholderAPI.setPlaceholders(player, text);
return PlaceholderAPI.setPlaceholders(player.getPlayer(), text);
return text;
})
@@ -122,10 +130,11 @@ public class PingEvent implements Listener{
if(!profile.getPlayerCount().isEmpty()){
ping.setVersionName(ComponentParser.text(profile.getPlayerCount())
.replacements(replacements)
.replacements(playerPlaceholders)
.replacements(serverPlaceholders)
.modifyText(text -> {
if(plugin.getServer().getPluginManager().isPluginEnabled("PlaceholderAPI"))
return PlaceholderAPI.setPlaceholders(player, text);
return PlaceholderAPI.setPlaceholders(player.getPlayer(), text);
return text;
})
@@ -137,16 +146,36 @@ public class PingEvent implements Listener{
if(!profile.getPlayers().isEmpty()){
ping.setPlayers(getFakePlayers(
ComponentParser.list(profile.getPlayers())
.replacements(replacements)
.replacements(playerPlaceholders)
.replacements(serverPlaceholders)
.modifyText(text -> {
if(plugin.getServer().getPluginManager().isPluginEnabled("PlaceholderAPI"))
return PlaceholderAPI.setPlaceholders(player, text);
return PlaceholderAPI.setPlaceholders(player.getPlayer(), text);
return text;
})
.toString()
));
}
if(!profile.getFavicon().isEmpty()){
String favName = StringReplacer.replace(profile.getFavicon(), playerPlaceholders.getReplacements());
WrappedServerPing.CompressedImage favicon = spigotPlugin.getFaviconHandler().getFavicon(favName, image -> {
try{
return WrappedServerPing.CompressedImage.fromPng(image);
}catch(Exception ex){
return null;
}
});
if(favicon == null){
spigotPlugin.getPluginLogger().warn("Could not obtain valid Favicon to use.");
ping.setFavicon(ping.getFavicon());
}else{
ping.setFavicon(favicon);
}
}
}
});
}
@@ -162,7 +191,7 @@ public class PingEvent implements Listener{
return profiles;
}
private OfflinePlayer resolvePlayer(InetSocketAddress address){
private SpigotPlayer resolvePlayer(InetSocketAddress address, int protocol){
String playerName = plugin.getCore().getPlayerHandler().getPlayerByIp(address.getHostString());
OfflinePlayer player = Bukkit.getPlayerExact(playerName);
@@ -170,9 +199,9 @@ public class PingEvent implements Listener{
//noinspection deprecation
player = Bukkit.getOfflinePlayer(playerName);
return player.hasPlayedBefore() ? player : null;
return new SpigotPlayer(player.hasPlayedBefore() ? player : null, playerName, protocol);
}
return player;
return new SpigotPlayer(player, playerName, protocol);
}
}
+6 -6
View File
@@ -8,11 +8,11 @@ main: 'ch.andre601.advancedserverlist.spigot.SpigotCore'
api-version: 1.19
libraries:
- 'org.spongepowered:configurate-yaml:${plugin.depend.configurate}'
- 'net.kyori:adventure-api:${plugin.depend.kyori-adventure}'
- 'net.kyori:adventure-text-minimessage:${plugin.depend.kyori-minimessage}'
- 'net.kyori:adventure-text-serializer-legacy:${plugin.depend.kyori-legacy}'
- 'net.kyori:adventure-platform-bukkit:${plugin.depend.kyori-platform-bukkit}'
- 'org.spongepowered:configurate-yaml:4.1.2'
- 'net.kyori:adventure-api:4.11.0'
- 'net.kyori:adventure-text-minimessage:4.11.0'
- 'net.kyori:adventure-text-serializer-legacy:4.11.0'
- 'net.kyori:adventure-platform-bukkit:4.1.2'
softdepend:
- 'ProtocolLib'
@@ -21,7 +21,7 @@ softdepend:
commands:
advancedserverlist:
description: 'Main command of AdvancedServerList'
usage: '/<command> [reload]'
usage: '/<command> [help|reload]'
aliases:
- 'asl'
permission: 'advancedserverlist.admin'
+7 -1
View File
@@ -35,6 +35,8 @@
<modelVersion>4.0.0</modelVersion>
<artifactId>velocity</artifactId>
<packaging>jar</packaging>
<version>${plugin.version}</version>
<properties>
<maven.compiler.source>16</maven.compiler.source>
@@ -88,7 +90,7 @@
<artifactId>maven-shade-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<minimizeJar>true</minimizeJar>
<createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
<relocation>
<pattern>org.spongepowered.configurate</pattern>
@@ -98,6 +100,10 @@
<pattern>org.bstats</pattern>
<shadedPattern>ch.andre601.advancedserverlist.velocity.depends.bstats</shadedPattern>
</relocation>
<relocation>
<pattern>com.github.benmanes.caffeine</pattern>
<shadedPattern>ch.andre601.advancedserverlist.velocity.depends.caffeine</shadedPattern>
</relocation>
</relocations>
<filters>
<filter>
@@ -28,6 +28,7 @@ package ch.andre601.advancedserverlist.velocity;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.PluginCore;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.profiles.favicon.FaviconHandler;
import ch.andre601.advancedserverlist.velocity.commands.CmdAdvancedServerList;
import ch.andre601.advancedserverlist.velocity.events.JoinEvent;
import ch.andre601.advancedserverlist.velocity.events.PingEvent;
@@ -39,13 +40,14 @@ import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
import com.velocitypowered.api.plugin.annotation.DataDirectory;
import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.util.Favicon;
import org.bstats.charts.SimplePie;
import org.bstats.velocity.Metrics;
import org.slf4j.LoggerFactory;
import java.nio.file.Path;
public class VelocityCore implements PluginCore{
public class VelocityCore implements PluginCore<Favicon>{
private final PluginLogger logger;
private final ProxyServer proxy;
@@ -53,6 +55,7 @@ public class VelocityCore implements PluginCore{
private final Metrics.Factory metrics;
private AdvancedServerList core;
private FaviconHandler<Favicon> faviconHandler = null;
@Inject
public VelocityCore(ProxyServer proxy, @DataDirectory Path path, Metrics.Factory metrics){
@@ -96,6 +99,11 @@ public class VelocityCore implements PluginCore{
));
}
@Override
public void clearFaviconCache(){
faviconHandler.clearCache();
}
@Override
public AdvancedServerList getCore(){
return core;
@@ -111,6 +119,14 @@ public class VelocityCore implements PluginCore{
return logger;
}
@Override
public FaviconHandler<Favicon> getFaviconHandler(){
if(faviconHandler == null)
faviconHandler = new FaviconHandler<>(core);
return faviconHandler;
}
@Override
public String getPlatformName(){
return getProxy().getVersion().getName();
@@ -0,0 +1,39 @@
/*
* MIT License
*
* Copyright (c) 2022 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.velocity;
import ch.andre601.advancedserverlist.core.profiles.players.GenericPlayer;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.proxy.Player;
public class VelocityPlayer extends GenericPlayer<Player>{
public VelocityPlayer(String name, int protocol){
this.name = name;
this.protocol = protocol;
this.version = ProtocolVersion.getProtocolVersion(protocol).getVersionIntroducedIn();
}
}
@@ -29,17 +29,19 @@ import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import ch.andre601.advancedserverlist.core.profiles.ProfileManager;
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
import ch.andre601.advancedserverlist.core.profiles.replacer.Placeholders;
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
import ch.andre601.advancedserverlist.core.profiles.replacer.placeholders.PlayerPlaceholders;
import ch.andre601.advancedserverlist.core.profiles.replacer.placeholders.ServerPlaceholders;
import ch.andre601.advancedserverlist.velocity.VelocityCore;
import ch.andre601.advancedserverlist.velocity.VelocityPlayer;
import com.velocitypowered.api.event.PostOrder;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.proxy.ProxyPingEvent;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.proxy.server.ServerPing;
import com.velocitypowered.api.util.Favicon;
import java.net.InetSocketAddress;
import java.util.List;
import java.util.Map;
public class PingEvent{
@@ -58,29 +60,35 @@ public class PingEvent{
return;
ServerPing.Builder builder = ping.asBuilder();
InetSocketAddress address = event.getConnection().getRemoteAddress();
String playerName = plugin.getCore().getPlayerHandler().getPlayerByIp(event.getConnection().getRemoteAddress().getHostString());
InetSocketAddress host = event.getConnection().getVirtualHost().orElse(null);
Map<String, Object> replacements = Placeholders.get(plugin.getCore())
.withProtocol(protocol.getProtocol())
.withPlayersOnline(builder.getOnlinePlayers())
.withPlayersMax(builder.getMaximumPlayers())
.withPlayerName(address)
.withHostAddress(host)
.withPlayerVersion(ProtocolVersion.getProtocolVersion(protocol.getProtocol()).toString())
.getReplacements();
int online = builder.getOnlinePlayers();
int max = builder.getMaximumPlayers();
PlayerPlaceholders playerPlaceholders = new PlayerPlaceholders(new VelocityPlayer(playerName, protocol.getProtocol()));
ServerPlaceholders serverPlaceholders = new ServerPlaceholders(online, max, host == null ? null : host.getHostString());
ServerListProfile profile = ProfileManager.get(plugin.getCore())
.replacements(replacements)
.replacements(playerPlaceholders)
.replacements(serverPlaceholders)
.getProfile();
if(profile == null)
return;
if(profile.getXMore() >= 0){
max = online + profile.getXMore();
builder.maximumPlayers(max);
}
serverPlaceholders = new ServerPlaceholders(online, max, host == null ? null : host.getHostString());
if(!profile.getMotd().isEmpty()){
List<String> motd = profile.getMotd();
builder.description(ComponentParser.list(motd)
.replacements(replacements)
.replacements(playerPlaceholders)
.replacements(serverPlaceholders)
.toComponent()
);
}
@@ -96,14 +104,16 @@ public class PingEvent{
builder.version(new ServerPing.Version(
-1,
ComponentParser.text(profile.getPlayerCount())
.replacements(replacements)
.replacements(playerPlaceholders)
.replacements(serverPlaceholders)
.toString()
));
}
if(!profile.getPlayers().isEmpty()){
String players = ComponentParser.list(profile.getPlayers())
.replacements(replacements)
.replacements(playerPlaceholders)
.replacements(serverPlaceholders)
.toString();
ServerPing.SamplePlayer[] playerSamples = AdvancedServerList.getPlayers(ServerPing.SamplePlayer.class, players)
@@ -113,6 +123,24 @@ public class PingEvent{
builder.clearSamplePlayers().samplePlayers(playerSamples);
}
if(!profile.getFavicon().isEmpty()){
String favName = StringReplacer.replace(profile.getFavicon(), playerPlaceholders.getReplacements());
Favicon favicon = plugin.getFaviconHandler().getFavicon(favName, image -> {
try{
return Favicon.create(image);
}catch(Exception ex){
return null;
}
});
if(favicon == null){
plugin.getPluginLogger().warn("Could not obtain valid Favicon to use.");
}else{
builder.favicon(favicon);
}
}
event.setPing(builder.build());
}
}
@@ -38,12 +38,12 @@ public class VelocityLogger implements PluginLogger{
@Override
public void info(String msg, Object... args){
logger.info(msg, args);
logger.info(String.format(msg, args));
}
@Override
public void warn(String msg, Object... args){
logger.warn(msg, args);
logger.warn(String.format(msg, args));
}
@Override