Compare commits

...
160 Commits
Author SHA1 Message Date
Andre_601 6f06c47de7 Merge pull request #34 from Andre601/feature/update-checker
Add Update Checker
2022-12-06 14:03:25 +01:00
Andre601 ad3ba0c8b3 Update config description 2022-12-06 00:49:52 +01:00
Andre601 12d8d930dd Use a ScheduledExecutorService instead of Timer 2022-12-06 00:26:55 +01:00
Andre601 9a30a6b679 Add info line 2022-12-06 00:01:24 +01:00
Andre601 b82cf69d43 Simplify more. 2022-12-05 23:58:05 +01:00
Andre601 fb6d93b455 Init timer only when UpdateChecker is used. 2022-12-05 23:55:54 +01:00
Andre601 a1276da68f Fix exceptions 2022-12-05 23:13:21 +01:00
Andre601 25c053d495 Use timer class from Java 2022-12-05 22:24:19 +01:00
Andre601 39c1fb5452 Better version comparison. 2022-12-05 21:26:24 +01:00
Andre601 48edebc043 Add config option 2022-12-03 20:29:45 +01:00
Andre601 3a672378ff Add Update Checker 2022-12-03 20:23:21 +01:00
Andre_601 9db9f2be7f Merge pull request #33 from Andre601/dependabot/maven/core/net.kyori-adventure-api-4.12.0
Bump adventure-api from 4.11.0 to 4.12.0 in /core
2022-11-28 16:31:53 +01:00
Andre_601 2cf47e351b Merge pull request #32 from Andre601/dependabot/maven/core/net.kyori-adventure-text-minimessage-4.12.0
Bump adventure-text-minimessage from 4.11.0 to 4.12.0 in /core
2022-11-28 16:31:39 +01:00
Andre_601 36abdb83cd Merge pull request #31 from Andre601/dependabot/maven/core/net.kyori-adventure-text-serializer-legacy-4.12.0
Bump adventure-text-serializer-legacy from 4.11.0 to 4.12.0 in /core
2022-11-28 16:31:21 +01:00
dependabot[bot] ad950bf330 Bump adventure-api from 4.11.0 to 4.12.0 in /core
Bumps [adventure-api](https://github.com/KyoriPowered/adventure) from 4.11.0 to 4.12.0.
- [Release notes](https://github.com/KyoriPowered/adventure/releases)
- [Commits](https://github.com/KyoriPowered/adventure/compare/v4.11.0...v4.12.0)

---
updated-dependencies:
- dependency-name: net.kyori:adventure-api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-28 15:12:17 +00:00
dependabot[bot] 143753d309 Bump adventure-text-minimessage from 4.11.0 to 4.12.0 in /core
Bumps [adventure-text-minimessage](https://github.com/KyoriPowered/adventure) from 4.11.0 to 4.12.0.
- [Release notes](https://github.com/KyoriPowered/adventure/releases)
- [Commits](https://github.com/KyoriPowered/adventure/compare/v4.11.0...v4.12.0)

---
updated-dependencies:
- dependency-name: net.kyori:adventure-text-minimessage
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-28 15:12:10 +00:00
dependabot[bot] 0c37c21650 Bump adventure-text-serializer-legacy from 4.11.0 to 4.12.0 in /core
Bumps [adventure-text-serializer-legacy](https://github.com/KyoriPowered/adventure) from 4.11.0 to 4.12.0.
- [Release notes](https://github.com/KyoriPowered/adventure/releases)
- [Commits](https://github.com/KyoriPowered/adventure/compare/v4.11.0...v4.12.0)

---
updated-dependencies:
- dependency-name: net.kyori:adventure-text-serializer-legacy
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-28 15:12:04 +00:00
Andre_601 40a6b4f059 Merge pull request #30 from Andre601/dependabot/maven/core/com.github.ben-manes.caffeine-caffeine-3.1.2
Bump caffeine from 3.1.1 to 3.1.2 in /core
2022-11-24 16:24:36 +01:00
dependabot[bot] 965e87d71b Bump caffeine from 3.1.1 to 3.1.2 in /core
Bumps [caffeine](https://github.com/ben-manes/caffeine) from 3.1.1 to 3.1.2.
- [Release notes](https://github.com/ben-manes/caffeine/releases)
- [Commits](https://github.com/ben-manes/caffeine/compare/v3.1.1...v3.1.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-24 15:08:34 +00:00
Andre_601 202a22f33a Update README.md 2022-11-21 15:20:02 +01:00
Andre_601 a4b2a6c350 Update MODRINTH.md 2022-11-21 15:03:28 +01:00
Andre601 ba55f5299b Bump version 2022-11-07 22:29:04 +01:00
Andre_601 24fdf798cf Merge pull request #29 from Andre601/feature/disable-cache-option
Add option to disable Cache
2022-11-07 22:28:16 +01:00
Andre601 e208d181b7 Add option to disable Cache 2022-11-07 22:14:50 +01:00
Andre_601 6c15c7b259 Merge pull request #28 from Andre601/dependabot/maven/paper/org.apache.maven.plugins-maven-shade-plugin-3.4.1
Bump maven-shade-plugin from 3.4.0 to 3.4.1 in /paper
2022-10-27 17:55:21 +02:00
Andre_601 dcd76a43f5 Merge pull request #27 from Andre601/dependabot/maven/bungeecord/org.apache.maven.plugins-maven-shade-plugin-3.4.1
Bump maven-shade-plugin from 3.4.0 to 3.4.1 in /bungeecord
2022-10-27 17:55:10 +02:00
Andre_601 adc2060499 Merge pull request #26 from Andre601/dependabot/maven/velocity/org.apache.maven.plugins-maven-shade-plugin-3.4.1
Bump maven-shade-plugin from 3.4.0 to 3.4.1 in /velocity
2022-10-27 17:55:01 +02:00
Andre_601 4d6befc857 Merge pull request #25 from Andre601/dependabot/maven/core/org.apache.maven.plugins-maven-shade-plugin-3.4.1
Bump maven-shade-plugin from 3.4.0 to 3.4.1 in /core
2022-10-27 17:54:52 +02:00
dependabot[bot] 7cfb792471 Bump maven-shade-plugin from 3.4.0 to 3.4.1 in /paper
Bumps [maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.4.0 to 3.4.1.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.4.0...maven-shade-plugin-3.4.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-shade-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-27 15:41:21 +00:00
dependabot[bot] d46245eefa Bump maven-shade-plugin from 3.4.0 to 3.4.1 in /bungeecord
Bumps [maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.4.0 to 3.4.1.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.4.0...maven-shade-plugin-3.4.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-shade-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-27 15:41:17 +00:00
dependabot[bot] d5e0fd3d7a Bump maven-shade-plugin from 3.4.0 to 3.4.1 in /velocity
Bumps [maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.4.0 to 3.4.1.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.4.0...maven-shade-plugin-3.4.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-shade-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-27 15:41:11 +00:00
dependabot[bot] 496e246b9e Bump maven-shade-plugin from 3.4.0 to 3.4.1 in /core
Bumps [maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.4.0 to 3.4.1.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.4.0...maven-shade-plugin-3.4.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-shade-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-27 15:41:11 +00:00
Andre_601 e263a45f1c width and not height 2022-10-05 17:40:40 +02:00
Andre_601 edfc977730 Update MODRINTH.md 2022-10-05 17:40:01 +02:00
Andre_601 5910c26b4b Add waterfall badge 2022-10-03 23:49:07 +02:00
Andre_601 5b9c506a89 Use jsdelivr url 2022-09-26 00:17:47 +02:00
Andre_601 913ddd7834 Create MODRINTH.md 2022-09-22 13:41:05 +02:00
Andre_601 397c7ea59a Merge pull request #23 from Andre601/feature/readme-new-badges
Prepare readme for new badges
2022-09-21 01:48:30 +02:00
Andre_601 6e7b2541e1 Update README.md 2022-09-21 01:48:22 +02:00
Andre_601 241c15a452 Update README.md 2022-09-20 22:07:40 +02:00
Andre_601 62c5d13aa2 Prepare readme for new badges 2022-09-20 22:05:33 +02:00
Andre601 3a73c5ce6b Fix wrong open-perms for certain OS 2022-09-20 00:41:33 +02:00
Andre_601 bf54e8eb0b Yes I update the README a lot today... 2022-09-18 01:45:46 +02:00
Andre_601 aa2cabedbf Update README.md 2022-09-18 01:09:01 +02:00
Andre_601 66878626e1 Update README.md 2022-09-17 23:35:34 +02:00
Andre_601 f6f3f3d8b6 Update README.md 2022-09-17 23:25:48 +02:00
Andre601 85e41b6c7e Fix wrong formatted messages in /asl reload 2022-09-17 22:51:33 +02:00
Andre_601 a220efc624 Update README.md 2022-09-17 17:58:49 +02:00
Andre_601 ea8871ce8f Update README.md 2022-09-17 17:50:32 +02:00
Andre_601 ea0fdc3798 Update README.md 2022-09-17 17:50:06 +02:00
Andre_601 1188ab0c9c Create config.yml 2022-09-15 01:52:30 +02:00
Andre_601 aaefd4c928 Create feature_request.yml 2022-09-15 01:50:28 +02:00
Andre_601 940bf2fb9d fix typo 2022-09-15 01:20:23 +02:00
Andre_601 0c24bf8d24 Update bug_report.yml 2022-09-15 01:19:36 +02:00
Andre_601 564ce7a820 Create bug_report.yml 2022-09-15 01:18:54 +02:00
Andre_601 bb8cd21b86 Merge pull request #22 from Andre601/dependabot/maven/velocity/org.apache.maven.plugins-maven-shade-plugin-3.4.0
Bump maven-shade-plugin from 3.3.0 to 3.4.0 in /velocity
2022-09-14 18:33:57 +02:00
Andre_601 2d2d8a6175 Merge pull request #20 from Andre601/dependabot/maven/bungeecord/org.apache.maven.plugins-maven-shade-plugin-3.4.0
Bump maven-shade-plugin from 3.3.0 to 3.4.0 in /bungeecord
2022-09-14 18:33:48 +02:00
Andre_601 fcd4bdbe14 Merge pull request #19 from Andre601/dependabot/maven/paper/org.apache.maven.plugins-maven-shade-plugin-3.4.0
Bump maven-shade-plugin from 3.3.0 to 3.4.0 in /paper
2022-09-14 18:33:37 +02:00
Andre_601 3a9b2a7c5a Merge pull request #18 from Andre601/dependabot/maven/core/org.apache.maven.plugins-maven-shade-plugin-3.4.0
Bump maven-shade-plugin from 3.3.0 to 3.4.0 in /core
2022-09-14 18:33:27 +02:00
dependabot[bot] 3b3793ab9a Bump maven-shade-plugin from 3.3.0 to 3.4.0 in /velocity
Bumps [maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.3.0 to 3.4.0.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.3.0...maven-shade-plugin-3.4.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-shade-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-14 16:33:17 +00:00
Andre_601 d679694d6e Merge pull request #21 from Andre601/dependabot/maven/spigot/org.apache.maven.plugins-maven-shade-plugin-3.4.0
Bump maven-shade-plugin from 3.3.0 to 3.4.0 in /spigot
2022-09-14 18:33:09 +02:00
dependabot[bot] 47405f7492 Bump maven-shade-plugin from 3.3.0 to 3.4.0 in /spigot
Bumps [maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.3.0 to 3.4.0.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.3.0...maven-shade-plugin-3.4.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-shade-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-14 16:31:57 +00:00
dependabot[bot] af7408dcd5 Bump maven-shade-plugin from 3.3.0 to 3.4.0 in /bungeecord
Bumps [maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.3.0 to 3.4.0.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.3.0...maven-shade-plugin-3.4.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-shade-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-14 16:31:30 +00:00
dependabot[bot] 17d0930195 Bump maven-shade-plugin from 3.3.0 to 3.4.0 in /paper
Bumps [maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.3.0 to 3.4.0.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.3.0...maven-shade-plugin-3.4.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-shade-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-14 16:31:28 +00:00
dependabot[bot] 91cd3b6032 Bump maven-shade-plugin from 3.3.0 to 3.4.0 in /core
Bumps [maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.3.0 to 3.4.0.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.3.0...maven-shade-plugin-3.4.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-shade-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-09-14 16:31:26 +00:00
Andre601 2d67145ae5 Bump version 2022-09-09 23:33:22 +02:00
Andre601 ba1dd8a70d Fix clearFaviconCache() + expression error 2022-09-09 23:33:00 +02:00
Andre_601 4ea77f2907 Update README.md 2022-09-09 15:11:42 +02:00
Andre_601 7fdc23baa1 Update release.yml 2022-09-09 14:52:13 +02:00
Andre601 d630b472ca Simplify validation check 2022-09-09 01:39:15 +02:00
Andre_601 99509b538b Merge pull request #16 from Andre601/feature/improve-fakeplayers-creation
Improve handling of fake players
2022-09-08 15:27:17 +02:00
Andre601 4539fe4628 Bump version 2022-09-08 15:25:31 +02:00
Andre601 8c81f4f5c8 Rewrite server list profile 2022-09-08 15:19:25 +02:00
Andre601 f34ef3fbe4 Add missing getPlugin() call 2022-09-08 14:16:30 +02:00
Andre601 45f68294c1 Use methods from PluginCore 2022-09-07 21:49:05 +02:00
Andre601 f4056e51ef Rename getPath to getFolderPath 2022-09-07 21:36:35 +02:00
Andre601 7f38c0f224 Update FaviconHandler 2022-09-07 21:34:33 +02:00
Andre601 17a4ba0f8c Improve Fake player creation 2022-09-07 21:33:29 +02:00
Andre_601 5cb1245126 Update README.md 2022-09-05 21:27:42 +02:00
Andre_601 0963d9ffb4 Don't feature a release 2022-09-05 13:50:30 +02:00
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
Andre_601 6392929298 Merge pull request #3 from Andre601/feature/further-condition-improvements
Further improvements of condition parsing
2022-08-03 13:37:03 +02:00
Andre601 0f7fb9b180 Better message 2022-08-02 23:00:54 +02:00
Andre601 4b24da8409 Further improve condition handling 2022-08-02 22:59:08 +02:00
Andre_601 afc32da0c3 Update README.md 2022-08-02 02:59:50 +02:00
Andre_601 6aaa169a86 Merge pull request #2 from Andre601/feature/improved-condition-parsing
Better condition parsing
2022-08-02 01:44:00 +02:00
Andre601 091a97076e Fix inverted check and add hidePlayers option 2022-08-02 01:43:37 +02:00
Andre601 d79733cafc Pushing changes recommended by @bergerkiller and @bbayu123 2022-08-02 00:56:54 +02:00
Andre601 99793f5c8a Get rid of ConditionsHolder in favour of Expression 2022-08-01 23:41:07 +02:00
Andre601 8d3cd980cf Move ConditionsHolder and Expression to own folder 2022-08-01 23:25:17 +02:00
Andre601 3e40ad34ab Better condition parsing 2022-08-01 23:18:33 +02:00
Andre601 356bc09c09 Version 1.1.0
- Add ${server host} placeholder to show the pinged server address
- Improved Placeholders class
- Improved StringReplacer to have a static method instead of constantly making new instances.
- Update default.yml with better examples and descriptions.
2022-07-27 16:28:00 +02:00
62 changed files with 2312 additions and 589 deletions

No files matched your search

+2
View File
@@ -0,0 +1,2 @@
patreon: andre_601
ko_fi: andre_601
+62
View File
@@ -0,0 +1,62 @@
name: Bug Report
description: Report an issue with the plugin
body:
- type: markdown
attributes:
value: |-
## Before opening
Please make sure you've checked the following things first:
- You're using the latest release of AdvancedServerList [[Download from Modrinth](https://modrinth.com/plugin/advancedserverlist)]
- You're using a supported Proxy/Server version. As of right now is only 1.19.x supported.
- The issue happens with just AdvancedServerList installed.
- type: dropdown
attributes:
label: Platform
description: On what platform do you use the plugin?
options:
- BungeeCord
- Other (Please specify)
- Paper
- Purpur
- Spigot
- Velocity
- Waterfall
validations:
required: true
- type: input
attributes:
label: Other platform
description: |-
Please provide the name of the platform (Proxy/Server) you use, if you selected `Other (Please specify)` in the above section.
Leave empty otherwise.
placeholder: SomeProxy
- type: textarea
attributes:
label: What happened?
description: |-
Give a detailed description of what exactly happened.
You can provide screenshots to further explain the issues.
When sharing errors, make sure to use a site such as https://paste.helpch.at to do so.
placeholder: When I do ... does ... happen.
validations:
required: true
- type: textarea
attributes:
label: Steps to reproduce
description: Provide a detailed step-by-step explanation on how to reproduce this issue.
placeholder: |-
1. Do this
2. ...
3. Profit!
validations:
required: true
- type: textarea
attributes:
label: Server List Profiles
description: |-
**Optional**
Provide any Server List Profiles you use, if you believe those to be the cause of the issue.
This text field will automatically render the text as YAML code.
render: yaml
+8
View File
@@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Discord Server
about: Ask questions about the plugin in the `#advancedserverlist` channel.
url: https://discord.gg/6dazXp6
- name: Wiki
about: Check the Wiki for explanations about the features and examples.
url: https://github.com/Andre601/AdvancedServerList/wiki
@@ -0,0 +1,34 @@
name: Feature Request
description: Suggest a new feature for the plugin
body:
- type: markdown
attributes:
value: |-
## Before opening
Please make sure you've checked the following things first:
- You're using the latest release of AdvancedServerList [[Download from Modrinth](https://modrinth.com/plugin/advancedserverlist)]
- You're using a supported Proxy/Server version. As of right now is only 1.19.x supported.
- The Feature you suggest hasn't been suggested before.
- type: dropdown
attributes:
label: Platforms
description: What platforms should this feature be usable on
multiple: true
options:
- Proxy (BungeeCord, Waterfall, ...)
- Proxy (Velocity)
- Server (Spigot, Paper, ...)
validations:
required: true
- type: textarea
attributes:
label: Feature
description: |-
Give a detailed description of what exactly should be added and/or changed in AdvancedServerList.
You can provide screenshots to further explain the idea.
When sharing code snippets, make sure to use a site such as https://paste.helpch.at to do so.
placeholder: AdvancedServerList should get ... because ...
validations:
required: true
+96
View File
@@ -0,0 +1,96 @@
# AdvancedServerList
AdvancedServerList is a plugin that allowys you to customize your server's MOTD, favicon, Player count text and player count hover displayed in a player's multiplayer server list based on conditions and priorities.
## Supported Platforms
<a href="https://www.spigotmc.org" target="_blank">
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/minimal/supported/spigot_vector.svg" width="64" alt="platform-spigot" title="Tested on Spigot">
</a>
<a href="https://papermc.io" target="_blank">
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/minimal/supported/paper_vector.svg" width="64" alt="platform-paper" title="Tested on Paper">
</a>
<a href="https://www.spigotmc.org" target="_blank">
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/minimal/supported/bungeecord_vector.svg" width="64" alt="platform-bungeecord" title="Tested on BungeeCord">
</a>
<a href="https://www.papermc.io" target="_blank">
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/minimal/supported/waterfall_vector.svg" width="64" alt="platform-waterfall" title="Tested on Waterfall">
</a>
<a href="https://velocitypowered.com" target="_blank">
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/minimal/supported/velocity_vector.svg" width="64" alt="platform-velocity" title="Tested on Velocity">
</a>
## What is a Server List Profile?
A Server List Profile refers to a YAML file located in the plugin's `profiles` directory.
It allows you to configure specific aspects of the server display in the MC-Client's multiplayer server list, such as the MOTD, player count text, player count hover or Favicon.
> [*Read More*][profiles]
### Conditions
Thanks to conditions can you determine when a profile should be displayed in the player’s server list, to allow displaying specific text (i.e. a warning when they are using an outdated version).
When multiple profiles exist that have valid conditions will the one with the highest priority (Higher number = higher priority) be selected. Having no conditions makes the profile automatically return true.
> [*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]
## Dependencies
| Dependency | Platforms | Required? |
| ---------------- | ------------- | --------- |
| [ProtocolLib] | Spigot | Yes |
| [PlaceholderAPI] | Spigot, Paper | No |
## Statistics
This plugin sends statistics to [bStats] to display.
You can disable this in the global bStats config file located in `/plugins/bstats/`
- [BungeeCord][bstats-bungee]
- [Paper/Spigot][bstats-spigot]
- [Velocity][bstats-velocity]
## Screenshots
<a href="https://modrinth.com/plugin/advancedserverlist/gallery" target="_blank">
<img src="https://raw.githubusercontent.com/intergrav/devins-badges/v2/assets/cozy/documentation/modrinth-gallery_vector.svg" width="208" alt="gallery" title="Check out the Gallery">
</a>
## Support
<a href="https://discord.gg/6dazXp6" target="_blank">
<img src="https://raw.githubusercontent.com/intergrav/devins-badges/v2/assets/minimal/social/discord-singular_vector.svg" width="64" alt="discord" title="Join my Discord Server">
</a>
<a href="https://app.revolt.chat/invite/74TpERXA" target="_blank">
<img src="https://raw.githubusercontent.com/intergrav/devins-badges/v2/assets/minimal/social/revolt-singular_vector.svg" width="64" alt="revolt" title="Join my Revolt Server">
</a>
<a href="https://blobfox.coffee/@andre_601" target="_blank">
<img src="https://raw.githubusercontent.com/intergrav/devins-badges/v2/assets/minimal/social/mastodon-singular_vector.svg" width="64" alt="revolt" title="Chat with me on Mastodon">
</a>
<!-- 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
[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
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'
+88 -8
View File
@@ -1,23 +1,103 @@
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:
- platforms: BungeeCord, Waterfall
directory: bungeecord
loaders: |
bungeecord
waterfall
- platforms: Paper
directory: paper
loaders: paper
- platforms: Spigot
directory: spigot
loaders: spigot
- platforms: Velocity
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.tag_name }} (${{ matrix.platforms }})
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
1.19.1
1.19.2
java: 16
modrinth-id: xss83sOY
modrinth-featured: false
modrinth-token: ${{ secrets.MODRINTH_TOKEN }}
github-token: ${{ secrets.GITHUB_TOKEN }}
+94 -49
View File
@@ -1,59 +1,104 @@
<!-- 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
<a href="https://modrinth.com/plugin/advancedserverlist" target="_blank">
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/cozy/available/modrinth_vector.svg" height="64" align="right" alt="modrinth" title="Available on Modrinth">
</a>
![platforms] ![tested]
AdvancedServerList is a plugin that allowys you to customize your server's MOTD, favicon, Player count text and player count hover displayed in a player's multiplayer server list based on conditions and priorities.
AdvancedServerList is a server and proxy plugin that allows you to create custom MOTDs and more in your server list with priority and conditions.
## Supported Platforms
## Downloads
<a href="https://www.spigotmc.org" target="_blank">
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/minimal/supported/spigot_vector.svg" height="64" alt="platform-spigot" title="Tested on Spigot">
</a>
<a href="https://papermc.io" target="_blank">
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/minimal/supported/paper_vector.svg" height="64" alt="platform-paper" title="Tested on Paper">
</a>
<a href="https://www.spigotmc.org" target="_blank">
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/minimal/supported/bungeecord_vector.svg" height="64" alt="platform-bungeecord" title="Tested on BungeeCord">
</a>
<a href="https://www.papermc.io" target="_blank">
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/minimal/supported/waterfall_vector.svg" height="64" alt="platform-waterfall" title="Tested on Waterfall">
</a>
<a href="https://velocitypowered.com" target="_blank">
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/minimal/supported/velocity_vector.svg" height="64" alt="platform-velocity" title="Tested on Velocity">
</a>
You can download AdvancedServerList on the following locations:
## 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.
[![download modrinth]][modrinth] [![download spigot]][spigot] [![download hangar]][hangar] [![download github]][github]
> [*Read More*][profiles]
## Features
### 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).
- 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.
- MiniMessage formatting for MOTD, player count and player count hover [[Read More][minimessage]]
- Placeholder support [[Read More][placeholders]]
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.
## Links
> [*Read More*][conditions]
- [Wiki][wiki]
- Statistics
- [Spigot/PaperMC][stats-spigot]
- [BungeeCord][stats-bungeecord]
- [Velocity][stats-velocity]
- [License][license]
### 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]
## Dependencies
| Dependency | Platforms | Required? |
| ---------------- | ------------- | --------- |
| [ProtocolLib] | Spigot | Yes |
| [PlaceholderAPI] | Spigot, Paper | No |
## Statistics
This plugin sends statistics to [bStats] to display.
You can disable this in the global bStats config file located in `/plugins/bstats/`
- [BungeeCord][bstats-bungee]
- [Paper/Spigot][bstats-spigot]
- [Velocity][bstats-velocity]
## Screenshots
<a href="https://modrinth.com/plugin/advancedserverlist/gallery" target="_blank">
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/cozy/documentation/modrinth-gallery_vector.svg" height="64" alt="gallery" title="Check out the Gallery">
</a>
## Support
<a href="https://discord.gg/6dazXp6" target="_blank">
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/minimal/social/discord-singular_vector.svg" height="64" alt="discord" title="Join my Discord Server">
</a>
<a href="https://app.revolt.chat/invite/74TpERXA" target="_blank">
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/minimal/social/revolt-singular_vector.svg" height="64" alt="revolt" title="Join my Revolt Server">
</a>
<a href="https://blobfox.coffee/@andre_601" target="_blank">
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@2/assets/minimal/social/mastodon-singular_vector.svg" height="64" alt="mastodon" title="Chat with me on Mastodon">
</a>
<!-- 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
[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
+14 -6
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>
@@ -103,22 +103,30 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.3.0</version>
<version>3.4.1</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>
<relocation>
<pattern>okhttp3</pattern>
<shadedPattern>ch.andre601.advancedserverlist.bungeecord.depends.okhttp3</shadedPattern>
</relocation>
</relocations>
<filters>
<filter>
@@ -30,17 +30,26 @@ import ch.andre601.advancedserverlist.bungeecord.events.JoinEvent;
import ch.andre601.advancedserverlist.bungeecord.events.PingEvent;
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.interfaces.core.ProxyCore;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import ch.andre601.advancedserverlist.core.profiles.favicon.FaviconHandler;
import ch.andre601.advancedserverlist.core.profiles.replacer.placeholders.Placeholders;
import net.md_5.bungee.api.Favicon;
import net.md_5.bungee.api.ServerPing;
import net.md_5.bungee.api.plugin.Plugin;
import org.bstats.bungeecord.Metrics;
import org.bstats.charts.SimplePie;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class BungeeCordCore extends Plugin implements PluginCore{
public class BungeeCordCore extends Plugin implements ProxyCore<Favicon, ServerPing.PlayerInfo>{
private AdvancedServerList core;
private FaviconHandler<Favicon> faviconHandler = null;
private final PluginLogger logger = new BungeeLogger(getLogger());
@Override
@@ -72,13 +81,21 @@ public class BungeeCordCore extends Plugin implements PluginCore{
}
@Override
public void clearFaviconCache(){
if(faviconHandler == null)
return;
faviconHandler.clearCache();
}
@Override
public AdvancedServerList getCore(){
return core;
}
@Override
public Path getPath(){
public Path getFolderPath(){
return getDataFolder().toPath();
}
@@ -87,6 +104,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();
@@ -96,4 +121,25 @@ public class BungeeCordCore extends Plugin implements PluginCore{
public String getPlatformVersion(){
return getProxy().getVersion();
}
@Override
public String getLoader(){
return "bungeecord";
}
@Override
public List<ServerPing.PlayerInfo> createPlayers(List<String> lines, Placeholders... placeholders){
List<ServerPing.PlayerInfo> players = new ArrayList<>(lines.size());
for(String line : lines){
String parsed = ComponentParser.text(line)
.replacements(placeholders[0])
.replacements(placeholders[1])
.toString();
players.add(new ServerPing.PlayerInfo(parsed, UUID.randomUUID()));
}
return players;
}
}
@@ -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,11 +26,15 @@
package ch.andre601.advancedserverlist.bungeecord.events;
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.bungeecord.BungeePlayer;
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.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;
@@ -39,7 +43,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{
@@ -57,48 +60,84 @@ public class PingEvent implements Listener{
if(protocol == null)
return;
InetSocketAddress address = (InetSocketAddress)event.getConnection().getSocketAddress();
Map<String, Object> replacements = plugin.getCore()
.loadPlaceholders(protocol.getProtocol(), ping.getPlayers().getOnline(), ping.getPlayers().getMax(), address);
String playerName = plugin.getCore().getPlayerHandler().getPlayerByIp(
((InetSocketAddress)event.getConnection().getSocketAddress()).getHostString()
);
InetSocketAddress host = event.getConnection().getVirtualHost();
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.isExtraPlayersEnabled()){
max = online + profile.getExtraPlayers();
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()
));
ping.setDescriptionComponent(component);
}
if(!profile.getPlayerCount().isEmpty()){
if(profile.shouldHidePlayers()){
ping.setPlayers(null);
}
if(!profile.getPlayerCount().isEmpty() && !profile.shouldHidePlayers()){
protocol.setName(ComponentParser.text(profile.getPlayerCount())
.replacements(replacements)
.replacements(playerPlaceholders)
.replacements(serverPlaceholders)
.toString()
);
protocol.setProtocol(-1);
}
if(!profile.getPlayers().isEmpty()){
String players = ComponentParser.list(profile.getPlayers())
.replacements(replacements)
.toString();
ServerPing.PlayerInfo[] playerInfos = AdvancedServerList.getPlayers(ServerPing.PlayerInfo.class, players)
if(!profile.getPlayers().isEmpty() && !profile.shouldHidePlayers()){
ServerPing.PlayerInfo[] playerInfos = plugin.createPlayers(profile.getPlayers(), playerPlaceholders, serverPlaceholders)
.toArray(new ServerPing.PlayerInfo[0]);
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){
plugin.getPluginLogger().warn("Unable to create Favicon. %s", ex.getMessage());
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);
@@ -44,8 +44,8 @@ public class BungeeLogger implements PluginLogger{
}
@Override
public void warn(String msg){
logger.warning(msg);
public void warn(String msg, Object... args){
logger.warning(String.format(msg, args));
}
@Override
+22 -6
View File
@@ -47,22 +47,38 @@
<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.12.0</version>
</dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-text-minimessage</artifactId>
<version>${plugin.depend.kyori-minimessage}</version>
<version>4.12.0</version>
</dependency>
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-text-serializer-legacy</artifactId>
<version>${plugin.depend.kyori-legacy}</version>
<version>4.12.0</version>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>3.1.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.9.1</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.10.0</version>
</dependency>
</dependencies>
@@ -83,9 +99,9 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.3.0</version>
<version>3.4.1</version>
<configuration>
<minimizeJar>true</minimizeJar>
<createDependencyReducedPom>false</createDependencyReducedPom>
<filters>
<filter>
<artifact>*:*</artifact>
@@ -25,32 +25,29 @@
package ch.andre601.advancedserverlist.core;
import ch.andre601.advancedserverlist.core.check.UpdateChecker;
import ch.andre601.advancedserverlist.core.commands.CommandHandler;
import ch.andre601.advancedserverlist.core.file.FileHandler;
import ch.andre601.advancedserverlist.core.interfaces.PluginCore;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
import ch.andre601.advancedserverlist.core.profiles.players.PlayerHandler;
import ch.andre601.advancedserverlist.core.profiles.replacer.Placeholders;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.InetSocketAddress;
import java.nio.file.Path;
import java.util.*;
import java.util.Properties;
public class AdvancedServerList{
private final PluginCore plugin;
private final PluginCore<?> plugin;
private final FileHandler fileHandler;
private final CommandHandler commandHandler;
private final PlayerHandler playerHandler;
private UpdateChecker updateChecker;
private String version;
public AdvancedServerList(PluginCore plugin){
public AdvancedServerList(PluginCore<?> plugin){
this.plugin = plugin;
this.fileHandler = new FileHandler(this);
this.commandHandler = new CommandHandler(this);
@@ -59,50 +56,8 @@ public class AdvancedServerList{
load();
}
public static <T> List<T> getPlayers(Class<T> clazz, String text){
try{
String[] lines = text.split("\n");
final List<T> players = new ArrayList<>(lines.length);
final Constructor<T> constructor = clazz.getDeclaredConstructor(String.class, UUID.class);
constructor.setAccessible(true);
for(String line : lines){
players.add(constructor.newInstance(
ComponentParser.text(line).toString(), UUID.randomUUID()
));
}
return players;
}catch(NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException ex){
return Collections.emptyList();
}
}
public Map<String, Object> loadPlaceholders(int protocol, int online, int max, InetSocketAddress ip){
Map<String, Object> replacements = new HashMap<>();
replacements.put(Placeholders.PLAYER_PROTOCOL, protocol);
replacements.put(Placeholders.PLAYERS_ONLINE, online);
replacements.put(Placeholders.PLAYERS_MAX, max);
replacements.put(Placeholders.PLAYER_NAME, getPlayerHandler().getPlayerByIp(ip.getHostString()));
return replacements;
}
public void disable(){
getPluginLogger().info("Saving cache.data file...");
getPlayerHandler().save();
getPluginLogger().info("AdvancedServerList disabled!");
}
public PluginLogger getPluginLogger(){
return plugin.getPluginLogger();
}
public Path getPath(){
return plugin.getPath();
public PluginCore<?> getPlugin(){
return plugin;
}
public FileHandler getFileHandler(){
@@ -121,59 +76,77 @@ public class AdvancedServerList{
return version;
}
public void disable(){
getPlugin().getPluginLogger().info("Saving cache.data file...");
getPlayerHandler().save();
if(updateChecker != null){
getPlugin().getPluginLogger().info("Disabling Update Checker...");
updateChecker.disable();
}
getPlugin().getPluginLogger().info("AdvancedServerList disabled!");
}
public void clearFaviconCache(){
plugin.clearFaviconCache();
}
private void load(){
printBanner();
resolveVersion();
getPluginLogger().info("Starting AdvancedServerList v%s...", version);
getPluginLogger().info("Proxy: " + plugin.getPlatformName() + " " + plugin.getPlatformVersion());
getPlugin().getPluginLogger().info("Starting AdvancedServerList v%s...", version);
getPlugin().getPluginLogger().info("Platform: " + plugin.getPlatformName() + " " + plugin.getPlatformVersion());
if(getFileHandler().loadConfig()){
getPluginLogger().info("Successfully loaded config.yml!");
getPlugin().getPluginLogger().info("Successfully loaded config.yml!");
}else{
getPluginLogger().warn("Unable to load config.yml! Check previous lines for errors.");
getPlugin().getPluginLogger().warn("Unable to load config.yml! Check previous lines for errors.");
return;
}
if(getFileHandler().loadProfiles()){
getPluginLogger().info("Successfully loaded " + getFileHandler().getProfiles().size() + " profiles!");
getPlugin().getPluginLogger().info("Successfully loaded " + getFileHandler().getProfiles().size() + " profiles!");
}else{
getPluginLogger().warn("Unable to load profiles! Check previous lines for errors.");
getPlugin().getPluginLogger().warn("Unable to load profiles! Check previous lines for errors.");
return;
}
getPluginLogger().info("Loading Commands...");
Path folder = getPlugin().getFolderPath().resolve("favicons");
if(!folder.toFile().exists() && folder.toFile().mkdirs())
getPlugin().getPluginLogger().info("Successfully created favicons folder.");
getPlugin().getPluginLogger().info("Loading Commands...");
plugin.loadCommands();
getPluginLogger().info("Commands loaded!");
getPluginLogger().info("Loading events...");
getPlugin().getPluginLogger().info("Commands loaded!");
getPlugin().getPluginLogger().info("Loading events...");
plugin.loadEvents();
getPluginLogger().info("Events loaded!");
getPluginLogger().info("Loading cache.data...");
getPlugin().getPluginLogger().info("Events loaded!");
getPlugin().getPluginLogger().info("Loading cache.data...");
getPlayerHandler().load();
getPlugin().getPluginLogger().info("Loading bStats metrics. Disable it in the global config under /plugins/bstats/");
plugin.loadMetrics();
getPlugin().getPluginLogger().info("Metrics loaded!");
getPlugin().getPluginLogger().info("AdvancedServerList is ready!");
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("AdvancedServerList is ready!");
if(getFileHandler().getBoolean("check_updates"))
this.updateChecker = new UpdateChecker(this);
}
private void printBanner(){
getPluginLogger().info("");
getPluginLogger().info(" _____ _");
getPluginLogger().info(" /\\ / ____| |");
getPluginLogger().info(" / \\ | (___ | |");
getPluginLogger().info(" / /\\ \\ \\___ \\| |");
getPluginLogger().info(" / ____ \\ ____) | |____");
getPluginLogger().info("/_/ \\_\\_____/|______|");
getPluginLogger().info("");
getPlugin().getPluginLogger().info("");
getPlugin().getPluginLogger().info(" _____ _");
getPlugin().getPluginLogger().info(" /\\ / ____| |");
getPlugin().getPluginLogger().info(" / \\ | (___ | |");
getPlugin().getPluginLogger().info(" / /\\ \\ \\___ \\| |");
getPlugin().getPluginLogger().info(" / ____ \\ ____) | |____");
getPlugin().getPluginLogger().info("/_/ \\_\\_____/|______|");
getPlugin().getPluginLogger().info("");
}
private void resolveVersion(){
@@ -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.core.check;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.ThreadFactory;
public class UpdateCheckThread implements ThreadFactory{
@Override
public Thread newThread(@NotNull Runnable r){
return new Thread(r, "AdvancedServerList Update-Thread");
}
}
@@ -0,0 +1,214 @@
/*
* 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.check;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;
import io.leangen.geantyref.TypeToken;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
public class UpdateChecker{
private final String url = "https://api.modrinth.com/v2/project/advancedserverlist/version?loaders=[\"%s\"]";
private final OkHttpClient client = new OkHttpClient();
private final AdvancedServerList core;
private final PluginLogger logger;
private final String loader;
private final Type listType = new TypeToken<ArrayList<ModrinthVersion>>(){}.getType();
private final Gson gson = new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.setPrettyPrinting()
.setLenient()
.create();
private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(new UpdateCheckThread());
public UpdateChecker(AdvancedServerList core){
this.core = core;
this.logger = core.getPlugin().getPluginLogger();
this.loader = core.getPlugin().getLoader();
startUpdateChecker();
}
public void startUpdateChecker(){
executor.scheduleAtFixedRate(() -> {
logger.info("Checking for a new update...");
checkUpdate().whenComplete((version, throwable) -> {
if(version == null || throwable != null){
logger.warn("Failed to look for any updates. See previous messages for reasons.");
return;
}
int result = version.compare(core.getVersion());
switch(result){
case -2 -> {
logger.warn("Encountered an exception while comparing versions. Are they valid?");
logger.warn("Own version: %s; New version: %s", core.getVersion(), version.getVersionNumber());
}
case -1 -> logger.info("You seem to run a newer version compared to Modrinth. Are you running a dev build?");
case 0 -> logger.info("No new update found. You're running the latest version!");
case 1 -> printUpdateBanner(version.getVersionNumber(), version.getId());
}
});
}, 0L, 12L, TimeUnit.HOURS);
}
public void disable(){
executor.shutdown();
try{
if(!executor.awaitTermination(1, TimeUnit.SECONDS)){
executor.shutdownNow();
if(!executor.awaitTermination(1, TimeUnit.SECONDS))
logger.warn("Scheduler didn't terminate in time!");
}
}catch(InterruptedException ex){
executor.shutdownNow();
Thread.currentThread().interrupt();
}
}
private CompletableFuture<ModrinthVersion> checkUpdate(){
return CompletableFuture.supplyAsync(() -> {
PluginLogger logger = core.getPlugin().getPluginLogger();
if(core.getVersion().equals("UNKNOWN")){
logger.warn("Cannot perform Update check! Plugin version couldn't be parsed.");
return null;
}
Request request = new Request.Builder()
.url(String.format(url, loader))
.header("User-Agent", "AdvancedServerList-" + loader + "/" + core.getVersion())
.build();
try(Response response = client.newCall(request).execute()){
if(!response.isSuccessful()){
logger.warn("Encountered a non-successful response from Modrinth! Code: %d", response.code());
return null;
}
ResponseBody body = response.body();
if(body == null){
logger.warn("Received an empty Response body from Modrinth!");
return null;
}
String responseString = body.string();
if(responseString.isEmpty()){
logger.warn("Received an empty Response body from Modrinth!");
return null;
}
List<ModrinthVersion> list = gson.fromJson(responseString, listType);
if(list == null || list.isEmpty()){
logger.warn("Couldn't convert JSON Array into a valid list.");
return null;
}
ModrinthVersion version = list.get(0);
if(version.getVersionNumber() == null || version.getVersionNumber().isEmpty()){
logger.warn("Cannot check latest version. Received version number was null/empty.");
return null;
}
return version;
}catch(JsonSyntaxException ex){
logger.warn("Encountered invalid JSON from Response body!", ex);
return null;
}catch(IOException ex){
logger.warn("Encountered Exception while checking for an update!", ex);
return null;
}
});
}
private void printUpdateBanner(String version, String versionId){
logger.info("==================================================================");
logger.info("You are running an outdated version of AdvancedServerList!");
logger.info("");
logger.info("Your version: %s", core.getVersion());
logger.info("Modrinth version: %s", version);
logger.info("");
logger.info("You can download the latest release from here:");
logger.info("https://modrinth.com/plugin/advancedserverlist/version/%s", versionId);
logger.info("==================================================================");
}
public static class ModrinthVersion{
private String id;
private String versionNumber;
public ModrinthVersion(String id, String versionNumber){
this.id = id;
this.versionNumber = versionNumber;
}
public String getId(){
return id;
}
public String getVersionNumber(){
return versionNumber;
}
public int compare(String version){
String[] oldParts = version.split("\\.");
String[] newParts = versionNumber.split("\\.");
int length = Math.max(oldParts.length, newParts.length);
for(int i = 0; i < length; i++){
try{
int oldPart = i < oldParts.length ? Integer.parseInt(oldParts[i]) : 0;
int newPart = i < newParts.length ? Integer.parseInt(newParts[i]) : 0;
if(oldPart < newPart)
return 1;
if(oldPart > newPart)
return -1;
}catch(NumberFormatException ex){
return -2;
}
}
return 0;
}
}
}
@@ -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>%d Profile(s)</grey>!", prefix, core.getFileHandler().getProfiles().size());
}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;
@@ -55,12 +52,12 @@ public class FileHandler{
private ConfigurationNode node = null;
public FileHandler(AdvancedServerList plugin){
this.plugin = plugin;
this.logger = plugin.getPluginLogger();
public FileHandler(AdvancedServerList core){
this.plugin = core;
this.logger = core.getPlugin().getPluginLogger();
this.config = plugin.getPath().resolve("config.yml");
this.profilesFolder = plugin.getPath().resolve("profiles");
this.config = core.getPlugin().getFolderPath().resolve("config.yml");
this.profilesFolder = core.getPlugin().getFolderPath().resolve("profiles");
}
public List<ServerListProfile> getProfiles(){
@@ -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;
@@ -130,7 +127,7 @@ public class FileHandler{
if(tmp == null)
continue;
profiles.add(new ServerListProfile(tmp));
profiles.add(new ServerListProfile(tmp, logger));
logger.info("Loaded " + file.getName());
}
@@ -161,6 +158,6 @@ public class FileHandler{
}
public boolean getBoolean(Object... path){
return node.node(path).getBoolean(true);
return node.node(path).getBoolean();
}
}
@@ -25,8 +25,6 @@
package ch.andre601.advancedserverlist.core.interfaces;
import net.kyori.adventure.text.format.NamedTextColor;
public interface CmdSender{
boolean hasPermission(String permission);
@@ -29,7 +29,7 @@ public interface PluginLogger{
void info(String msg, Object... args);
void warn(String msg);
void warn(String msg, Object... args);
void warn(String msg, Throwable throwable);
}
@@ -23,13 +23,15 @@
*
*/
package ch.andre601.advancedserverlist.core.interfaces;
package ch.andre601.advancedserverlist.core.interfaces.core;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.profiles.favicon.FaviconHandler;
import java.nio.file.Path;
public interface PluginCore{
public interface PluginCore<F>{
void loadCommands();
@@ -37,13 +39,19 @@ public interface PluginCore{
void loadMetrics();
void clearFaviconCache();
AdvancedServerList getCore();
Path getPath();
Path getFolderPath();
PluginLogger getPluginLogger();
FaviconHandler<F> getFaviconHandler();
String getPlatformName();
String getPlatformVersion();
String getLoader();
}
@@ -0,0 +1,34 @@
/*
* 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.interfaces.core;
import ch.andre601.advancedserverlist.core.profiles.replacer.placeholders.Placeholders;
import java.util.List;
public interface ProxyCore<F, P> extends PluginCore<F>{
List<P> createPlayers(List<String> lines, Placeholders... placeholders);
}
@@ -0,0 +1,34 @@
/*
* 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.interfaces.core;
import ch.andre601.advancedserverlist.core.profiles.replacer.placeholders.Placeholders;
import java.util.List;
public interface ServerCore<F, P, P2> extends PluginCore<F>{
List<P> createPlayers(List<String> lines, P2 player, Placeholders... placeholders);
}
@@ -26,24 +26,22 @@
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{
private static final MiniMessage mm;
private static final LegacyComponentSerializer legacy;
private static final StringReplacer replacer;
static {
mm = MiniMessage.miniMessage();
legacy = LegacyComponentSerializer.legacySection();
replacer = new StringReplacer();
}
private String text;
@@ -60,18 +58,18 @@ public class ComponentParser{
return new ComponentParser(String.join("\n", lines));
}
public ComponentParser replacements(Map<String, Object> replacements){
replacements.forEach(replacer::add);
public ComponentParser replacements(Placeholders placeholders){
text = StringReplacer.replace(text, placeholders.getReplacements());
return this;
}
public ComponentParser function(Function<String, String> function){
public ComponentParser modifyText(Function<String, String> function){
this.text = function.apply(text);
return this;
}
public Component toComponent(){
return mm.deserialize(replacer.replace(text));
return mm.deserialize(text);
}
@Override
@@ -1,139 +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;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class ConditionsHolder{
private final List<String> expressions = new ArrayList<>();
private final StringReplacer replacer = new StringReplacer();
public ConditionsHolder(List<String> expressions){
if(expressions != null && !expressions.isEmpty())
this.expressions.addAll(expressions);
}
public void replace(String from, Object to){
replacer.add(from, to);
}
public boolean eval(PluginLogger logger){
if(expressions.isEmpty())
return true;
for(String expression : expressions){
if(!parseExpression(expression, logger))
return false;
}
return true;
}
private boolean parseExpression(String expression, PluginLogger logger){
if(expression == null || expression.isEmpty())
return true;
String newExpression = replacer.replace(expression);
char[] chars = newExpression.toCharArray();
StringBuilder left = new StringBuilder();
StringBuilder operator = new StringBuilder();
StringBuilder right = new StringBuilder();
boolean operatorFound = false;
for(int i = 0; i < chars.length; i++){
char c = chars[i];
if(c == ' ')
continue;
if((c != '<' && c != '>' && c != '=' && c != '!') || i + 1 >= chars.length){
if(operatorFound){
right.append(c);
continue;
}
left.append(c);
continue;
}
if(operatorFound){
logger.warn("Encountered second operator in condition! AdvancedServerList currently only supports one operator!");
return false;
}
operatorFound = true;
char next = chars[i + 1];
if(c == '!' && next != '='){
logger.warn("Invalid condition found. Expected '!=' but found '!" + next + "' in condition " + newExpression);
return false;
}
operator.append(c);
i++;
if(c == '!' || ((c == '<' || c == '>') && next == '=')){
operator.append(next);
}
}
if(left.isEmpty() || operator.isEmpty() || right.isEmpty()){
logger.warn("Failed to evaluate condition. One part of the expression was empty!");
return false;
}
int leftInt = tryParse(left.toString());
int rightInt = tryParse(right.toString());
return switch(operator.toString().toLowerCase(Locale.ROOT)){
case ">" -> leftInt > rightInt;
case ">=" -> leftInt >= rightInt;
case "=" -> left.toString().equals(right.toString());
case "!=" -> !left.toString().equals(right.toString());
case "<" -> leftInt < rightInt;
case "<=" -> leftInt <= rightInt;
default -> false;
};
}
private int tryParse(String value){
try{
return Integer.parseInt(value);
}catch(NumberFormatException ex){
return value.length();
}
}
}
@@ -26,7 +26,7 @@
package ch.andre601.advancedserverlist.core.profiles;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
import ch.andre601.advancedserverlist.core.profiles.replacer.placeholders.Placeholders;
import java.util.HashMap;
import java.util.Map;
@@ -35,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;
@@ -45,19 +45,17 @@ 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;
}
public ServerListProfile getProfile(){
for(ServerListProfile profile : core.getFileHandler().getProfiles()){
if(profile.getMotd().isEmpty() && profile.getPlayers().isEmpty() && profile.getPlayerCount().isEmpty())
if(profile.isInvalid())
continue;
ConditionsHolder conditions = profile.getConditions();
replacements.forEach(conditions::replace);
if(conditions.eval(core.getPluginLogger()))
if(profile.evalConditions(replacements))
return profile;
}
@@ -25,32 +25,40 @@
package ch.andre601.advancedserverlist.core.profiles;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.profiles.conditions.Expression;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.serialize.SerializationException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class ServerListProfile{
private final ConditionsHolder conditions;
private final int priority;
private final List<Expression> expressions;
private final List<String> motd;
private final List<String> players;
private final String playerCount;
private final String favicon;
private final boolean hidePlayers;
private final boolean extraPlayersEnabled;
private final int extraPlayers;
public ServerListProfile(ConfigurationNode node){
this.conditions = new ConditionsHolder(getList(node, "conditions", false));
public ServerListProfile(ConfigurationNode node, PluginLogger logger){
this.priority = node.node("priority").getInt();
this.expressions = createExpressions(getList(node, false, "conditions"), logger);
this.motd = getList(node, "motd", true);
this.players = getList(node, "players", false);
this.playerCount = node.node("playerCount").getString("");
}
public ConditionsHolder getConditions(){
return conditions;
this.motd = getList(node, true, "motd");
this.players = getList(node, false, "playerCount", "hover");
this.playerCount = node.node("playerCount", "text").getString("");
this.favicon = node.node("favicon").getString("");
this.hidePlayers = node.node("playerCount", "hidePlayers").getBoolean();
this.extraPlayersEnabled = node.node("playerCount", "extraPlayers", "enabled").getBoolean();
this.extraPlayers = node.node("playerCount", "extraPlayers", "amount").getInt();
}
public int getPriority(){
@@ -69,10 +77,65 @@ public class ServerListProfile{
return playerCount;
}
private List<String> getList(ConfigurationNode node, String key, boolean trim){
public String getFavicon(){
return favicon;
}
public boolean shouldHidePlayers(){
return hidePlayers;
}
public boolean isExtraPlayersEnabled(){
return extraPlayersEnabled;
}
public int getExtraPlayers(){
return extraPlayers;
}
public boolean evalConditions(Map<String, Object> replacements){
if(expressions.isEmpty())
return true;
for(Expression expression : expressions){
if(!expression.evaluate(replacements)){
return false;
}
}
return true;
}
public boolean isInvalid(){
return getMotd().isEmpty() &&
getPlayers().isEmpty() &&
(getPlayerCount().isEmpty() && !shouldHidePlayers()) &&
getFavicon().isEmpty();
}
private List<Expression> createExpressions(List<String> list, PluginLogger logger) {
if(list.isEmpty())
return Collections.emptyList();
List<Expression> expressions = new ArrayList<>();
for(String str : list){
Expression expression = new Expression(str);
if(expression.getResult() != Expression.ExpressionResult.VALID){
logger.warn("Detected Invalid condition '%s'! Cause: %s", str, expression.getResult().getMessage());
continue;
}
expressions.add(expression);
}
return expressions;
}
private List<String> getList(ConfigurationNode node, boolean trim, Object... path){
List<String> list;
try{
list = node.node(key).getList(String.class);
list = node.node(path).getList(String.class);
}catch(SerializationException ex){
return Collections.emptyList();
}
@@ -0,0 +1,208 @@
/*
* 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.conditions;
import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
import java.util.Map;
public class Expression{
private ExpressionResult result = ExpressionResult.VALID;
private String left;
private Operator operator = Operator.UNKNOWN;
private String right;
public Expression(String expression){
resolveExpression(expression);
}
public boolean evaluate(Map<String, Object> replacements){
String newLeft = StringReplacer.replace(left, replacements).trim();
String newRight = StringReplacer.replace(right, replacements).trim();
return operator.evaluate(newLeft, newRight);
}
public ExpressionResult getResult(){
return result;
}
private void resolveExpression(String expression){
if(expression == null || expression.isEmpty()){
result = ExpressionResult.INVALID_NO_EXPRESSION;
return;
}
char[] chars = expression.toCharArray();
StringBuilder left = new StringBuilder();
StringBuilder right = new StringBuilder();
boolean foundOperator = false;
for(int i = 0; i < chars.length; i++){
char c = chars[i];
char next = (i == (chars.length - 1)) ? '\0' : chars[i + 1];
Operator tmp = Operator.getOperand(c, next);
if(tmp != Operator.UNKNOWN && !foundOperator){
operator = tmp;
foundOperator = true;
if(tmp.hasSecond())
i++; // Skip next character if operator has 2
continue;
}
if(foundOperator){
right.append(c);
}else{
left.append(c);
}
}
if(left.isEmpty() || right.isEmpty()){
result = ExpressionResult.INVALID_EMPTY_PARTS;
return;
}
this.left = left.toString();
this.right = right.toString();
}
public enum Operator{
LESS('<', '\0'){
@Override
public boolean evaluate(String left, String right){
int leftInt = Operator.getInt(left);
int rightInt = Operator.getInt(right);
return leftInt < rightInt;
}
},
LESS_OR_EQUAL('<', '='){
@Override
public boolean evaluate(String left, String right){
int leftInt = Operator.getInt(left);
int rightInt = Operator.getInt(right);
return leftInt <= rightInt;
}
},
EQUAL('=', '\0'){
@Override
public boolean evaluate(String left, String right){
return left.equals(right);
}
},
NOT_EQUAL('!', '='){
@Override
public boolean evaluate(String left, String right){
return !left.equals(right);
}
},
GREATER('>', '\0'){
@Override
public boolean evaluate(String left, String right){
int leftInt = Operator.getInt(left);
int rightInt = Operator.getInt(right);
return leftInt > rightInt;
}
},
GREATER_OR_EQUAL('>', '='){
@Override
public boolean evaluate(String left, String right){
int leftInt = Operator.getInt(left);
int rightInt = Operator.getInt(right);
return leftInt >= rightInt;
}
},
UNKNOWN('\0', '\0'){
@Override
public boolean evaluate(String left, String right){
return false;
}
};
private static final Operator[] VALUES = values();
private final char first;
private final char second;
Operator(char first, char second){
this.first = first;
this.second = second;
}
public static Operator getOperand(char first, char second){
for(Operator operator : VALUES){
if(operator.first == first){
if((!operator.hasSecond() && second != '=') || operator.second == second)
return operator;
}
}
return Operator.UNKNOWN;
}
public boolean hasSecond(){
return second != '\0';
}
public abstract boolean evaluate(String left, String right);
private static int getInt(String text){
try{
return Integer.parseInt(text);
}catch(NumberFormatException ex){
return text.length();
}
}
}
public enum ExpressionResult{
VALID(null),
INVALID_NO_EXPRESSION ("Received empty condition which isn't allowed!"),
INVALID_EMPTY_PARTS ("Received condition with either left or right part being empty.");
private final String message;
ExpressionResult(String message){
this.message = message;
}
public String getMessage(){
return message;
}
}
}
@@ -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<F>{
private final Cache<String, F> favicons = Caffeine.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES)
.build();
private final AdvancedServerList core;
public FaviconHandler(AdvancedServerList core){
this.core = core;
}
public F getFavicon(String input, Function<BufferedImage, F> 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.getPlugin().getFolderPath().resolve("favicons").toFile();
if(!folder.exists()){
core.getPlugin().getPluginLogger().warn("Cannot get Favicon %s from favicons folder. Folder doesn't exist!", input);
return null;
}
File file = new File(folder, input);
try{
stream = new FileInputStream(file);
}catch(IOException ex){
core.getPlugin().getPluginLogger().warn("Cannot create Favicon from File %s.", input);
core.getPlugin().getPluginLogger().warn("Cause: %s", ex.getMessage());
return null;
}
}else{
stream = getFromUrl(core, "https://mc-heads.net/avatar/" + input + "/64");
}
if(stream == null){
core.getPlugin().getPluginLogger().warn("Cannot create Favicon. InputStream was null.");
return null;
}
try{
BufferedImage original = ImageIO.read(stream);
if(original == null){
core.getPlugin().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.getPlugin().getPluginLogger().warn("Unable to create Favicon. Encountered IOException during creation.");
core.getPlugin().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.getPlugin().getPluginLogger().warn("Error while connecting to %s for Favicon creation.", url);
core.getPlugin().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,11 @@ 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.util.List;
import java.util.Map;
import java.util.StringJoiner;
@@ -47,12 +45,17 @@ public class PlayerHandler{
public PlayerHandler(AdvancedServerList core){
this.core = core;
this.cache = core.getPath().resolve("cache.data");
this.cache = core.getPlugin().getFolderPath().resolve("cache.data");
}
public void load(){
if(!cache.toFile().exists()){
core.getPluginLogger().info("No cache.data present. Skipping...");
core.getPlugin().getPluginLogger().info("No cache.data present. Skipping...");
return;
}
if(core.getFileHandler().getBoolean("disable_cache")){
core.getPlugin().getPluginLogger().info("Cache disabled. Skipping player loading...");
return;
}
@@ -60,12 +63,12 @@ public class PlayerHandler{
try{
lines = Files.readAllLines(cache);
}catch(IOException ex){
core.getPluginLogger().warn("Encountered IOException while trying to read cache.data", ex);
core.getPlugin().getPluginLogger().warn("Encountered IOException while trying to read cache.data", ex);
return;
}
if(lines.isEmpty()){
core.getPluginLogger().info("cache.data is empty. Skipping...");
core.getPlugin().getPluginLogger().info("cache.data is empty. Skipping...");
return;
}
@@ -80,12 +83,17 @@ public class PlayerHandler{
players.add(parts[0], parts[1]);
}
core.getPluginLogger().info("Loaded " + players.size() + " players into cache!");
core.getPlugin().getPluginLogger().info("Loaded " + players.size() + " players into cache!");
}
public void save(){
if(players.isEmpty()){
core.getPluginLogger().info("No data to save. Skipping...");
core.getPlugin().getPluginLogger().info("No data to save. Skipping...");
return;
}
if(core.getFileHandler().getBoolean("disable_cache")){
core.getPlugin().getPluginLogger().info("Cache disabled. Skipping player saving...");
return;
}
@@ -93,23 +101,30 @@ 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);
writer.write(joiner.toString());
writer.close();
core.getPlugin().getPluginLogger().info("Successfully saved cache.data file.");
}catch(IOException ex){
core.getPluginLogger().warn("Cannot save player data to cache.data file!", ex);
core.getPlugin().getPluginLogger().warn("Cannot save player data to cache.data file!", ex);
}
}
public void addPlayer(String name, String ip){
if(players.containsKey(name))
if(players.containsKey(name) || core.getFileHandler().getBoolean("disable_cache"))
return;
players.add(name, ip);
}
public String getPlayerByIp(String ip){
if(core.getFileHandler().getBoolean("disable_cache"))
core.getFileHandler().getString("Anonymous", "unknown_player");
for(Map.Entry<String, String> entry : players){
if(entry.getValue().equals(ip))
return entry.getKey();
@@ -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;
@@ -25,42 +25,14 @@
package ch.andre601.advancedserverlist.core.profiles.replacer;
import java.util.Iterator;
import java.util.Map;
/*
* Original by Imo van den Berge (aka Bergerkiller: https://github.com/Bergerkiller)
*
* Original Source: https://github.com/bergerhealer/BKCommonLib/blob/master/src/main/java/com/bergerkiller/bukkit/common/StringReplaceBundle.java
*/
public class StringReplacer{
private final EntryList<String, Object> entries = new EntryList<>();
public void add(String from, Object to){
if(from == null || to == null)
return;
entries.add(from, to);
}
public Object get(String from){
Iterator<Map.Entry<String, Object>> iterator = entries.iterator();
Map.Entry<String, Object> entry;
while(iterator.hasNext()){
entry = iterator.next();
if(entry.getKey().equals(from)){
iterator.remove();
return entry.getValue();
}
}
return null;
}
public String replace(String input){
public static String replace(String input, Map<String, Object> replacements){
StringBuilder output = new StringBuilder(input);
int index;
for(Map.Entry<String, Object> entry : entries){
for(Map.Entry<String, Object> entry : replacements.entrySet()){
index = 0;
while((index = output.indexOf(entry.getKey(), index)) != -1){
output.replace(index, index + entry.getKey().length(), String.valueOf(entry.getValue()));
@@ -23,14 +23,11 @@
*
*/
package ch.andre601.advancedserverlist.core.profiles.replacer;
package ch.andre601.advancedserverlist.core.profiles.replacer.placeholders;
public class Placeholders{
import java.util.Map;
public interface Placeholders{
public static final String PLAYERS_ONLINE = "${players online}";
public static final String PLAYERS_MAX = "${players max}";
public static final String PLAYER_NAME = "${player name}";
public static final String PLAYER_PROTOCOL = "${player protocol}";
public static final String PLAYER_VERSION = "${player version}";
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;
}
}
+14 -2
View File
@@ -2,7 +2,19 @@
# 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.
# Should the Caching of players be disabled?
#
send_statistics: true
# When set to true will AdvancedServerList not load any players from the cache.data file (if present) nor save any to it.
# Placeholders that rely on the player being cached (such as ${player isWhitelisted}) will not work while this option is enabled.
#
disable_cache: false
#
# Should AdvancedServerList check for new versions?
#
# When set to true will AdvancedServerList check for a new version on modrinth.com every 12 hours and inform you in the
# console about whether it found any new update or not.
#
check_updates: true
+74 -13
View File
@@ -17,29 +17,90 @@ priority: 0
#
# Set the MOTD that should be displayed.
# Can be removed or set to "motd: []" to not alter the MOTD.
# Supports HEX colors for 1.16+ servers including gradients using MiniMessage's <gradient:color:color> format.
#
# Remove this option or set it to motd: [] to not alter the MOTD.
#
# Read more: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#motd
#
motd:
- 'Line 1'
- 'Line 2'
- '<grey>Line 1'
- '<grey>Line 2'
#
# Set the hover text that usually displays online players.
# Can be removed or set to "players: []" to not alter the player list.
# Allows you to set a favicon for this server list profile.
# You can use one of three possible options:
# 1. A file name matching a PNG file located in the 'favicons' folder (Needs to end with .png)
# 2. A URL pointing to a valid Image
# 3. ${player name} to display the player's head as favicon. Uses https://mc-heads.net for this
#
# Read more: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#players
# Read more: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#favicon
#
players:
- 'Line 1'
- 'Line 2'
- 'Line 3'
favicon: ''
#
# Set the text that usually shows online players and max that can join.
# Can be removed or set to "playerCount: ''" to not alter the player count text.
# Contains various options to manipulate the player count (Text displaying online and max players allowed).
#
# Read more: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#playercount
#
playerCount: 'Text'
playerCount:
#
# Whether AdvancedServerList should hide the player count or not.
# When set to true will the player count display '???' instead of <online>/<max>
#
# Note that when this is enabled will all other options, except for 'extraPlayers', be ignored.
#
# Read more: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#hideplayers
#
hidePlayers: false
#
# Sets the text displayed when hovering over the player count.
# You can set this to 'hover: []' or remove the option to not modify the hover text.
#
# Read more: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#hover
#
hover:
- '<grey>Line 1'
- '<grey>Line 2'
- '<grey>Line 3'
#
# Modifies the text that usually displays '<online>/<max>'
#
# Note that when used, the Ping icon will display as 'outdated server'/'outdated client'.
# This is nothing that can be fixed or avoided and would require changes from Mojang.
#
# You can set this to 'count: ''' or remove the option to not modify the player count text.
#
# Read more: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#text
#
text: ''
#
# Allows you to modify the max player count displayed.
# Note that this will affect ${server playersMax} (Except for when used in conditions).
#
# Read more: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#extraPlayers
#
extraPlayers:
#
# Enables/Disables the extraPlayers option.
# When enabled will the total amount of players allowed be modified to the current
# number of online players + 'amount'
#
# Defaults to false when not present.
#
# Read more: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#enabled
#
enabled: false
#
# Sets how much should be added/subtracted from the current number of online players
# to then use for the max player count.
#
# Example:
# When set to 1 while 10 players are online would the player count - if unmodified -
# display '10/11'. When -1 is used will it display '10/9'
#
# Defaults to 0 when not present.
#
# Read more: https://github.com/Andre601/AdvancedServerList/wiki/Profiles#amount
#
amount: 0
+9 -5
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>
@@ -101,9 +101,9 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.3.0</version>
<version>3.4.1</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>
@@ -26,33 +26,46 @@
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.interfaces.core.ServerCore;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import ch.andre601.advancedserverlist.core.profiles.favicon.FaviconHandler;
import ch.andre601.advancedserverlist.core.profiles.replacer.placeholders.Placeholders;
import ch.andre601.advancedserverlist.paper.commands.CmdAdvancedServerList;
import ch.andre601.advancedserverlist.paper.events.JoinEvent;
import ch.andre601.advancedserverlist.paper.events.PingEvent;
import ch.andre601.advancedserverlist.paper.logging.PaperLogger;
import com.destroystokyo.paper.profile.PlayerProfile;
import me.clip.placeholderapi.PlaceholderAPI;
import org.bstats.bukkit.Metrics;
import org.bstats.charts.SimplePie;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.PluginCommand;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.util.CachedServerIcon;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class PaperCore extends JavaPlugin implements PluginCore{
public class PaperCore extends JavaPlugin implements ServerCore<CachedServerIcon, PlayerProfile, OfflinePlayer>{
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,13 +115,21 @@ public class PaperCore extends JavaPlugin implements PluginCore{
));
}
@Override
public void clearFaviconCache(){
if(faviconHandler == null)
return;
faviconHandler.clearCache();
}
@Override
public AdvancedServerList getCore(){
return core;
}
@Override
public Path getPath(){
public Path getFolderPath(){
return getDataFolder().toPath();
}
@@ -117,6 +138,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 +155,35 @@ public class PaperCore extends JavaPlugin implements PluginCore{
public String getPlatformVersion(){
return getServer().getVersion();
}
@Override
public String getLoader(){
return "paper";
}
@Override
public List<PlayerProfile> createPlayers(List<String> lines, OfflinePlayer player, Placeholders... placeholders){
List<PlayerProfile> players = new ArrayList<>(lines.size());
for(String line : lines){
String parsed = ComponentParser.text(line)
.replacements(placeholders[0])
.replacements(placeholders[1])
.modifyText(text -> {
if(getServer().getPluginManager().isPluginEnabled("PlaceholderAPI"))
return PlaceholderAPI.setPlaceholders(player, text);
return text;
})
.toString();
players.add(Bukkit.createProfile(UUID.randomUUID(), parsed));
}
return players;
}
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,20 +28,20 @@ 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.StringReplacer;
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;
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{
@@ -55,36 +55,55 @@ public class PingEvent implements Listener{
@EventHandler
public void onServerPing(PaperServerListPingEvent event){
InetSocketAddress address = event.getClient().getAddress();
Map<String, Object> replacements = plugin.getCore()
.loadPlaceholders(event.getClient().getProtocolVersion(), event.getNumPlayers(), event.getMaxPlayers(), address);
InetSocketAddress host = event.getClient().getVirtualHost();
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;
if(profile.isExtraPlayersEnabled()){
max = online + profile.getExtraPlayers();
event.setMaxPlayers(max);
}
OfflinePlayer player = resolvePlayer(address);
serverPlaceholders = new ServerPlaceholders(online, max, host == null ? null : host.getHostString());
if(!profile.getMotd().isEmpty()){
event.motd(ComponentParser.list(profile.getMotd())
.replacements(replacements)
.function(text -> {
.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;
})
.toComponent());
}
if(!profile.getPlayerCount().isEmpty()){
if(profile.shouldHidePlayers()){
event.setHidePlayers(true);
}
if(!profile.getPlayerCount().isEmpty() && !profile.shouldHidePlayers()){
event.setVersion(ComponentParser.text(profile.getPlayerCount())
.replacements(replacements)
.function(text -> {
.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;
})
@@ -92,39 +111,44 @@ public class PingEvent implements Listener{
event.setProtocolVersion(-1);
}
if(!profile.getPlayers().isEmpty()){
if(!profile.getPlayers().isEmpty() && !profile.shouldHidePlayers()){
event.getPlayerSample().clear();
event.getPlayerSample().addAll(getPlayers(profile.getPlayers(), replacements, player));
event.getPlayerSample().addAll(
plugin.createPlayers(profile.getPlayers(), player.getPlayer(), playerPlaceholders, serverPlaceholders)
);
}
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){
List<PlayerProfile> players = new ArrayList<>();
lines.forEach(line -> players.add(Bukkit.createProfile(UUID.randomUUID(), ComponentParser.text(line)
.replacements(replacements)
.function(text -> {
if(plugin.getServer().getPluginManager().isPluginEnabled("PlaceholderAPI"))
return PlaceholderAPI.setPlaceholders(player, text);
return text;
})
.toString())));
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);
}
}
@@ -44,8 +44,8 @@ public class PaperLogger implements PluginLogger{
}
@Override
public void warn(String msg){
logger.warning(msg);
public void warn(String msg, Object... args){
logger.warning(String.format(msg, args));
}
@Override
+4 -1
View File
@@ -7,13 +7,16 @@ main: 'ch.andre601.advancedserverlist.paper.PaperCore'
api-version: 1.19
libraries:
- 'com.squareup.okhttp3:okhttp:4.10.0'
softdepend:
- 'PlaceholderAPI'
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.0.3</plugin.version>
<plugin.version>1.7.0</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>
+10 -6
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>
@@ -116,13 +116,17 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.3.0</version>
<version>3.4.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>
@@ -26,22 +26,34 @@
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.interfaces.core.ServerCore;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import ch.andre601.advancedserverlist.core.profiles.favicon.FaviconHandler;
import ch.andre601.advancedserverlist.core.profiles.replacer.placeholders.Placeholders;
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.WrappedGameProfile;
import com.comphenix.protocol.wrappers.WrappedServerPing;
import me.clip.placeholderapi.PlaceholderAPI;
import org.bstats.bukkit.Metrics;
import org.bstats.charts.SimplePie;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.PluginCommand;
import org.bukkit.plugin.java.JavaPlugin;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class SpigotCore extends JavaPlugin implements PluginCore{
public class SpigotCore extends JavaPlugin implements ServerCore<WrappedServerPing.CompressedImage, WrappedGameProfile, OfflinePlayer>{
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,13 +100,21 @@ public class SpigotCore extends JavaPlugin implements PluginCore{
));
}
@Override
public void clearFaviconCache(){
if(faviconHandler == null)
return;
faviconHandler.clearCache();
}
@Override
public AdvancedServerList getCore(){
return core;
}
@Override
public Path getPath(){
public Path getFolderPath(){
return getDataFolder().toPath();
}
@@ -103,6 +123,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();
@@ -113,11 +141,38 @@ public class SpigotCore extends JavaPlugin implements PluginCore{
return getServer().getVersion();
}
@Override
public String getLoader(){
return "spigot";
}
@Override
public List<WrappedGameProfile> createPlayers(List<String> lines, OfflinePlayer player, Placeholders... placeholders){
List<WrappedGameProfile> players = new ArrayList<>(lines.size());
for(String line : lines){
String parsed = ComponentParser.text(line)
.replacements(placeholders[0])
.replacements(placeholders[1])
.modifyText(text -> {
if(getServer().getPluginManager().isPluginEnabled("PlaceholderAPI"))
return PlaceholderAPI.setPlaceholders(player, text);
return text;
})
.toString();
players.add(new WrappedGameProfile(UUID.randomUUID(), parsed));
}
return players;
}
private void printPaperInfo(){
getPluginLogger().warn("======================================================================================");
getPluginLogger().warn("You are using the Spigot version of AdvancedServerList on a PaperMC server.");
getPluginLogger().warn("It is recommended to use the dedicated PaperMC version, to benefit from the");
getPluginLogger().warn("Following improvements:");
getPluginLogger().warn("You are using the Spigot version of AdvancedServerList on a Paper server.");
getPluginLogger().warn("It is recommended to use the dedicated Paper version, to benefit from the");
getPluginLogger().warn("following improvements:");
getPluginLogger().warn(" - No need to download external libraries already provided by PaperMC.");
getPluginLogger().warn(" - No dependency on ProtocolLib thanks to provided Events.");
getPluginLogger().warn("");
@@ -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();
}
}
@@ -46,7 +46,7 @@ public class LoadEvent implements Listener{
PluginManager manager = plugin.getServer().getPluginManager();
if(!manager.isPluginEnabled("ProtocolLib")){
plugin.getCore().getPluginLogger().warn("ProtocolLib not found! AdvancedServerList requires it to work on Spigot!");
plugin.getCore().getPlugin().getPluginLogger().warn("ProtocolLib not found! AdvancedServerList requires it to work on Spigot!");
manager.disablePlugin(plugin);
return;
@@ -28,14 +28,17 @@ 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.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;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.wrappers.AdventureComponentConverter;
import com.comphenix.protocol.wrappers.WrappedGameProfile;
import com.comphenix.protocol.wrappers.WrappedServerPing;
import me.clip.placeholderapi.PlaceholderAPI;
import net.kyori.adventure.text.Component;
@@ -44,13 +47,16 @@ import org.bukkit.OfflinePlayer;
import org.bukkit.event.Listener;
import java.net.InetSocketAddress;
import java.util.*;
import java.util.HashMap;
import java.util.Map;
public class PingEvent implements Listener{
private final SpigotCore plugin;
private final ProtocolManager protocolManager;
private final Map<String, String> hostAddresses = new HashMap<>();
public PingEvent(SpigotCore plugin, ProtocolManager protocolManager){
this.plugin = plugin;
this.protocolManager = protocolManager;
@@ -59,6 +65,19 @@ public class PingEvent implements Listener{
}
private void loadPacketListener(SpigotCore spigotPlugin){
protocolManager.addPacketListener(new PacketAdapter(spigotPlugin, ListenerPriority.LOW, PacketType.Handshake.Client.SET_PROTOCOL){
@Override
public void onPacketReceiving(PacketEvent event){
InetSocketAddress address = event.getPlayer().getAddress();
if(address == null)
return;
String host = event.getPacket().getStrings().read(0);
hostAddresses.put(address.getHostString(), host);
}
});
protocolManager.addPacketListener(new PacketAdapter(spigotPlugin, ListenerPriority.LOW, PacketType.Status.Server.SERVER_INFO){
@Override
public void onPacketSending(PacketEvent event){
@@ -66,25 +85,37 @@ public class PingEvent implements Listener{
InetSocketAddress address = event.getPlayer().getAddress();
if(address == null)
return;
SpigotPlayer player = resolvePlayer(address, ping.getVersionProtocol());
Map<String, Object> replacements = spigotPlugin.getCore()
.loadPlaceholders(ping.getVersionProtocol(), ping.getPlayersOnline(), ping.getPlayersMaximum(), address);
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;
if(profile.isExtraPlayersEnabled()){
max = online + profile.getExtraPlayers();
ping.setPlayersMaximum(max);
}
OfflinePlayer player = resolvePlayer(address);
serverPlaceholders = new ServerPlaceholders(online, max, hostAddresses.get(address.getHostString()));
if(!profile.getMotd().isEmpty()){
Component component = ComponentParser.list(profile.getMotd())
.replacements(replacements)
.function(text -> {
.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;
})
@@ -92,12 +123,17 @@ public class PingEvent implements Listener{
ping.setMotD(AdventureComponentConverter.fromComponent(component));
}
if(!profile.getPlayerCount().isEmpty()){
if(profile.shouldHidePlayers()){
ping.setPlayersVisible(false);
}
if(!profile.getPlayerCount().isEmpty() && !profile.shouldHidePlayers()){
ping.setVersionName(ComponentParser.text(profile.getPlayerCount())
.replacements(replacements)
.function(text -> {
.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,35 +142,35 @@ public class PingEvent implements Listener{
ping.setVersionProtocol(-1);
}
if(!profile.getPlayers().isEmpty()){
ping.setPlayers(getFakePlayers(
ComponentParser.list(profile.getPlayers())
.replacements(replacements)
.function(text -> {
if(plugin.getServer().getPluginManager().isPluginEnabled("PlaceholderAPI"))
return PlaceholderAPI.setPlaceholders(player, text);
if(!profile.getPlayers().isEmpty() && !profile.shouldHidePlayers()){
ping.setPlayers(
spigotPlugin.createPlayers(profile.getPlayers(), player.getPlayer(), playerPlaceholders, serverPlaceholders)
);
}
if(!profile.getFavicon().isEmpty()){
String favName = StringReplacer.replace(profile.getFavicon(), playerPlaceholders.getReplacements());
return text;
})
.toString()
));
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);
}
}
}
});
}
private List<WrappedGameProfile> getFakePlayers(String text){
String[] lines = text.split("\n");
List<WrappedGameProfile> profiles = new ArrayList<>();
for(String line : lines){
profiles.add(new WrappedGameProfile(UUID.randomUUID(), line));
}
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);
@@ -142,9 +178,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);
}
}
@@ -44,8 +44,8 @@ public class SpigotLogger implements PluginLogger{
}
@Override
public void warn(String msg){
logger.warning(msg);
public void warn(String msg, Object... args){
logger.warning(String.format(msg, args));
}
@Override
+7 -6
View File
@@ -8,11 +8,12 @@ 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'
- 'com.squareup.okhttp3:okhttp:4.10.0'
softdepend:
- 'ProtocolLib'
@@ -21,7 +22,7 @@ softdepend:
commands:
advancedserverlist:
description: 'Main command of AdvancedServerList'
usage: '/<command> [reload]'
usage: '/<command> [help|reload]'
aliases:
- 'asl'
permission: 'advancedserverlist.admin'
+12 -2
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>
@@ -86,9 +88,9 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.3.0</version>
<version>3.4.1</version>
<configuration>
<minimizeJar>true</minimizeJar>
<createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
<relocation>
<pattern>org.spongepowered.configurate</pattern>
@@ -98,6 +100,14 @@
<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>
<relocation>
<pattern>okhttp3</pattern>
<shadedPattern>ch.andre601.advancedserverlist.velocity.depends.okhttp3</shadedPattern>
</relocation>
</relocations>
<filters>
<filter>
@@ -26,8 +26,11 @@
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.interfaces.core.ProxyCore;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import ch.andre601.advancedserverlist.core.profiles.favicon.FaviconHandler;
import ch.andre601.advancedserverlist.core.profiles.replacer.placeholders.Placeholders;
import ch.andre601.advancedserverlist.velocity.commands.CmdAdvancedServerList;
import ch.andre601.advancedserverlist.velocity.events.JoinEvent;
import ch.andre601.advancedserverlist.velocity.events.PingEvent;
@@ -39,13 +42,18 @@ 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.proxy.server.ServerPing;
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;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class VelocityCore implements PluginCore{
public class VelocityCore implements ProxyCore<Favicon, ServerPing.SamplePlayer>{
private final PluginLogger logger;
private final ProxyServer proxy;
@@ -53,6 +61,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,13 +105,21 @@ public class VelocityCore implements PluginCore{
));
}
@Override
public void clearFaviconCache(){
if(faviconHandler == null)
return;
faviconHandler.clearCache();
}
@Override
public AdvancedServerList getCore(){
return core;
}
@Override
public Path getPath(){
public Path getFolderPath(){
return path;
}
@@ -111,6 +128,30 @@ public class VelocityCore implements PluginCore{
return logger;
}
@Override
public FaviconHandler<Favicon> getFaviconHandler(){
if(faviconHandler == null)
faviconHandler = new FaviconHandler<>(core);
return faviconHandler;
}
@Override
public List<ServerPing.SamplePlayer> createPlayers(List<String> lines, Placeholders... placeholders){
List<ServerPing.SamplePlayer> players = new ArrayList<>(lines.size());
for(String line : lines){
String parsed = ComponentParser.text(line)
.replacements(placeholders[0])
.replacements(placeholders[1])
.toString();
players.add(new ServerPing.SamplePlayer(parsed, UUID.randomUUID()));
}
return players;
}
@Override
public String getPlatformName(){
return getProxy().getVersion().getName();
@@ -121,6 +162,11 @@ public class VelocityCore implements PluginCore{
return getProxy().getVersion().getVersion();
}
@Override
public String getLoader(){
return "velocity";
}
public ProxyServer getProxy(){
return proxy;
}
@@ -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();
}
}
@@ -25,21 +25,22 @@
package ch.andre601.advancedserverlist.velocity.events;
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,47 +59,79 @@ 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 = plugin.getCore()
.loadPlaceholders(protocol.getProtocol(), builder.getOnlinePlayers(), builder.getMaximumPlayers(), address);
replacements.put(Placeholders.PLAYER_VERSION, ProtocolVersion.getProtocolVersion(protocol.getProtocol()));
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.isExtraPlayersEnabled()){
max = online + profile.getExtraPlayers();
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()
);
}
if(!profile.getPlayerCount().isEmpty()){
if(profile.shouldHidePlayers()){
builder.nullPlayers();
}
if(!profile.getPlayerCount().isEmpty() && !profile.shouldHidePlayers()){
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)
.toString();
ServerPing.SamplePlayer[] playerSamples = AdvancedServerList.getPlayers(ServerPing.SamplePlayer.class, players)
if(!profile.getPlayers().isEmpty() && !profile.shouldHidePlayers()){
ServerPing.SamplePlayer[] playerSamples = plugin.createPlayers(profile.getPlayers(), playerPlaceholders, serverPlaceholders)
.toArray(new ServerPing.SamplePlayer[0]);
if(playerSamples.length > 0)
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){
logger.warn(msg);
public void warn(String msg, Object... args){
logger.warn(String.format(msg, args));
}
@Override