Compare commits

...
163 Commits
Author SHA1 Message Date
Andre601 6bf44f6208 Fix hover not supporting PlaceholderAPI Placeholders 2024-10-06 00:01:06 +02:00
Andre601 428dd3cd06 Merge pull request 'Update dependency org.junit.jupiter:junit-jupiter-engine to v5.11.2' (#350) from renovate/org.junit.jupiter-junit-jupiter-engine-5.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/350
2024-10-05 12:12:34 +00:00
Andre601's Bot 871e2efbe2 Update dependency org.junit.jupiter:junit-jupiter-engine to v5.11.2 2024-10-05 12:01:14 +00:00
Andre601 a5b45e2c82 Add SECURITY.md 2024-10-04 22:54:25 +00:00
Andre601 9feb3dfac6 Bump version 2024-10-02 13:43:45 +02:00
Andre601 5961d0dca0 Don't log errors when fetching servers (+ misc changes) 2024-10-02 13:43:05 +02:00
Andre601 3d5d4fcab2 Fix wrong name for AdvancedBan in BanPlugins Addon 2024-10-01 19:58:11 +02:00
Andre601 0763a9b3b4 Fix wrong main class for Paper BanPluginsAddon 2024-10-01 02:26:14 +02:00
Andre601 2d67a89fc2 Merge pull request 'Update dependency mkdocs-material to v9.5.39' (#349) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/349
2024-09-29 12:07:56 +00:00
Andre601's Bot 4207d875f9 Update dependency mkdocs-material to v9.5.39 2024-09-29 12:03:17 +00:00
Andre601 5da420c6c6 Merge pull request 'feature/online-players-setting' (#348) from feature/online-players-setting into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/348
2024-09-27 14:27:47 +00:00
Andre601 1ffa4842c3 Update API docs and bump version to major v5 2024-09-26 16:47:28 +02:00
Andre601 819e194f27 Make Server placeholders return empty String instead of null. 2024-09-26 16:11:38 +02:00
Andre601 269e55b93f Merge branch 'master' into feature/online-players-setting 2024-09-26 15:54:50 +02:00
Andre601 04412f7138 Implement feature to set online player count 2024-09-26 15:54:28 +02:00
Andre601 0fce9d01e1 Merge pull request 'Update dependency mkdocs-material to v9.5.38' (#346) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/346
2024-09-26 13:50:41 +00:00
Andre601's Bot 1c29301635 Update dependency mkdocs-material to v9.5.38 2024-09-26 12:02:06 +00:00
Andre601 8bd7bbb5d7 Merge pull request 'Update dependency org.junit.jupiter:junit-jupiter-engine to v5.11.1' (#345) from renovate/org.junit.jupiter-junit-jupiter-engine-5.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/345
2024-09-25 12:04:33 +00:00
Andre601 1a99663b59 Merge pull request 'Update dependency mkdocs-material to v9.5.37' (#344) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/344
2024-09-25 12:04:14 +00:00
Andre601's Bot 36e31279b2 Update dependency org.junit.jupiter:junit-jupiter-engine to v5.11.1 2024-09-25 12:01:31 +00:00
Andre601's Bot 4aa7eba675 Update dependency mkdocs-material to v9.5.37 2024-09-25 12:01:21 +00:00
Andre601 3bbe2d26b8 Merge pull request 'Update dependency com.google.guava:guava to v33.3.1-jre' (#342) from renovate/com.google.guava-guava-33.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/342
2024-09-24 13:11:35 +00:00
Andre601 782ad838be Merge pull request 'Update dependency org.bstats:bstats-velocity to v3.1.0' (#343) from renovate/org.bstats-bstats-velocity-3.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/343
2024-09-24 13:11:22 +00:00
Andre601's Bot ceddb26137 Update dependency org.bstats:bstats-velocity to v3.1.0 2024-09-24 12:01:32 +00:00
Andre601's Bot ff044d75c7 Update dependency com.google.guava:guava to v33.3.1-jre 2024-09-24 12:01:25 +00:00
Andre601 8955df695d Merge pull request 'Update dependency org.bstats:bstats-bungeecord to v3.1.0' (#341) from renovate/org.bstats-bstats-bungeecord-3.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/341
2024-09-23 12:57:03 +00:00
Andre601 8ddcb208f5 Merge pull request 'Update dependency org.bstats:bstats-bukkit to v3.1.0' (#340) from renovate/org.bstats-bstats-bukkit-3.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/340
2024-09-23 12:56:27 +00:00
Andre601's Bot 95834df89f Update dependency org.bstats:bstats-bungeecord to v3.1.0 2024-09-23 12:01:58 +00:00
Andre601's Bot 2f67f26cbe Update dependency org.bstats:bstats-bukkit to v3.1.0 2024-09-23 12:01:52 +00:00
Andre601 00957f9458 Merge pull request 'Create ${proxy status ...} placeholder.' (#334) from feature/proxy-status-placeholder into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/334
2024-09-22 13:12:42 +00:00
Andre601 2e9e886c48 Merge pull request 'Update dependency mkdocs-material to v9.5.36' (#338) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/338
2024-09-21 12:24:01 +00:00
Andre601's Bot d2d4e48b73 Update dependency mkdocs-material to v9.5.36 2024-09-21 12:01:47 +00:00
Andre601 fe16df27f2 Merge pull request 'Update dependency org.apache.httpcomponents.client5:httpclient5 to v5.4' (#337) from renovate/org.apache.httpcomponents.client5-httpclient5-5.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/337
2024-09-20 15:51:44 +00:00
Andre601's Bot cc29f70dff Update dependency org.apache.httpcomponents.client5:httpclient5 to v5.4 2024-09-20 12:02:38 +00:00
Andre601 e136f7cfaf Merge pull request 'Update dependency mkdocs-material to v9.5.35' (#336) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/336
2024-09-18 12:05:57 +00:00
Andre601's Bot fd52f124fb Update dependency mkdocs-material to v9.5.35 2024-09-18 12:01:38 +00:00
Andre601 5a656cee39 Merge pull request 'Update alpine Docker tag to v3.20.3' (#335) from renovate/alpine-3.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/335
2024-09-17 14:39:09 +00:00
Andre601's Bot 21a89f9b14 Update alpine Docker tag to v3.20.3 2024-09-17 12:01:40 +00:00
Andre601 9ded4d2d57 Add more placeholders 2024-09-09 14:49:07 +02:00
Andre601 fb64d92879 Create Proxy Placeholder 2024-09-09 02:05:50 +02:00
Andre601 1a4bcae4d1 Merge pull request 'Update dependency ch.qos.logback:logback-classic to v1.5.8' (#331) from renovate/ch.qos.logback-logback-classic-1.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/331
2024-09-07 12:07:57 +00:00
Andre601's Bot 25ee4da4f4 Update dependency ch.qos.logback:logback-classic to v1.5.8 2024-09-07 12:01:12 +00:00
Andre601 35cb39c35e Merge pull request 'Update dependency mkdocs-material to v9.5.34' (#330) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/330
2024-09-01 14:09:33 +00:00
Andre601's Bot 3a5f232f92 Update dependency mkdocs-material to v9.5.34 2024-09-01 12:03:23 +00:00
Andre601 4ed201fba9 Bump version 2024-08-29 20:31:14 +02:00
Andre601 03835f71d9 Fix local favicon saving using non-lowercased names. 2024-08-29 20:30:44 +02:00
Andre601 480e50e71e .woodpecker/publish_assets.yml aktualisiert 2024-08-29 11:51:38 +00:00
Andre601 39110b2898 Merge pull request 'Update dependency mkdocs-material to v9.5.33' (#329) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/329
2024-08-23 13:08:17 +00:00
Andre601's Bot e8db70e319 Update dependency mkdocs-material to v9.5.33 2024-08-23 12:02:52 +00:00
Andre601 eb907988fb Merge pull request 'Update maven Docker tag to v3.9.9' (#328) from renovate/maven-3.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/328
2024-08-21 12:39:31 +00:00
Andre601's Bot 95935022b8 Update maven Docker tag to v3.9.9 2024-08-21 12:10:41 +00:00
Andre601 1e70cb0651 Merge pull request 'Update dependency org.bstats:bstats-velocity to v3.0.3' (#327) from renovate/org.bstats-bstats-velocity-3.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/327
2024-08-20 13:55:27 +00:00
Andre601 1594d062e5 Merge pull request 'Update dependency org.bstats:bstats-bungeecord to v3.0.3' (#326) from renovate/org.bstats-bstats-bungeecord-3.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/326
2024-08-20 13:55:11 +00:00
Andre601's Bot 04b266f558 Update dependency org.bstats:bstats-velocity to v3.0.3 2024-08-20 12:03:13 +00:00
Andre601's Bot 9989fec809 Update dependency org.bstats:bstats-bungeecord to v3.0.3 2024-08-20 12:03:06 +00:00
Andre601 ab8eabc348 Merge pull request 'Update dependency org.bstats:bstats-bukkit to v3.0.3' (#325) from renovate/org.bstats-bstats-bukkit-3.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/325
2024-08-19 13:54:53 +00:00
Andre601 931b8b5c36 Merge pull request 'Update dependency mkdocs-material to v9.5.32' (#324) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/324
2024-08-19 13:53:45 +00:00
Andre601's Bot 64957ba13c Update dependency org.bstats:bstats-bukkit to v3.0.3 2024-08-19 12:04:55 +00:00
Andre601's Bot a03be990ab Update dependency mkdocs-material to v9.5.32 2024-08-19 12:04:46 +00:00
Andre601 44729495f5 Merge pull request 'Update dependency ch.qos.logback:logback-classic to v1.5.7' (#322) from renovate/ch.qos.logback-logback-classic-1.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/322
2024-08-19 00:59:33 +00:00
Andre601 9e7500f0cd Merge pull request 'Update dependency com.google.guava:guava to v33.3.0-jre' (#323) from renovate/com.google.guava-guava-33.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/323
2024-08-17 12:06:21 +00:00
Andre601's Bot d10ff8bdbc Update dependency com.google.guava:guava to v33.3.0-jre 2024-08-17 12:04:11 +00:00
Andre601's Bot f91fc36365 Update dependency ch.qos.logback:logback-classic to v1.5.7 2024-08-16 12:02:51 +00:00
Andre601 84ddff07a2 Merge pull request 'Update dependency org.junit.jupiter:junit-jupiter-engine to v5.11.0' (#321) from renovate/org.junit.jupiter-junit-jupiter-engine-5.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/321
2024-08-14 12:46:12 +00:00
Andre601's Bot 4a89658cf4 Update dependency org.junit.jupiter:junit-jupiter-engine to v5.11.0 2024-08-14 12:31:56 +00:00
Andre601 5daef41031 Fix renovate.json 2024-08-14 12:22:44 +00:00
Andre601 07cc1e8160 Update registry URL for Libby 2024-08-13 12:45:02 +00:00
Andre601 8b2d763207 Adding Maintenance placeholders 2024-08-12 23:29:53 +02:00
Andre601 fb8c556e24 Merge pull request 'Update dependency net.william278:papiproxybridge to v1.6.2' (#320) from renovate/net.william278-papiproxybridge-1.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/320
2024-08-12 12:04:15 +00:00
Andre601's Bot 397fa12f12 Update dependency net.william278:papiproxybridge to v1.6.2 2024-08-12 12:03:25 +00:00
Andre601 d86ecf8d8b Merge pull request 'Update dependency com.viaversion:viaversion-api to v5.0.3' (#319) from renovate/com.viaversion-viaversion-api-5.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/319
2024-08-08 12:49:45 +00:00
Andre601's Bot 2882e9ecdf Update dependency com.viaversion:viaversion-api to v5.0.3 2024-08-08 12:03:10 +00:00
Andre601 69a4a05069 Merge pull request 'Update dependency net.kyori:adventure-platform-bungeecord to v4.3.4' (#318) from renovate/dependency.adventure-platform-bungeecord into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/318
2024-08-07 12:35:00 +00:00
Andre601's Bot 361a340ef1 Update dependency net.kyori:adventure-platform-bungeecord to v4.3.4 2024-08-07 12:03:12 +00:00
Andre601 ee7c0451af Merge pull request 'Update dependency mkdocs-material to v9.5.31' (#316) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/316
2024-08-02 12:11:44 +00:00
Andre601's Bot 200c7cbfea Update dependency mkdocs-material to v9.5.31 2024-08-02 12:03:08 +00:00
Andre601 9a665ddf26 Merge pull request 'Make various improvements to UpdateChecker' (#315) from feat/update-checker-improvements into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/315
2024-07-30 14:08:41 +00:00
Andre601 c4327ac238 Bump version and don't use lenient setting in Gson 2024-07-30 16:07:00 +02:00
Andre601 9f4b798848 Make various improvements to UpdateChecker 2024-07-29 23:42:10 +02:00
Andre601 3cc18f4dc0 Merge pull request 'Update dependency com.viaversion:viaversion-api to v5.0.2' (#313) from renovate/com.viaversion-viaversion-api-5.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/313
2024-07-29 12:21:52 +00:00
Andre601's Bot 9637308045 Update dependency com.viaversion:viaversion-api to v5.0.2 2024-07-29 12:02:59 +00:00
Andre601 772603e785 Merge pull request 'Update dependency dev.masecla:Modrinth4J to v2.2.0' (#312) from renovate/dev.masecla-modrinth4j-2.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/312
2024-07-26 14:30:44 +00:00
Andre601's Bot f9417ee2f7 Update dependency dev.masecla:Modrinth4J to v2.2.0 2024-07-26 12:03:04 +00:00
Andre601 2db85bff60 Merge pull request 'Update dependency mkdocs-material to v9.5.30' (#311) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/311
2024-07-23 12:06:48 +00:00
Andre601's Bot 527b5aa25c Update dependency mkdocs-material to v9.5.30 2024-07-23 12:03:04 +00:00
Andre601 5d9bb0dc4a Merge pull request 'Update dependency mkdocs-material to v9.5.29' (#310) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/310
2024-07-14 12:05:50 +00:00
Andre601's Bot cc51756f0d Update dependency mkdocs-material to v9.5.29 2024-07-14 12:01:13 +00:00
Andre601 5ff66adb0c Merge pull request 'Fix Paper PlayerSample deprecation.' (#309) from fix/paper-playersample-deprecation into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/309
2024-07-11 14:59:21 +00:00
Andre601 8e9cc98ded Update registry URLs for Renovate 2024-07-11 13:41:07 +00:00
Andre601 4387e78007 Update VersionUploader to list latest MC release as supported. 2024-07-11 15:33:27 +02:00
Andre601 4fff1e24cc Fix Paper PlayerSample deprecation. 2024-07-11 15:28:14 +02:00
Andre601 9791ed0cee Merge pull request 'Update dependency mkdocs-material to v9.5.28' (#308) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/308
2024-07-02 15:07:08 +00:00
Andre601's Bot e8e6f3a8fd Update dependency mkdocs-material to v9.5.28 2024-07-02 12:01:55 +00:00
Andre601 5e6da9b24e Merge pull request 'Use allorigins.win for fetching stats' (#307) from feat/docs-use-allorigins.win into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/307
2024-07-01 12:28:50 +00:00
Andre601 59bd9239b2 Use raw instead? 2024-07-01 12:24:52 +00:00
Andre601 08436a278c Fix wrong json keys 2024-07-01 12:11:14 +00:00
Andre601 5d512e5e89 Use allorigins.win for fetching stats 2024-07-01 12:02:11 +00:00
Andre601 ec1a367691 Merge pull request 'Update maven Docker tag to v3.9.8' (#306) from renovate/maven-3.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/306
2024-06-28 12:16:32 +00:00
Andre601 457450683b Merge pull request 'Update dependency org.junit.jupiter:junit-jupiter-engine to v5.10.3' (#305) from renovate/org.junit.jupiter-junit-jupiter-engine-5.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/305
2024-06-28 12:16:21 +00:00
Andre601's Bot a8d76d6b0f Update maven Docker tag to v3.9.8 2024-06-28 12:01:20 +00:00
Andre601's Bot 5036d62824 Update dependency org.junit.jupiter:junit-jupiter-engine to v5.10.3 2024-06-28 12:01:12 +00:00
Andre601 4f5f6e724f Merge pull request 'Update dependency com.viaversion:viaversion-api to v5.0.1' (#304) from renovate/com.viaversion-viaversion-api-5.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/304
2024-06-23 12:12:00 +00:00
Andre601's Bot 71f7532fe3 Update dependency com.viaversion:viaversion-api to v5.0.1 2024-06-23 12:01:14 +00:00
Andre601 9ea37af603 Merge pull request 'Update dependency org.apache.maven.plugins:maven-jar-plugin to v3.4.2' (#303) from renovate/org.apache.maven.plugins-maven-jar-plugin-3.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/303
2024-06-20 18:35:21 +00:00
Andre601's Bot 1964a6b4e3 Update dependency org.apache.maven.plugins:maven-jar-plugin to v3.4.2 2024-06-20 12:01:22 +00:00
Andre601 94a9ea31a0 Merge pull request 'Update dependency mkdocs-material to v9.5.27' (#301) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/301
2024-06-17 12:05:56 +00:00
Andre601 2855d268da Merge pull request 'Update dependency com.viaversion:viaversion-api to v5' (#302) from renovate/com.viaversion-viaversion-api-5.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/302
2024-06-17 12:05:27 +00:00
Andre601's Bot d6d576da20 Update dependency com.viaversion:viaversion-api to v5 2024-06-17 12:01:48 +00:00
Andre601's Bot 34ed832d79 Update dependency mkdocs-material to v9.5.27 2024-06-17 12:01:39 +00:00
Andre601 42ef8c0c39 Update getting-started guide 2024-06-10 13:07:57 +02:00
Andre601 1ce0c2db4e Merge pull request 'Update dependency mkdocs-material to v9.5.26' (#299) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/299
2024-06-06 12:06:19 +00:00
Andre601's Bot 028aaa1cf7 Update dependency mkdocs-material to v9.5.26 2024-06-06 12:03:07 +00:00
Andre601 66937916c4 Bump version 2024-06-06 02:32:46 +02:00
Andre601 82a053095e Display yt video thumbnail 2024-06-03 23:56:41 +00:00
Andre601 f24e62687d Merge pull request 'Update dependency net.kyori:adventure-platform-bungeecord to v4.3.3' (#298) from renovate/dependency.adventure-platform-bungeecord into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/298
2024-06-02 12:03:11 +00:00
Andre601's Bot 184cf8443c Update dependency net.kyori:adventure-platform-bungeecord to v4.3.3 2024-06-02 12:01:20 +00:00
Andre601 2b06bcc497 Merge pull request 'Update dependency org.apache.maven.plugins:maven-shade-plugin to v3.6.0' (#297) from renovate/org.apache.maven.plugins-maven-shade-plugin-3.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/297
2024-06-01 12:32:39 +00:00
Andre601 743f4cc5eb Merge branch 'master' into renovate/org.apache.maven.plugins-maven-shade-plugin-3.x 2024-06-01 12:32:31 +00:00
Andre601 45ccb18133 Merge pull request 'Update dependency com.google.guava:guava to v33.2.1-jre' (#296) from renovate/com.google.guava-guava-33.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/296
2024-06-01 12:32:21 +00:00
Andre601's Bot 3812e11702 Update dependency org.apache.maven.plugins:maven-shade-plugin to v3.6.0 2024-06-01 12:02:46 +00:00
Andre601's Bot c731cd3c87 Update dependency com.google.guava:guava to v33.2.1-jre 2024-06-01 12:02:34 +00:00
Andre601 466a24eea3 Bump ExpressionParser to 1.4.3 2024-05-29 15:05:31 +02:00
Andre601 d747a0c19a Merge pull request 'Update maven Docker tag to v3.9.7' (#295) from renovate/maven-3.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/295
2024-05-29 12:21:38 +00:00
Andre601's Bot 59a64620bf Update maven Docker tag to v3.9.7 2024-05-29 12:05:46 +00:00
Andre601 f36b4b4078 Merge pull request 'Update dependency mkdocs-material to v9.5.25' (#292) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/292
2024-05-27 12:03:05 +00:00
Andre601's Bot 9298b0270b Update dependency mkdocs-material to v9.5.25 2024-05-27 12:01:04 +00:00
Andre601 d8dc50ceec Make ProfileEntry nav consistent 2024-05-26 00:30:17 +00:00
Andre601 60be698c61 Upload command hover images 2024-05-25 22:17:57 +00:00
Andre601 0b37e92260 Update docs 2024-05-25 15:51:56 +02:00
Andre601 b7b1b63c4e Bump version 2024-05-25 15:43:54 +02:00
Andre601 98b923aa54 Redo command system and add profiles sub-command 2024-05-25 15:42:57 +02:00
Andre601 b24d7cb849 Simplify folder path retrieval 2024-05-23 14:57:24 +02:00
Andre601 7df7157d5f Fix another wrong folder name and bump version 2024-05-23 14:55:50 +02:00
Andre601 47263746db Merge pull request 'Add MiniMOTD migrator' (#291) from feat/minimotd-migrator into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/291
2024-05-23 12:52:32 +00:00
Andre601 ff06b06966 Fix wrong folder name on Velocity 2024-05-23 14:25:28 +02:00
Andre601 fe42d282d1 Update documentation 2024-05-23 14:19:16 +02:00
Andre601 12df4e49c6 Add serializations 2024-05-22 13:42:20 +02:00
Andre601 06812b2725 Add MiniMOTD migrator 2024-05-21 21:13:04 +02:00
Andre601 93e4ae7ca7 Merge pull request 'Update dependency me.clip:placeholderapi to v2.11.6' (#290) from renovate/me.clip-placeholderapi-2.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/290
2024-05-21 12:04:06 +00:00
Andre601's Bot d57f3f20e3 Update dependency me.clip:placeholderapi to v2.11.6 2024-05-21 12:02:46 +00:00
Andre601 f418fb961b Merge pull request 'Update dependency mkdocs-material to v9.5.24' (#288) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/288
2024-05-20 12:06:14 +00:00
Andre601 267af92ceb Merge pull request 'Update dependency com.google.code.gson:gson to v2.11.0' (#289) from renovate/com.google.code.gson-gson-2.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/289
2024-05-20 12:05:28 +00:00
Andre601's Bot 57448ddaf6 Update dependency com.google.code.gson:gson to v2.11.0 2024-05-20 12:02:53 +00:00
Andre601's Bot 9f40af4553 Update dependency mkdocs-material to v9.5.24 2024-05-20 12:02:42 +00:00
Andre601 e25da2c6c5 Remove unused GitHub Actions label 2024-05-20 11:51:38 +00:00
Andre601 897cccaa86 Update description in renovate.json 2024-05-20 11:50:27 +00:00
Andre601 512efd0efe Merge pull request 'Update dependency eu.kennytv.maintenance:maintenance-api to v4.2.1' (#287) from renovate/eu.kennytv.maintenance-maintenance-api-4.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/287
2024-05-19 12:07:28 +00:00
Andre601's Bot b67fa683c6 Update dependency eu.kennytv.maintenance:maintenance-api to v4.2.1 2024-05-19 12:01:19 +00:00
Andre601 34387925b8 Update docker image to temurin 21 2024-05-17 14:15:36 +02:00
Andre601 303dbc5ae9 Bump version 2024-05-17 14:02:50 +02:00
Andre601 ee565ff6f7 Update Paper API to 1.20.6 and use new BuildInfo class 2024-05-17 14:02:11 +02:00
Andre601 98baaab36a Add LiteBansAPI to jitpack lookup 2024-05-16 12:07:28 +00:00
Andre601 92e9d790a4 Merge pull request 'Update dependency mkdocs-material to v9.5.23' (#286) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/286
2024-05-16 12:05:26 +00:00
Andre601's Bot b8f2e2932b Update dependency mkdocs-material to v9.5.23 2024-05-16 12:02:13 +00:00
Andre601 45f9202bdd Use a normal h1 header here 2024-05-16 12:01:18 +00:00
Andre601 ffeffc70c3 Also update readme itself 2024-05-16 12:01:00 +00:00
Andre601 60080a5af6 Improve Modrinth page 2024-05-16 11:52:46 +00:00
Andre601 1191265c8c Fix missing muteDuration and banDuration placeholders in LiteBansPlaceholders
Also, make ban and mute return String instead of boolean.
2024-05-15 18:23:45 +02:00
Andre601 27dfeea12c Improve formatting page a bit 2024-05-15 16:17:18 +00:00
Andre601 e50ec1632d Add LiteBans support for BanPlugins addon 2024-05-15 17:06:09 +02:00
Andre601 a0d4dedc9d Merge pull request 'Update dependency mkdocs-material to v9.5.22' (#285) from renovate/mkdocs-material-9.x into master
Reviewed-on: https://codeberg.org/Andre601/AdvancedServerList/pulls/285
2024-05-13 12:07:09 +00:00
Andre601's Bot 9eda026738 Update dependency mkdocs-material to v9.5.22 2024-05-13 12:01:27 +00:00
Andre601 f3b81b7cb6 Fix a typo in the migration page of slp 2024-05-13 11:56:42 +00:00
93 changed files with 2435 additions and 976 deletions

No files matched your search

+53 -58
View File
@@ -1,108 +1,103 @@
# 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.
<center><strong><u><font size="6">AdvancedServerList</font ></u></strong></center>
AdvancedServerList is a plugin designed to allow the largest possible customization for your server's appearance in a Player's multiplayer screen.
The plugin offers extensive customization including changing the MOTD, player count text, player count hover and favicon of your server. All while also allowing you to create multiple profiles with priorities and conditions to set when a specific profile should be displayed.
## Supported Platforms
<a href="https://www.spigotmc.org" target="_blank">
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact-minimal/supported/spigot_vector.svg&w=64 alt="platform-spigot" title="Tested on Spigot">
</a>
<a href="https://papermc.io" target="_blank">
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact-minimal/supported/paper_vector.svg&w=64 alt="platform-paper" title="Tested on Paper">
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/supported/paper_vector.svg&h=48" alt="platform-paper" title="Tested on Paper">
</a>
<br>
<a href="https://www.spigotmc.org" target="_blank">
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact-minimal/supported/bungeecord_vector.svg&w=64 alt="platform-bungeecord" title="Tested on BungeeCord">
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/supported/bungeecord_vector.svg&h=48" alt="platform-bungeecord" title="Tested on BungeeCord">
</a>
<br>
<a href="https://www.papermc.io" target="_blank">
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact-minimal/supported/waterfall_vector.svg&w=64 alt="platform-waterfall" title="Tested on Waterfall">
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/supported/waterfall_vector.svg&h=48" alt="platform-waterfall" title="Tested on Waterfall">
</a>
<br>
<a href="https://velocitypowered.com" target="_blank">
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact-minimal/supported/velocity_vector.svg&w=64 alt="platform-velocity" title="Tested on Velocity">
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/supported/velocity_vector.svg&h=48" 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.
## Server List Profiles
> [*Read More*][profiles]
A Server List Profile is a single YAML file located in the plugin's `profiles` folder. It contains settings that allow you to modify the server's appearance within a Player's multiplayer screen.
### 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).
### Priority and Conditions
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.
Each file has a priority and optional condition. The priority is used to determine what file AdvancedServerList should use first - starting from highest number to lowest - with conditions being used to set when the profile should be used.
Once a profile has been found with a condition returning true - which is the default should there be no condition - will AdvancedServerList use said profile.
> [*Read More*][conditions]
> *Read more about [Priority](https://asl.andre601.ch/profiles/#priority) and [Conditions](https://asl.andre601.ch/profiles/#condition)*
### 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.
AdvancedServerList supports two sets of placeholders. The first one being its own placeholders using the `${<type> <values>}` format adobted from BungeeTabListPlus and the second one being placeholders from PlaceholderAPI using its `%<identifier>_<values>%` placeholder format.
> [*Read More*][placeholders]
Note that internal placeholders can be used in all text-based options of a profile, while PlaceholderAPI placeholders can be used in all text-based options except the `condition` one.
As a final note can plugins provide their own placeholders to use within AdvancedServerList by using its API.
> *Read more about [Placeholders](https://asl.andre601.ch/profiles/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]
AdvancedServerList utilizes the MiniMessage formatting to handle colors and formatting of text. This option was chosen over legacy formatting - using `&` character - for being more clear and readable in its design, not to mention having an easier way for more complex features such as RGB gradients.
> *Read more about [Formatting](https://asl.andre601.ch/profiles/formatting/)*
## Dependencies
| Dependency | Platforms | Required? |
|------------------|---------------|-----------|
| [ProtocolLib] | Spigot | Yes |
| [PlaceholderAPI] | Spigot, Paper | No |
| [ViaVersion] | Spigot, Paper | No |
AdvancedServerList soft-depends on the following plugins, meaning their inclusion is not required.
| Plugin | Supported Platforms |
|-------------------------------------------------------------------------|----------------------------------------|
| [PlaceholderAPI](https://hangar.papermc.io/HelpChat/PlaceholderAPI) | Paper |
| [ViaVersion](https://hangar.papermc.io/ViaVersion/ViaVersion) | Paper |
| [PAPIProxyBridge](https://hangar.papermc.io/William278/PAPIProxyBridge) | BungeeCord, Waterfall, Velocity |
| [Maintenance](https://hangar.papermc.io/kennytv/Maintenance) | Paper, BungeeCord, Waterfall, Velocity |
## Statistics
This plugin sends statistics to [bStats] to display.
You can disable this in the global bStats config file located in `/plugins/bstats/`
The plugin sends statistics to [bStats](https://bstats.org) to show.
You can disable the sending of statistics in the global bStats config located inside `/plugins/bstats/`.
- [BungeeCord][bstats-bungee]
- [Paper/Spigot][bstats-spigot]
- [Velocity][bstats-velocity]
You can find the bStats pages of the plugin for the following platforms:
- [Paper](https://bstats.org/plugin/bungeecord/AdvancedServerList/15584)
- [BungeeCord, Waterfall](https://bstats.org/plugin/bungeecord/AdvancedServerList/15585)
- [Velocity](https://bstats.org/plugin/velocity/AdvancedServerList/15587)
## Videos
Do you have your own video to share? Contact me and I will add it to this section.
<details><summary>Click to Show/Hide Videos</summary>
Below can you find a collection of videos made for my plugin. If you made a video and it isn't shown here, let me know and I'll add it.
<details><summary>Click to show/hide Videos</summary>
<p>
Spanish Video by Ajneb97
<iframe width="560" height="auto" src="https://www.youtube.com/embed/rIbljm_4HVI" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
</p>
</details>
## Screenshots
<a href="https://modrinth.com/plugin/advancedserverlist/gallery" target="_blank">
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/cozy/documentation/modrinth-gallery_vector.svg&w=208" alt="gallery" title="Check out the Gallery">
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/documentation/modrinth-gallery_vector.svg&h=48" alt="gallery" title="Check out the Gallery">
</a>
## Support
<a href="https://discord.gg/MyPTjpsgGH" target="_blank">
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact-minimal/social/discord-singular_vector.svg&w=64" alt="discord" title="Join my Discord Server">
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/social/discord-singular_vector.svg&h=48" alt="discord" title="Join the M.O.S.S. Discord Server">
</a>
<br>
<a href="https://app.revolt.chat/invite/74TpERXA" target="_blank">
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact-minimal/social/revolt-singular_vector.svg&w=64" alt="revolt" title="Join my Revolt Server">
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/social/revolt-singular_vector.svg&h=48" alt="revolt" title="Join my Revolt Server">
</a>
<br>
<a href="https://blobfox.coffee/@andre_601" target="_blank">
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact-minimal/social/mastodon-singular_vector.svg&w=64" alt="revolt" title="Chat with me on Mastodon">
</a>
<!-- Links -->
[profiles]: https://docs.andre601.ch/AdvancedServerList/latest/profiles
[conditions]: https://docs.andre601.ch/AdvancedServerList/latest/profiles/#conditions
[placeholders]: https://docs.andre601.ch/AdvancedServerList/latest/profiles/placeholders
[minimessage]: https://docs.andre601.ch/AdvancedServerList/latest/profiles/formatting
[protocollib]: https://www.spigotmc.org/resources/1997/
[placeholderapi]: https://www.spigotmc.org/resources/6245/
[viaversion]: https://www.spigotmc.org/resources/19254/
[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
<img src="https://wsrv.nl/?url=https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/social/mastodon-singular_vector.svg&h=48" alt="revolt" title="Chat with me on Mastodon">
</a>
Binary file not shown.

After

Width:  |  Height:  |  Size: 876 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 877 KiB

+2 -2
View File
@@ -11,7 +11,7 @@ variables:
steps:
- name: "Clone Preview Repository"
image: alpine:3.18.4
image: alpine:3.20.3
commands:
- chmod -R a+w .
- <<: *setup_git
@@ -24,7 +24,7 @@ steps:
settings:
pip_install_file: requirements.txt
- name: "Commit and Push"
image: alpine:3.18.4
image: alpine:3.20.3
secrets:
- bot_token
commands:
+2 -2
View File
@@ -4,7 +4,7 @@ when:
steps:
- name: "Build Jar and Upload"
image: maven:3.9.6-eclipse-temurin-17
image: maven:3.9.9-eclipse-temurin-21
secrets:
- modrinth_api_token
- hangar_api_token
@@ -34,7 +34,7 @@ steps:
when:
- status: ["success"]
settings:
server_url: https://blobfox.coffee
server_url: https://swiss.social
access_token:
from_secret: mastodon_token
status: |-
+2 -2
View File
@@ -12,7 +12,7 @@ variables:
steps:
- name: "Clone target Repository"
image: alpine:3.18.4
image: alpine:3.20.3
commands:
- chmod -R a+w .
- <<: *setup_git
@@ -23,7 +23,7 @@ steps:
settings:
pip_install_file: requirements.txt
- name: "Commit and Push"
image: alpine:3.18.4
image: alpine:3.20.3
secrets:
- bot_token
commands:
+57 -63
View File
@@ -1,119 +1,113 @@
# AdvancedServerList
AdvancedServerList is a plugin that allows you to customize your server's MOTD, favicon, Player count text and player count hover displayed in a player's multiplayer server list based on conditions and priorities.
AdvancedServerList is a plugin designed to allow the largest possible customization for your server's appearance in a Player's multiplayer screen.
The plugin offers extensive customization including changing the MOTD, player count text, player count hover and favicon of your server. All while also allowing you to create multiple profiles with priorities and conditions to set when a specific profile should be displayed.
## Downloads
<a href="https://modrinth.com/plugin/advancedserverlist" target="_blank">
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact/available/modrinth_vector.svg" height="46" alt="modrinth" title="Available on Modrinth">
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact/available/modrinth_vector.svg" height="48" alt="modrinth" title="Available on Modrinth">
</a>
<br>
<a href="https://hangar.papermc.io/Andre_601/AdvancedServerList" target="_blank">
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact/available/hangar_vector.svg" height="46" alt="hangar" title="Available on Hangar">
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact/available/hangar_vector.svg" height="48" alt="hangar" title="Available on Hangar">
</a>
## Supported Platforms
<a href="https://papermc.io" target="_blank">
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact-minimal/supported/paper_vector.svg" height="64" alt="platform-paper" title="Tested on Paper">
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/supported/paper_vector.svg" height="48" alt="platform-paper" title="Tested on Paper">
</a>
<br>
<a href="https://www.spigotmc.org" target="_blank">
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact-minimal/supported/bungeecord_vector.svg" height="64" alt="platform-bungeecord" title="Tested on BungeeCord">
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/supported/bungeecord_vector.svg" height="48" alt="platform-bungeecord" title="Tested on BungeeCord">
</a>
<br>
<a href="https://www.papermc.io" target="_blank">
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact-minimal/supported/waterfall_vector.svg" height="64" alt="platform-waterfall" title="Tested on Waterfall">
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/supported/waterfall_vector.svg" height="48" alt="platform-waterfall" title="Tested on Waterfall">
</a>
<br>
<a href="https://velocitypowered.com" target="_blank">
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact-minimal/supported/velocity_vector.svg" height="64" alt="platform-velocity" title="Tested on Velocity">
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/supported/velocity_vector.svg" height="48" alt="platform-velocity" title="Tested on Velocity">
</a>
## What is a Server List Profile?
## Server List Profiles
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.
A Server List Profile is a single YAML file located in the plugin's `profiles` folder. It contains settings that allow you to modify the server's appearance within a Player's multiplayer screen.
> [*Read More*][profiles]
### Priority and Conditions
### Conditions
Each file has a priority and optional condition. The priority is used to determine what file AdvancedServerList should use first - starting from highest number to lowest - with conditions being used to set when the profile should be used.
Once a profile has been found with a condition returning true - which is the default should there be no condition - will AdvancedServerList use said profile.
Thanks to conditions can you determine when a profile should be displayed in the player's server list, to allow displaying specific text (i.e. a warning when they are using an outdated version).
When multiple profiles exist that have valid conditions will the one with the highest priority (Higher number = higher priority) be selected. Having no conditions makes it automatically true.
> [*Read More*][conditions]
> *Read more about [Priority](https://asl.andre601.ch/profiles/#priority) and [Conditions](https://asl.andre601.ch/profiles/#condition)*
### Placeholders
Placeholders can be used within conditions to further customize them. They can also be used in any other text option to display their respective values.
The format is `${<target> <identifier>}` which was adopted from BungeeTabListPlus. Depending on what platform you use the plugin on are only specific placeholders available.
AdvancedServerList supports two sets of placeholders. The first one being its own placeholders using the `${<type> <values>}` format adobted from BungeeTabListPlus and the second one being placeholders from PlaceholderAPI using its `%<identifier>_<values>%` placeholder format.
When using the SpigotMC/PaperMC version, or while [PAPIProxyBridge][papiproxybridge] is installed on your proxy, can you also use placeholders from [PlaceholderAPI][placeholderapi] using its `%<identifier>_<values>%` placeholder format. PlaceholderAPI needs to be installed on the server (not proxy) for that.
Note that internal placeholders can be used in all text-based options of a profile, while PlaceholderAPI placeholders can be used in all text-based options except the `condition` one.
As a final note can plugins provide their own placeholders to use within AdvancedServerList by using its API.
If you're a plugin dev can you even add your own custom placeholders through AdvancedServerList's own API.
> [*Read More*][placeholders]
> *Read more about [Placeholders](https://asl.andre601.ch/profiles/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.
AdvancedServerList utilizes the MiniMessage formatting to handle colors and formatting of text. This option was chosen over legacy formatting - using `&` character - for being more clear and readable in its design, not to mention having an easier way for more complex features such as RGB gradients.
> [*Read More*][minimessage]
> *Read more about [Formatting](https://asl.andre601.ch/profiles/formatting/)*
## Dependencies
All listed dependencies are optional.
AdvancedServerList soft-depends on the following plugins, meaning their inclusion is not required.
| Dependency | Platforms |
|-------------------|----------------------|
| [PlaceholderAPI] | Paper |
| [ViaVersion] | Paper |
| [PAPIProxyBridge] | BungeeCord, Velocity |
| [Maintenance] | All |
| Plugin | Supported Platforms |
|-------------------------------------------------------------------------|----------------------------------------|
| [PlaceholderAPI](https://hangar.papermc.io/HelpChat/PlaceholderAPI) | Paper |
| [ViaVersion](https://hangar.papermc.io/ViaVersion/ViaVersion) | Paper |
| [PAPIProxyBridge](https://hangar.papermc.io/William278/PAPIProxyBridge) | BungeeCord, Waterfall, Velocity |
| [Maintenance](https://hangar.papermc.io/kennytv/Maintenance) | Paper, BungeeCord, Waterfall, Velocity |
## Statistics
This plugin sends statistics to [bStats] to display.
You can disable this in the global bStats config file located in `/plugins/bstats/`
The plugin sends statistics to [bStats](https://bstats.org) to show.
You can disable the sending of statistics in the global bStats config located inside `/plugins/bstats/`.
- [BungeeCord][bstats-bungee]
- [Paper/Spigot][bstats-spigot]
- [Velocity][bstats-velocity]
You can find the bStats pages of the plugin for the following platforms:
- [Paper](https://bstats.org/plugin/bungeecord/AdvancedServerList/15584)
- [BungeeCord, Waterfall](https://bstats.org/plugin/bungeecord/AdvancedServerList/15585)
- [Velocity](https://bstats.org/plugin/velocity/AdvancedServerList/15587)
## Videos
Below can you find a collection of videos made for my plugin. If you made a video and it isn't shown here, let me know and I'll add it.
<details><summary>Click to show/hide Videos</summary>
<p>
Spanish Video by Ajneb97
[![video thumbnail](https://img.youtube.com/vi/rIbljm_4HVI/0.jpg)](https://youtube.com/watch?v=rIbljm_4HVI)
</p>
</details>
## Screenshots
<a href="https://modrinth.com/plugin/advancedserverlist/gallery" target="_blank">
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/cozy/documentation/modrinth-gallery_vector.svg" height="64" alt="gallery" title="Check out the Gallery">
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/documentation/modrinth-gallery_vector.svg" height="48" alt="gallery" title="Check out the Gallery">
</a>
## Support
<a href="https://discord.gg/MyPTjpsgGH" target="_blank">
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact-minimal/social/discord-singular_vector.svg" height="64" alt="discord" title="Join the M.O.S.S. Discord Server">
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/social/discord-singular_vector.svg" height="48" alt="discord" title="Join the M.O.S.S. Discord Server">
</a>
<br>
<a href="https://app.revolt.chat/invite/74TpERXA" target="_blank">
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact-minimal/social/revolt-singular_vector.svg" height="64" alt="revolt" title="Join my Revolt Server">
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/social/revolt-singular_vector.svg" height="48" alt="revolt" title="Join my Revolt Server">
</a>
<br>
<a href="https://blobfox.coffee/@andre_601" target="_blank">
<img src="https://cdn.jsdelivr.net/gh/Andre601/devins-badges@13e0142/assets/compact-minimal/social/mastodon-singular_vector.svg" height="64" alt="mastodon" title="Chat with me on Mastodon">
</a>
<!-- Links -->
[profiles]: https://asl.andre601.ch/profiles/
[conditions]: https://asl.andre601.ch/profiles/#condition
[placeholders]: https://asl.andre601.ch/profiles/placeholders/
[minimessage]: https://asl.andre601.ch/profiles/formatting/
[modrinth]: https://modrinth.com/plugin/advancedserverlist
[placeholderapi]: https://hangar.papermc.io/HelpChat/PlaceholderAPI
[viaversion]: https://hangar.papermc.io/ViaVersion/ViaVersion
[papiproxybridge]: https://hangar.papermc.io/William278/PAPIProxyBridge
[maintenance]: https://hangar.papermc.io/kennytv/Maintenance
[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
<img src="https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/social/mastodon-singular_vector.svg" height="48" alt="revolt" title="Chat with me on Mastodon">
</a>
+58
View File
@@ -0,0 +1,58 @@
# Supported Versions
To ensure proper safety and support are only certain versions and Platforms of AdvancedServerList maintained and supported.
## Supported Plugin Versions
| Major Version | Supported |
|---------------|-----------|
| v4 | Yes |
| v3 | Yes* |
| v2 | No |
| v1 | No |
\*Only receives support but no updates or bug fixes.
## Supported Server/Proxy Versions
| Server/Proxy Version* | Supported |
|-----------------------|-----------|
| 1.21.x | Yes |
| 1.20.x | Yes |
| 1.19.x | No |
| 1.18.x | No |
| 1.17.x | No |
| 1.16.x | No |
| 1.15.x | No |
| 1.14.x | No |
| 1.13.x | No |
| 1.12.x | No |
| 1.11.x | No |
| 1.10.x | No |
| 1.19.x | No |
| 1.8.x | No |
\*Only the latest patch version is actively supported should "Supported" have "Yes".
## Supported Platforms
### Servers
| Server | Supported |
|--------|-----------|
| Spigot | No |
| Paper | Yes |
| Purpur | Yes* |
| Mohist | No |
\*Support hasn't actively been tested, but should work without issues.
### Proxies
| Proxy | Supported |
|------------|-----------|
| BungeeCord | Yes** |
| Waterfall | Yes** |
| Velocity | Yes |
\*\*Platform version of this plugin is maintenance only, not receiving any bug fixes for major breaking changes anymore.
+8 -2
View File
@@ -52,7 +52,7 @@
</repository>
<repository>
<id>papermc</id>
<url>https://papermc.io/repo/repository/maven-public/</url>
<url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
<repository>
<id>libertybans</id>
@@ -79,7 +79,7 @@
<dependency>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.21-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -102,6 +102,12 @@
<version>1.1.0-RC1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.gitlab.ruany</groupId>
<artifactId>LiteBansAPI</artifactId>
<version>0.5.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>ch.andre601.asl-api</groupId>
<artifactId>api</artifactId>
@@ -23,35 +23,48 @@
*
*/
package ch.andre601.advancedserverlist.banplugins.bungeecord;
package ch.andre601.advancedserverlist.banplugins;
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
import ch.andre601.advancedserverlist.banplugins.placeholders.AdvancedBanPlaceholders;
import ch.andre601.advancedserverlist.banplugins.placeholders.LibertyBansPlaceholders;
import ch.andre601.advancedserverlist.banplugins.placeholders.LiteBansPlaceholders;
import java.util.HashMap;
import java.util.Map;
public enum BungeeCordBanPlugins{
public enum BanPluginsList{
ADVANCED_BAN("AdvancedBan", new AdvancedBanPlaceholders()),
LIBERTY_BANS("LibertyBans", new LibertyBansPlaceholders());
ADVANCED_BAN("AdvancedBan", new AdvancedBanPlaceholders(), true, true, false),
LIBERTY_BANS("LibertyBans", new LibertyBansPlaceholders(), true, true, true),
LITE_BANS("LiteBans", new LiteBansPlaceholders(), true, true, true);
private final String plugin;
private final String name;
private final PlaceholderProvider placeholderProvider;
private final boolean paper, bungeecord, velocity;
BungeeCordBanPlugins(String plugin, PlaceholderProvider placeholderProvider){
this.plugin = plugin;
BanPluginsList(String name, PlaceholderProvider placeholderProvider, boolean paper, boolean bungeecord, boolean velocity){
this.name = name;
this.placeholderProvider = placeholderProvider;
this.paper = paper;
this.bungeecord = bungeecord;
this.velocity = velocity;
}
public static Map<String, PlaceholderProvider> getBanPlugins(){
Map<String, PlaceholderProvider> content = new HashMap<>();
for(BungeeCordBanPlugins bungeeCordBanPlugins : BungeeCordBanPlugins.values()){
content.put(bungeeCordBanPlugins.plugin, bungeeCordBanPlugins.placeholderProvider);
}
return content;
public String getName(){
return name;
}
public PlaceholderProvider getPlaceholderProvider(){
return placeholderProvider;
}
public boolean supportsPaper(){
return paper;
}
public boolean supportsBungeeCord(){
return bungeecord;
}
public boolean supportsVelocity(){
return velocity;
}
}
@@ -26,11 +26,9 @@
package ch.andre601.advancedserverlist.banplugins.bungeecord;
import ch.andre601.advancedserverlist.api.AdvancedServerListAPI;
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
import ch.andre601.advancedserverlist.banplugins.BanPluginsList;
import net.md_5.bungee.api.plugin.Plugin;
import java.util.Map;
public class BungeeCordBanPluginsAddon extends Plugin{
@Override
@@ -50,14 +48,16 @@ public class BungeeCordBanPluginsAddon extends Plugin{
private int loadPlaceholderProviders(){
int loaded = 0;
Map<String, PlaceholderProvider> banPlugins = BungeeCordBanPlugins.getBanPlugins();
AdvancedServerListAPI api = AdvancedServerListAPI.get();
for(Map.Entry<String, PlaceholderProvider> entry : banPlugins.entrySet()){
if(getProxy().getPluginManager().getPlugin(entry.getKey()) != null){
getLogger().info("Registering Placeholders for " + entry.getKey() + "...");
api.addPlaceholderProvider(entry.getValue());
getLogger().info("Placeholder successfully registered!");
for(BanPluginsList entry : BanPluginsList.values()){
if(!entry.supportsBungeeCord())
continue;
if(getProxy().getPluginManager().getPlugin(entry.getName()) != null){
getLogger().info("Registering Placeholders for " + entry.getName() + "...");
api.addPlaceholderProvider(entry.getPlaceholderProvider());
getLogger().info("Placeholders successfully registered!");
loaded++;
}
@@ -1,57 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022-2024 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.banplugins.paper;
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
import ch.andre601.advancedserverlist.banplugins.placeholders.AdvancedBanPlaceholders;
import ch.andre601.advancedserverlist.banplugins.placeholders.LibertyBansPlaceholders;
import java.util.HashMap;
import java.util.Map;
public enum PaperBanPlugins{
ADVANCED_BAN("AdvancedBan", new AdvancedBanPlaceholders()),
LIBERTY_BANS("LibertyBans", new LibertyBansPlaceholders());
private final String plugin;
private final PlaceholderProvider placeholderProvider;
PaperBanPlugins(String plugin, PlaceholderProvider placeholderProvider){
this.plugin = plugin;
this.placeholderProvider = placeholderProvider;
}
public static Map<String, PlaceholderProvider> getBanPlugins(){
Map<String, PlaceholderProvider> content = new HashMap<>();
for(PaperBanPlugins paperBanPlugins : PaperBanPlugins.values()){
content.put(paperBanPlugins.plugin, paperBanPlugins.placeholderProvider);
}
return content;
}
}
@@ -26,11 +26,9 @@
package ch.andre601.advancedserverlist.banplugins.paper;
import ch.andre601.advancedserverlist.api.AdvancedServerListAPI;
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
import ch.andre601.advancedserverlist.banplugins.BanPluginsList;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.Map;
public class PaperBanPluginsAddon extends JavaPlugin{
@Override
@@ -53,14 +51,16 @@ public class PaperBanPluginsAddon extends JavaPlugin{
private int loadPlaceholderProviders(){
int loaded = 0;
Map<String, PlaceholderProvider> banPlugins = PaperBanPlugins.getBanPlugins();
AdvancedServerListAPI api = AdvancedServerListAPI.get();
for(Map.Entry<String, PlaceholderProvider> entry : banPlugins.entrySet()){
if(getServer().getPluginManager().isPluginEnabled(entry.getKey())){
getLogger().info("Registering Placeholders for " + entry.getKey() + "...");
api.addPlaceholderProvider(entry.getValue());
getLogger().info("Placeholder successfully registered!");
for(BanPluginsList entry : BanPluginsList.values()){
if(!entry.supportsPaper())
continue;
if(getServer().getPluginManager().isPluginEnabled(entry.getName())){
getLogger().info("Registering Placeholders for " + entry.getName() + "...");
api.addPlaceholderProvider(entry.getPlaceholderProvider());
getLogger().info("Placeholders successfully registered!");
loaded++;
}
@@ -32,7 +32,7 @@ import ch.andre601.advancedserverlist.banplugins.providers.AdvancedBanProvider;
public class AdvancedBanPlaceholders extends PlaceholderProvider{
private final AdvancedBanProvider provider = new AdvancedBanProvider();
private AdvancedBanProvider provider = null;
public AdvancedBanPlaceholders(){
super("advancedban");
@@ -40,11 +40,14 @@ public class AdvancedBanPlaceholders extends PlaceholderProvider{
@Override
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
if(provider == null)
provider = new AdvancedBanProvider();
String[] args = placeholder.split("\\s", 2);
return switch(args[0]) {
// Mute-related placeholders
case "isMuted" -> String.valueOf(provider.muted(player));
case "isMuted" -> provider.muted(player);
case "muteReason" -> provider.muteReason(player);
case "muteDuration" -> {
if(args.length == 1)
@@ -61,7 +64,7 @@ public class AdvancedBanPlaceholders extends PlaceholderProvider{
}
// Ban-related placeholders
case "isBanned" -> String.valueOf(provider.banned(player));
case "isBanned" -> provider.banned(player);
case "banReason" -> provider.banReason(player);
case "banDuration" -> {
if(args.length == 1)
@@ -32,7 +32,7 @@ import ch.andre601.advancedserverlist.banplugins.providers.LibertyBansProvider;
public class LibertyBansPlaceholders extends PlaceholderProvider{
private final LibertyBansProvider provider = LibertyBansProvider.create();
private LibertyBansProvider provider = null;
public LibertyBansPlaceholders(){
super("libertybans");
@@ -40,11 +40,14 @@ public class LibertyBansPlaceholders extends PlaceholderProvider{
@Override
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
if(provider == null)
provider = LibertyBansProvider.create();
String[] args = placeholder.split("\\s", 2);
return switch(args[0]){
// Mute-related placeholders
case "isMuted" -> String.valueOf(provider.muted(player));
case "isMuted" -> provider.muted(player);
case "muteReason" -> provider.muteReason(player);
case "muteExpiration" -> {
if(args.length == 1)
@@ -54,7 +57,7 @@ public class LibertyBansPlaceholders extends PlaceholderProvider{
}
// Ban-related placeholders
case "isBanned" -> String.valueOf(provider.banned(player));
case "isBanned" -> provider.banned(player);
case "banReason" -> provider.banReason(player);
case "banExpiration" -> {
if(args.length == 1)
@@ -0,0 +1,87 @@
/*
* MIT License
*
* Copyright (c) 2022-2024 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.banplugins.placeholders;
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.banplugins.providers.LiteBansProvider;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
public class LiteBansPlaceholders extends PlaceholderProvider{
private LiteBansProvider provider = null;
public LiteBansPlaceholders(){
super("litebans");
}
@Override
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
if(provider == null)
provider = new LiteBansProvider();
String[] args = placeholder.split("\\s", 2);
CompletableFuture<String> future = CompletableFuture.supplyAsync(() ->
switch(args[0]){
// Mute-related placeholders
case "isMuted" -> provider.muted(player);
case "muteReason" -> provider.muteReason(player);
case "muteDuration" -> provider.muteDuration(player);
case "muteExpiration" -> {
if(args.length == 1)
yield provider.muteExpirationDate(player);
yield provider.muteExpirationDate(player, args[1]);
}
// Ban-related placeholders
case "isBanned" -> provider.banned(player);
case "banReason" -> provider.banReason(player);
case "banDuration" -> provider.banDuration(player);
case "banExpiration" -> {
if(args.length == 1)
yield provider.banExpirationDate(player);
yield provider.banExpirationDate(player, args[1]);
}
//Unknown/Invalid placeholder
default -> null;
}
);
try{
return future.join();
}catch(CancellationException | CompletionException ex){
return null;
}
}
}
@@ -58,13 +58,13 @@ public class AdvancedBanProvider implements PunishmentProvider{
}
@Override
public boolean muted(GenericPlayer player){
return getAPI().isMuted(noDashesUUID(player.getUUID()));
public String muted(GenericPlayer player){
return String.valueOf(getAPI().isMuted(noDashesUUID(player.getUUID())));
}
@Override
public boolean banned(GenericPlayer player){
return getAPI().isBanned(noDashesUUID(player.getUUID()));
public String banned(GenericPlayer player){
return String.valueOf(getAPI().isBanned(noDashesUUID(player.getUUID())));
}
@Override
@@ -53,13 +53,13 @@ public class LibertyBansProvider implements PunishmentProvider{
}
@Override
public boolean muted(GenericPlayer player){
return punishment(player.getUUID(), PunishmentType.MUTE) != null;
public String muted(GenericPlayer player){
return String.valueOf(punishment(player.getUUID(), PunishmentType.MUTE) != null);
}
@Override
public boolean banned(GenericPlayer player){
return punishment(player.getUUID(), PunishmentType.BAN) != null;
public String banned(GenericPlayer player){
return String.valueOf(punishment(player.getUUID(), PunishmentType.BAN) != null);
}
@Override
@@ -0,0 +1,103 @@
/*
* MIT License
*
* Copyright (c) 2022-2024 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.banplugins.providers;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import litebans.api.Database;
import litebans.api.Entry;
public class LiteBansProvider implements PunishmentProvider{
@Override
public String muted(GenericPlayer player){
return String.valueOf(Database.get().isPlayerMuted(player.getUUID(), null));
}
@Override
public String banned(GenericPlayer player){
return String.valueOf(Database.get().isPlayerBanned(player.getUUID(), null));
}
@Override
public String muteReason(GenericPlayer player){
Entry mute = Database.get().getMute(player.getUUID(), null, null);
if(mute == null)
return null;
return mute.getReason();
}
@Override
public String banReason(GenericPlayer player){
Entry ban = Database.get().getBan(player.getUUID(), null, null);
if(ban == null)
return null;
return ban.getReason();
}
@Override
public String muteDuration(GenericPlayer player){
Entry mute = Database.get().getMute(player.getUUID(), null, null);
if(mute == null)
return null;
return mute.getDurationString();
}
@Override
public String banDuration(GenericPlayer player){
Entry ban = Database.get().getBan(player.getUUID(), null, null);
if(ban == null)
return null;
return ban.getDurationString();
}
@Override
public String muteExpirationDate(GenericPlayer player, String pattern){
Entry mute = Database.get().getMute(player.getUUID(), null, null);
if(mute == null)
return null;
if(mute.isPermanent())
return "never";
return this.returnDate(pattern, mute.getDateEnd());
}
@Override
public String banExpirationDate(GenericPlayer player, String pattern){
Entry ban = Database.get().getBan(player.getUUID(), null, null);
if(ban == null)
return null;
if(ban.isPermanent())
return "never";
return this.returnDate(pattern, ban.getDateEnd());
}
}
@@ -32,9 +32,9 @@ import java.util.Date;
public interface PunishmentProvider{
boolean muted(GenericPlayer player);
String muted(GenericPlayer player);
boolean banned(GenericPlayer player);
String banned(GenericPlayer player);
String muteReason(GenericPlayer player);
@@ -1,56 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022-2024 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.banplugins.velocity;
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
import ch.andre601.advancedserverlist.banplugins.paper.PaperBanPlugins;
import ch.andre601.advancedserverlist.banplugins.placeholders.LibertyBansPlaceholders;
import java.util.HashMap;
import java.util.Map;
public enum VelocityBanPlugins{
LIBERTY_BANS("libertybans", new LibertyBansPlaceholders());
private final String plugin;
private final PlaceholderProvider placeholderProvider;
VelocityBanPlugins(String plugin, PlaceholderProvider placeholderProvider){
this.plugin = plugin;
this.placeholderProvider = placeholderProvider;
}
public static Map<String, PlaceholderProvider> getBanPlugins(){
Map<String, PlaceholderProvider> content = new HashMap<>();
for(VelocityBanPlugins velocityBanPlugins : VelocityBanPlugins.values()){
content.put(velocityBanPlugins.plugin, velocityBanPlugins.placeholderProvider);
}
return content;
}
}
@@ -26,15 +26,15 @@
package ch.andre601.advancedserverlist.banplugins.velocity;
import ch.andre601.advancedserverlist.api.AdvancedServerListAPI;
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
import ch.andre601.advancedserverlist.banplugins.BanPluginsList;
import com.google.inject.Inject;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import net.md_5.bungee.api.ProxyServer;
import com.velocitypowered.api.proxy.ProxyServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.Locale;
public class VelocityBanPluginsAddon{
@@ -49,7 +49,7 @@ public class VelocityBanPluginsAddon{
@Subscribe
public void init(ProxyInitializeEvent event){
if(proxy.getPluginManager().getPlugin("advancedserverlist") == null){
if(!proxy.getPluginManager().isLoaded("advancedserverlist")){
logger.warn("AdvancedServerList is not enabled. This plugin requires it to function!");
return;
}
@@ -64,14 +64,16 @@ public class VelocityBanPluginsAddon{
private int loadPlaceholderProviders(){
int loaded = 0;
Map<String, PlaceholderProvider> banPlugins = VelocityBanPlugins.getBanPlugins();
AdvancedServerListAPI api = AdvancedServerListAPI.get();
for(Map.Entry<String, PlaceholderProvider> entry : banPlugins.entrySet()){
if(proxy.getPluginManager().getPlugin(entry.getKey()) != null){
logger.info("Registering placeholders for {}...", entry.getKey());
api.addPlaceholderProvider(entry.getValue());
logger.info("Placeholder successfully registered!");
for(BanPluginsList entry : BanPluginsList.values()){
if(!entry.supportsVelocity())
continue;
if(proxy.getPluginManager().isLoaded(entry.getName().toLowerCase(Locale.ROOT))){
logger.info("Registering Placeholders for " + entry.getName() + "...");
api.addPlaceholderProvider(entry.getPlaceholderProvider());
logger.info("Placeholders successfully registered!");
loaded++;
}
@@ -7,5 +7,6 @@ softDepends:
- AdvancedServerList
- AdvancedBan
- LibertyBans
- LiteBans
main: 'ch.andre601.advancedserverlist.banplugins.bungeecord.BungeeCordBanPluginsAddon'
@@ -2,7 +2,7 @@ name: 'ASLBanPluginsAddon'
author: 'Andre_601'
version: '${plugin.version}'
main: 'ch.andre601.advancedserverlist.banplugins.paper.AdvancedBanPlaceholders'
main: 'ch.andre601.advancedserverlist.banplugins.paper.PaperBanPluginsAddon'
api-version: '1.19'
@@ -11,9 +11,12 @@ dependencies:
AdvancedServerList:
required: false
load: BEFORE
AdvancedBans:
AdvancedBan:
required: false
load: BEFORE
LibertyBans:
required: false
load: BEFORE
LiteBans:
required: false
load: BEFORE
@@ -14,6 +14,10 @@
{
"id": "libertybans",
"optional": true
},
{
"id": "litebans",
"optional": true
}
],
"main": "ch.andre601.advancedserverlist.banplugins.velocity.VelocityBanPluginsAddon"
+3 -7
View File
@@ -49,10 +49,6 @@
<id>sonatype</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</repository>
<repository>
<id>sonatype-snapshots</id>
<url>https://s01.oss.sonatype.org/content/repositories/snapshots/</url>
</repository>
</repositories>
<dependencies>
@@ -85,7 +81,7 @@
<scope>provided</scope>
</dependency>
<!-- Adventure Library. Needs to be shaded in -->
<!-- Adventure Library -->
<dependency>
<groupId>net.kyori</groupId>
<artifactId>adventure-api</artifactId>
@@ -109,7 +105,7 @@
<dependency>
<groupId>org.bstats</groupId>
<artifactId>bstats-bungeecord</artifactId>
<version>3.0.2</version>
<version>3.1.0</version>
<scope>compile</scope>
</dependency>
@@ -155,7 +151,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.3</version>
<version>3.6.0</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
@@ -30,15 +30,18 @@ import ch.andre601.advancedserverlist.bungeecord.listeners.JoinEvent;
import ch.andre601.advancedserverlist.bungeecord.listeners.PingEvent;
import ch.andre601.advancedserverlist.bungeecord.logging.BungeeLogger;
import ch.andre601.advancedserverlist.bungeecord.objects.placeholders.BungeePlayerPlaceholders;
import ch.andre601.advancedserverlist.bungeecord.objects.placeholders.BungeeProxyPlaceholders;
import ch.andre601.advancedserverlist.bungeecord.objects.placeholders.BungeeServerPlaceholders;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
import ch.andre601.advancedserverlist.core.profiles.favicon.FaviconHandler;
import ch.andre601.advancedserverlist.core.profiles.handlers.FaviconHandler;
import com.alessiodp.libby.BungeeLibraryManager;
import com.alessiodp.libby.Library;
import de.myzelyam.api.vanish.BungeeVanishAPI;
import net.kyori.adventure.platform.bungeecord.BungeeAudiences;
import net.md_5.bungee.api.Favicon;
import net.md_5.bungee.api.ServerPing;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Plugin;
@@ -49,15 +52,22 @@ import java.awt.image.BufferedImage;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
private final PluginLogger logger = new BungeeLogger(this);
private final Map<String, ServerPing> fetchedServers = new ConcurrentHashMap<>();
private boolean successfulLoad = false;
private AdvancedServerList<Favicon> core;
private FaviconHandler<Favicon> faviconHandler = null;
private BungeeAudiences audiences = null;
private final PluginLogger logger = new BungeeLogger(this);
private BungeeLibraryManager libraryManager = null;
@Override
public void onLoad(){
@@ -79,12 +89,14 @@ public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
}
this.audiences = BungeeAudiences.create(this);
this.core = AdvancedServerList.init(this, BungeePlayerPlaceholders.init(), BungeeServerPlaceholders.init(this));
this.core = AdvancedServerList.init(this,
BungeePlayerPlaceholders.init(), BungeeServerPlaceholders.init(this), BungeeProxyPlaceholders.init(this));
}
@Override
public void onDisable(){
core.disable();
getProxy().getScheduler().cancel(this);
}
@Override
@@ -119,6 +131,28 @@ public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
faviconHandler.cleanCache();
}
@Override
public void downloadLibrary(String groupId, String artifactId, String version){
if(libraryManager == null){
libraryManager = new BungeeLibraryManager(this);
libraryManager.addRepository("https://repo.papermc.io/repository/maven-public");
}
Library lib = Library.builder()
.groupId(groupId)
.artifactId(artifactId)
.version(version)
.resolveTransitiveDependencies(true)
.build();
libraryManager.loadLibrary(lib);
}
@Override
public void startScheduler(){
getProxy().getScheduler().schedule(this, this::fetchServers, 0, 10, TimeUnit.SECONDS);
}
@Override
public AdvancedServerList<Favicon> getCore(){
return core;
@@ -143,13 +177,8 @@ public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
}
@Override
public String getPlatformName(){
return getProxy().getName();
}
@Override
public String getPlatformVersion(){
return getProxy().getVersion();
public String getPlatformInfo(){
return getProxy().getName() + " " + getProxy().getVersion();
}
@Override
@@ -182,9 +211,17 @@ public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
return players.size();
}
public Map<String, ServerPing> getFetchedServers(){
return fetchedServers;
}
private boolean loadLibs(){
try{
BungeeLibraryManager libraryManager = new BungeeLibraryManager(this);
if(libraryManager == null){
libraryManager = new BungeeLibraryManager(this);
libraryManager.addRepository("https://repo.papermc.io/repository/maven-public");
}
libraryManager.configureFromJSON("dependencies.json");
return true;
@@ -193,4 +230,14 @@ public class BungeeCordCore extends Plugin implements PluginCore<Favicon>{
return false;
}
}
private void fetchServers(){
fetchedServers.clear();
getProxy().getServers().forEach((name, server) -> server.ping((ping, throwable) -> {
if(throwable != null)
return;
fetchedServers.put(name, ping);
}));
}
}
@@ -31,7 +31,8 @@ import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
import ch.andre601.advancedserverlist.bungeecord.objects.impl.BungeePlayerImpl;
import ch.andre601.advancedserverlist.bungeecord.objects.impl.BungeeProxyImpl;
import ch.andre601.advancedserverlist.core.events.PingEventHandler;
import ch.andre601.advancedserverlist.core.compat.maintenance.MaintenanceUtil;
import ch.andre601.advancedserverlist.core.compat.papi.PAPIUtil;
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
import ch.andre601.advancedserverlist.core.interfaces.events.GenericEventWrapper;
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
@@ -78,6 +79,11 @@ public class BungeeEventWrapper implements GenericEventWrapper<Favicon, BungeePl
ping.getPlayers().setMax(maxPlayers);
}
@Override
public void setOnlinePlayers(int onlinePlayers){
ping.getPlayers().setOnline(onlinePlayers);
}
@Override
public void setMotd(Component component){
ping.setDescriptionComponent(new TextComponent(BungeeComponentSerializer.get().serialize(component)));
@@ -101,6 +107,7 @@ public class BungeeEventWrapper implements GenericEventWrapper<Favicon, BungeePl
for(int i = 0; i < players.length; i++){
String parsed = ComponentParser.text(lines.get(i))
.modifyText(text -> StringReplacer.replace(text, player, server))
.modifyText(text -> parsePAPIPlaceholders(text, player))
.toString();
ServerPing.PlayerInfo pi = new ServerPing.PlayerInfo(parsed, UUID.randomUUID());
@@ -137,7 +144,7 @@ public class BungeeEventWrapper implements GenericEventWrapper<Favicon, BungeePl
if(plugin.getProxy().getPluginManager().getPlugin("Maintenance") == null)
return false;
return PingEventHandler.getMaintenanceUtil().isMaintenanceEnabled();
return MaintenanceUtil.get().isMaintenanceEnabled();
}
@Override
@@ -165,10 +172,10 @@ public class BungeeEventWrapper implements GenericEventWrapper<Favicon, BungeePl
if(plugin.getProxy().getPluginManager().getPlugin("PAPIProxyBridge") == null)
return text;
if(!PingEventHandler.getPAPIUtil().isCompatible())
if(!PAPIUtil.get().isCompatible())
return text;
String server = PingEventHandler.getPAPIUtil().getServer();
String server = PAPIUtil.get().getServer();
if(server == null || server.isEmpty())
return text;
@@ -176,11 +183,11 @@ public class BungeeEventWrapper implements GenericEventWrapper<Favicon, BungeePl
if(serverInfo == null || serverInfo.getPlayers().isEmpty())
return text;
ProxiedPlayer carrier = PingEventHandler.getPAPIUtil().getPlayer(serverInfo.getPlayers());
ProxiedPlayer carrier = PAPIUtil.get().getPlayer(serverInfo.getPlayers());
if(carrier == null)
return text;
return PingEventHandler.getPAPIUtil().parse(text, carrier.getUniqueId(), player.getUUID());
return PAPIUtil.get().parse(text, carrier.getUniqueId(), player.getUUID());
}
@Override
@@ -25,14 +25,35 @@
package ch.andre601.advancedserverlist.bungeecord.objects.impl;
import ch.andre601.advancedserverlist.api.bungeecord.objects.BungeePlayer;
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
import ch.andre601.advancedserverlist.core.profiles.players.GenericPlayerImpl;
public class BungeePlayerImpl extends GenericPlayerImpl{
import java.util.UUID;
public class BungeePlayerImpl implements BungeePlayer{
private final String name;
private final int protocol;
private final UUID uuid;
public BungeePlayerImpl(CachedPlayer player, int protocol){
this.name = player.name();
this.protocol = protocol;
this.uuid = player.uuid();
}
@Override
public String getName(){
return name;
}
@Override
public int getProtocol(){
return protocol;
}
@Override
public UUID getUUID(){
return uuid;
}
}
@@ -0,0 +1,61 @@
package ch.andre601.advancedserverlist.bungeecord.objects.placeholders;
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.bungeecord.BungeeCordCore;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer;
import net.md_5.bungee.api.ServerPing;
import net.md_5.bungee.api.chat.BaseComponent;
public class BungeeProxyPlaceholders extends PlaceholderProvider{
private final BungeeCordCore plugin;
private BungeeProxyPlaceholders(BungeeCordCore plugin){
super("proxy");
this.plugin = plugin;
}
public static BungeeProxyPlaceholders init(BungeeCordCore plugin){
return new BungeeProxyPlaceholders(plugin);
}
@Override
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
String[] args = placeholder.split("\\s", 2);
if(args.length < 2)
return null;
ServerPing ping = plugin.getFetchedServers().get(args[1]);
return switch(args[0]){
case "status" -> ping == null ? "offline" : "online";
case "motd" -> {
if(ping == null)
yield "none";
BaseComponent[] components = new BaseComponent[]{ping.getDescriptionComponent()};
Component component = BungeeComponentSerializer.get().deserialize(components);
yield ComponentParser.toMMString(component);
}
case "players" -> {
if(ping == null)
yield "0";
yield String.valueOf(ping.getPlayers().getOnline());
}
case "maxPlayers" -> {
if(ping == null)
yield "0";
yield String.valueOf(ping.getPlayers().getMax());
}
default -> null;
};
}
}
@@ -79,18 +79,18 @@ public class BungeeServerPlaceholders extends PlaceholderProvider{
case "playersMax" -> {
// ServerInfo doesn't provide the max players that could join, so we won't allow an extra argument
if(args.length >= 2)
yield null;
yield "";
yield String.valueOf(proxy.getPlayersMax());
}
case "host" -> {
if(args.length > 2)
yield null;
yield "";
if(args.length == 2){
if(args.length == 2 && args[1] != null && !args[1].isEmpty()){
ServerInfo info = proxy.getServers().get(args[1]);
if(info == null)
yield null;
yield "";
yield String.valueOf(((InetSocketAddress)info.getSocketAddress()).getHostString());
}
@@ -1,7 +1,4 @@
{
"repositories": [
"https://repo.papermc.io/repository/maven-public"
],
"libraries": [
{
"groupId": "net{}kyori",
+14 -8
View File
@@ -41,7 +41,7 @@
<properties>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
<plugin.config.version>5</plugin.config.version>
<plugin.config.version>6</plugin.config.version>
</properties>
<repositories>
@@ -77,7 +77,7 @@
<dependency>
<groupId>ch.andre601</groupId>
<artifactId>expressionparser</artifactId>
<version>1.4.2</version>
<version>1.4.3</version>
<scope>compile</scope>
</dependency>
<dependency>
@@ -86,6 +86,12 @@
<version>${dependency.configurate-yaml}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.spongepowered</groupId>
<artifactId>configurate-hocon</artifactId>
<version>4.1.2</version>
<scope>provided</scope>
</dependency>
<!-- MiniMessage -->
<dependency>
@@ -111,7 +117,7 @@
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
<version>2.11.0</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -123,7 +129,7 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.2.0-jre</version>
<version>33.3.1-jre</version>
<scope>provided</scope>
</dependency>
@@ -131,13 +137,13 @@
<dependency>
<groupId>net.william278</groupId>
<artifactId>papiproxybridge</artifactId>
<version>1.6.1</version>
<version>1.6.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>eu.kennytv.maintenance</groupId>
<artifactId>maintenance-api</artifactId>
<version>4.2.0-SNAPSHOT</version>
<version>4.2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -151,7 +157,7 @@
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.10.2</version>
<version>5.11.2</version>
<scope>test</scope>
</dependency>
</dependencies>
@@ -173,7 +179,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.3</version>
<version>3.6.0</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<filters>
@@ -29,10 +29,11 @@ import ch.andre601.advancedserverlist.api.AdvancedServerListAPI;
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
import ch.andre601.advancedserverlist.core.check.UpdateChecker;
import ch.andre601.advancedserverlist.core.commands.CommandHandler;
import ch.andre601.advancedserverlist.core.compat.maintenance.MaintenancePlaceholder;
import ch.andre601.advancedserverlist.core.file.FileHandler;
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
import ch.andre601.advancedserverlist.core.profiles.conditions.ProfileConditionParser;
import ch.andre601.advancedserverlist.core.profiles.players.PlayerHandler;
import ch.andre601.advancedserverlist.core.profiles.handlers.PlayerHandler;
import java.io.IOException;
import java.io.InputStream;
@@ -59,7 +60,16 @@ public class AdvancedServerList<F>{
this.commandHandler = new CommandHandler(this);
this.playerHandler = new PlayerHandler(this);
placeholders.forEach(AdvancedServerList.getApi()::addPlaceholderProvider);
plugin.getPluginLogger().info("Registering internal Placeholders...");
placeholders.forEach(this::addPlaceholder);
if(plugin.isPluginEnabled("Maintenance")){
plugin.getPluginLogger().info("Found Maintenance Plugin. Registering extra Placeholder...");
addPlaceholder(new MaintenancePlaceholder(this));
}
plugin.getPluginLogger().info("Completed internal Placeholder registration!");
load();
}
@@ -68,6 +78,10 @@ public class AdvancedServerList<F>{
return new AdvancedServerList<>(plugin, Arrays.asList(placeholders));
}
public static AdvancedServerListAPI getApi(){
return api;
}
public PluginCore<F> getPlugin(){
return plugin;
}
@@ -88,10 +102,6 @@ public class AdvancedServerList<F>{
return version;
}
public static AdvancedServerListAPI getApi(){
return api;
}
public ProfileConditionParser getParser(){
return parser;
}
@@ -125,7 +135,7 @@ public class AdvancedServerList<F>{
resolveVersion();
getPlugin().getPluginLogger().info("Starting AdvancedServerList v%s...", version);
getPlugin().getPluginLogger().info("Platform: " + plugin.getPlatformName() + " " + plugin.getPlatformVersion());
getPlugin().getPluginLogger().info("Platform: %s", plugin.getPlatformInfo());
if(getFileHandler().loadConfig()){
getPlugin().getPluginLogger().info("Successfully loaded config.yml!");
@@ -167,6 +177,10 @@ public class AdvancedServerList<F>{
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("Enabling Schedulers...");
plugin.startScheduler();
getPlugin().getPluginLogger().info("Schedulers enabled.");
getPlugin().getPluginLogger().info("AdvancedServerList is ready!");
@@ -195,4 +209,9 @@ public class AdvancedServerList<F>{
version = "UNKNOWN";
}
}
private void addPlaceholder(PlaceholderProvider placeholderProvider){
getPlugin().getPluginLogger().info("Registering %s Placeholders...", placeholderProvider.getIdentifier());
AdvancedServerList.getApi().addPlaceholderProvider(placeholderProvider);
}
}
@@ -51,57 +51,60 @@ import java.util.concurrent.TimeUnit;
public class UpdateChecker{
@SuppressWarnings("FieldCanBeLocal")
// 'https://api.modrinth.com/v2/project/advancedserverlist/version?loaders=["%s"]' URL encoded.
private final String url = "https://api.modrinth.com/v2/project/advancedserverlist/version?loaders=%%5B%%22%s%%22%%5D";
private final HttpClient client = HttpClient.newHttpClient();
private final Type listType = new TypeToken<ArrayList<ModrinthVersion>>(){}.getType();
private final Gson gson = new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.setPrettyPrinting()
.setLenient()
.create();
private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(new UpdateCheckThread());
private final CacheUtil<ModrinthVersion> cache = new CacheUtil<>(Duration.ofMinutes(5));
private final CacheUtil<CompletableFuture<ModrinthVersion>> cache = new CacheUtil<>(Duration.ofMinutes(5));
private final AdvancedServerList<?> core;
private final PluginLogger logger;
private final String loader;
private final HttpClient client;
public UpdateChecker(AdvancedServerList<?> core){
this.core = core;
this.logger = core.getPlugin().getPluginLogger();
this.loader = core.getPlugin().getLoader();
this.client = HttpClient.newBuilder().executor(Executors.newSingleThreadExecutor(new UpdateCheckThread())).build();
startUpdateChecker();
}
public void performCachedUpdateCheck(CmdSender sender){
ModrinthVersion version = cache.get(() -> {
try{
return performUpdateCheck().join();
}catch(Exception ex){
return null;
CompletableFuture<ModrinthVersion> modrinthVersion = cache.get(this::performUpdateCheck);
modrinthVersion.whenComplete((version, throwable) -> {
if(throwable != null){
logger.warn("Encountered an Exception while checking for an update!", throwable);
sender.sendErrorMsg("There was an exception while checking for an update. Please check the console for details.");
return;
}
if(version == null)
return;
int result = version.compare(core.getVersion());
if(result == -1){
sender.sendPrefixedMsg("<green>A new Version of AdvancedServerList is available!");
sender.sendPrefixedMsg("<green>Your version: <white>%s", core.getVersion());
sender.sendPrefixedMsg("<green>Version on Modrinth: <white>%s", version.versionNumber());
sender.sendPrefixedMsg(
"<click:open_url:'https://modrinth.com/plugin/advancedserverlist/version/%s'>" +
"<green>[<white>Download Page</white>]" +
"</click>",
version.id()
);
}else
if(result == 1){
sender.sendPrefixedMsg("You seem to run a newer Version (<white>%</white>) than what is available on Modrinth (<white>%s</white>).", core.getVersion(), version.versionNumber());
sender.sendPrefixedMsg("Are you running a development build?");
}
});
if(version == null)
return;
int result = version.compare(core.getVersion());
if(result == -1){
sender.sendPrefixedMsg("<green>A new version of AdvancedServerList is available!");
sender.sendPrefixedMsg("<green>Your version: <white>%s", core.getVersion());
sender.sendPrefixedMsg("<green>Modrinth: <white>%s", version.versionNumber());
sender.sendPrefixedMsg("<click:open_url:'https://modrinth.com/plugin/advancedserverlist/version/%s'><green>[<white>Download Page</white>]</click>", version.id());
}else
if(result == 1){
sender.sendPrefixedMsg("Your version (<white>%s</white>) seems newer than the latest release on Modrinth (<white>%s</white>)", core.getVersion(), version.versionNumber);
sender.sendPrefixedMsg("Are you running a dev-build?");
}
}
public void disable(){
@@ -144,7 +147,11 @@ public class UpdateChecker{
}
private CompletableFuture<ModrinthVersion> performUpdateCheck(){
String finalUrl = String.format(url, loader);
String finalUrl = String.format(
// 'https://api.modrinth.com/v2/project/advancedserverlist/version?loaders=["%s"]' URL encoded.
"https://api.modrinth.com/v2/project/advancedserverlist/version?loaders=%%5B%%22%s%%22%%5D",
loader
);
logger.debug(UpdateChecker.class, "Checking '%s' for updates...", finalUrl);
@@ -157,6 +164,7 @@ public class UpdateChecker{
try{
request = HttpRequest.newBuilder()
.uri(new URI(finalUrl))
.timeout(Duration.ofSeconds(5))
.header("User-Agent", "AdvancedServerList-" + loader + "/" + core.getVersion())
.build();
}catch(URISyntaxException ex){
@@ -25,13 +25,26 @@
package ch.andre601.advancedserverlist.core.commands;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
import ch.andre601.advancedserverlist.core.interfaces.commands.PluginCommand;
import ch.andre601.advancedserverlist.core.migration.minimotd.MiniMOTDConfigMigrator;
import ch.andre601.advancedserverlist.core.migration.serverlistplus.SLPConfigMigrator;
import ch.andre601.advancedserverlist.core.profiles.ServerListProfile;
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileSerializer;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.serialize.SerializationException;
import org.spongepowered.configurate.yaml.NodeStyle;
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
public class CommandHandler{
@@ -39,13 +52,18 @@ public class CommandHandler{
public CommandHandler(AdvancedServerList<?> core){
subCommands = List.of(
new Help(),
new Help(core),
new Reload(core),
new ClearCache(core),
new Migrate(core)
new Migrate(core),
new Profiles(core)
);
}
public List<PluginCommand> getSubCommands(){
return subCommands;
}
public void handle(CmdSender sender, String[] args){
if(args.length == 0){
sender.sendErrorMsg("<red>Too few arguments! Use <grey>/asl help</grey> for a list of commands.");
@@ -53,11 +71,11 @@ public class CommandHandler{
}
for(PluginCommand subCommand : subCommands){
if(subCommand.getArgument().equalsIgnoreCase(args[0])){
if(!sender.hasPermission(subCommand.getPermission())){
if(subCommand.name().equalsIgnoreCase(args[0])){
if(!sender.hasPermission(subCommand.permission())){
sender.sendErrorMsg(
"<red>You do not have the permission <grey>%s</grey> to execute this command.",
subCommand.getPermission()
subCommand.permission()
);
return;
}
@@ -72,21 +90,54 @@ public class CommandHandler{
private static class Help extends PluginCommand{
public Help(){
private final AdvancedServerList<?> core;
public Help(AdvancedServerList<?> core){
super("help");
this.core = core;
}
@Override
public void handle(CmdSender sender, String[] args){
sender.sendPrefixedMsg("- Commands");
sender.sendMsg();
sender.sendMsg("<aqua>/asl <white>help <grey>- Shows this help");
sender.sendMsg();
sender.sendMsg("<aqua>/asl <white>reload <grey>- Reloads the config.yml and profiles");
sender.sendMsg();
sender.sendMsg("<aqua>/asl <white>clearCache <grey>- Clears the Player and Favicon cache");
sender.sendMsg();
sender.sendMsg("<aqua>/asl <white>migrate <grey><</grey>plugin<grey>> - Migrates configuration of another plugin");
sender.sendPrefixedMsg("- Commands. Hover for details.");
for(PluginCommand command : core.getCommandHandler().getSubCommands()){
sender.sendPrefixedMsg("");
sender.sendPrefixedMsg(
"<aqua><hover:show_text:\"%s\">" +
"<click:suggest_command:/asl %s>" +
"/asl <white>%s</white>" +
"</click>" +
"</hover></aqua>",
getCommandHover(command),
command.name(),
command.name()
);
}
}
@Override
public String usage(){
return "<aqua>/asl <white>help</white></aqua>";
}
@Override
public String description(){
return "Shows all available commands.";
}
private String getCommandHover(PluginCommand command){
return String.format(
"""
<grey>Usage: %s
Permission: <white>%s</white>
<white>%s</white>
""",
command.usage(),
command.permission(),
command.description()
);
}
}
@@ -118,6 +169,16 @@ public class CommandHandler{
sender.sendPrefixedMsg("<green>Reload complete!");
}
@Override
public String usage(){
return "<aqua>/asl <white>reload</white></aqua>";
}
@Override
public String description(){
return "Reloads the main config and all profiles.";
}
}
private static class ClearCache extends PluginCommand{
@@ -125,7 +186,7 @@ public class CommandHandler{
private final AdvancedServerList<?> core;
public ClearCache(AdvancedServerList<?> core){
super("clearCache");
super("clearcache");
this.core = core;
}
@@ -142,6 +203,16 @@ public class CommandHandler{
sender.sendPrefixedMsg("<green>Cache clearing complete!");
}
@Override
public String usage(){
return "<aqua>/asl <white>clearcache</white></aqua>";
}
@Override
public String description(){
return "Clears the Favicon and Player Cache.";
}
}
private static class Migrate extends PluginCommand{
@@ -160,6 +231,7 @@ public class CommandHandler{
sender.sendErrorMsg("<red>Insufficient arguments! Please provide a plugin to migrate from.");
sender.sendErrorMsg("<red>Available options:");
sender.sendErrorMsg(" - ServerListPlus");
sender.sendErrorMsg(" - MiniMOTD");
return;
}
@@ -178,10 +250,208 @@ public class CommandHandler{
}else{
sender.sendPrefixedMsg("<green>Migration complete!");
}
}else
if(args[0].equalsIgnoreCase("minimotd")){
sender.sendPrefixedMsg("Migrating MiniMOTD configuration file...");
if(MiniMOTDConfigMigrator.migrate(core, sender)){
sender.sendPrefixedMsg("<green>Migration complete!");
}else{
sender.sendErrorMsg("<red>Unable to migrate MiniMOTD configuration. Check console for details!");
}
}else{
sender.sendErrorMsg("<red>Unknown plugin <grey>%s</grey>. Available Options:", args[0]);
sender.sendErrorMsg(" - ServerListPlus");
sender.sendErrorMsg(" - MiniMOTD");
}
}
@Override
public String usage(){
return "<aqua>/asl <white>migrate <grey>\\<</grey>Plugin<grey>></grey></white></aqua>";
}
@Override
public String description(){
return "Migrates the configuration from supported Plugins to AdvancedServerList.";
}
}
private static class Profiles extends PluginCommand{
private final AdvancedServerList<?> core;
public Profiles(AdvancedServerList<?> core){
super("profiles");
this.core = core;
}
@Override
public void handle(CmdSender sender, String[] args){
if(args.length == 0){
sender.sendErrorMsg("<red>Invalid command usage.");
sender.sendErrorMsg("<red>Usage:</red> %s", usage());
return;
}
switch(args[0].toLowerCase(Locale.ROOT)){
case "list" -> {
sender.sendPrefixedMsg("Available Profiles:");
core.getFileHandler().getProfiles().stream()
.sorted(Comparator.comparingInt(ServerListProfile::priority).reversed())
.forEach(
profile -> sender.sendPrefixedMsg("- <white><hover:show_text:\"%s\">%s</hover></white>", getHover(profile), profile.file())
);
}
case "add" -> {
if(args.length == 1){
sender.sendErrorMsg("<red>Insufficient arguments.");
sender.sendErrorMsg("<red>Usage:</red> /asl profiles add <name>");
return;
}
String name = getProfileName(args[1]);
if(core.getFileHandler().getProfiles().stream().anyMatch(profile -> profile.file().equalsIgnoreCase(name))){
sender.sendErrorMsg("<red>A profile with file name</red> %s <red>already exists!", name);
return;
}
if(core.getFileHandler().createFile(name)){
sender.sendPrefixedMsg("<green>Successfully created</green> %s<green>!", name);
sender.sendPrefixedMsg("<green>Load the file using</green> /asl reload");
}else{
sender.sendErrorMsg("<red>Error while trying to create</red> %s<red>!", name);
sender.sendErrorMsg("<red>Check console for further details.");
}
}
case "copy" -> {
if(args.length < 3){
sender.sendErrorMsg("<red>Insufficient arguments.");
sender.sendErrorMsg("<red>Usage:</red> /asl profiles copy <profile> <name>");
return;
}
String name = getProfileName(args[1]);
String copy = getProfileName(args[2]);
ServerListProfile targetProfile = core.getFileHandler().getProfiles().stream()
.filter(file -> file.file().equalsIgnoreCase(name))
.findFirst()
.orElse(null);
boolean copyExists = core.getFileHandler().getProfiles().stream()
.anyMatch(profile -> profile.file().equals(copy));
if(targetProfile == null){
sender.sendErrorMsg("<red>There is no file with name</red> %s<red>!", name);
return;
}
if(copyExists){
sender.sendErrorMsg("<red>A profile with file name</red> %s <red>already exists!", copy);
return;
}
Path profilePath = core.getPlugin().getFolderPath().resolve("profiles").resolve(copy);
try{
Files.createFile(profilePath);
}catch(IOException ex){
sender.sendErrorMsg("<red>There was an error while creating the file</red> %s<red>!", copy);
sender.sendErrorMsg("<red>Check console for further details.");
core.getPlugin().getPluginLogger().warn("Encountered IOException while creating file %s", ex, copy);
return;
}
YamlConfigurationLoader loader = YamlConfigurationLoader.builder()
.path(profilePath)
.indent(2)
.nodeStyle(NodeStyle.BLOCK)
.defaultOptions(options -> options.serializers(builder -> builder.register(ProfileEntry.class, ProfileSerializer.INSTANCE)))
.build();
ConfigurationNode node;
try{
node = loader.load();
}catch(IOException ex){
sender.sendErrorMsg("<red>There was an error while loading the file</red> %s<red>!", copy);
sender.sendErrorMsg("<red>Check console for further details.");
core.getPlugin().getPluginLogger().warn("Encountered IOException while loading file %s", ex, copy);
return;
}
if(node == null){
sender.sendErrorMsg("Cannot copy</red> %s <red>to</red> %s<red>. ConfigurationNode was null.", name, copy);
return;
}
try{
node.node("priority").set(targetProfile.priority());
node.node("condition").set(targetProfile.condition());
node.node("profiles").setList(ProfileEntry.class, targetProfile.profiles());
node.set(ProfileEntry.class, targetProfile.defaultProfile());
}catch(SerializationException ex){
sender.sendErrorMsg("<red>There was an Error while copying values from</red> %s <red>to</red> %s<red>.", name, copy);
sender.sendErrorMsg("<red>Check console for details.");
core.getPlugin().getPluginLogger().warn("Encountered SerializationException while set values for %s!", ex, copy);
return;
}
try{
loader.save(node);
sender.sendPrefixedMsg("<green>Successfully created copy of</green> %s <green>as</green> %s<green>!", name, copy);
sender.sendPrefixedMsg("<green>Load the file using</green> /asl reload");
}catch(IOException ex){
sender.sendErrorMsg("<red>There was an Error while trying to save</red> %s<red>!", copy);
sender.sendErrorMsg("<red>Check console for details.");
core.getPlugin().getPluginLogger().warn("Encountered IOException while saving ConfigurationNode for %s!", ex, copy);
}
}
default -> {
sender.sendErrorMsg("<red>Unknown argument</red> %s<red>!", args[0]);
sender.sendErrorMsg("<red>Usage:</red> %s", usage());
}
}
}
@Override
public String usage(){
return "<aqua>/asl <white>profiles</white> <grey>\\<" +
"<white>add</white> \\<<white>name</white>> | " +
"<white>copy</white> \\<<white>profile</white>> \\<<white>name</white>> | " +
"<white>list</white>" +
"></grey></aqua>";
}
@Override
public String description(){
return "Creates a new profile, copies one from an existing file, or lists all available profiles.";
}
private String getHover(ServerListProfile profile){
return String.format(
"""
<grey>Priority: <white>%s</white>
Condition: <white>%s</white>
Valid profile: %s
""",
profile.priority(),
profile.condition() == null || profile.condition().isEmpty() ? "<i>None</i>" : profile.condition(),
profile.isInvalidProfile() ? "<red>No</red>" : "<green>Yes</green>"
);
}
private String getProfileName(String name){
String fileName = name.toLowerCase(Locale.ROOT);
return fileName.endsWith(".yml") ? fileName : fileName + ".yml";
}
}
}
@@ -0,0 +1,24 @@
package ch.andre601.advancedserverlist.core.compat.maintenance;
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
public class MaintenancePlaceholder extends PlaceholderProvider{
private final AdvancedServerList<?> plugin;
public MaintenancePlaceholder(AdvancedServerList<?> plugin){
super("maintenance");
this.plugin = plugin;
}
@Override
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
if(!placeholder.equals("maintenanceEnabled") || !plugin.getPlugin().isPluginEnabled("Maintenance"))
return null;
return String.valueOf(MaintenanceUtil.get().isMaintenanceEnabled());
}
}
@@ -30,12 +30,21 @@ import eu.kennytv.maintenance.api.MaintenanceProvider;
public class MaintenanceUtil{
private static MaintenanceUtil instance;
private final Maintenance api;
public MaintenanceUtil(){
private MaintenanceUtil(){
this.api = MaintenanceProvider.get();
}
public static MaintenanceUtil get(){
if(instance != null)
return instance;
return (instance = new MaintenanceUtil());
}
public boolean isMaintenanceEnabled(){
return api.isMaintenance();
}
@@ -34,19 +34,26 @@ import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
public class PAPIUtil{
private final PlaceholderAPI papi;
private static PAPIUtil instance;
private final CacheUtil<String> cache = new CacheUtil<>(Duration.ofSeconds(5));
private final PlaceholderAPI papi;
public PAPIUtil(){
private PAPIUtil(){
this.papi = PlaceholderAPI.createInstance();
}
public static PAPIUtil get(){
if(instance != null)
return instance;
return (instance = new PAPIUtil());
}
// Make sure the version of PAPIProxyBridge we get has the required methods we need...
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
public boolean isCompatible(){
@@ -88,8 +95,7 @@ public class PAPIUtil{
public String parse(String text, UUID carrier, UUID player){
try{
CompletableFuture<String> future = papi.formatPlaceholders(text, carrier, player);
return future.getNow(text);
return papi.formatPlaceholders(text, carrier, player).getNow(text);
}catch(IllegalArgumentException | CancellationException | CompletionException ex){
return text;
}
@@ -29,8 +29,6 @@ import ch.andre601.advancedserverlist.api.events.GenericServerListEvent;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import ch.andre601.advancedserverlist.core.compat.maintenance.MaintenanceUtil;
import ch.andre601.advancedserverlist.core.compat.papi.PAPIUtil;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
import ch.andre601.advancedserverlist.core.interfaces.events.GenericEventWrapper;
@@ -41,9 +39,6 @@ import ch.andre601.advancedserverlist.core.profiles.replacer.StringReplacer;
public class PingEventHandler{
private static PAPIUtil papiUtil = null;
private static MaintenanceUtil maintenanceUtil = null;
public static <F, P extends GenericPlayer> ProfileEntry handleEvent(GenericEventWrapper<F, P> event){
event.getPlugin().getPluginLogger().debug(PingEventHandler.class, "Received ping event. Handling it...");
if(event.isInvalidProtocol()){
@@ -75,42 +70,75 @@ public class PingEventHandler{
logger.debug(PingEventHandler.class, "Received valid Server List Profile. Calling PreServerListSetEvent...");
GenericServerListEvent e = event.callEvent(ProfileManager.merge(profile));
if(e == null || e.isCancelled()){
GenericServerListEvent slEvent = event.callEvent(ProfileManager.merge(profile));
if(slEvent == null || slEvent.isCancelled()){
logger.debug(PingEventHandler.class, "PreServerListSetEvent was cancelled. Stopping ping handling...");
return null;
}
logger.debug(PingEventHandler.class, "PreServerListSetEvent completed. Proceeding with ping handling...");
ProfileEntry entry = e.getEntry();
ProfileEntry entry = slEvent.getEntry();
if(entry.isInvalid()){
logger.debugWarn(PingEventHandler.class, "No valid ProfileEntry retrieved. Cancelling ping handling...");
return null;
}
boolean extraPlayers = ProfileManager.checkOption(entry.extraPlayersEnabled());
if(extraPlayers && ignoreMaintenance(event, "extraPlayers")){
max = online + (entry.extraPlayersCount() == null ? 0 : entry.extraPlayersCount());
if(ProfileManager.checkOption(entry.onlinePlayersEnabled()) && ignoreMaintenance(event, "onlinePlayers")){
logger.debug(PingEventHandler.class, "'playerCount -> onlinePlayers -> enabled' option is true. Trying to apply '%s'...", entry.onlinePlayersCount());
String onlinePlayers = ComponentParser.text(entry.onlinePlayersCount())
.modifyText(text -> StringReplacer.replace(text, player, server))
.modifyText(text -> event.parsePAPIPlaceholders(text, player))
.toString();
logger.debug(PingEventHandler.class, "Extra Players enabled. Applying '%d' as max player count...", max);
event.setMaxPlayers(max);
try{
online = onlinePlayers == null ? online : Integer.parseInt(onlinePlayers);
event.setOnlinePlayers(online);
}catch(NumberFormatException ex){
logger.warn("Option 'playerCount -> onlinePlayers -> amount' is not a valid Number!");
}
}
if(ProfileManager.checkOption(entry.maxPlayersEnabled()) && !extraPlayers && ignoreMaintenance(event, "maxPlayers")){
max = (entry.maxPlayersCount() == null) ? 0 : entry.maxPlayersCount();
boolean extraPlayersEnabled = ProfileManager.checkOption(entry.extraPlayersEnabled());
if(extraPlayersEnabled && ignoreMaintenance(event, "extraPlayers")){
logger.debug(PingEventHandler.class, "'playerCount -> extraPlayers -> enabled' option is true. Trying to apply '%s'...", entry.extraPlayersCount());
String extraPlayers = ComponentParser.text(entry.extraPlayersCount())
.modifyText(text -> StringReplacer.replace(text, player, server))
.modifyText(text -> event.parsePAPIPlaceholders(text, player))
.toString();
logger.debug(PingEventHandler.class, "Max Players enabled. Applying '%d' as max player count...", max);
try{
max = online + (extraPlayers == null ? 0 : Integer.parseInt(extraPlayers));
logger.debug(PingEventHandler.class, "'playerCount -> extraPlayers -> amount' is a valid number. Applying it...");
event.setMaxPlayers(max);
}catch(NumberFormatException ex){
logger.warn("Option 'playerCount -> extraPlayers -> amount' is not a valid Number!");
}
}
if(ProfileManager.checkOption(entry.maxPlayersEnabled()) && !extraPlayersEnabled && ignoreMaintenance(event, "maxPlayers")){
logger.debug(PingEventHandler.class, "'playerCount -> maxPlayers -> enabled' option is true. Trying to apply '%s'...", entry.maxPlayersCount());
String maxPlayers = ComponentParser.text(entry.maxPlayersCount())
.modifyText(text -> StringReplacer.replace(text, player, server))
.modifyText(text -> event.parsePAPIPlaceholders(text, player))
.toString();
event.setMaxPlayers(max);
try{
max = maxPlayers == null ? 0 : Integer.parseInt(maxPlayers);
logger.debug(PingEventHandler.class, "'playerCount -> maxPlayers -> amount' is a valid number. Applying it...");
event.setMaxPlayers(max);
}catch(NumberFormatException ex){
logger.warn("Option 'playerCount -> maxPlayers -> amount' is not a valid Number!");
}
}
GenericServer finalServer = event.createGenericServer(online, max, host);
if(ProfileManager.checkOption(entry.motd()) && ignoreMaintenance(event, "motd")){
logger.debug(PingEventHandler.class, "MOTD set. Applying '%s'...", String.join("\\n", entry.motd()));
logger.debug(PingEventHandler.class, "'motd' option present. Applying '%s'...", String.join("\\n", entry.motd()));
event.setMotd(
ComponentParser.list(entry.motd())
@@ -123,13 +151,13 @@ public class PingEventHandler{
boolean hidePlayers = ProfileManager.checkOption(entry.hidePlayersEnabled());
if(hidePlayers && ignoreMaintenance(event, "hidePlayers")){
logger.debug(PingEventHandler.class, "Hide Players enabled. Hiding player count...");
logger.debug(PingEventHandler.class, "'playerCount -> hidePlayers' enabled. Hiding player count...");
event.hidePlayers();
}
if(ProfileManager.checkOption(entry.playerCountText()) && !hidePlayers && ignoreMaintenance(event, "playerCountText")){
logger.debug(PingEventHandler.class, "Player Count Text set. Applying '%s'...", entry.playerCountText());
logger.debug(PingEventHandler.class, "'playerCount -> text' option set. Applying '%s'...", entry.playerCountText());
event.setPlayerCount(
ComponentParser.text(entry.playerCountText())
@@ -140,13 +168,13 @@ public class PingEventHandler{
}
if(ProfileManager.checkOption(entry.players()) && !hidePlayers && ignoreMaintenance(event, "playerCountHover")){
logger.debug(PingEventHandler.class, "Player Count Hover set. Applying '%s'...", String.join("\\n", entry.players()));
logger.debug(PingEventHandler.class, "'playerCount -> hover' option set. Applying '%s'...", String.join("\\n", entry.players()));
event.setPlayers(entry.players(), player, server);
}
if(ProfileManager.checkOption(entry.favicon()) && ignoreMaintenance(event, "favicon")){
logger.debug(PingEventHandler.class, "Favicon set. Resolving '%s'...", entry.favicon());
logger.debug(PingEventHandler.class, "'favicon' option set. Resolving '%s'...", entry.favicon());
String faviconString = StringReplacer.replace(entry.favicon(), player, server);
@@ -169,20 +197,6 @@ public class PingEventHandler{
return entry;
}
public static PAPIUtil getPAPIUtil(){
if(papiUtil != null)
return papiUtil;
return (papiUtil = new PAPIUtil());
}
public static MaintenanceUtil getMaintenanceUtil(){
if(maintenanceUtil != null)
return maintenanceUtil;
return (maintenanceUtil = new MaintenanceUtil());
}
private static <F, P extends GenericPlayer> boolean ignoreMaintenance(GenericEventWrapper<F, P> event, String option){
if(!event.isMaintenanceModeActive())
return true;
@@ -46,13 +46,24 @@ public class ConfigMigrator{
public static ConfigurationTransformation.Versioned create(){
return ConfigurationTransformation.versionedBuilder()
.versionKey("configVersion")
.addVersion(LATEST, fourToFive())
.addVersion(LATEST, fiveToSix())
.addVersion(5, fourToFive())
.addVersion(4, threeToFour())
.addVersion(3, twoToThree())
.addVersion(2, oneToTwo())
.build();
}
public static ConfigurationTransformation fiveToSix(){
return ConfigurationTransformation.builder()
.addAction(NodePath.path("disableDuringMaintenance"), (path, value) -> {
value.node("onlinePlayers").set(true);
return null;
})
.build();
}
public static ConfigurationTransformation fourToFive(){
return ConfigurationTransformation.builder()
.addAction(NodePath.path(), (path, value) -> {
@@ -99,23 +99,36 @@ public class FileHandler{
public boolean loadProfiles(){
logger.info("Loading profiles...");
if(!profilesFolder.toFile().exists() && profilesFolder.toFile().mkdirs()){
if(createFile("default.yml")){
return reloadProfiles();
}else{
return false;
}
}
public boolean createFile(String name){
if(Files.notExists(profilesFolder) && profilesFolder.toFile().mkdirs()){
logger.info("Successfully created profiles folder.");
try(InputStream stream = plugin.getClass().getResourceAsStream("/profiles/default.yml")){
if(stream == null){
logger.warn("Cannot retrieve default.yml from Plugin.");
return false;
}
Files.copy(stream, profilesFolder.resolve("default.yml"));
}catch(IOException ex){
logger.warn("Cannot create default.yml for plugin.", ex);
return false;
}
}
return reloadProfiles();
File file = new File(profilesFolder.toFile(), name);
if(file.exists()){
return true;
}
try(InputStream stream = plugin.getClass().getResourceAsStream("/profiles/default.yml")){
if(stream == null){
logger.warn("Cannot retrieve content of internal default.yml file.");
return false;
}
Files.copy(stream, profilesFolder.resolve(name));
return true;
}catch(IOException ex){
logger.warn("Encountered IOException while trying to create file %s", ex, name);
return false;
}
}
public boolean migrateConfig(){
@@ -29,19 +29,23 @@ import java.util.Locale;
public abstract class PluginCommand{
private final String argument;
private final String name;
public PluginCommand(String argument){
this.argument = argument;
public PluginCommand(String name){
this.name = name;
}
public String getArgument(){
return argument;
public String name(){
return name;
}
public String getPermission(){
return "advancedserverlist.command." + getArgument().toLowerCase(Locale.ROOT);
public String permission(){
return "advancedserverlist.command." + name().toLowerCase(Locale.ROOT);
}
public abstract void handle(CmdSender sender, String[] args);
public abstract String usage();
public abstract String description();
}
@@ -27,7 +27,7 @@ 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 ch.andre601.advancedserverlist.core.profiles.handlers.FaviconHandler;
import java.awt.image.BufferedImage;
import java.nio.file.Path;
@@ -44,6 +44,10 @@ public interface PluginCore<F>{
void clearFaviconCache();
void downloadLibrary(String groupId, String artifactId, String version);
void startScheduler();
AdvancedServerList<F> getCore();
Path getFolderPath();
@@ -52,9 +56,7 @@ public interface PluginCore<F>{
FaviconHandler<F> getFaviconHandler();
String getPlatformName();
String getPlatformVersion();
String getPlatformInfo();
String getLoader();
@@ -42,6 +42,8 @@ public interface GenericEventWrapper<F, P extends GenericPlayer>{
void setMaxPlayers(int maxPlayers);
void setOnlinePlayers(int onlinePlayers);
void setMotd(Component component);
void hidePlayers();
@@ -0,0 +1,235 @@
/*
* MIT License
*
* Copyright (c) 2022-2024 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.core.migration.minimotd;
import ch.andre601.advancedserverlist.api.objects.NullBool;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.interfaces.commands.CmdSender;
import ch.andre601.advancedserverlist.core.migration.minimotd.serializing.MiniMOTDConfig;
import ch.andre601.advancedserverlist.core.migration.minimotd.serializing.MiniMOTDSerializer;
import ch.andre601.advancedserverlist.core.profiles.profile.ProfileSerializer;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.hocon.HoconConfigurationLoader;
import org.spongepowered.configurate.serialize.SerializationException;
import org.spongepowered.configurate.yaml.NodeStyle;
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class MiniMOTDConfigMigrator{
public static boolean migrate(AdvancedServerList<?> core, CmdSender sender){
core.getPlugin().downloadLibrary("org.spongepowered", "configurate-hocon", "4.1.2");
PluginLogger logger = core.getPlugin().getPluginLogger();
String folder = core.getPlugin().getLoader().equals("velocity") ? "minimotd-velocity" : "MiniMOTD";
Path mainConf = core.getPlugin().getFolderPath().getParent().resolve(folder).resolve("main.conf");
if(!Files.exists(mainConf)){
logger.warn("[Migrator - MiniMOTD] Cannot find a main.conf file in /plugins/%s/ folder.", folder);
sender.sendErrorMsg(" -> <red>No main.conf file found.");
return false;
}
HoconConfigurationLoader loader = HoconConfigurationLoader.builder()
.path(mainConf)
.defaultOptions(options -> options.serializers(builder ->
builder.register(MiniMOTDConfig.class, MiniMOTDSerializer.MINI_MOTD_SERIALIZER)
.register(MiniMOTDConfig.Motd.class, MiniMOTDSerializer.MOTD_SERIALIZER)
.register(MiniMOTDConfig.PlayerCount.class, MiniMOTDSerializer.PLAYER_COUNT_SERIALIZER)
))
.build();
MiniMOTDConfig config;
try{
ConfigurationNode node = loader.load();
config = node.get(MiniMOTDConfig.class);
}catch(IOException ex){
logger.warn("[Migrator - MiniMOTD] Encountered IOException while loading main.conf file.", ex);
sender.sendErrorMsg(" -> <red>IOException while loading</red> main.conf <red>file.");
return false;
}
if(config == null){
logger.warn("[Migrator - MiniMOTD] Retrieved main.conf file returned null.");
sender.sendErrorMsg(" -> <red>Received invalid</red> main.conf <red>file.");
return false;
}
ProfileEntry.Builder profileBuilder = ProfileEntry.empty().builder();
List<ProfileEntry.Builder> profilesBuilders = new ArrayList<>();
if(config.motdEnabled() && config.motds().size() > 1){
for(int i = 0; i < config.motds().size(); i++){
profilesBuilders.add(ProfileEntry.empty().builder());
}
}
if(config.motdEnabled()){
if(config.motds().size() == 1){
applyMotd(profileBuilder, config.motds().get(0));
}else
if(config.motds().size() > 1){
for(int i = 0; i < config.motds().size(); i++){
applyMotd(profilesBuilders.get(i), config.motds().get(i));
}
}
}
if(config.iconEnabled()){
if(config.motds().size() == 1){
MiniMOTDConfig.Motd motd = config.motds().get(0);
if(!motd.icon().isEmpty() && !motd.icon().equalsIgnoreCase("random")){
profileBuilder.favicon(motd.icon());
}
}else
if(config.motds().size() > 1){
for(int i = 0; i < config.motds().size(); i++){
MiniMOTDConfig.Motd motd = config.motds().get(i);
if(!motd.icon().isEmpty() && !motd.icon().equalsIgnoreCase("random")){
profilesBuilders.get(i).favicon(motd.icon());
}
}
}
}
if(config.playerCount() != null){
MiniMOTDConfig.PlayerCount playerCount = config.playerCount();
NullBool hidePlayers = NullBool.resolve(playerCount.hidePlayers());
NullBool xMoreEnabled = NullBool.resolve(playerCount.xMoreEnabled());
int xMore = playerCount.xMore();
NullBool maxPlayersEnabled = NullBool.resolve(playerCount.maxPlayersEnabled());
int maxPlayers = playerCount.maxPlayers();
profileBuilder.hidePlayersEnabled(hidePlayers)
.extraPlayersEnabled(xMoreEnabled)
.extraPlayersCount(String.valueOf(xMore))
.maxPlayersEnabled(maxPlayersEnabled)
.maxPlayersCount(String.valueOf(maxPlayers));
}
ProfileEntry entry = profileBuilder.build();
List<ProfileEntry> profiles = profilesBuilders.stream()
.map(ProfileEntry.Builder::build)
.toList();
boolean profilesInvalid = profiles.isEmpty() || profiles.stream().allMatch(ProfileEntry::isInvalid);
if(entry.isInvalid() && profilesInvalid){
logger.warn("[Migrator - MiniMOTD] Main ProfileEntry was invalid and profiles were empty.");
sender.sendErrorMsg(" -> <red>Received invalid configuration.");
return false;
}
Path profile = core.getPlugin().getFolderPath().resolve("profiles").resolve("minimotd_migrated.yml");
if(Files.exists(profile)){
logger.warn("[Migrator - MiniMOTD] Cannot create new file minimotd_migrated.yml. One with the same name is already present.");
sender.sendErrorMsg(" -> <red>File</red> minimotd_migrated.yml <red>already present.");
return false;
}
try{
Files.createFile(profile);
}catch(IOException ex){
logger.warn("[Migrator - MiniMOTD] Encountered an IOException while trying to create file minimotd_migrated.yml.", ex);
sender.sendErrorMsg(" -> <red>File creation error.");
return false;
}
YamlConfigurationLoader yamlLoader = YamlConfigurationLoader.builder()
.path(profile)
.indent(2)
.nodeStyle(NodeStyle.BLOCK)
.defaultOptions(option -> option.serializers(builder -> builder.register(ProfileEntry.class, ProfileSerializer.INSTANCE)))
.build();
ConfigurationNode migrated;
try{
migrated = yamlLoader.load();
}catch(IOException ex){
logger.warn("[Migrator - MiniMOTD] Encountered an IOException while trying to load file minimotd_migrated.yml.", ex);
sender.sendErrorMsg(" -> <red>File loading error.");
return false;
}
if(migrated == null){
logger.warn("[Migrator - MiniMOTD] Cannot migrate Configuration. ConfigurationNode was null.");
sender.sendErrorMsg(" -> <red>File loading error.");
return false;
}
try{
migrated.node("priority").set(0);
if(!profiles.isEmpty()){
migrated.node("profiles").setList(ProfileEntry.class, profiles);
}
migrated.set(entry);
}catch(SerializationException ex){
logger.warn("[Migrator - MiniMOTD] Encountered a SerializationException while setting values.", ex);
sender.sendErrorMsg(" -> <red>Error while updating file</red> minimotd_migrated.yml<red>.");
return false;
}
try{
yamlLoader.save(migrated);
sender.sendPrefixedMsg(" -> <green>Completed!");
return true;
}catch(IOException ex){
logger.warn("[Migrator - MiniMOTD] Encountered an IOException while trying to save new file minimotd_migrated.yml.", ex);
sender.sendErrorMsg(" -> <red>File saving error.");
return false;
}
}
private static void applyMotd(ProfileEntry.Builder builder, MiniMOTDConfig.Motd motd){
if(motd.line1().isEmpty() && !motd.line2().isEmpty()){
builder.motd(List.of("<grey>", motd.line2()));
}else
if(!motd.line1().isEmpty() && motd.line2().isEmpty()){
builder.motd(Collections.singletonList(motd.line1()));
}else
if(!motd.line1().isEmpty()){ // Line2 is by logic not empty here. So this check is not required.
builder.motd(List.of(motd.line1(), motd.line2()));
}
}
}
@@ -1,7 +1,7 @@
/*
* MIT License
*
* Copyright (c) 2022-2023 Andre_601
* Copyright (c) 2022-2024 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,30 +23,13 @@
*
*/
package ch.andre601.advancedserverlist.core.profiles.players;
package ch.andre601.advancedserverlist.core.migration.minimotd.serializing;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import java.util.List;
import java.util.UUID;
public abstract class GenericPlayerImpl implements GenericPlayer{
public record MiniMOTDConfig(boolean iconEnabled, boolean motdEnabled, List<Motd> motds, PlayerCount playerCount){
protected String name = null;
protected int protocol = 0;
protected UUID uuid = null;
public record Motd(String icon, String line1, String line2){}
@Override
public String getName(){
return name;
}
@Override
public int getProtocol(){
return protocol;
}
@Override
public UUID getUUID(){
return uuid;
}
public record PlayerCount(boolean hidePlayers, boolean xMoreEnabled, int xMore, boolean maxPlayersEnabled, int maxPlayers){}
}
@@ -0,0 +1,129 @@
/*
* MIT License
*
* Copyright (c) 2022-2024 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
package ch.andre601.advancedserverlist.core.migration.minimotd.serializing;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.serialize.SerializationException;
import org.spongepowered.configurate.serialize.TypeSerializer;
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.List;
public class MiniMOTDSerializer implements TypeSerializer<MiniMOTDConfig>{
public static final MiniMOTDSerializer MINI_MOTD_SERIALIZER = new MiniMOTDSerializer();
public static final MotdSerializer MOTD_SERIALIZER = new MotdSerializer();
public static final PlayerCountSerializer PLAYER_COUNT_SERIALIZER = new PlayerCountSerializer();
@Override
public MiniMOTDConfig deserialize(Type type, ConfigurationNode node) throws SerializationException{
boolean iconsEnabled = node.node("icon-enabled").getBoolean();
boolean motdEnabled = node.node("motd-enabled").getBoolean();
List<MiniMOTDConfig.Motd> motds = node.node("motds").getList(MiniMOTDConfig.Motd.class);
MiniMOTDConfig.PlayerCount playerCount = node.node("player-count-settings").get(MiniMOTDConfig.PlayerCount.class);
return new MiniMOTDConfig(iconsEnabled, motdEnabled, motds, playerCount);
}
@Override
public void serialize(Type type, @Nullable MiniMOTDConfig obj, ConfigurationNode node) throws SerializationException{
if(obj == null){
node.raw(null);
return;
}
node.node("icon-enabled").set(obj.iconEnabled());
node.node("motd-enable").set(obj.motdEnabled());
node.node("motds").setList(MiniMOTDConfig.Motd.class, obj.motds());
node.node("player-count-settings").set(MiniMOTDConfig.PlayerCount.class, obj.playerCount());
}
public static class MotdSerializer implements TypeSerializer<MiniMOTDConfig.Motd>{
@Override
public MiniMOTDConfig.Motd deserialize(Type type, ConfigurationNode node) throws SerializationException{
String icon = node.node("icon").getString("");
String line1 = node.node("line1").getString("");
String line2 = node.node("line2").getString("");
return new MiniMOTDConfig.Motd(icon, line1, line2);
}
@Override
public void serialize(Type type, MiniMOTDConfig.@Nullable Motd obj, ConfigurationNode node) throws SerializationException{
if(obj == null){
node.raw(null);
return;
}
node.node("icon").set(obj.icon());
node.node("line1").set(obj.line1());
node.node("line2").set(obj.line2());
}
}
public static class PlayerCountSerializer implements TypeSerializer<MiniMOTDConfig.PlayerCount>{
@Override
public MiniMOTDConfig.PlayerCount deserialize(Type type, ConfigurationNode node) throws SerializationException{
boolean hidePlayerCount = node.node("hide-player-count").getBoolean();
boolean xMoreEnabled = node.node("just-x-more-settings", "just-x-more-enabled").getBoolean();
int xMore = node.node("just-x-more-settings", "x-value").getInt();
boolean maxPlayersEnabled = node.node("max-players-enabled").getBoolean();
int maxPlayers = node.node("max-players").getInt();
return new MiniMOTDConfig.PlayerCount(hidePlayerCount, xMoreEnabled, xMore, maxPlayersEnabled, maxPlayers);
}
@Override
public void serialize(Type type, MiniMOTDConfig.@Nullable PlayerCount obj, ConfigurationNode node) throws SerializationException{
if(obj == null){
node.raw(null);
return;
}
node.node("allow-exceeding-maximum").set(false);
node.node("disable-player-list-hover").set(false);
node.node("fake-players", "fake-players").set("25%");
node.node("fake-players", "fake-players-enabled").set(false);
node.node("hide-player-count").set(obj.hidePlayers());
node.node("just-x-more-settings", "just-x-more-enabled").set(obj.xMoreEnabled());
node.node("just-x-more-settings", "x-value").set(obj.xMore());
node.node("max-players").set(obj.maxPlayers());
node.node("max-players-enabled").set(obj.maxPlayersEnabled());
node.node("servers").setList(String.class, Collections.emptyList());
}
}
}
@@ -129,7 +129,7 @@ public class SLPConfigMigrator{
apply(motds, builder, profiles, ProfileEntry.Builder::motd);
apply(favicons, builder, profiles, ProfileEntry.Builder::favicon);
apply(hovers, builder, profiles, ProfileEntry.Builder::players);
apply(maxPlayers, builder, profiles, (build, count) -> build.maxPlayersEnabled(NullBool.TRUE).maxPlayersCount(count));
apply(maxPlayers, builder, profiles, (build, count) -> build.maxPlayersEnabled(NullBool.TRUE).maxPlayersCount(String.valueOf(count)));
apply(playerCount, builder, profiles, ProfileEntry.Builder::playerCountText);
builder.hidePlayersEnabled(hidePlayers);
@@ -139,7 +139,8 @@ public class SLPConfigMigrator{
.map(ProfileEntry.Builder::build)
.toList();
if(entry.isInvalid() && profileEntries.isEmpty()){
boolean profilesInvalid = profileEntries.isEmpty() || profileEntries.stream().anyMatch(ProfileEntry::isInvalid);
if(entry.isInvalid() && profilesInvalid){
logger.warn("[Migrator - ServerListPlus] Unable to parse ServerListPlus configuration of type %s. Generated ProfileEntry was invalid.", type.getName());
sender.sendErrorMsg(" -> <red>Received invalid Configuration.");
@@ -208,7 +209,7 @@ public class SLPConfigMigrator{
node.set(entry);
}catch(SerializationException ex){
logger.warn("Encountered a SerializationException while setting values.", ex);
logger.warn("[Migrator - ServerListPlus] Encountered a SerializationException while setting values.", ex);
sender.sendErrorMsg(" -> <red>Error while updating file</red> %s<red>.", type.getFile());
return 0;
@@ -65,6 +65,10 @@ public class ComponentParser{
return mm.deserialize(text);
}
public static String toMMString(Component component){
return mm.serialize(component);
}
@Override
public String toString(){
return legacy.serialize(toComponent());
@@ -28,8 +28,8 @@ package ch.andre601.advancedserverlist.core.profiles;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.profiles.conditions.ProfileConditionParser;
import ch.andre601.expressionparser.ParseWarnCollector;
import org.spongepowered.configurate.ConfigurationNode;
import org.spongepowered.configurate.serialize.SerializationException;
@@ -41,13 +41,14 @@ import java.util.Random;
public record ServerListProfile(int priority, String condition, ProfileEntry defaultProfile, List<ProfileEntry> profiles, String file){
private static final Random random = new Random();
public boolean evalConditions(ProfileConditionParser parser, PluginLogger logger, GenericPlayer player, GenericServer server){
public boolean evalConditions(AdvancedServerList<?> core, GenericPlayer player, GenericServer server){
if(condition == null || condition.isEmpty())
return true;
ParseWarnCollector collector = new ParseWarnCollector(condition);
PluginLogger logger = core.getPlugin().getPluginLogger();
boolean result = parser.evaluate(condition, player, server, collector);
boolean result = core.getParser().evaluate(condition, player, server, collector);
if(collector.hasWarnings()){
logger.warn("Encountered %d Error(s) while parsing condition for file '%s':", collector.getWarnings().size(), file);
@@ -55,9 +56,8 @@ public record ServerListProfile(int priority, String condition, ProfileEntry def
for(ParseWarnCollector.Context context : collector.getWarnings()){
logger.warn(" - At position %s:", context.position() == -1 ? "Unknown" : context.position());
logger.warn(" %s", condition);
logger.warn(" ".repeat(context.position() + 5) + "^");
logger.warn(" ".repeat(context.position() + 4) + "^");
logger.warn(" -> %s", context.message());
}
}
@@ -120,13 +120,6 @@ public record ServerListProfile(int priority, String condition, ProfileEntry def
this.logger = logger;
}
public Builder(String filename, int priority, PluginLogger logger){
this.fileName = filename;
this.node = null;
this.priority = priority;
this.logger = logger;
}
public static Builder resolve(String fileName, ConfigurationNode node, PluginLogger logger){
return new Builder(fileName, node, logger)
.resolveCondition()
@@ -1,7 +1,7 @@
/*
* MIT License
*
* Copyright (c) 2022-2023 Andre_601
* Copyright (c) 2022-2024 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,7 @@
*
*/
package ch.andre601.advancedserverlist.core.profiles.favicon;
package ch.andre601.advancedserverlist.core.profiles.handlers;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
@@ -70,11 +70,20 @@ public class FaviconHandler<F>{
}
public F getFavicon(String input){
if(localFavicons.containsKey(input.toLowerCase(Locale.ROOT).split("\\.")[0])){
return localFavicons.get(input.toLowerCase(Locale.ROOT).split("\\.")[0]);
if(localFavicons.size() > 0){
logger.debug(FaviconHandler.class, "Current Local Favicons:");
for(String key : localFavicons.keySet()){
logger.debug(FaviconHandler.class, " - %s", key);
}
}
if(localFavicons.containsKey(input.toLowerCase(Locale.ROOT))){
logger.debug(FaviconHandler.class, "Input matches local favicon Image. Returning it...");
return localFavicons.get(input.toLowerCase(Locale.ROOT));
}
try{
logger.debug(FaviconHandler.class, "Getting Favicon image from cache...");
return faviconCache.get(input, () -> getFuture(input)).getNow(null);
}catch(ExecutionException ex){
logger.warn("Received ExecutionException while retrieving Favicon for '%s'.", ex, input);
@@ -94,7 +103,7 @@ public class FaviconHandler<F>{
}else
if(input.toLowerCase(Locale.ROOT).endsWith(".png")){
logger.debug(FaviconHandler.class, "Resolving image file '%s'...", input);
return CompletableFuture.completedFuture(localFavicons.get(input.toLowerCase(Locale.ROOT).split("\\.")[0]));
return CompletableFuture.completedFuture(localFavicons.get(input.toLowerCase(Locale.ROOT)));
}else{
logger.debug(FaviconHandler.class, "Resolving Name/UUID as https://mc-heads.net/avatar/%s/64...", input);
return CompletableFuture.supplyAsync(() -> fromURL(core, "https://mc-heads.net/avatar/" + input + "/64"), this.faviconThreadPool);
@@ -134,7 +143,7 @@ public class FaviconHandler<F>{
return;
}
localFavicons.put(path.getFileName().toString().split("\\.")[0], favicon);
localFavicons.put(path.getFileName().toString().toLowerCase(Locale.ROOT), favicon);
logger.info("Loaded file '%s' as Favicon.", path.getFileName().toString());
}catch(IOException ex){
logger.warn("Cannot create Favicon from file '%s'. Encountered IOException.", ex);
@@ -1,7 +1,7 @@
/*
* MIT License
*
* Copyright (c) 2022-2023 Andre_601
* Copyright (c) 2022-2024 Andre_601
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,7 @@
*
*/
package ch.andre601.advancedserverlist.core.profiles.players;
package ch.andre601.advancedserverlist.core.profiles.handlers;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
@@ -66,7 +66,7 @@ public class PlayerHandler{
}
public void load(){
if(!cache.toFile().exists()){
if(!Files.exists(cache)){
logger.info("No playercache.json file present. Skipping...");
return;
}
@@ -82,7 +82,7 @@ public class PlayerHandler{
logger.warn("Encountered IOException while reading the playercache.json file!", ex);
return;
}catch(JsonIOException | JsonSyntaxException ex){
logger.warn("Encountered Json exception while parsing playercache.json file!", ex);
logger.warn("Encountered JsonSyntaxException while parsing playercache.json file!", ex);
return;
}
@@ -114,8 +114,6 @@ public class PlayerHandler{
}catch(IOException ex){
logger.warn("Encountered IOException while saving cached players to playercache.json!", ex);
}
}
public void addPlayer(String ip, String name, UUID uuid){
@@ -36,6 +36,7 @@ import org.spongepowered.configurate.serialize.SerializationException;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
public class ProfileManager{
@@ -44,22 +45,34 @@ public class ProfileManager{
* If the random profile's value is not null will it be used instead of the default one.
*/
public static ProfileEntry merge(ServerListProfile profile){
ProfileEntry entry = profile.getRandomProfile();
ProfileEntry defEntry = profile.defaultProfile();
ProfileEntry entry = profile.getRandomProfile();
List<String> motd = resolveMOTD(entry, defEntry);
List<String> players = resolvePlayers(entry, defEntry);
String playerCountText = resolvePlayerCountText(entry, defEntry);
String favicon = resolveFavicon(entry, defEntry);
boolean isHidePlayersEnabled = resolveHidePlayersEnabled(entry, defEntry);
boolean isExtraPlayersEnabled = resolveExtraPlayersEnabled(entry, defEntry);
boolean isMaxPlayersEnabled = resolveMaxPlayersEnabled(entry, defEntry);
Integer extraPlayersCount = resolveExtraPlayersCount(entry, defEntry);
Integer maxPlayersCount = resolveMaxPlayersCount(entry, defEntry);
List<String> motd = resolve(defEntry, entry, ProfileEntry::motd);
List<String> players = resolve(defEntry, entry, ProfileEntry::players);
String playerCountText = resolve(defEntry, entry, ProfileEntry::playerCountText);
String favicon = resolve(defEntry, entry, ProfileEntry::favicon);
NullBool hidePlayersEnabled = resolve(defEntry, entry, ProfileEntry::hidePlayersEnabled);
NullBool extraPlayersEnabled = resolve(defEntry, entry, ProfileEntry::extraPlayersEnabled);
NullBool maxPlayersEnabled = resolve(defEntry, entry, ProfileEntry::maxPlayersEnabled);
NullBool onlinePlayersEnabled = resolve(defEntry, entry, ProfileEntry::onlinePlayersEnabled);
String extraPlayersCount = resolve(defEntry, entry, ProfileEntry::extraPlayersCount);
String maxPlayersCount = resolve(defEntry, entry, ProfileEntry::maxPlayersCount);
String onlinePlayersCount = resolve(defEntry, entry, ProfileEntry::onlinePlayersCount);
return new ProfileEntry(motd, players, playerCountText, favicon,
NullBool.resolve(isHidePlayersEnabled), NullBool.resolve(isExtraPlayersEnabled), NullBool.resolve(isMaxPlayersEnabled),
extraPlayersCount, maxPlayersCount);
return new ProfileEntry.Builder()
.motd(motd)
.players(players)
.playerCountText(playerCountText)
.favicon(favicon)
.hidePlayersEnabled(hidePlayersEnabled)
.extraPlayersEnabled(extraPlayersEnabled)
.maxPlayersEnabled(maxPlayersEnabled)
.onlinePlayersEnabled(onlinePlayersEnabled)
.extraPlayersCount(extraPlayersCount)
.maxPlayersCount(maxPlayersCount)
.onlinePlayersCount(onlinePlayersCount)
.build();
}
public static ServerListProfile resolveProfile(AdvancedServerList<?> core, GenericPlayer player, GenericServer server){
@@ -67,7 +80,7 @@ public class ProfileManager{
if(profile.isInvalidProfile())
continue;
if(profile.evalConditions(core.getParser(), core.getPlugin().getPluginLogger(), player, server))
if(profile.evalConditions(core, player, server))
return profile;
}
@@ -82,8 +95,10 @@ public class ProfileManager{
NullBool hidePlayers = resolveNullBool(node, "playerCount", "hidePlayers");
NullBool extraPlayersEnabled = resolveNullBool(node, "playerCount", "extraPlayers", "enabled");
NullBool maxPlayersEnabled = resolveNullBool(node, "playerCount", "maxPlayers", "enabled");
Integer extraPlayers = resolveNullableInt(node, "playerCount", "extraPlayers", "amount");
Integer maxPlayers = resolveNullableInt(node, "playerCount", "maxPlayers", "amount");
NullBool onlinePlayersEnabled = resolveNullBool(node, "playerCount", "onlinePlayers", "enabled");
String extraPlayers = resolveNullableString(node, "playerCount", "extraPlayers", "amount");
String maxPlayers = resolveNullableString(node, "playerCount", "maxPlayers", "amount");
String onlinePlayers = resolveNullableString(node, "playerCount", "onlinePlayers", "amount");
return new ProfileEntry.Builder()
.motd(motd)
@@ -93,8 +108,10 @@ public class ProfileManager{
.hidePlayersEnabled(hidePlayers)
.extraPlayersEnabled(extraPlayersEnabled)
.maxPlayersEnabled(maxPlayersEnabled)
.onlinePlayersEnabled(onlinePlayersEnabled)
.extraPlayersCount(extraPlayers)
.maxPlayersCount(maxPlayers)
.onlinePlayersCount(onlinePlayers)
.build();
}
@@ -115,67 +132,11 @@ public class ProfileManager{
return false;
}
private static List<String> resolveMOTD(ProfileEntry profile, ProfileEntry defaultProfile){
if(profile == null || !checkOption(profile.motd()))
return defaultProfile.motd();
private static <T> T resolve(ProfileEntry defProfile, ProfileEntry profile, Function<ProfileEntry, T> function){
if(profile == null || !checkOption(function.apply(profile)))
return function.apply(defProfile);
return profile.motd();
}
private static List<String> resolvePlayers(ProfileEntry profile, ProfileEntry defaultProfile){
if(profile == null || !checkOption(profile.players()))
return defaultProfile.players();
return profile.players();
}
private static String resolvePlayerCountText(ProfileEntry profile, ProfileEntry defaultProfile){
if(profile == null || !checkOption(profile.playerCountText()))
return defaultProfile.playerCountText();
return profile.playerCountText();
}
private static String resolveFavicon(ProfileEntry profile, ProfileEntry defaultProfile){
if(profile == null || !checkOption(profile.favicon()))
return defaultProfile.favicon();
return profile.favicon();
}
private static boolean resolveHidePlayersEnabled(ProfileEntry profile, ProfileEntry defaultProfile){
if(profile == null || !checkOption(profile.hidePlayersEnabled()))
return defaultProfile.hidePlayersEnabled().getOrDefault(false);
return profile.hidePlayersEnabled().getOrDefault(false);
}
private static boolean resolveExtraPlayersEnabled(ProfileEntry profile, ProfileEntry defaultProfile){
if(profile == null || !checkOption(profile.extraPlayersEnabled()))
return defaultProfile.extraPlayersEnabled().getOrDefault(false);
return profile.extraPlayersEnabled().getOrDefault(false);
}
private static boolean resolveMaxPlayersEnabled(ProfileEntry profile, ProfileEntry defaultProfile){
if(profile == null || !checkOption(profile.maxPlayersEnabled()))
return defaultProfile.maxPlayersEnabled().getOrDefault(false);
return profile.maxPlayersEnabled().getOrDefault(false);
}
private static Integer resolveExtraPlayersCount(ProfileEntry profile, ProfileEntry defaultProfile){
if(profile == null || profile.extraPlayersCount() == null)
return defaultProfile.extraPlayersCount() == null ? 0 : defaultProfile.extraPlayersCount();
return profile.extraPlayersCount();
}
private static Integer resolveMaxPlayersCount(ProfileEntry profile, ProfileEntry defaultProfile){
if(profile == null || profile.maxPlayersCount() == null)
return defaultProfile.maxPlayersCount() == null ? 0 : defaultProfile.maxPlayersCount();
return profile.maxPlayersCount();
return function.apply(profile);
}
private static List<String> resolveList(ConfigurationNode node, Object... path){
@@ -193,10 +154,10 @@ public class ProfileManager{
return NullBool.resolve(node.node(path).getBoolean());
}
private static Integer resolveNullableInt(ConfigurationNode node, Object... path){
private static String resolveNullableString(ConfigurationNode node, Object... path){
if(node.node(path).virtual())
return null;
return node.node(path).getInt();
return node.node(path).getString();
}
}
@@ -54,8 +54,10 @@ public class ProfileSerializer implements TypeSerializer<ProfileEntry>{
node.node("favicon").set(profile.favicon());
node.node("playerCount", "hidePlayers").set(profile.hidePlayersEnabled().getOrDefault(false));
node.node("playerCount", "extraPlayers", "enabled").set(profile.extraPlayersEnabled().getOrDefault(false));
node.node("playerCount", "extraPlayers", "amount").set((profile.extraPlayersCount() == null) ? 0 : profile.extraPlayersCount());
node.node("playerCount", "extraPlayers", "amount").set((profile.extraPlayersCount() == null) ? "0" : profile.extraPlayersCount());
node.node("playerCount", "maxPlayers", "enabled").set(profile.maxPlayersEnabled().getOrDefault(false));
node.node("playerCount", "maxPlayers", "amount").set((profile.maxPlayersCount() == null) ? 0 : profile.maxPlayersCount());
node.node("playerCount", "maxPlayers", "amount").set((profile.maxPlayersCount() == null) ? "0" : profile.maxPlayersCount());
node.node("playerCount", "onlinePlayers", "enabled").set(profile.onlinePlayersEnabled().getOrDefault(false));
node.node("playerCount", "onlinePlayers", "amount").set(profile.onlinePlayersCount() == null ? "0" : profile.onlinePlayersCount());
}
}
@@ -64,8 +64,6 @@ public class StringReplacer{
private static String parsePlaceholder0(String input, ParsePosition position, GenericPlayer player, GenericServer server, ParseWarnCollector collector){
AdvancedServerListAPI api = AdvancedServerList.getApi();
int placeholderStart = position.getIndex() - 2;
int index = position.getIndex();
StringBuilder identifier = new StringBuilder();
@@ -113,7 +111,7 @@ public class StringReplacer{
raw.append(' ').append(valuesStr);
if(collector != null)
collector.appendWarningFormatted(placeholderStart, "Placeholder '%s' does not have a closing bracket (})", raw.toString());
collector.appendWarningFormatted(index, "Placeholder '%s' does not have a closing bracket (})", raw.toString());
return raw.toString();
}
@@ -128,7 +126,7 @@ public class StringReplacer{
raw.append('}');
if(collector != null)
collector.appendWarningFormatted(placeholderStart, "Placeholder '%s' does not have any available PlaceholderProvider", raw.toString());
collector.appendWarningFormatted(index, "Placeholder '%s' does not have any available PlaceholderProvider", raw.toString());
return raw.toString();
}
@@ -143,7 +141,7 @@ public class StringReplacer{
raw.append('}');
if(collector != null)
collector.appendWarningFormatted(placeholderStart, "Placeholder '%s' has an invalid value String '%s'", raw.toString(), valuesStr);
collector.appendWarningFormatted(index, "Placeholder '%s' has an invalid value String '%s'", raw.toString(), valuesStr);
return raw.toString();
}
+7 -1
View File
@@ -107,6 +107,12 @@ disableDuringMaintenance:
# Default: true
#
maxPlayers: true
#
# Whether the online players feature should be disabled while Maintenance mode is active.
#
# Default: true
#
onlinePlayers: true
#
# DO NOT EDIT!
@@ -114,4 +120,4 @@ disableDuringMaintenance:
# This is used internally to determine if the config needs to be migrated.
# Changing or even removing this option could result in your config being broken.
#
config-version: ${plugin.config.version}
configVersion: ${plugin.config.version}
@@ -134,6 +134,7 @@ playerCount:
enabled: false
#
# Set the number that should be added to the online player count to then use as the new max player count.
# Placeholders resolving to numbers can be used here.
#
# Example: Setting this to 1 will result in ${server playersMax} displaying 11 while 10 players are online,
# 9 when 8 are online and so on.
@@ -162,9 +163,34 @@ playerCount:
enabled: false
#
# Set the number that should be used as the new max players count.
# Placeholders resolving to numbers can be used here.
#
# If not present, defaults to 0.
#
# Read more: https://asl.andre601.ch/profiles/#maxplayers-amount
#
amount: 0
#
# The onlinePlayers feature allows to set a number to use as the online player count to display.
#
# Read more: https://asl.andre601.ch/profiles/#onlineplayers
#
onlinePlayers:
#
# Set whether the onlinePlayers feature should be enabled or not.
# When set to true, the max player count will be set to the 'amount' value.
#
# If not present, defaults to false.
#
# Read more: https://asl.andre601.ch/profiles/#onlineplayers-enabled
#
enabled: false
#
# Set the number that should be used as the new online players count.
# Placeholders resolving to numbers can be used here.
#
# If not present, defaults to current online player count.
#
# Read more: https://asl.andre601.ch/profiles/#onlineplayers-amount
#
amount: 0
+102 -43
View File
@@ -4,55 +4,34 @@ The BanPlugins Addon was made to provide placeholders for different punishment p
## Placeholders
### AdvancedBan
/// tab | AdvancedBan
[Plugin Page](https://www.spigotmc.org/resources/8695/){ target="_blank" rel="nofollow" }
Placeholders for the plugin [AdvancedBan](https://www.spigotmc.org/resources/8695/){ target="_blank" rel="nofollow" } are available to use.
**Supported Platforms:**
| Placeholder | Description |
|---------------------------------|-------------------------------------------------------------------------------------------|
| `${advancedban isMuted}` | Whether the player is muted or not. |
| `${advancedban muteReason}` | The reason for why the player was muted. Returns invalid placeholder if no mute was set. |
| `${advancedban muteDuration}` | Relative time until the mute expires.[^1] Returns invalid placeholder if no mute was set. |
| `${advancedban muteExpiration}` | Date on when the mute will expire.[^2] |
| `${advancedban isBanned}` | Whether the player is banned or not. |
| `${advancedban banReason}` | The reason for why the player was banned. Returns invalid placeholder if no ban was set. |
| `${advancedban banDuration}` | Relative time until the ban expires.[^3] Returns invalid placeholder if no ban was set. |
| `${advancedban banExpiration}` | Date on when the ban will expire.[^4] |
[^1]:
An optional boolean can be added to set whether the duration should be from the start or not. `false` is the default.
Example: `${advancedban muteDuration true}`
[^2]:
An optional Date and time Pattern can be set to change the displayed output. The default is `dd, MMM yyyy HH:mm:ss`.
Example: `${advancedban muteExpiration yyyy-MM-dd HH:mm:ss}`
[^3]:
An optional boolean can be added to set whether the duration should be from the start or not. `false` is the default.
Example: `${advancedban banDuration true}`
[^4]:
An optional Date and time Pattern can be set to change the displayed output. The default is `dd, MMM yyyy HH:mm:ss`.
Example: `${advancedban banExpiration yyyy-MM-dd HH:mm:ss}`
### LibertyBans
Placeholders for the plugin [LibertyBans](https://modrinth.com/plugin/libertybans/){ target="_blank" rel="nofollow" } are available to use.
- :fontawesome-solid-paper-plane: Paper
- :simple-spigotmc: BungeeCord
| Placeholder | Description |
|---------------------------------|------------------------------------------------------------------------------------------|
| `${libertybans isMuted}` | Whether the player is muted or not. |
| `${libertybans muteReason}` | The reason for why the player was muted. Returns invalid placeholder if no mute was set. |
| `${libertybans muteExpiration}` | Date on when the mute will expire.[^5] |
| `${libertybans isBanned}` | Whether the player is banned or not. |
| `${libertybans banReason}` | The reason for why the player was banned. Returns invalid placeholder if no ban was set. |
| `${libertybans banExpiration}` | Date on when the ban will expire.[^6] |
| `${advancedban isMuted}` | Whether the player is muted or not. |
| `${advancedban muteReason}` | The reason for why the player was muted. Returns invalid placeholder if no mute was set. |
| `${advancedban muteDuration}` | Relative time until the mute expires. Returns invalid placeholder if no mute was set. |
| `${advancedban muteExpiration}` | Date on when the mute will expire- |
| `${advancedban isBanned}` | Whether the player is banned or not. |
| `${advancedban banReason}` | The reason for why the player was banned. Returns invalid placeholder if no ban was set. |
| `${advancedban banDuration}` | Relative time until the ban expires. Returns invalid placeholder if no ban was set. |
| `${advancedban banExpiration}` | Date on when the ban will expire. |
[^5]:
An optional Date and time Pattern can be set to change the displayed output. The default is `dd, MMM yyyy HH:mm:ss`.
Example: `${libertybans muteExpiration yyyy-MM-dd HH:mm:ss}`
[^6]:
An optional Date and time Pattern can be set to change the displayed output. The default is `dd, MMM yyyy HH:mm:ss`.
Example: `${libertybans banExpiration yyyy-MM-dd HH:mm:ss}`
//// note | Notes
- `${advancedban muteDuration}` and `${advancedban banDuration}` accept an optional boolean to set, whether the mute/ban duration should be from the start.
Default is `false`.
- `${advancedban muteExpiration}` and `${advancedban banExpiration}` accept an optional Date and Time pattern to format the time into.
Default is `dd, MMM yyyy HH:mm:ss`.
////
## Example
//// details | Example
type: example
```yaml title="banned.yml"
priority: 1
@@ -61,4 +40,84 @@ condition: '${advancedban isBanned}'
motd:
- '<red>You were <bold>BANNED</bold>!'
- '<red>Expires: <grey>${advancedban banExpiration}'
```
```
////
///
/// tab | LibertyBans
[Plugin Page](https://modrinth.com/plugin/libertybans/){ target="_blank" rel="nofollow" }
**Supported Platforms:**
- :fontawesome-solid-paper-plane: Paper
- :simple-spigotmc: BungeeCord
- :fontawesome-solid-paper-plane: Velocity
| Placeholder | Description |
|---------------------------------|------------------------------------------------------------------------------------------|
| `${libertybans isMuted}` | Whether the player is muted or not. |
| `${libertybans muteReason}` | The reason for why the player was muted. Returns invalid placeholder if no mute was set. |
| `${libertybans muteExpiration}` | Date on when the mute will expire. |
| `${libertybans isBanned}` | Whether the player is banned or not. |
| `${libertybans banReason}` | The reason for why the player was banned. Returns invalid placeholder if no ban was set. |
| `${libertybans banExpiration}` | Date on when the ban will expire. |
//// note | Notes
- `${libertybans muteExpiration}` and `${libertybans banExpiration}` accept an optional Date and Time pattern to format the time into.
Default is `dd, MMM yyyy HH:mm:ss`.
////
//// details | Example
type: example
```yaml title="banned.yml"
priority: 1
condition: '${libertybans isBanned}'
motd:
- '<red>You were <bold>BANNED</bold>!'
- '<red>Expires: <grey>${libertybans banExpiration}'
```
////
///
/// tab | LiteBans
[Plugin Page](https://www.spigotmc.org/resources/3715/){ target="_blank" rel="nofollow" }
**Supported Platforms:**
- :fontawesome-solid-paper-plane: Paper
- :simple-spigotmc: BungeeCord
- :fontawesome-solid-paper-plane: Velocity
| Placeholder | Description |
|------------------------------|------------------------------------------------------------------------------------------|
| `${litebans isMuted}` | Whether the player is muted or not. |
| `${litebans muteReason}` | The reason for why the player was muted. Returns invalid placeholder if no mute was set. |
| `${litebans muteDuration}` | Relative time until the mute expires. Returns invalid placeholder if no mute was set. |
| `${litebans muteExpiration}` | Date on when the mute will expire- |
| `${litebans isBanned}` | Whether the player is banned or not. |
| `${litebans banReason}` | The reason for why the player was banned. Returns invalid placeholder if no ban was set. |
| `${litebans banDuration}` | Relative time until the ban expires. Returns invalid placeholder if no ban was set. |
| `${litebans banExpiration}` | Date on when the ban will expire. |
//// note | Notes
- `${litebans muteExpiration}` and `${litebans banExpiration}` accept an optional Date and Time pattern to format the time into.
Default is `dd, MMM yyyy HH:mm:ss`.
////
//// details | Example
type: example
```yaml title="banned.yml"
priority: 1
condition: '${litebans isBanned}'
motd:
- '<red>You were <bold>BANNED</bold>!'
- '<red>Expires: <grey>${litebans banExpiration}'
```
////
///
+17
View File
@@ -7,6 +7,23 @@ icon: octicons/log-24
This page lists the recent changes made towards the AdvancedServerListAPI.
They are ordered newest to oldest.
## v4.0.0 { #v4.0.0 }
### :octicons-alert-24:{ .changelog-breaking title="Breaking Changes" } Breaking Changes { #v4.0.0-breaking }
- Changed `extraPlayersCount()` and `maxPlayersCount()` from using an Integer to using a String instead.
- This also affects their corresponding `ProfileEntry.Builder` methods.
- Removed all previously deprecated methods.
### :octicons-plus-circle-24:{ .changelog-added title="Added" } Added { #v4.0.0-added }
- New setter methods added to [`ProfileEntry.Builder`][profilentry.builder] class:
- [`onlinePlayersCount(String)`][onlinePlayersCount]
- [`onlinePlayersEnabled(NullBool)`][onlinePlayersEnabled]
[onlinePlayersCount]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#onlineplayerscount(integer)
[onlinePlayersEnabled]: reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md#onlineplayersenabled(nullbool)
## v3.3.0 { #v3.3.0 }
### :octicons-plus-circle-24:{ .changelog-added title="Added" } Added { #v3.3.0-added }
@@ -119,6 +119,34 @@ methods:
throws:
- name: 'IllegalArgumentException'
description: 'Thrown by the <code>CheckUtil</code> in case <code>null</code> has been provided as parameter.'
- name: 'onlinePlayersCount'
description: |
Sets the value to resolve into a number by AdvancedServerList.<br>
Strings not resolving into valid numbers will be treated as this option not being set.
parameters:
- name: 'onlinePlayersCount'
description: 'The number of online players to set.'
type: 'String'
attribute:
- 'nullable'
returns: 'This Builder after the max player count has been set. Useful for chaining.'
- name: 'onlinePlayersEnabled'
description: |
Sets whether the online players feature should be enabled.<br>
<br>
Set to <a href="../../../objects/nullbool/#not_set"><code>NullBool.NOT_SET</code></a> to not set this.<br>
<br>
An <code>IllegalArgumentException</code> may be thrown by the <code>CheckUtil</code> should onlinePlayersEnabled be null.
parameters:
- name: 'onlinePlayersEnabled'
description: 'Whether the extra players feature should be enabled or not.'
type: 'NullBool'
attribute:
- 'notnull'
returns: 'This Builder after the NullBool has been set. Useful for chaining.'
throws:
- name: 'IllegalArgumentException'
description: 'Thrown by the <code>CheckUtil</code> in case <code>null</code> has been provided as parameter.'
- name: 'playerCountText'
description: |
Sets the text to override the player count with.<br>
@@ -155,192 +183,6 @@ methods:
name: 'ProfileEntry'
type: 'object'
link: './..'
#
# Deprecated stuff
#
- name: 'setExtraPlayerCount'
description: |
Sets the number of players to add to the online players to use as the new max players value.<br>
This option has no effect when <a href="../#extraplayersenabled()"><code>extraPlayersEnabled</code></a> is set to <a href="../../objects/nullbool/#false"><code>NullBool.FALSE</code></a> or <a href="../../objects/nullbool/#not_set"><code>NullBool.NOT_SET</code></a>.<br>
<br>
Set this to <code>null</code> to not alter the max player count. Alternatively, set <a href="#setextraplayersenabled(nullbool)"><code>setExtraPlayersEnabled(NullBool)</code></a> to <a href="../../objects/nullbool/#false"><code>NullBool.FALSE</code></a>.
returns: 'This Builder after the extra player count has been set. Useful for chaining.'
parameters:
- name: 'extraPlayersCount'
description: 'The number of extra players to add.'
type: Integer
attribute:
- nullable
deprecated: 'Typo in the name. Use <a href="#setextraplayerscount(integer)">setExtraPlayersCount(Integer)</a> instead.'
type:
name: 'Builder'
type: 'object'
- name: 'setExtraPlayersCount'
description: |
Sets the number of players to add to the online players to use as the new max players value.<br>
This option has no effect when <a href="../#extraplayersenabled()"><code>extraPlayersEnabled</code></a> is set to <a href="../../objects/nullbool/#false"><code>NullBool.FALSE</code></a> or <a href="../../objects/nullbool/#not_set"><code>NullBool.NOT_SET</code></a>.<br>
<br>
Set this to <code>null</code> to not alter the max player count. Alternatively, set <a href="#setextraplayersenabled(nullbool)"><code>setExtraPlayersEnabled(NullBool)</code></a> to <a href="../../objects/nullbool/#false"><code>NullBool.FALSE</code></a>.
returns: 'This Builder after the extra player count has been set. Useful for chaining.'
parameters:
- name: 'extraPlayersCount'
description: 'The number of extra players to add.'
type: Integer
attribute:
- nullable
deprecated: 'Method renamed to fit <a href="..">ProfileEntry</a> record more closely. Use <a href="#extraplayerscount(integer)">extraPlayersCount(Integer)</a> instead.'
type:
name: 'Builder'
type: 'object'
- name: 'setExtraPlayersEnabled'
description: |
Sets whether the extra players feature should be enabled or not.<br>
<br>
Set to <a href="../../objects/nullbool/#not_set"><code>NullBool.NOT_SET</code></a> to not set this.
returns: 'This Builder after the NullBool has been set. Useful for chaining.'
parameters:
- name: 'extraPlayersEnabled'
description: 'Whether the extra players feature should be enabled or not.'
type: NullBool
attribute:
- notnull
deprecated: 'Method renamed to fit <a href="..">ProfileEntry</a> record more closely. Use <a href="#extraplayersenabled(nullbool)">extraPlayersEnabled(NullBool)</a> instead.'
throws:
- name: 'IllegalArgumentException'
description: 'Thrown by the <code>CheckUtil</code> in case <code>null</code> has been provided as parameter.'
type:
name: 'Builder'
type: 'object'
- name: 'setFavicon'
description: |
Sets the value to use for the favicon.<br>
The following values are supported:
<ul>
<li>URL to a valid PNG file.</li>
<li>File name (with <code>.png</code> extension) matching a file saved in the favicons folder of AdvancedServerList.</li>
<li><code>${player uuid}</code> to display the avatar of the player.</li>
</ul>
returns: 'This Builder after the favicon has been set. Useful for chaining.'
parameters:
- name: 'favicon'
description: 'The favicon to set'
type: String
attribute:
- nullable
deprecated: 'Method renamed to fit <a href="..">ProfileEntry</a> record more closely. Use <a href="#favicon(string)">favicon(String)</a> instead.'
type:
name: 'Builder'
type: 'object'
- name: 'setHidePlayersEnabled'
description: |
Sets whether the player count should be hidden or not.<br>
<br>
Set to <a href="../../objects/nullbool/#not_set"><code>NullBool.NOT_SET</code></a> to not set this.
returns: 'This Builder after the NullBool has been set. Useful for chaining.'
parameters:
- name: 'hidePlayersEnabled'
description: 'Whether the player count should be hidden or not.'
type: NullBool
attribute:
- notnull
deprecated: 'Method renamed to fit <a href="..">ProfileEntry</a> record more closely. Use <a href="#hideplayersenabled(nullbool)">hidePlayersEnabled(NullBool)</a> instead.'
throws:
- name: 'IllegalArgumentException'
description: 'Thrown by the <code>CheckUtil</code> in case <code>null</code> has been provided as parameter.'
type:
name: 'Builder'
type: 'object'
- name: 'setMaxPlayersCount'
description: |
Sets the number of max players allowed to join this server.<br>
This option has no effect when <a href="../#maxplayersenabled()"><code>maxPlayersEnabled</code></a> is set to <a href="../../objects/nullbool/#false"><code>NullBool.FALSE</code></a> or <a href="../../objects/nullbool/#not_set"><code>NullBool.NOT_SET</code></a>.<br>
<br>
Set this to <code>null</code> to not alter the max player count. Alternatively, set <a href="#setmaxplayersenabled(nullbool)"><code>setMaxPlayersEnabled(NullBool)</code></a> to <a href="../../objects/nullbool/#false"><code>NullBool.FALSE</code></a>.
returns: 'This Builder after the extra player count has been set. Useful for chaining.'
parameters:
- name: 'maxPlayersCount'
description: 'The number of max players to set.'
type: Integer
attribute:
- nullable
deprecated: 'Method renamed to fit <a href="..">ProfileEntry</a> record more closely. Use <a href="#maxplayerscount(integer)">maxPlayersCount(Integer)</a> instead.'
type:
name: 'Builder'
type: 'object'
- name: 'setMaxPlayersEnabled'
description: |
Sets whether the max players feature should be enabled.<br>
<br>
Set to <a href="../../objects/nullbool/#not_set"><code>NullBool.NOT_SET</code></a> to not set this.
returns: 'This Builder after the NullBool has been set. Useful for chaining.'
parameters:
- name: 'maxPlayersEnabled'
description: 'Whether the extra players feature should be enabled or not.'
type: NullBool
attribute:
- notnull
deprecated: 'Method renamed to fit <a href="..">ProfileEntry</a> record more closely. Use <a href="#maxplayersenabled(nullbool)">maxPlayersEnabled(NullBool)</a> instead.'
throws:
- name: 'IllegalArgumentException'
description: 'Thrown by the <code>CheckUtil</code> in case <code>null</code> has been provided as parameter.'
type:
name: 'Builder'
type: 'object'
- name: 'setMotd'
description: |
Sets a new MOTD to use.<br>
<br>
Set to an empty list to not change the MOTD.<br>
Only the first two entries of the list will be considered and any additional ones discarded.
returns: 'This Builder after the motd has been set. Useful for chaining.'
parameters:
- name: 'motd'
description: 'The MOTD to use.'
type: 'List<String>'
attribute:
- notnull
deprecated: 'Method renamed to fit <a href="..">ProfileEntry</a> record more closely. Use <a href="#motd(string)">motd(String)</a> instead.'
throws:
- name: 'IllegalArgumentException'
description: 'Thrown by the <code>CheckUtil</code> in case <code>null</code> has been provided as parameter.'
type:
name: 'Builder'
type: 'object'
- name: 'setPlayerCountText'
description: |
Sets the text to override the player count with.<br>
<br>
Set to an empty String or <code>null</code> to not alter the player count text.
returns: 'This Builder after the player count text has been set. Useful for chaining.'
parameters:
- name: 'playerCountText'
description: 'The text to show in the player count.'
type: String
attribute:
- nullable
deprecated: 'Method renamed to fit <a href="..">ProfileEntry</a> record more closely. Use <a href="#playercounttext(string)">playerCountText(String)</a> instead.'
type:
name: 'Builder'
type: 'object'
- name: 'setPlayers'
description: |
Sets the players (lines) to use for the hover.<br>
<br>
Set to an empty list to not change the hover text.
returns: 'This Builder after the players have been set. Useful for chaining.'
parameters:
- name: 'players'
description: 'The lines to set for the hover.'
type: 'List<String>'
attribute:
- notnull
deprecated: 'Method renamed to fit <a href="..">ProfileEntry</a> record more closely. Use <a href="#players(list<string>)">players(List&lt;String&gt;)</a> instead.'
throws:
- name: 'IllegalArgumentException'
description: 'Thrown by the <code>CheckUtil</code> in case <code>null</code> has been provided as parameter.'
type:
name: 'Builder'
type: 'object'
---
# <api__class></api__class> Builder
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

+11 -8
View File
@@ -1,5 +1,7 @@
document$.subscribe(async () => {
const url = 'https://codeberg-stats-proxy.vercel.app'
const url = 'https://api.allorigins.win/raw?url='
const apiUrl = `https://api.allorigins.win/raw?url=${encodeURIComponent('https://codeberg.org/api/v1/repos/Andre601/asl-api/releases/latest')}`
const repo_stats = document.querySelector('[data-md-component="source"] .md-source__repository');
function loadCodebergInfo(data) {
@@ -45,10 +47,11 @@ document$.subscribe(async () => {
}
async function fetchApiInfo() {
const tag = await fetch(`${url}/api/latest-release`).then(_ => _.json());
const tag = await fetch(`${apiUrl}`)
.then(_ => _.json());
const data = {
"version": tag.name
"version": tag.tag_name
};
__md_set("__api_tag", data, sessionStorage);
@@ -57,14 +60,14 @@ document$.subscribe(async () => {
async function fetchInfo() {
const [release, repo] = await Promise.all([
fetch(`${url}/repo/latest-release`).then(_ => _.json()),
fetch(`${url}/repo/stats`).then(_ => _.json()),
fetch(`${url}${encodeURIComponent('https://codeberg.org/api/v1/repos/Andre601/AdvancedServerList/releases/latest')}`).then(_ => _.json()),
fetch(`${url}${encodeURIComponent('https://codeberg.org/api/v1/repos/Andre601/AdvancedServerList')}`).then(_ => _.json()),
]);
const data = {
"version": release.name,
"stars": repo.stars,
"forks": repo.forks
"version": release.tag_name,
"stars": repo.stars_count,
"forks": repo.forks_count
};
__md_set("__git_repo", data, sessionStorage);
+26 -13
View File
@@ -19,40 +19,53 @@ The following subcommands are available (Subcommands are case-insensitive):
- [`reload`](#reload)
- [`clearCache`](#clearcache)
- [`migrate <plugin>`](#migrate)
- [`profiles <add <profile> | copy <profile> <name> | list>`](#profiles)
### help
### `help`
/// info |
**Permission:** `advancedserverlist.command.help`
Shows a list of all available [subcommands](#subcommands) for AdvancedServerList.
///
### reload
----
### `reload`
/// info |
**Permission:** `advancedserverlist.command.reload`
Reloads the plugin's `config.yml` and all available YAML files in the `profiles` folder.
///
### clearCache
----
### `clearcache`
/// info |
**Permission:** `advancedserverlist.command.clearcache`
Clears the currently cached favicons and players.
///
### migrate &lt;plugin&gt; { #migrate }
----
### `migrate <plugin>` { #migrate }
/// info |
**Permission:** `advancedserverlist.command.migrate`
**Arguments:
**Arguments:**
- `<plugin>` - The plugin to migrate from.
Migrates files from one plugin over to AdvancedServerList.
Check the [Migration Page](../migration/index.md) for a list of supported plugins.
///
----
### `profiles <add <profile> | copy <profile> <name> | list>` { #profiles }
**Permission:** `advancedserverlist.command.profiles`
**Arguments:**
- `add <profile>` - Creates a new profile with name `<profile>` using the default profile values.
- `copy <profile> <name>` - Creates a copy of `<profile>` and saves it as `<name>`.
- `list` - Lists all loaded profiles. The entries have hover text for extra info.
Creates, copies or shows profiles in AdvancedServerList.
+6 -8
View File
@@ -502,16 +502,14 @@ motd:
### Additional profiles
To add additional profiles, create a new YAML file inside the `profiles` folder. The name can be whatever you like, but it is recommended to keep it simple and only use alphanumeric characters (`a-z` and `0-9`), underlines and hyphens.
Additional profiles can be created to display different content under specific situations. To create a new file, either manually create a YAML file in the `profiles` folder, or use [`/asl profiles add <name>`](../commands/index.md#profiles) to have one created for you. In either case is it recommended to only use alphanummeric (`a-z` abd `0-9`) characters, dashes and underscores for the file name. You should also choose a name that fits the purpose of the file (i.e. for a profile that displays stuff when someone is banned, name it `banned.yml`).
Inside the file, add a priority and at least one setting, similar to the above shown example.
This would already be enough to have a valid profile, but depending on the priority and file name may the file not be used, or used over other profiles.
In case you manually created a YAML file, make sure it contains the [`priority`](../profiles/index.md#priority) setting and one of the other settings, to have a valid profile.
You should also add a [`condition`](../profiles/index.md#condition) to ensure that the profile is only loaded when needed. The [Expressions page](../profiles/expressions.md) covers what counts as valid expressions and conditions.
Do note that the plugin goes through the profiles in order of priority, starting with the highest number first, picking the first one that returns a `condition` returning true.
If you want to only show this file under specific situations can you use the [`condition`](../profiles/index.md#condition) option to apply conditions that need to be met to show the profile.
The condition option would have a single String containing one or multiple [Expressions](../profiles/expressions.md). Only if the condition would return true, would the profile be displayed, granted that it has a higher priority than any other valid file with a true condition output.
/// info | Note
Files without a condition or an empty condition will be treated as always having a true condition.
/// info | Note about Condition
The Condition option, if not set or empty, will always return true.
///
Here is another example profile using conditions to show it when the player was banned on the server:
+7 -1
View File
@@ -11,11 +11,17 @@ These pages may include important information about the migration process and wh
<div class="grid cards" markdown>
- [**MiniMOTD**](minimotd.md)
----
Migrate from the Plugin [MiniMOTD](https://github.com/jpenilla/MiniMOTD){ target="_blank" rel="nofollow" }
- [**ServerListPlus**](serverlistplus.md)
----
Migrate from the Plugin [ServerListPlus](https://github.com/Minecrell/ServerListPlus).
Migrate from the Plugin [ServerListPlus](https://github.com/Minecrell/ServerListPlus){ target="_blank" rel="nofollow" }.
</div>
+100
View File
@@ -0,0 +1,100 @@
---
icon: octicons/arrow-right-24
---
Version `4.10.0` added support for migrating your existing `main.conf` configuration from MiniMOTD to AdvancedServerList.
## Important Notes
- MiniMOTD does not need to be present on the server/proxy to migrate its files. Only the `main.conf` file needs to be available.
- The plugin will **only** migrate the `main.conf` file. No other files will be migrated.
## How to Migrate
Execute the command [`/asl migrate minimotd`](../commands/index.md#migrate) to start the migration process. Make sure the `main.conf` file is present in `/plugins/MiniMOTD/` (`minimotd-velocity` on Velocity).
## Example
Below can you find a full example of a `main.conf` file and the corresponding migrated files from AdvancedServerList:
/// tab | :octicons-file-code-24: main.conf
```conf
icon-enabled=true
motd-enabled=true
motds=[
{
icon=random
line1="<rainbow>MiniMOTD Default"
line2="MiniMessage <gradient:blue:red>Gradients"
},
{
icon=random
line1="<blue>Another <bold><red>MOTD"
line2="<italic><underlined><gradient:red:green>much wow"
}
]
player-count-settings {
allow-exceeding-maximum=false
disable-player-list-hover=false
fake-players {
fake-players="25%"
fake-players-enabled=false
}
hide-player-count=false
just-x-more-settings {
just-x-more-enabled=false
x-value=3
}
max-players=69
max-players-enabled=true
servers=[]
}
```
///
/// tab | :octicons-file-code-24: minimotd_migrated.yml
```yaml
priority: 0
profiles:
- motd:
- <rainbow>MiniMOTD Default
- MiniMessage <gradient:blue:red>Gradients
playerCount:
hover: []
text: ''
hidePlayers: false
extraPlayers:
enabled: false
amount: 0
maxPlayers:
enabled: false
amount: 0
favicon: ''
- motd:
- <blue>Another <bold><red>MOTD
- <italic><underlined><gradient:red:green>much wow
playerCount:
hover: []
text: ''
hidePlayers: false
extraPlayers:
enabled: false
amount: 0
maxPlayers:
enabled: false
amount: 0
favicon: ''
motd: []
playerCount:
hover: []
text: ''
hidePlayers: false
extraPlayers:
enabled: false
amount: 3
maxPlayers:
enabled: true
amount: 69
favicon: ''
```
///
+1 -1
View File
@@ -13,7 +13,7 @@ This is due to AdvancedServerList using the internal API of ServerListPlus to re
## Conversions
Specific values within the ServerListPlus configuration will be converted into equivalents supported by AdvancedServerListPlus.
Specific values within the ServerListPlus configuration will be converted into equivalents supported by AdvancedServerList.
### Placeholders
+4 -2
View File
@@ -16,6 +16,8 @@ You can find the tool at https://webui.advntr.dev/
Please make sure to surround your text with either single quotes (`'`) or double quotes (`"`).
This avoids possible issues where the YAML parser would treat lines starting with specific characters as special options (i.e. `<` would be treated as a scolar value).
Also, should your text contain single quotes (for example when using `you're`), either surround the text with double quotes, or change the single quote in your text into two single quotes (`you're -> you''re`).
```yaml title="Wrong formatting"
motd:
- <red>This will cause
@@ -24,8 +26,8 @@ motd:
```yaml title="Right formatting"
motd:
- '<green>This will be formatted'
- '<green>properly.'
- "<green>This will be formatted"
- "<green>properly."
```
## Unsupported options
+48 -5
View File
@@ -127,7 +127,7 @@ The Value can be one of three possible options, each being checked for in order:
Note that for the name/UUID, the site https://mc-heads.net is being used.
Use the URL option with the `${player uuid}` placeholder if you want to use another service.
/// details | Example
type: example
@@ -161,7 +161,7 @@ When set to true will the player count be replaced with `???`.
In addition are the [`playerCount -> text`](#text) and [`playerCount -> hover`](#hover) options ignored.
If you want to not show any text at all, set this option to `false` (or remove it) and instead use the [`playerCount -> text`](#text) option.
/// details | Example
type: example
@@ -227,7 +227,7 @@ Please take note of the following caveats:
If you want to not show any text, just use a single color (i.e. `text: '<grey>'`) to do so.
This option only supports basic colors and no HEX colors.
/// details | Example
type: example
@@ -267,7 +267,9 @@ Use the [`playerCount -> extraPlayers -> amount`](#extraplayers-amount) option t
The `playerCount -> extraPlayers -> amount` option defines how much should be added to the current online player count to then use as max player count.
Example: Setting this option to `1` while currently 10 players are online will result in `10/11` being displayed on the player count (Assuming it is not being overriden by the [`playerCount -> text`](#text) option).
You can use placeholders that resolve into numbers for this option.
/// details | Example
type: example
@@ -309,7 +311,9 @@ Use the [`playerCount -> maxPlayers -> amount`](#maxplayers-amount) option to se
The `playerCount -> maxPlayers -> amount` option defines the number to use as the server's max players count.
Unlike the [`playerCount -> extraPlayers -> amount`](#extraplayers-amount) option does this one not first add the current online player count to the number to then set.
You can use placeholders that resolve into numbers for this option.
/// details | Example
type: example
@@ -330,5 +334,44 @@ playerCount:
![maxplayers-example](../assets/images/examples/maxplayers-example.jpg){ loading="lazy" }
</div>
///
### OnlinePlayers
<!-- admo:warning Using this option alters the output of <code>playerCount -> extraPlayers</code> -->
The `playerCount -> onlinePlayers` option contains settings to enable and set the number of players online on the server.
#### Enabled { #onlineplayers-enabled }
Enables the online players feature.
Use the [`playerCount -> onlinePlayers -> amount`](#onlineplayers-amount) option to set the online players value itself.
#### Amount { #onlineplayers-amount }
Sets the number to display as the server's only player count.
You can use placeholders that resolve into numbers for this option.
/// details | Example
type: example
```yaml title="YAML file
priority: 0
# Hides the MOTD for demonstration purposes
motd:
- '<grey>'
- '<grey>'
playerCount:
onlinePlayers:
enabled: true
amount: 10
```
<div class="result" markdown>
![onlineplayers-example](../assets/images/examples/onlineplayers-example.png)
</div>
///
+28 -2
View File
@@ -11,7 +11,7 @@ It also has built-in [PlaceholderAPI support](#placeholderapi) for Spigot and Pa
The following placeholders are available in AdvancedServerList itself. Please note that not all placeholders are available on all platforms.
### Player Placeholders
### Player
These placeholders use the player who pinged the server, to return values. They may require the player to be cached in order to work.
@@ -44,7 +44,8 @@ These placeholders use values given by the server/proxy AdvancedServerList runs
[^4]:
A comma-separated list of world (On Paper) or Server (On BungeeCord/Velocity) names can be provided to display the added numbers of players in these worlds/servers.
**Example:** `${server playersOnline lobby1,lobby2}` will display the collective numbers of players in the servers `lobby1` and `lobby2`.
**Example:** `${server playersOnline lobby1,lobby2}` will display the collective numbers of players in the servers `lobby1` and `lobby2`.
Using the [onlinePlayers' `amount`](index.md#onlineplayers-amount) option will modify the output of this placeholder, except when used in [`condition`](index.md#condition).
[^5]:
Using either the [extraPlayers' `amount`](index.md#extraplayers-amount) or [maxPlayers' `amount`](index.md#maxplayers-amount) option will make this placeholder return the modified max players count.
Only exception to this rule is when the placeholder is used in the [`condition`](index.md#condition) option in which case it returns the actual max player count of the proxy/server.
@@ -52,6 +53,31 @@ These placeholders use values given by the server/proxy AdvancedServerList runs
An optional server name can be provided to display the IP/Domain associated with that server. This only works on BungeeCord or Velocity.
**Example:** `${server host survival}` would display the IP/Domain associated with the `survival` server.
### Proxy
These placeholders are only available on the BungeeCord and Velocity versions of AdvancedServerList.
/// note
Servers are pinged every 10 seconds by the plugin and cached for that time period.
///
| Placeholders | Description | Default[^7] |
|------------------------------|-------------------------------------------------------------------|-------------|
| `${proxy status <name>}` | Returns `online` or `offline` based on the Server's availability. | `offline` |
| `${proxy motd <name>}` | Returns the Server's MOTD as MiniMessage String. | `none` |
| `${proxy players <name>}` | Returns the number of online Players on the Server. | `0` |
| `${proxy maxPlayers <name>}` | Returns the max number of Players allowed to join the Server. | `0` |
[^7]: The default value returned, should the Server or parts of it not be available.
### Maintenance
These placeholders require the [Maintenance](https://hangar.papermc.io/kennytv/Maintenance) plugin to work.
| Placeholder | Description |
|-------------------------------------|----------------------------------------------------------------|
| `${maintenance maintenanceEnabled}` | Returns whether the Global maintenance mode is enabled or not. |
## PlaceholderAPI
Please visit the [PlaceholderAPI page](../placeholderapi/index.md) for how AdvancedServerList works with PlaceholderAPI.
+2 -1
View File
@@ -119,6 +119,7 @@ nav:
- Migration:
- migration/index.md
- Other Plugins:
- MiniMOTD: migration/minimotd.md
- ServerListPlus: migration/serverlistplus.md
- AdvancedServerList:
- v3.8.0 to v3.9.0: migration/v3_8_0-to-v3_9_0.md
@@ -147,7 +148,7 @@ nav:
- api/reference/api/ch.andre601.advancedserverlist.api/objects/genericserver.md
- api/reference/api/ch.andre601.advancedserverlist.api/objects/nullbool.md
- profiles:
- '<api__record></api__record> ProfileEntry':
- ProfileEntry:
- api/reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/index.md
- api/reference/api/ch.andre601.advancedserverlist.api/profiles/profileentry/builder.md
- platform-bukkit:
+26 -7
View File
@@ -46,7 +46,7 @@
<repositories>
<repository>
<id>papermc</id>
<url>https://papermc.io/repo/repository/maven-public/</url>
<url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
<repository>
<id>placeholderapi-repo</id>
@@ -59,6 +59,7 @@
</repositories>
<dependencies>
<!-- AdvancedServerList -->
<dependency>
<groupId>ch.andre601.advancedserverlist</groupId>
<artifactId>core</artifactId>
@@ -71,30 +72,44 @@
<version>${api.version}</version>
<scope>compile</scope>
</dependency>
<!-- Paper API -->
<dependency>
<groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.21-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<!-- bStats -->
<dependency>
<groupId>org.bstats</groupId>
<artifactId>bstats-bukkit</artifactId>
<version>3.0.2</version>
<version>3.1.0</version>
<scope>compile</scope>
</dependency>
<!-- Plugins -->
<dependency>
<groupId>me.clip</groupId>
<artifactId>placeholderapi</artifactId>
<version>2.11.5</version>
<version>2.11.6</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.viaversion</groupId>
<artifactId>viaversion-api</artifactId>
<version>4.10.2</version>
<version>5.0.3</version>
<scope>provided</scope>
</dependency>
<!-- Other -->
<dependency>
<groupId>com.alessiodp.libby</groupId>
<artifactId>libby-paper</artifactId>
<version>2.0.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
@@ -117,13 +132,17 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.3</version>
<version>3.6.0</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
<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.alessiodp.libby</pattern>
<shadedPattern>ch.andre601.advancedserverlist.paper.depends.libby</shadedPattern>
</relocation>
</relocations>
<filters>
@@ -28,7 +28,7 @@ package ch.andre601.advancedserverlist.paper;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
import ch.andre601.advancedserverlist.core.profiles.favicon.FaviconHandler;
import ch.andre601.advancedserverlist.core.profiles.handlers.FaviconHandler;
import ch.andre601.advancedserverlist.paper.commands.CmdAdvancedServerList;
import ch.andre601.advancedserverlist.paper.listeners.LoadEvent;
import ch.andre601.advancedserverlist.paper.logging.PaperLogger;
@@ -36,6 +36,9 @@ import ch.andre601.advancedserverlist.paper.objects.WorldCache;
import ch.andre601.advancedserverlist.paper.objects.placeholders.PAPIPlaceholders;
import ch.andre601.advancedserverlist.paper.objects.placeholders.PaperPlayerPlaceholders;
import ch.andre601.advancedserverlist.paper.objects.placeholders.PaperServerPlaceholders;
import com.alessiodp.libby.Library;
import com.alessiodp.libby.PaperLibraryManager;
import io.papermc.paper.ServerBuildInfo;
import org.bstats.bukkit.Metrics;
import org.bstats.charts.SimplePie;
import org.bukkit.Bukkit;
@@ -49,6 +52,7 @@ import java.awt.image.BufferedImage;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.OptionalInt;
public class PaperCore extends JavaPlugin implements PluginCore<CachedServerIcon>{
@@ -59,6 +63,8 @@ public class PaperCore extends JavaPlugin implements PluginCore<CachedServerIcon
private PAPIPlaceholders papiPlaceholders = null;
private WorldCache worldCache = null;
private PaperLibraryManager libraryManager = null;
@Override
public void onEnable(){
try{
@@ -126,6 +132,28 @@ public class PaperCore extends JavaPlugin implements PluginCore<CachedServerIcon
faviconHandler.cleanCache();
}
@Override
public void downloadLibrary(String groupId, String artifactId, String version){
if(libraryManager == null){
libraryManager = new PaperLibraryManager(this);
libraryManager.addRepository("https://repo.papermc.io/repository/maven-public");
}
Library lib = Library.builder()
.groupId(groupId)
.artifactId(artifactId)
.version(version)
.resolveTransitiveDependencies(true)
.build();
libraryManager.loadLibrary(lib);
}
@Override
public void startScheduler(){
// Unused
}
@Override
public AdvancedServerList<CachedServerIcon> getCore(){
return core;
@@ -150,13 +178,14 @@ public class PaperCore extends JavaPlugin implements PluginCore<CachedServerIcon
}
@Override
public String getPlatformName(){
return getServer().getName();
}
@Override
public String getPlatformVersion(){
return getServer().getVersion();
public String getPlatformInfo(){
try{
Class.forName("io.papermc.paper.ServerBuildInfo");
return getNewVersion();
}catch(ClassNotFoundException ignored){
// Old Paper versions (Before 16th of May 2024)
return getOldVersion();
}
}
@Override
@@ -216,4 +245,22 @@ public class PaperCore extends JavaPlugin implements PluginCore<CachedServerIcon
Bukkit.getPluginManager().disablePlugin(this);
}
private String getNewVersion(){
ServerBuildInfo info = ServerBuildInfo.buildInfo();
String name = info.brandName();
String id = info.brandId().asString();
String version = info.minecraftVersionName();
OptionalInt build = info.buildNumber();
if(build.isEmpty())
return String.format("%s (%s, Version: %s)", name, id, version);
return String.format("%s (ID: %s, Version: %s, Build: %d)", name, id, version, build.getAsInt());
}
private String getOldVersion(){
return getServer().getName() + " " + getServer().getVersion();
}
}
@@ -28,7 +28,7 @@ package ch.andre601.advancedserverlist.paper.listeners;
import ch.andre601.advancedserverlist.api.events.GenericServerListEvent;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import ch.andre601.advancedserverlist.core.events.PingEventHandler;
import ch.andre601.advancedserverlist.core.compat.maintenance.MaintenanceUtil;
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
import ch.andre601.advancedserverlist.core.interfaces.events.GenericEventWrapper;
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
@@ -48,6 +48,8 @@ import org.bukkit.util.CachedServerIcon;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.function.Function;
public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon, PaperPlayerImpl>{
@@ -72,6 +74,11 @@ public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon,
event.setMaxPlayers(maxPlayers);
}
@Override
public void setOnlinePlayers(int onlinePlayers){
event.setNumPlayers(onlinePlayers);
}
@Override
public void setMotd(Component component){
event.motd(component);
@@ -90,24 +97,13 @@ public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon,
@Override
public void setPlayers(List<String> lines, PaperPlayerImpl player, GenericServer server){
event.getPlayerSample().clear();
List<PlayerProfile> players = new ArrayList<>(lines.size());
for(String line : lines){
String parsed = ComponentParser.text(line)
.modifyText(text -> StringReplacer.replace(text, player, server))
.modifyText(text -> {
if(plugin.getServer().getPluginManager().isPluginEnabled("PlaceholderAPI"))
return PlaceholderAPI.setPlaceholders(player.getPlayer(), text);
return text;
})
.toString();
players.add(FakePlayerProfile.create(parsed));
try{
event.getListedPlayers();
setListedPlayers(lines, player, server);
}catch(NoSuchMethodError ex){
// Version before latest 1.20.6 builds(?)
setPlayerSample(lines, player, server);
}
event.getPlayerSample().addAll(players);
}
@Override
@@ -135,7 +131,7 @@ public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon,
if(!Bukkit.getPluginManager().isPluginEnabled("Maintenance"))
return false;
return PingEventHandler.getMaintenanceUtil().isMaintenanceEnabled();
return MaintenanceUtil.get().isMaintenanceEnabled();
}
@Override
@@ -187,4 +183,34 @@ public class PaperEventWrapper implements GenericEventWrapper<CachedServerIcon,
public GenericServer createGenericServer(int playersOnline, int playersMax, String host){
return new PaperServerImpl(plugin.getWorldCache().worlds(), playersOnline, playersMax, host);
}
private void setListedPlayers(List<String> lines, PaperPlayerImpl player, GenericServer server){
event.getListedPlayers().clear();
List<PaperServerListPingEvent.ListedPlayerInfo> playerList = getPlayerList(lines, player, server,
text -> new PaperServerListPingEvent.ListedPlayerInfo(text, UUID.randomUUID()));
event.getListedPlayers().addAll(playerList);
}
@SuppressWarnings({"Deprecation", "removal"})
private void setPlayerSample(List<String> lines, PaperPlayerImpl player, GenericServer server){
event.getPlayerSample().clear();
List<PlayerProfile> playerProfiles = getPlayerList(lines, player, server, FakePlayerProfile::create);
event.getPlayerSample().addAll(playerProfiles);
}
private <T> List<T> getPlayerList(List<String> lines, PaperPlayerImpl player, GenericServer server, Function<String, T> function){
List<T> playerList = new ArrayList<>(lines.size());
for(String line : lines){
String parsed = ComponentParser.text(line)
.modifyText(text -> StringReplacer.replace(text, player, server))
.modifyText(text -> parsePAPIPlaceholders(text, player))
.toString();
playerList.add(function.apply(parsed));
}
return playerList;
}
}
@@ -70,7 +70,7 @@ public record FakePlayerProfile(String name, UUID uuid) implements PlayerProfile
@Override
public @NotNull PlayerTextures getTextures(){
return new FakePlayeerTextures();
return new FakePlayerTextures();
}
@Override
@@ -153,7 +153,7 @@ public record FakePlayerProfile(String name, UUID uuid) implements PlayerProfile
return Collections.emptyMap();
}
private static record FakePlayeerTextures() implements PlayerTextures{
private record FakePlayerTextures() implements PlayerTextures{
@Override
public boolean isEmpty(){
@@ -27,12 +27,18 @@ package ch.andre601.advancedserverlist.paper.objects.impl;
import ch.andre601.advancedserverlist.api.bukkit.objects.BukkitPlayer;
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
import ch.andre601.advancedserverlist.core.profiles.players.GenericPlayerImpl;
import org.bukkit.OfflinePlayer;
public class PaperPlayerImpl extends GenericPlayerImpl implements BukkitPlayer{
import java.util.UUID;
public class PaperPlayerImpl implements BukkitPlayer{
private final OfflinePlayer player;
private final String name;
private int protocol;
private final UUID uuid;
private boolean playedBefore = false;
private boolean banned = false;
private boolean whitelisted = false;
@@ -52,6 +58,21 @@ public class PaperPlayerImpl extends GenericPlayerImpl implements BukkitPlayer{
this.whitelisted = player.isWhitelisted();
}
@Override
public String getName(){
return name;
}
@Override
public int getProtocol(){
return protocol;
}
@Override
public UUID getUUID(){
return uuid;
}
@Override
public OfflinePlayer getPlayer(){
return player;
@@ -94,16 +94,22 @@ public class PAPIPlaceholders extends PlaceholderExpansion{
ProfileEntry entry = ProfileManager.merge(profile);
Integer onlinePlayers = null;
if(ProfileManager.checkOption(entry.onlinePlayersEnabled())){
onlinePlayers = parseNumberOption(entry.onlinePlayersCount(), pl, player, server);
online = onlinePlayers == null ? online : onlinePlayers;
}
Integer maxPlayers = null;
if(ProfileManager.checkOption(entry.maxPlayersEnabled())){
max = entry.maxPlayersCount() == null ? 0 : entry.maxPlayersCount();
maxPlayers = entry.maxPlayersCount();
maxPlayers = parseNumberOption(entry.maxPlayersCount(), pl, player, server);
max = maxPlayers == null ? 0 : maxPlayers;
}
Integer extraPlayers = null;
if(ProfileManager.checkOption(entry.extraPlayersEnabled())){
max = online + (entry.extraPlayersCount() == null ? 0 : entry.extraPlayersCount());
extraPlayers = entry.extraPlayersCount();
extraPlayers = parseNumberOption(entry.extraPlayersCount(), pl, player, server);
max = online + (extraPlayers == null ? 0 : extraPlayers);
}
BukkitServer finalServer = new PaperServerImpl(plugin.getWorldCache().worlds(), online, max, host);
@@ -114,6 +120,7 @@ public class PAPIPlaceholders extends PlaceholderExpansion{
case "playercount_text" -> getOption(entry.playerCountText(), pl, player, finalServer);
case "playercount_extraplayers" -> extraPlayers == null ? "null" : String.valueOf(extraPlayers);
case "playercount_maxplayers" -> maxPlayers == null ? "null" : String.valueOf(maxPlayers);
case "playercount_onlineplayers" -> onlinePlayers == null ? "null" : String.valueOf(onlinePlayers);
case "server_playersmax" -> String.valueOf(max);
default -> null;
};
@@ -134,8 +141,21 @@ public class PAPIPlaceholders extends PlaceholderExpansion{
private String getOption(List<String> list, Player pl, BukkitPlayer player, BukkitServer server){
return ComponentParser.list(list)
.modifyText(text -> PlaceholderAPI.setPlaceholders(pl, text))
.modifyText(text -> StringReplacer.replace(text, player, server))
.modifyText(text -> PlaceholderAPI.setPlaceholders(pl, text))
.toString();
}
private Integer parseNumberOption(String option, Player pl, BukkitPlayer player, BukkitServer server){
String parsed = ComponentParser.text(option)
.modifyText(text -> StringReplacer.replace(text, player, server))
.modifyText(text -> PlaceholderAPI.setPlaceholders(pl, text))
.toString();
try{
return Integer.parseInt(parsed);
}catch(NumberFormatException ex){
return null;
}
}
}
@@ -73,19 +73,19 @@ public class PaperServerPlaceholders extends PlaceholderProvider{
}
case "playersMax" -> {
if(args.length >= 2)
yield null;
yield "";
yield String.valueOf(paperServer.getPlayersMax());
}
case "host" -> {
if(args.length >= 2)
yield null;
yield "";
yield paperServer.getHost();
}
case "whitelistEnabled" -> {
if(args.length >= 2)
yield null;
yield "";
yield String.valueOf(Bukkit.hasWhitelist());
}
+7 -3
View File
@@ -37,15 +37,15 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<plugin.version>4.8.0</plugin.version>
<plugin.version>5.0.4</plugin.version>
<plugin.description>Create multiple Server lists based on conditions.</plugin.description>
<api.version>3.3.0</api.version>
<api.version>4.0.0</api.version>
<dependency.adventure-api>4.17.0</dependency.adventure-api>
<dependency.adventure-text-minimessage>4.17.0</dependency.adventure-text-minimessage>
<dependency.adventure-text-serializer-legacy>4.17.0</dependency.adventure-text-serializer-legacy>
<dependency.adventure-platform-bungeecord>4.3.2</dependency.adventure-platform-bungeecord>
<dependency.adventure-platform-bungeecord>4.3.4</dependency.adventure-platform-bungeecord>
<dependency.configurate-yaml>4.1.2</dependency.configurate-yaml>
<maven.compiler.source>16</maven.compiler.source>
@@ -61,6 +61,10 @@
<id>codeberg</id>
<url>https://codeberg.org/api/packages/Andre601/maven/</url>
</repository>
<repository>
<id>sonatype-snapshots</id>
<url>https://s01.oss.sonatype.org/content/repositories/snapshots/</url>
</repository>
</repositories>
<modules>
+42 -8
View File
@@ -7,17 +7,18 @@
],
"packageRules": [
{
"description": "Use Jitpack registry for AdvancedBan",
"description": "Use Jitpack registry for various Libs",
"matchPackageNames": [
"com.github.DevLeoko:AdvancedBan",
"com.github.LeonMangler:PremiumVanishAPI"
"com.github.LeonMangler:PremiumVanishAPI",
"com.gitlab.ruany:LiteBansAPI"
],
"registryUrls": [
"https://jitpack.io"
]
},
{
"description": "Use Codeberg packages for asl-api",
"description": "Use Codeberg packages for Own API stuff",
"matchPackageNames": [
"ch.andre601.asl-api:api",
"ch.andre601.asl-api:parent",
@@ -30,6 +31,44 @@
"https://codeberg.org/api/packages/Andre601/maven"
]
},
{
"description": "Use Paper Repo for Paper API",
"matchPackageNames": [
"io.papermc.paper:paper-api"
],
"registryUrls": [
"https://papermc.io/repo/repository/maven-public"
]
},
{
"description": "Use PlaceholderAPI Repo for PlaceholderAPI",
"matchPackageNames": [
"me.clip:placeholderapi"
],
"registryUrls": [
"https://repo.extendedclip.com/content/repositories/placeholderapi"
]
},
{
"description": "Use ViaVersion Repo for ViaVersion",
"matchPackageNames": [
"com.viaversion:viaversion-api"
],
"registryUrls": [
"https://repo.viaversion.com"
]
},
{
"description": "Use Sonatype for Libby",
"matchPackageNames": [
"com.alessiodp.libby:libby-bungee",
"com.alessiodp.libby:libby-paper",
"com.alessiodp.libby:libby-velocity"
],
"registryUrls": [
"https://s01.oss.sonatype.org/content/repositories/snapshots/"
]
},
{
"description": "Apply label for Bukkit platform",
"matchFileNames": ["bukkit/pom.xml"],
@@ -50,11 +89,6 @@
"matchFileNames": ["velocity/pom.xml"],
"addLabels": ["PR Target/Velocity"]
},
{
"description": "Apply label for GitHub Actions",
"matchFileNames": [".github/workflows/*.yml"],
"addLabels": ["PR Target/GitHub Action"]
},
{
"description": "Apply label for MkDocs",
"matchFileNames": ["requirements.txt"],
+1 -1
View File
@@ -1,3 +1,3 @@
mkdocs-material==9.5.21
mkdocs-material==9.5.39
mkdocs-glightbox==0.4.0
git+https://github.com/Andre601/mkdocs-pagenav-generator
+15 -3
View File
@@ -46,7 +46,7 @@
<repositories>
<repository>
<id>velocity-repo</id>
<url>https://papermc.io/repo/repository/maven-public/</url>
<url>https://repo.papermc.io/repository/maven-public/</url>
</repository>
</repositories>
@@ -76,7 +76,7 @@
<dependency>
<groupId>org.bstats</groupId>
<artifactId>bstats-velocity</artifactId>
<version>3.0.2</version>
<version>3.1.0</version>
<scope>compile</scope>
</dependency>
@@ -95,6 +95,14 @@
<version>2.9.0-4</version>
<scope>provided</scope>
</dependency>
<!-- Other -->
<dependency>
<groupId>com.alessiodp.libby</groupId>
<artifactId>libby-velocity</artifactId>
<version>2.0.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
@@ -114,7 +122,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.3</version>
<version>3.6.0</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
@@ -122,6 +130,10 @@
<pattern>org.bstats</pattern>
<shadedPattern>ch.andre601.advancedserverlist.velocity.depends.bstats</shadedPattern>
</relocation>
<relocation>
<pattern>com.alessiodp.libby</pattern>
<shadedPattern>ch.andre601.advancedserverlist.velocity.depends.libby</shadedPattern>
</relocation>
</relocations>
<filters>
<filter>
@@ -28,13 +28,16 @@ package ch.andre601.advancedserverlist.velocity;
import ch.andre601.advancedserverlist.core.AdvancedServerList;
import ch.andre601.advancedserverlist.core.interfaces.PluginLogger;
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
import ch.andre601.advancedserverlist.core.profiles.favicon.FaviconHandler;
import ch.andre601.advancedserverlist.core.profiles.handlers.FaviconHandler;
import ch.andre601.advancedserverlist.velocity.commands.CmdAdvancedServerList;
import ch.andre601.advancedserverlist.velocity.listeners.JoinEvent;
import ch.andre601.advancedserverlist.velocity.listeners.PingEvent;
import ch.andre601.advancedserverlist.velocity.logging.VelocityLogger;
import ch.andre601.advancedserverlist.velocity.objects.placeholders.VelocityPlayerPlaceholders;
import ch.andre601.advancedserverlist.velocity.objects.placeholders.VelocityProxyPlaceholders;
import ch.andre601.advancedserverlist.velocity.objects.placeholders.VelocityServerPlaceholders;
import com.alessiodp.libby.Library;
import com.alessiodp.libby.VelocityLibraryManager;
import com.google.inject.Inject;
import com.velocitypowered.api.command.CommandMeta;
import com.velocitypowered.api.event.Subscribe;
@@ -44,10 +47,13 @@ import com.velocitypowered.api.plugin.annotation.DataDirectory;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.proxy.server.ServerPing;
import com.velocitypowered.api.scheduler.ScheduledTask;
import com.velocitypowered.api.util.Favicon;
import de.myzelyam.api.vanish.VelocityVanishAPI;
import org.bstats.charts.SimplePie;
import org.bstats.velocity.Metrics;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.awt.image.BufferedImage;
@@ -55,10 +61,16 @@ import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
public class VelocityCore implements PluginCore<Favicon>{
private final PluginLogger logger;
private final Logger logger = LoggerFactory.getLogger("AdvancedServerList");
private final Map<String, ServerPing> fetchedServers = new ConcurrentHashMap<>();
private final PluginLogger pluginLogger;
private final ProxyServer proxy;
private final Path path;
private final Metrics.Factory metrics;
@@ -66,9 +78,13 @@ public class VelocityCore implements PluginCore<Favicon>{
private AdvancedServerList<Favicon> core;
private FaviconHandler<Favicon> faviconHandler = null;
private VelocityLibraryManager<VelocityCore> libraryManager = null;
private ScheduledTask scheduledTask = null;
@Inject
public VelocityCore(ProxyServer proxy, @DataDirectory Path path, Metrics.Factory metrics){
this.logger = new VelocityLogger(this, LoggerFactory.getLogger("AdvancedServerList"));
this.pluginLogger = new VelocityLogger(this, this.logger);
this.proxy = proxy;
this.path = path;
@@ -77,12 +93,15 @@ public class VelocityCore implements PluginCore<Favicon>{
@Subscribe
public void init(ProxyInitializeEvent event){
this.core = AdvancedServerList.init(this, VelocityPlayerPlaceholders.init(), VelocityServerPlaceholders.init(this));
this.core = AdvancedServerList.init(this,
VelocityPlayerPlaceholders.init(), VelocityServerPlaceholders.init(this), VelocityProxyPlaceholders.init(this));
}
@Subscribe
public void pluginDisable(ProxyShutdownEvent event){
core.disable();
if(scheduledTask != null)
scheduledTask.cancel();
}
@Override
@@ -121,6 +140,30 @@ public class VelocityCore implements PluginCore<Favicon>{
faviconHandler.cleanCache();
}
@Override
public void downloadLibrary(String groupId, String artifactId, String version){
if(libraryManager == null){
libraryManager = new VelocityLibraryManager<>(this, this.logger, getFolderPath(), getProxy().getPluginManager());
libraryManager.addRepository("https://repo.papermc.io/repository/maven-public");
}
Library lib = Library.builder()
.groupId(groupId)
.artifactId(artifactId)
.version(version)
.resolveTransitiveDependencies(true)
.build();
libraryManager.loadLibrary(lib);
}
@Override
public void startScheduler(){
scheduledTask = getProxy().getScheduler().buildTask(this, this::fetchServers)
.repeat(10, TimeUnit.SECONDS)
.schedule();
}
@Override
public AdvancedServerList<Favicon> getCore(){
return core;
@@ -133,7 +176,7 @@ public class VelocityCore implements PluginCore<Favicon>{
@Override
public PluginLogger getPluginLogger(){
return logger;
return pluginLogger;
}
@Override
@@ -145,13 +188,8 @@ public class VelocityCore implements PluginCore<Favicon>{
}
@Override
public String getPlatformName(){
return getProxy().getVersion().getName();
}
@Override
public String getPlatformVersion(){
return getProxy().getVersion().getVersion();
public String getPlatformInfo(){
return getProxy().getVersion().getName() + " " + getProxy().getVersion().getVersion();
}
@Override
@@ -189,4 +227,18 @@ public class VelocityCore implements PluginCore<Favicon>{
return players.size();
}
public Map<String, ServerPing> getFetchedServers(){
return fetchedServers;
}
private void fetchServers(){
fetchedServers.clear();
getProxy().getAllServers().forEach(server -> server.ping().whenComplete((ping, throwable) -> {
if(throwable != null)
return;
fetchedServers.put(server.getServerInfo().getName(), ping);
}));
}
}
@@ -28,7 +28,8 @@ package ch.andre601.advancedserverlist.velocity.listeners;
import ch.andre601.advancedserverlist.api.events.GenericServerListEvent;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.api.profiles.ProfileEntry;
import ch.andre601.advancedserverlist.core.events.PingEventHandler;
import ch.andre601.advancedserverlist.core.compat.maintenance.MaintenanceUtil;
import ch.andre601.advancedserverlist.core.compat.papi.PAPIUtil;
import ch.andre601.advancedserverlist.core.interfaces.core.PluginCore;
import ch.andre601.advancedserverlist.core.interfaces.events.GenericEventWrapper;
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
@@ -44,7 +45,10 @@ import com.velocitypowered.api.proxy.server.ServerPing;
import com.velocitypowered.api.util.Favicon;
import net.kyori.adventure.text.Component;
import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
public class VelocityEventWrapper implements GenericEventWrapper<Favicon, VelocityPlayerImpl>{
@@ -78,6 +82,11 @@ public class VelocityEventWrapper implements GenericEventWrapper<Favicon, Veloci
builder.maximumPlayers(maxPlayers);
}
@Override
public void setOnlinePlayers(int onlinePlayers){
builder.onlinePlayers(onlinePlayers);
}
@Override
public void setMotd(Component component){
builder.description(component);
@@ -100,6 +109,7 @@ public class VelocityEventWrapper implements GenericEventWrapper<Favicon, Veloci
for(int i = 0; i < players.length; i++){
String parsed = ComponentParser.text(lines.get(i))
.modifyText(text -> StringReplacer.replace(text, player, server))
.modifyText(text -> parsePAPIPlaceholders(text, player))
.toString();
players[i] = new ServerPing.SamplePlayer(parsed, UUID.randomUUID());
@@ -133,7 +143,7 @@ public class VelocityEventWrapper implements GenericEventWrapper<Favicon, Veloci
if(!plugin.getProxy().getPluginManager().isLoaded("maintenance"))
return false;
return PingEventHandler.getMaintenanceUtil().isMaintenanceEnabled();
return MaintenanceUtil.get().isMaintenanceEnabled();
}
@Override
@@ -165,10 +175,10 @@ public class VelocityEventWrapper implements GenericEventWrapper<Favicon, Veloci
if(!plugin.getProxy().getPluginManager().isLoaded("papiproxybridge"))
return text;
if(!PingEventHandler.getPAPIUtil().isCompatible())
if(!PAPIUtil.get().isCompatible())
return text;
String server = PingEventHandler.getPAPIUtil().getServer();
String server = PAPIUtil.get().getServer();
if(server == null || server.isEmpty())
return text;
@@ -176,11 +186,11 @@ public class VelocityEventWrapper implements GenericEventWrapper<Favicon, Veloci
if(registeredServer == null || registeredServer.getPlayersConnected().isEmpty())
return text;
Player carrier = PingEventHandler.getPAPIUtil().getPlayer(registeredServer.getPlayersConnected());
Player carrier = PAPIUtil.get().getPlayer(registeredServer.getPlayersConnected());
if(carrier == null)
return text;
return PingEventHandler.getPAPIUtil().parse(text, carrier.getUniqueId(), player.getUUID());
return PAPIUtil.get().parse(text, carrier.getUniqueId(), player.getUUID());
}
@Override
@@ -27,10 +27,15 @@ package ch.andre601.advancedserverlist.velocity.objects.impl;
import ch.andre601.advancedserverlist.api.velocity.objects.VelocityPlayer;
import ch.andre601.advancedserverlist.core.objects.CachedPlayer;
import ch.andre601.advancedserverlist.core.profiles.players.GenericPlayerImpl;
import com.velocitypowered.api.network.ProtocolVersion;
public class VelocityPlayerImpl extends GenericPlayerImpl implements VelocityPlayer{
import java.util.UUID;
public class VelocityPlayerImpl implements VelocityPlayer{
private final String name;
private final int protocol;
private final UUID uuid;
private final String version;
@@ -41,6 +46,21 @@ public class VelocityPlayerImpl extends GenericPlayerImpl implements VelocityPla
this.version = ProtocolVersion.getProtocolVersion(protocol).getVersionIntroducedIn();
}
@Override
public String getName(){
return name;
}
@Override
public int getProtocol(){
return protocol;
}
@Override
public UUID getUUID(){
return uuid;
}
@Override
public String getVersion(){
return version;
@@ -0,0 +1,62 @@
package ch.andre601.advancedserverlist.velocity.objects.placeholders;
import ch.andre601.advancedserverlist.api.PlaceholderProvider;
import ch.andre601.advancedserverlist.api.objects.GenericPlayer;
import ch.andre601.advancedserverlist.api.objects.GenericServer;
import ch.andre601.advancedserverlist.core.parsing.ComponentParser;
import ch.andre601.advancedserverlist.velocity.VelocityCore;
import com.velocitypowered.api.proxy.server.ServerPing;
public class VelocityProxyPlaceholders extends PlaceholderProvider{
private final VelocityCore plugin;
private VelocityProxyPlaceholders(VelocityCore plugin){
super("proxy");
this.plugin = plugin;
}
public static VelocityProxyPlaceholders init(VelocityCore plugin){
return new VelocityProxyPlaceholders(plugin);
}
@Override
public String parsePlaceholder(String placeholder, GenericPlayer player, GenericServer server){
String[] args = placeholder.split("\\s", 2);
if(args.length < 2)
return null;
ServerPing ping = plugin.getFetchedServers().get(args[1]);
return switch(args[0]){
case "status" -> ping == null ? "offline" : "online";
case "motd" -> {
if(ping == null)
yield "none";
yield ComponentParser.toMMString(ping.getDescriptionComponent());
}
case "players" -> {
if(ping == null)
yield "0";
ServerPing.Players players = ping.getPlayers().orElse(null);
if(players == null)
yield "0";
yield String.valueOf(players.getOnline());
}
case "maxPlayers" -> {
if(ping == null)
yield "0";
ServerPing.Players players = ping.getPlayers().orElse(null);
if(players == null)
yield "0";
yield String.valueOf(players.getMax());
}
default -> null;
};
}
}
@@ -80,18 +80,18 @@ public class VelocityServerPlaceholders extends PlaceholderProvider{
}
case "playersMax" -> {
if(args.length >= 2)
yield null;
yield "";
yield String.valueOf(proxy.getPlayersMax());
}
case "host" -> {
if(args.length > 2)
yield null;
yield "";
if(args.length == 2){
if(args.length == 2 && args[1] != null && !args[1].isEmpty()){
RegisteredServer info = proxy.getServers().get(args[1]);
if(info == null)
yield null;
yield "";
yield info.getServerInfo().getAddress().getHostString();
}
+6 -6
View File
@@ -46,19 +46,19 @@
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
<version>2.11.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.5.6</version>
<version>1.5.8</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.3.1</version>
<version>5.4</version>
<scope>compile</scope>
</dependency>
<dependency>
@@ -70,7 +70,7 @@
<dependency>
<groupId>dev.masecla</groupId>
<artifactId>Modrinth4J</artifactId>
<version>2.0.0</version>
<version>2.2.0</version>
<scope>compile</scope>
</dependency>
<dependency>
@@ -101,7 +101,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.4.1</version>
<version>3.4.2</version>
<configuration>
<archive>
<manifest>
@@ -115,7 +115,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.3</version>
<version>3.6.0</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
@@ -53,7 +53,7 @@ public class VersionUploader{
if(args.length == 0){
LOGGER.warn("MISSING ARGUMENT!");
LOGGER.warn("COMMAND USAGE: java -jar VersionUploader.jar [--dryrun] --all | --modrinth | --hangar");
LOGGER.warn("COMMAND USAGE: java -jar VersionUploader.jar --all | --modrinth | --hangar [--dryrun]");
System.exit(1);
return;
}
@@ -84,7 +84,7 @@ public class VersionUploader{
}
default -> {
LOGGER.warn("Unknown argument '{}' provided.", args[0]);
LOGGER.warn("COMMAND USAGE: java -jar VersionUploader.jar [--dryrun] --all | --modrinth | --hangar");
LOGGER.warn("COMMAND USAGE: java -jar VersionUploader.jar --all | --modrinth | --hangar [--dryrun]");
System.exit(1);
return;
}
@@ -50,9 +50,9 @@ public class CodebergReleaseFetcher{
public static CodebergRelease fetch(){
String tag = System.getenv("CI_COMMIT_TAG");
String codbergToken = System.getenv("CODEBERG_API_TOKEN");
String codebergToken = System.getenv("CODEBERG_API_TOKEN");
if(tag == null || codbergToken == null || tag.isEmpty() || codbergToken.isEmpty()){
if(tag == null || codebergToken == null || tag.isEmpty() || codebergToken.isEmpty()){
LOGGER.warn("Cannot fetch release data. Either Tag or Codeberg token was null/empty.");
return null;
}
@@ -64,7 +64,7 @@ public class CodebergReleaseFetcher{
.url(url)
.header("User-Agent", "VersionUploader-CodebergReleaseFetcher/v1.0.0")
.header("Accept", "application/json")
.header("Authorization", "token " + codbergToken)
.header("Authorization", "token " + codebergToken)
.build();
try(Response response = CLIENT.newCall(request).execute()){
@@ -130,8 +130,8 @@ public class HangarVersionUploader{
Platform.VELOCITY, velocityDependencies
),
Map.of(
Platform.PAPER, List.of("1.20.x"),
Platform.WATERFALL, List.of("1.19.x", "1.20.x"),
Platform.PAPER, List.of("1.20.x", "1.21"),
Platform.WATERFALL, List.of("1.19.x", "1.20.x", "1.21"),
Platform.VELOCITY, Collections.singletonList("3.2")
),
changelog.replaceAll("\r\n", "\n"),
@@ -25,8 +25,8 @@
package ch.andre601.advancedserverlist.versionuploader.modrinth;
import ch.andre601.advancedserverlist.versionuploader.ReleaseHolder;
import ch.andre601.advancedserverlist.versionuploader.PlatformInfo;
import ch.andre601.advancedserverlist.versionuploader.ReleaseHolder;
import ch.andre601.advancedserverlist.versionuploader.VersionUploader;
import ch.andre601.advancedserverlist.versionuploader.data.CodebergRelease;
import com.google.gson.Gson;
@@ -55,7 +55,7 @@ public class ModrinthVersionUploader{
PlatformInfo.VELOCITY
);
private final List<String> versions = List.of(
"1.20", "1.20.1", "1.20.2", "1.20.3", "1.20.4", "1.20.5", "1.20.6"
"1.20", "1.20.1", "1.20.2", "1.20.3", "1.20.4", "1.20.5", "1.20.6", "1.21"
);
private final ModrinthAPI api;
@@ -143,7 +143,8 @@ public class ModrinthVersionUploader{
String url = versionUrl + projectVersion.getId();
logger.info("Created new release!");
logger.info("Link: {}", url);
logger.info("Link: {}", url);
logger.info("Platform: {}", platforms.get(index).getPlatform());
releaseHolder.addRelease(
"modrinth",